pax_global_header00006660000000000000000000000064122454676760014535gustar00rootroot0000000000000052 comment=dcde6b9ac3314ff282975efd05aec53d94a8bccf libzorpll-3.9.4.1/000077500000000000000000000000001224546767600137225ustar00rootroot00000000000000libzorpll-3.9.4.1/.cvsignore000066400000000000000000000003361224546767600157240ustar00rootroot00000000000000zorplibconfig.h.in zorplibconfig.h stamp-h.in stamp-h libtool configure config.status config.log config.cache aclocal.m4 Makefile.in Makefile zorplibll.pc config.guess config.sub install-sh ltmain.sh missing mkinstalldirs libzorpll-3.9.4.1/.gitignore000066400000000000000000000005211224546767600157100ustar00rootroot00000000000000Makefile.in .project .cproject .pydevproject .settings *.sw? \#* *~ *.rej *.orig aclocal.m4 autom4te.cache/ config.guess config.sub configure configure.in debian/Makefile.in depcomp install-sh ltmain.sh m4/ missing mkinstalldirs INSTALL semantic.cache scripts/Makefile.in src/Makefile.in src/zorp/Makefile.in src/zorp/zorplibconfig.h.in libzorpll-3.9.4.1/AUTHORS000066400000000000000000000001671224546767600147760ustar00rootroot00000000000000This library was written by the people who authored Zorp itself, please see the AUTHORS file in the Zorp distribution. libzorpll-3.9.4.1/COPYING000066400000000000000000000360571224546767600147700ustar00rootroot00000000000000Use of this library is defined by the terms of the GNU GPL version 2, or by the terms of BalaBit's commercial licence at your option. A copy of the GNU GPL version 2 is included here as a reference, BalaBit's commercial licence resides in the root of the Zorp installation CD. 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 libzorpll-3.9.4.1/Makefile.am000066400000000000000000000002641224546767600157600ustar00rootroot00000000000000SUBDIRS = src tests scripts ACLOCAL_AMFLAGS= -I m4 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = zorplibll.pc EXTRA_DIST = dist.conf ${pkgconfig_DATA} makefile.msc VERSION libzorpll-3.9.4.1/NEWS000066400000000000000000000001521224546767600144170ustar00rootroot00000000000000There's no separate NEWS file for libzorpll, user visible changes are documented in the Zorp source tree. libzorpll-3.9.4.1/README000066400000000000000000000001271224546767600146020ustar00rootroot00000000000000This library contains the low level routines that Zorp and related software depend on. libzorpll-3.9.4.1/TODO000066400000000000000000000000001224546767600144000ustar00rootroot00000000000000libzorpll-3.9.4.1/VERSION000066400000000000000000000000101224546767600147610ustar00rootroot000000000000003.9.4.1 libzorpll-3.9.4.1/archived-changelogs/000077500000000000000000000000001224546767600176175ustar00rootroot00000000000000libzorpll-3.9.4.1/archived-changelogs/3.0/000077500000000000000000000000001224546767600201175ustar00rootroot00000000000000libzorpll-3.9.4.1/archived-changelogs/3.0/ChangeLog000066400000000000000000002020231224546767600216700ustar00rootroot000000000000002006-03-20 Balazs Scheidler * VERSION: bumped to 3.0.6.5.1 * src/thread.c (z_thread_init): query the value for RLIMIT_STACK and use g_thread_create_full() to specify stack size, it does not work for thread pools (fixes: #8587) 2006-02-23 Pal Tamas * src/makefile.msc: Added instruction to add pdb file to windows package. * winbuild/build.bat.in: Both normal and dbg package contain the debug symbols in the debug directory. Removed unnecessery CR's. Fixed exit's parameter. 2006-02-23 Balazs Scheidler * src/ssl.c (z_ssl_session_unref): check if self is NULL, (z_ssl_session_new): fixed heap corruption on win32 as the store passed from the caller is not to be used as self->crl_store as it will definitely cause a segfault 2006-02-10 Simon Gabor * src/zorp/log.h: z_enter(), z_leave(), z_cp() are now wrappers around z_session_*(), so unified handling is possible, these latter functions do the indenting itself * src/log.h: indentation helper function z_log_trace_indent() added * src/misc.c: duplicate code from z_data_dump() and z_format_data_dup() separated into z_hexdump(), the last (partial) line of the dump is also aligned 2006-02-09 Balazs Scheidler * src/ssl.c (z_ssl_session_free): fixed compile error in last leak fix (fixes: #7458), (z_ssl_password): fixed warnings on unused arguments 2006-02-08 Attila SZALAY * src/ssl.c (z_ssl_session_free): Free crl_store. (fixes: #7458) * debian/control.in: Added zlib1g-dev build dependency. (fixes: #7460) 2005-12-06 Balazs Scheidler * configure.in: bumped version number to 3.0.6.4.2 * src/ssl.c (z_ssl_session_new): don't make the CRL directory verification fatal (fixes: #7556) 2005-12-06 Simon Gabor * src/process.c: null value of pidfile handled in z_process_daemonize (fixes #6725) 2005-12-05 Balazs Scheidler * configure.in: bumped to 3.0.6.4.1 2005-12-05 Simon Gabor * src/process.c (z_process_daemonize): the daemon process now runs in the dir of the pidfile (fixes #6725) 2005-12-02 Attila SZALAY * src/ssl.c (z_ssl_destroy): Do not frees mutexes, because threads might need them after z_ssl_destroy. (fixes: nobug) * src/ssl.c (z_ssl_password): New function. Log a message when password needed to loading a keyfile. (fixes: #7656) (z_ssl_session_new): Set password loader. (fixes: #7656) * src/ssl.c (z_ssl_password): Fixed return value. (z_ssl_password): Raise log level into CORE_ERROR 1. 2005-12-02 Balazs Scheidler * src/ssl.c (z_ssl_session_new): added access checks and log messages in case of failure when a CA/CRL directory cannot be used (fixes: #7556) 2005-12-02 Balazs Scheidler * src/connect.c (z_io_connect_new): added a log message when z_bind() fails 2005-11-24 Balazs Scheidler * src/misc.c (z_zorplib_version_info): increase local buf to 512 bytes as the version string did not fit. 2005-11-03 Balazs Scheidler * configure.in: bumped to 3.0.6.4 2005-10-07 Simon Gabor * lib/error.c, lib/zorp/error.h: typo fixed in win-specific code (fixes #6444) * lib/zorp/error.h: added another missing constant in the win-specific code (fixes #6444) * src/zorp/error.h, src/streamfd.h: On win32 now fails with error message instead of silently covering the error (fixes #6444) 2005-09-26 Balazs Scheidler * configure.in: bumped to 3.0.6.3.1 2005-09-26 Attila SZALAY * connect.c (z_io_connect_cancel): Unlock the connect lock before calling g_source_destroy. (fixes: #6615) 2005-09-26 SZALAY Attila * configure.in: Added -Werror to CFLAGS when compiled without debug. * *.c: Fixed some compilation warnings. (fixes: #5267) 2005-09-26 Balazs Scheidler * src/streamfd.c (z_stream_fd_ctrl_method): fixed typo & warning in parentheses 2005-09-20 Attila SZALAY * lib/log.c: Fixes some signedness problem. (fixes: nobug) * configure.in: Keep version number between recompiles. (fixes: nobug) * configure.in: Disable crypt in FreeBSD because crypt.h no found. Use own crypt implementation instead. * src/socket.c: Define MAGIC_FAMILY_NUMBER instead of using fix 999 as magic family number. Change this number to 111 to fit unsigned short (fixes: nobug) * src/zorp/io.h: Mark unused parameters as unused. (fixes: nobug) 2005-09-20 Krisztian Kovacs * src/stackdump.c: don't compile stackdump-related functions unless ZORPLIB_ENABLE_STACKDUMP is true (fixes: #6979) 2005-09-20 Balazs Scheidler * src/error.c (z_errno_translate): added support for ENOTSOCK (fixes: #6444) * src/streamfd.c (z_stream_fd_ctrl_method): use z_errno_is for error detection, accept ENOTSOCK error as not-broken (fixes: #6444) * src/stream.h (z_stream_broken): new function, returns whether connection identified by the specified stream is broken * src/streamfd.c (z_stream_fd_ctrl_method): add support for Z_CTRL_GET_BROKEN message, and use recv and MSG_PEEK to determine whether the connection was broken 2005-08-17 Balazs Scheidler * configure.in: bumped to 3.0.6.3 2005-08-05 Balazs Scheidler * src/log.h (z_log_data_dump): new function backported from 3.1 needed by the ZCode backport * src/misc.c (z_format_data_dump): -"- * src/ssl.c (z_ssl_verify_crl): fixed a possible EVP_PKEY reference leak 2005-07-29 Balazs Scheidler * configure.in: bumped to 3.0.6.2.1 2005-07-29 Attila SZALAY * src/connect.c, src/io.c: Fixed some documentation issue. * src/misc.c (z_charset_parse): Fixed state machine to be able to enable \ char. (fixes: #6661) * tests/test_valid_chars.c: Created testcases for charset validation. 2005-07-29 Simon Gabor * configure.in: checking of zlib1g-dev added (fixes #6464) 2005-04-26 SZALAY Attila * Bumped to version 3.0.6.2 2005-04-13 ABONYI Balint * makefile.msc, winbuild/build.bat.in: fixed compiler error handling in zbs (fixes: #6612) 2005-04-10 SZALAY Attila * Bumped to test version 3.0.6.1.1 2005-04-06 Balazs Scheidler * src/log.c (z_send_syslog): implement log message escaping, (z_log_init): understand ZLF_ESCAPE and enable log message escaping if that bit is present * src/zorp/log.h: added ZLF_ESCAPE, fixed the value for ZLF_WINDEBUG 2005-03-31 SZALAY Attila * Bumped to version 3.0.6.1 2005-03-03 SZALAY Attila * Bumped to version 3.0.6.0.4 2005-03-03 Balazs Scheidler * src/misc.c: added case insensitive hash functions 2005-03-03 ABONYI Balint * added EADDRINUSE to win32 defines (as WSAEADDRINUSE) * src/log.c: added loglevel checking to zorplib under win32 (fixes: #5844) 2005-02-28 Balazs Scheidler * src/connect.c (z_io_connect_start_internal): fixed Cannot connect error message as it displayed the same string for both the local and remote endpoints * src/sockaddr.c (z_sockaddr_inet_bind_prepare): do not set SO_REUSEADDR for ZSF_LOOSE_BIND binds (fixes: #1088) * src/socket.c (z_do_ll_bind): only loop bind() calls if errno == EADDRINUSE (e.g. the port is reserved) (fixes: #1088) * src/log.c (z_log_init): store initial logspec to the log_spec_str (fixes: #4667) 2005-02-28 ABONYI Balint * src/streamfd.c: fixed winsock event creation and destroy, now only one per stream (fixes: #6303) 2005-02-28 Balazs Scheidler * src/ssl.c, src/stackdump.c: fixed three strict-aliasing warnings (fixes: #6195) * src/zorp/zobject.h (z_object_check_compatible): added G_GNUC_UNUSED to the class parameter 2005-02-28 Attila SZALAY * src/random.c: Return with FALSE when dev/(u|)random cannot opened. (fixes: #4879) * lib/memtrace.c: Memory allocation will be traced only if an eniroment variable is set. (fixes: #5829) * *.c: Fixed some compilation warning. (fixes: #5267) * random.c, sockaddr.c: Fixed signedness and size problems. (fixes: #5267) 2005-02-25 Sandor Geller * zorplibll.spec: renamed the libzorpll-devel RPM package to libzorpll-dev (fixes: #6343), fixed branching problems in dev packages (fixes: #6343) 2005-02-18 Sandor Geller * solbuild/*: from now we create two packages, ZOSlibzll and ZOSzlldev; ZOSlibzll contains the stripped libzorpll library, ZOSzlldev contains the headers and the static library * configure.in: solbuild/pkginfo replaced with solbuild/pkginfo.lib and solbuild/pkginfo.dev files 2005-02-08 ABONYI Balint * version info in rc files can be only 4 numbers long, it is now trimmed to this lengths. * Added winbuild to libzorpll. 2005-02-02 Balazs Scheidler * src/connect.c (ZIORealConnect): changed structure to avoid possible strict-aliasing problem, instead of listing the same members in the ZIOConnect and ZIORealConnect structures, ZIORealConnect uses ZIOConnect and all references are updatedaccordingly. * src/listen.c (ZIORealListen): -"- * src/zorp/zobject.h (ZClass): changed the type for funcs field to ZObjectFuncs to make it possible to avoid casts when statically initializing ZClass structures. (fixes: #6124) * src/*.c: adapted to the ZClass change (fixes: #6124) 2005-01-29 SZALAY Attila * src/log.c (z_log_spec_init): Check if logspec_str NULL. 2005-01-28 SZALAY Attila * Bumped to version 3.0.6.0.2 2005-01-28 Sandor Geller * configure.in: set ZORPLIBLL_VERSION to (initial) VERSION, pkgconfig works again 2005-01-27 SZALAY Attila * Bumped to version 3.0.6.0.1 2005-01-27 Sandor Geller * Makefile.am: added zorplibll.spec to EXTRA_DIST * zorplibll.spec.in: created (fixes: #6005) * configure.in: updated according to the configure.in in the libzas package; added zorplibll.spec to the list of the generated files * debian/Makefile.am, debian/control.in, debian/libzorpll.shlibs.in.in, solbuild/rules.conf.in, src/Makefile.am: updated to use the new exported variables * debian/control.in: changed the name of the dbg package from libzorpll-dbg to libzorpll3.0.5-dbg * renamed debian/rules to debian/rules.in * debian/rules.in: changed libzorpll-dbg to libzorpll@BINARY_BRANCH@-dbg * debian/Makefile.am: added rules to the generated files 2005-01-25 Balazs Scheidler * src/log.c (z_log_enabled_len): cached values are stored in the mapped_tags cache under the protection of the lock to avoid a possible race which would cause an invalid value to be cached, the other part which causes some messages to be written/dropped because of the changing log-spec is not protected by the same lock but its effects are not so severe (fixes: #5392), (z_log_change_logspec): store the unparsed string form of a logspec to make it possible retrieve it later (fixes: #5392) * src/log.c (z_log_clear_caches): also zerofill the maptag cache (fixes: #5392) * src/log.c (ZLogSpec, ZLogSpecItem): new structures to represent parsed --log-spec argument, (various globals): made them static, their access is restricted through a couple of new functions (z_log_change_* and friends) (z_log_spec_init, z_log_spec_destroy, z_log_spec_eval): new functions to work on the new representation of ZLogSpec, (fixes: #5392) (z_log_enabled_len): renamed z_log_enabled with an addition length parameter, added support for maptag cache, and the new ZLogSpec representation (fixes: #5392) * src/log.h: removed Zorp specific defines, added z_log_enabled() macro for source compatibility (fixes: #5392) * src/log.c (z_log_change_verbose_level, z_log_change_logspec): new functions to change logging options at run-time (fixes: #4667) 2005-01-06 SZALAY Attila * Bumped to version 3.0.5.3 * src/zobject.c (z_object_is_subclass): fixed compatibility check for non-debug builds. 2004-12-22 Balazs Scheidler * Bumped to version 3.0.5.2 2004-12-21 SZALAY Attila * Bumped to version 3.0.5.1.2 * src/zorp/io.h: Fixed dummy definition of z_fd_get_peer_tos, z_fd_get_our_tos and z_fd_set_our_tos, because empty defines cannot be used in ifs. * Bumped to version 3.0.5.1.1 2004-12-14 Balazs Scheidler * src/log.c (z_send_syslog): do not append a trailing \0 character to log messages (fixes: #5623) 2004-12-14 ABONYI Balint * src/ssl.c: fixed a g_snprintf in z_ssl_get_error_str (fixes: #5843) 2004-12-08 Sandor Geller * debian/control.in: changed Provide and Conflict from libzorpll* to virtual-libzorpll*, binary branches no more provide libzorpll3.0.5 package. (fixes: #5770) * debian/control.in: added versioned libzorpll* dependency to the libzorpll*dbg package. (fixes: #5770) * debian/control.in: changed provided and conflicting package names from libzorpll-dev to virtual-libzorpll-dev. (fixes: #5770) 2004-12-03 Attila SZALAY * lib/memtrace.c (z_malloc): Fixed the order of value assign and using it's value. (fixes: #5290) * configure.in: Set enable-debug to false by default. 2004-10-22 Marton Illes * src/*.c: log message updates 2004-10-19 bazsi * Bumped to version 3.0.5.1 2004-10-14 Balazs Scheidler * Bumped to version 3.0.5.0.4 2004-10-13 Balazs Scheidler * configure.in: added detection code for SOL_IP, IP_PKTOPTIONS and IP_RECVTOS, also added --enable-tos argument and autodetection code which defines ZORPLIB_ENABLE_TOS if the results are positive (fixes: #5234) 2004-10-12 SZALAY Attila * Bumped to version 3.0.5.0.3 2004-10-08 Balazs Scheidler * src/io.c (z_fd_get_peer_tos): fixed CMSG iteration, the buffer length was set to 1 instead of the value returned by the kernel * Bumped to version 3.0.5.0.2 * src/listen.c, src/connect.c: finalized arguments, session_id is first, everything else follows 2004-10-07 SZALAY Attila * Bumped to version 3.0.5.0.1 2004-10-07 Balazs Scheidler * src/connect.c: added ToS handling * src/io.c: added ToS manipulation functions 2004-10-06 Balazs Scheidler * debian/control.in: fixed maintainer, removed provides: libzorpll * debian/Makefile.am: fixed binary name generation (for .files and .shlibs files) 2004-10-05 Kishazi Daniel * src/connect.c: add session_id to ZIOConnect object * src/listen.c: add session_id to ZIOListen object 2004-09-24 Balazs Scheidler * configure.in & Makefiles & debian/: changed build system to make it possible to create binaries in various BINARY_BRANCH-es) 2004-09-21 Balazs Scheidler * src/streamline.c (z_stream_line_get_copy): when the line does not fit into the target buffer, return G_IO_STATUS_AGAIN with line_len != 0; also added a FIXME about this hack 2004-09-16 SZALAY Attila * Bumped to version 3.0.0.4 2004-09-16 Sandor Geller * debian/control.in: removed Conflicts: libzorpll from the libzorpll-dev package 2004-09-14 Sandor Geller * debian/control.in: removed Conflict and Replaces fields from the libzorpll-dbg package 2004-09-07 Sandor Geller * debian/control.in: added zlib1g-dev to the build dependancies; added Conflicts: libzorpll Replaces: libzorpll to successfully upgrade from the older versions 2004-09-03 SZALAY Attila * Bumped to version 3.0.0.3.4 2004-08-24 Balazs Scheidler * src/crypt.c (md5_crypt): added md5 crypt support for platforms which do not support it, (z_crypt): added three conditional version, one for platforms which support md5 + des based crypt, one which has a crypt but does not support md5 crypt and a third on platforms which do not support crypt at all (e.g. win32) (fixes: #2811) * tests/zcrypt.c: new file to test the new md5 based crypt function 2004-08-18 Balazs Scheidler * src/log.c: use g_strlcpy() instead of a couple of strcpy(), nothing important, just to be safe * src/memtrace.c: use g_snprintf instead of sprintf just to be safe (boundchecking was correct previously) * src/registry.c: use g_strlcpy instead of unguarded strncpy(), nothing important registry is only used internally * src/sockaddr.c: use g_strlcpy instead of strncpy and NUL setting, nothing really important, but shortens the code 2004-08-18 SZALAY Attila * Bumped to version 3.0.0.3.2 2004-08-18 bazsi * configure.in, src/Makefile.am: fixed automake 1.7 and autoconf 2.59 related problems * src/log.c (z_send_syslog): use syslog("%s", msg) instead of referencing msg directly for non-Linux platforms 2004-08-11 Sandor Geller * solbuild/prototype-maker.sh: removed /opt from the prototype 2004-08-05 SZALAY Attila * Bumped to version 3.0.0.3.1 2004-08-03 Sandor Geller * solbuild/admin: added * solbuild/pkgmaker.sh: removed stdout, stderr redirections * solbuild/prototype-maker.sh: add the admin file to the package * solbuild/Makefile.am: added admin file 2004-07-29 Balazs Scheidler * src/streamline.c: cleaned up ZRL_NUL_NONFATAL handling (no functional change) 2004-07-28 Sandor Geller * solbuild/pkgmaker.sh: clean up the spool after the package creation 2004-07-27 Sandor Geller * solbuild/pkgmaker.sh: include rules.conf; changed the FILENAME prefix to the prefix which the .tar.gz package uses; compress the native Solaris package with gzip 2004-07-26 Sandor Geller * solbuild/pkginfo.in, solbuild/pkgmaker.sh, solbuild/prototype-maker.sh: added native Solaris packaging * solbuild/Makefile.am: changed EXTRA_DIST to include the files mentioned above * solbuild/rules: added pkgpackage target which is included in the binary target too * configure.in: added solbuild/pkginfo to AC_OUTPUT 2004-07-19 SZALAY Attila * Bumped to version 3.0.0.3 2004-07-08 SZALAY Attila * Bumped to version 3.0.0.2.3 2004-07-01 * Fixed a couple of 64bit cleanness issues 2004-06-21 SZALAY Attila * src/zorp/misc.h (z_decref): Introduce new inline functions to increment and decrement reference counts with bounce checking. 2004-06-17 SZALAY Attila * src/streamline.c: If enabled to split line then if gived buffer length not enough to receive the readed line, then split it. 2004-06-03 SZALAY Attila * Bumped to version 3.0.0.2.2 * src/stream.c (z_stream_context_destroy): remove of freeing context, because it'is not allocated here. 2004-06-01 SZALAY Attila * Bumped to version 3.0.0.2.1 2004-06-01 ABONYI Balint * src/crypt.c: fixed crypt under win32 2004-05-22 Balazs Scheidler * integrated log message documentation by Martin 2004-05-21 ABONYI Balint * src/socketsource.c, socket.c, errors.h: some Win32 fixes (ccompiler directives change) 2004-05-20 Kishazi Daniel * src/crypt.c: include zorplib.h to be able to use configuration flags 2004-04-15 ABONYI Balint *src/log.c,/src/zorp/log.h: changed logging under win32, if ZLF_SYSLOG is set then it logs messages to $windir\debug\syslog_tag.log . Added ZLF_WINDEBUG, it uses the windows debug messaging, usable by debuggers. 2004-05-18 Balazs Scheidler * src/misc.c: broken out z_crypt() function to a separate crypt.c to make it easier to support multiple platforms (Win32 does not have a crypt() function) 2004-05-11 Balazs Scheidler * src/socket.c: fixed IP option parsing (NOOP was repeated indefinitely) (fixes #3926) 2004-05-07 Balazs Scheidler * src/streamline.c: added explanatory log messages to error cases (fixes #3890) 2004-05-03 SZALAY Attila * Bumped to version 3.0.0.2 2004-04-27 Balazs Scheidler * src/listen.c, src/connect.c: moved the previously internal 'fd' member to public part * src/streamgzip.c, src/streamfd.c: fixed 64bit issues * src/stackdump.c: include for non-x86 platforms (Linux-IA64) 2004-04-15 Balint Abonyi * src/connect.c: removed some win32 defines. Fixed bug: 2970 2004-04-05 Balazs Scheidler * solbuild/rules, solbuild/rules.conf.in: new files to make it possible to automatically build under solaris 2004-04-02 Balazs Scheidler * src/streamline.c (z_stream_line_watch_dispatch): instead of always calling the read callback for both PRI and normal data, call the read callback when want_read is true and call the pri callback when want_pri is null * src/ssl.c (z_ssl_init): fixed dynamic engine loading, it previously worked with statically builtin modules only * src/sockaddr.c (z_sockaddr_inet_bind_prepare): change sock_flags type to guint32 from gboolean * src/streamgzip.c (z_stream_gzip_watch_dispatch): add default FALSE value to rc variable (was uninitalized) * src/log.[ch] (z_log_enable_syslog): add const qualifier to parameter 2004-03-29 SZALAY Attila * src/log.c (z_log_enable_syslog): New function (moved from z_log_init) to start syslog Bug: #2827 (z_log_enable_stderr_redirect): New function (moved from z_log_init) to start stderr catching and redirecting to syslog Bug: #2827 2004-03-23 SZALAY Attila * src/streamline.c: Set pri callback in child stream. Setting pri callback is useless, but I think it's OK Bug: #3327 2004-03-12 SZALAY Attila * Bumped to version 3.0beta1 2004-03-09 Balazs Scheidler * configure.in: changed version number to 3.0.0.0 in the preparation of the stable 3.0 branch 2004-02-18 SZALAY Attila * src/log.c (z_log_register_class): Copy glob to temp variable and not change logspec. Bug: #3112 2004-02-06 Balazs Scheidler * src/sockaddr.c: this was not adapted to sock_flags previously, did the transition (bind_prepare & bind functions did not have the sock_flags argument) 2004-02-11 SZALAY Attila * src/thread.c (z_pt_thread_new): Remove stack size setup. Zorp set it in more generic way. 2004-02-10 SZALAY Attila * src/log.c (z_log_init): Check if thread creation failed and handle it. Bug: #2098 2004-02-06 SZALAY Attila * src/stream.c (z_stream_save_context): Save timeout. Closes: #2128 2004-02-02 Balint Abonyi * src/streamfd.c: removed g_io_channel_set_flags from z_stream_fd_ctrl_method in win32 builds, because its not implemented in glib, and it shows a warning 2004-01-26 Balazs Scheidler * src/socket.c: support ZSF_LOOSE_BIND in the fallback bind function (e.g. allocate a port in the same port range) 2004-01-20 Balazs Scheidler * src/streamline.c: added NUL as a possible EOL character (ZRL_EOL_NUL) * lib/ssl.c: added ENGINE initialization * configure.in: added --enable-ssl-engine parameter (autodetected when a new enough OpenSSL version is present) 2004-01-15 SZALAY Attila * src/thread.c (z_tp_thread_new): Inicialize error variable to NULL. 2004-01-09 Balazs Scheidler * src/stream.c: implemented z_stream_extra_*() family of functions to make it possible to save|restore stream specific context, removed explicit nonblocking mode saving (rely on ZStreamFD to do that) * src/streamfd.c: implemented nonblocking state save|restore using the z_stream_extra functions 2004-01-09 SZALAY Attila * Bumped to version 2.2.3.0 * src/process.c (z_process_failed): Exit only if caller function explicit want it. (API Changed!) 2004-01-07 Balazs Scheidler * debian/control: added dev package dependencies to libzorpll-dev 2003-12-08 Kishazi Daniel * src/streamgzip.c: fix typo in prepare and dispatch 2003-12-02 Balazs Scheidler * src/ssl.c: reverted change wrt allowing certificates when a local issuer certificate is not found, it does not solve our direct problem and weakening the verification is not good in general 2003-12-02 Kishazi Daniel * src/parser.c: increase verbose level of debug messages to 7 2003-11-26 Balazs Scheidler * src/log.c (z_log_enabled): do not use logtag hash if logspec is NULL * src/listen.c, src/connect.c: adapted to the sock_flags change * src/socket.c, src/zorp/socket.h: added a new sock_flags parameter to every socket call, added all previously flag like arguments to this set (both source & binary incompatible change !!!) * src/log.c: do not log all messages at startup (before z_log_init is called), only those which have a verbosity <= verbose_level * src/zorp/stream.h: changed Z_STREAM_MAX_NAME to 128 chars, backport requires a binary incompatible release! 2003-11-12 Szalay Attila * Implement GZip capable stream. 2003-06-23 Kishazi Daniel * src/log.c: move GMutex and GPrivate to their static pairs 2003-11-06 Balazs Scheidler * src/log.c: implemented less contented locking (introduced logtag hash pool, and each thread uses a separate hashtable) * src/thread.c: fixed language of the thread creation failure message, fixed warning in g_clear_error invocation 2003-10-29 Szalay Attila * src/thread.c (z_tp_thread_new): Write out an error message when using threadpool and thread creation failed. 2003-10-17 Balazs Scheidler * src/zorp/zobject.h (z_object_check_comatible): accept NULL as a compatible pointer 2003-10-13 Balazs Scheidler * src/streamline.c: fixed an error case with CRLF terminated lines where the CR is missing (erroneously the buffer was cleaned and G_IO_STATUS_AGAIN was returned instead of G_IO_STATUS_ERROR) * src/streamfd.c: do not use the blocking timeout in z_stream_wait_fd if the stream is in nonblocking mode * src/log.c, src/zorp/log.h: the verbosity level is checked earlier (in the z_log macro instead of in the z_logv function) to avoid having to call functions embedded in the argument list 2003-10-10 Balazs Scheidler * src/zobject.c: do not really check class inheritence when running in non-debug mode 2003-10-09 Balazs Scheidler * src/thread.c: if thread creation failed, decrement the thread counter * src/process.c (z_process_daemonize): added progname argument to make it possible to report program name in error messages, use fprintf instead of z_log (API incompatible change) * src/process.c (z_process_fail): exit instead of silently failing when z_process_daemonize was not called 2003-10-06 Balazs Scheidler * src/stream.c: z_stream_{save|restore}_context now saves the nonblocking state of streams 2003-10-02 Balazs Scheidler * src/socket.c, src/sockaddr.c: introduced 'loose' binding, this means that we only want to make sure that a port is allocated in the same category as the port number in the supplied ZSockAddr argument, but otherwise we don't care the port number. This change changed a couple of internal APIs and interfaces, though user need not be changed (as a z_bind2 was introduced instead of adding a new argument to z_bind) 2003-09-30 Balazs Scheidler * src/ssl.c: changed ceritificate verification callback, accept certificates with incomplete chains when at least one subordinate CA is trusted (this way we don't have to trust the root CA when trusting a subordinate is enough) 2003-09-29 Balazs Scheidler * src/*.c: added a lot of function comments 2003-09-25 Szalay Attila * debian/control: Change libzorpll-dev and libzorpll-dbg section to libdevel, according the debian changes. 2003-09-25 Balazs Scheidler * src/streamline.c: new function z_stream_line_unget, a more general version of z_stream_line_unget_line (needed to support correct HTTP/0.9 fallback in HTTP) 2003-09-24 Balazs Scheidler * src/Makefile.am, src/zorp/Makefile.am: removed freeq.c and freeq.h * configure.in: removed gobject from dependencies 2003-09-11 Balazs Scheidler * src/stackdump.c: do not use backtrace() if it is not available * src/log.c: fixed warnings in the libc based syslog code * configure.in: added detection of backtrace() function 2003-09-10 Balazs Scheidler * src/log.c: renamed z_close_syslog to z_close_syslog_internal, new z_close_syslog function which does not take arguments * src/*.c: changed all occurences of printf("%m") to printf("%s", g_strerror(errno)) * configure.in: autodetect whether to use the syslog implementation in the libc * src/log.c: added alternate libc based syslog implementation (to be used on Solaris) 2003-09-04 Balazs Scheidler * src/parser.c: added to includes * configure.in: exported OPENSSL_CPPFLAGS * zorplibll.pc: added OPENSSL_CPPFLAGS to Cflags section 2003-09-03 Szalay Attila * src/log.c: Lock class_hash locks when destroy or recreate it. 2003-09-02 Balazs Scheidler * configure.in: autodetect SSL libraries and headers in non-standard location 2003-09-01 Balazs Scheidler * src/stream.c (z_stream_context_destroy, z_stream_save_context, z_stream_restore_context): new functions to save/restore ZStream callback context 2003-08-25 Balazs Scheidler * src/stackdump.c: liberalized system dependent functions a bit, now we report maps dump and libc symbol dump on sparcs as well 2003-07-28 Balazs Scheidler * src/thread.c: as GLib 2.0 does not abort when creating a thread failed, we need to handle this case 2003-07-24 Balazs Scheidler * src/stackdump.c: dump stack even if the ESP in the signal context is NULL (and fall back to the address of a local variable) 2003-07-18 Balazs Scheidler * src/cap.c: removed capability related messages as cap_to_text() is not reentrant and those messages are annoying anyway 2003-07-11 Balazs Scheidler * src/listen.c: maximize the number of accepted connections in a single poll loop (currently 50) * src/stream.c: removed z_stream_set_timeout_forward() function as it is not used * src/zorp/stream.h: changed z_stream_set_timeout() so it actually works, and removed timeout type argument 2003-07-02 Balazs Scheidler * src/thread.c: both threadpool based and simple thread support is compiled in and is runtime configurable (via the use_threadpools global variable) 2003-07-01 Balazs Scheidler * src/misc.c: moved z_parse_interval code here (and renamed to z_charset_parse), defined a couple of ZCharSet related functions 2003-06-23 Kishazi Daniel * configure.in: again, check libcrypto before libcrypt to make sure libcrypto is linked after libcrypt (I know it's insane) 2003-06-19 Kishazi Daniel * configure.in: don't check ssl/crypto libs again if already found * configure.in: swap library checkings of ssl and crypto 2003-06-19 Balazs Scheidler * src/log.c (z_log_enabled): use an RW lock instead of a mutex to protect the class_hash * src/zorp/log.h (z_log): avoid warning when NULL is passed as session_id (always call z_log_session_id) * src/zorp.c (z_log_session_id): handle session_id[0]==0 case so the function can be called from all z_log() invocations 2003-06-16 Balazs Scheidler * configure.in: added a couple of tests to make it easier to compile on Solaris 2003-06-16 Balint Abonyi * src/ssl.c (ssl_session_new): windows implementation uses X509_STORE instead of files 2003-06-13 Szalay Attila * src/zobject.c (z_object_unref): Bugfix. Unlock mutex before freeing self. 2003-05-30 Kishazi Daniel * src/connect.[ch]: swap user_data and error parameters of ZConnectFunc 2003-06-10 Szalay Attila * New script. Try to get all file cvs version and put it to /usr/share/docs/libzorpll 2003-06-05 Balint Abonyi * src/zorp/error.h: ENOTTCONN implemented for Windows 2003-06-04 Balazs Scheidler * src/streamssl.c: do not SSL_shutdown() an SSL connection twice * src/streamssl.c: bugfix, return G_IO_STATUS_EOF in z_stream_ssl_read when the stream was already shut down * src/streambuf.c: renamed callback functions to conform to naming scheme 2003-05-30 Szalay Attila * src/random.c (z_random_sequence_get_bounded): Remove thread private variables. Now use lock. 2003-05-30 Kishazi Daniel * configure.in: swap search order of crypt and ssl routines * src/connect.c (z_io_connect_connected): added GError parameter for connect callback * configure.in: use CFLAGS environment variable even if debug mode turned on 2003-05-29 Balint Abonyi * src/misc.c: z_crypt for windows implemented * src/connect.c: g_source_destroy cleanup * src/poll.c: g_source_destroy cleanup 2003-05-29 Balazs Scheidler * src/stream.h (z_stream_get_nonblock): new inline function to interface with ZST_CTRL_GET_NONBLOCK * src/streamfd.c (ZST_CTRL_SET_NONBLOCK): fix in nonblock flag handling, the original code did not query the old set of flags, (ZST_CTRL_GET_NONBLOCK): also added a ctrl message to query current blocking state * src/misc.c: the function z_crypt was added 2003-05-26 Balazs Scheidler * src/sockaddr.c (z_sockaddr_inet_new, z_sockaddr_inet_range_new): check if the IP address is valid, and fail otherwise 2003-05-20 Szalay Attila * src/socketsource.c (z_socket_source_check): Bugfix: Remember accept even till dispatch it. * Various patches from windows port. 2003-05-20 Balazs Scheidler * src/streamfd.c: the conversion to ZObject framework missed the function z_stream_fd_watch_finalize * src/streamline.c (z_stream_line_attach_source_method): make sure that the priority of our source is only changed prior to attaching to a context (caused a corrupt linked list in Context) 2003-05-15 Balazs Scheidler * src/zobject.c (z_object_is_compatible, z_object_is_instance): handle NULL pointers * src/streamline.c: did stream separation 2003-05-14 Balazs Scheidler * src/stream*.c: new, ZObject based ZStreams (the starting base for ZStream reorg), CHANGES API (z_stream_new renamed to z_stream_fd_new) * src/misc.c (z_data_dump): moved from stream.c * src/log.c (z_log_session_id): changed the return argument to const gchar * to remove warning * src/zorp/zobject.h: fixed a couple of cases when macro arguments were evaluated multiple times * src/streambuf.c (z_stream_buf_shutdown): flush buffers before doing real shutdown 2003-04-30 Balazs Scheidler * src/log.c (z_log_session): changed argument to const pointer (as it triggered several warnings in ZAS 2003-04-28 Balazs Scheidler * src/zobject.c, src/zorp/zobject.h: moved from zorp-core, the files implement a generic OO-like framework with RTTI (to be used for inter-proxy communication) 2003-04-18 Balazs Scheidler * connect.c: fixed a reference and fdleak 2003-02-28 Balazs Scheidler * configure.in: bumped version number to 2.0.27 binary age 1 2003-02-27 Balazs Scheidler * src/parser.c: added a couple of debug messages to help discovering configuration file problems * src/streamfd.c: changed data dump logging to use 'core.dump' category 2003-02-04 Balazs Scheidler * src/misc.c (z_process_ok): added (void) to prototype 2003-02-03 Szalay Attila * src/log.c (z_log_set_session_id): New function. Set default session_id to main thread. 2002-11-25 Kishazi Daniel * src/misc.[ch] (z_str_escape, z_str_compress): allocate space for trailing zero (EOS) 2002-11-25 Kishazi Daniel * src/misc.[ch] (z_str_escape, z_str_compress): new functions to (un)escape space in a string 2003-01-30 Szalay Attila * src/misc.c: Change the behavior of daemonizing. Wait the child process to be sure that it started. 2003-01-30 Balazs Scheidler * src/streamline.c: changed 'Too long line' to 'Line too long', and also added buffer contents to make it easier to recognize what was in the buffer * src/zorp/registry.h: changed a couple of gchar * parameters to const 2003-01-24 Balazs Scheidler * lib/sockaddr.c (z_sockaddr_format_unix): handle the case when sockaddr_un has length of 2 * lib/parser.c: changed ZParser to be reference counted, kill ZRealParser as no public interface is available * added a couple of const declarations to function prototypes * lib/socket.c (z_accept): workaround a linux 2.4.20 unix domain socket problem 2003-01-14 Balazs Scheidler * configure.in: bumped version number to 2.0.22 binary age 4 * lib/parser.c: added functions for looking up specialized types (_get_int, get_boolean etc.) 2003-01-21 Szalay Attila * Include updates for windows platform. (Logging, better socket handling, ...) 2003-01-10 Kishazi Daniel * src/ssl.c (z_ssl_init): load all encryption methods 2003-01-09 Szalay Attila * src/memtrace.c (z_mem_trace_printf): Bugfix: Use local variable in stack instead of global variable. 2003-01-09 Balazs Scheidler * src/log.c, src/cap.c: updated function documentation * src/listen.c: updated function documentation * src/connect.c: updated function documentation 2003-01-08 Balazs Scheidler * src/connect.c, src/listen.c: added new function z_io_xxx_start_in_context() where the context to use for polling can be specified, (z_io_connect_start_block): establish the connection in blocking mode (in fact it is done non-blocking and a private poll loop to enable using the connection timeout) 2003-01-02 Balazs Scheidler * added a couple of COPYRIGHT headers 2002-12-30 Szalay Attila * src/streambuf.c (_ZStreamBuf): Bugfix. Create new variable, buffer_lock, to lock buffer insert and remove. 2002-12-16 Szalay Attila * src/streamline.c (z_stream_line_read_callback): First part of stream separation. 2002-12-12 Balazs Scheidler * src/source.c (ZTimeoutSource): interpret time argument in milliseconds (it is used as milliseconds and was interpreted in seconds) * src/streamssl.c (z_stream_ssl_read_method, z_stream_ssl_write_method): log SSL error reasons 2002-12-11 Balazs Scheidler * src/connect.c: change all z_sockaddr_format buffers to have length of MAX_SOCKADDR_STRING * src/zorp/sockaddr.h: MAX_SOCKADDR_STRING new define for z_sockaddr_format() string lengths 2002-12-09 Szalay Attila * src/stream.c (z_stream_ref): Locking when changing stream reference. 2002-12-06 Szalay Attila * src/zorp/log.h: Tracing symbols doesn't depenq on libzorpll compile options. 2002-12-03 Balazs Scheidler * configure.in: added --enable-threadpool parameter, bumped version number to 2.0.12 age 7 * src/misc.c (z_zorplib_version_info): added threadpool information * src/ssl.c: added a thread stop function which calls ERR_remove_state(), so our thread implementation is independent from SSL _AND_ thread specific error states are freed. * src/thread.c: readded threadpool implementation, added start_callbacks and stop_callbacks which are functions called right before a thread starts, and right after it exits, this can serve as a basis for removing SSL states, and to gather the number of currently running threads for SZIG, (z_thread_new): now it returns gboolean instead of GThread *, joinable threads should be implemented differently. As nothing else uses this interface, I don't change binary compatibility * configure.in: bumped version number to 2.0.11 age 6 * src/misc.c (z_zorplib_version_info): added stackdump information * src/stackdump.c, src/zorp/stackdump.h: added stackdump handling to a single location, now includes portions of the stack (64*4 bytes), and also tries to resolve symbols * configure.in: bumped version number to 2.0.10 age 5 * src/connect.c: fixed the race added while correcting connection cancellation, using a source_id for determining wheather the operation was cancelled contains an inherent race, as by the time g_source_attach returns, the callback might already have been called * configure.in: bumped version number to 2.0.9 age 4 * src/ssl.c: fixed a couple of BIO bugs, in general G_IO_STATUS_EOF was not handled, and G_IO_STATUS_ERROR was sometimes returned as success * src/listen.c: use self->lock to protect _cancel and _accepted race, no user callbacks should be called if the connection was cancelled (now it is guaranteed that no user callbacks are called when _cancel had been called) * src/connect.c: use self->lock to protect _cancel and _connected race, no user callbacks should be called if the connection was cancelled (now it is guaranteed that no user callbacks are called when _cancel had been called) 2002-11-26 Balazs Scheidler * src/source.c: added timeout source 2002-11-25 Kishazi Daniel * src/source.c (z_threshold_source_set_threshold): new function to set a threshold source 2002-11-25 Balazs Scheidler * src/stream.c: removed poll timeout support completely, as the whole idea was broken, a new source will be defined instead * src/source.c (z_threshold_source_new): new function to initialize a threshold source 2002-11-25 Balazs Scheidler * configure.in: bumped version number to 2.0.4, binary age 3 * src/source.c: fixed a problem in stream timeouts (poll_timeout was checked in check & dispatch and poll_timeout_target should have been) * src/streamfd.c: report errors using %m instead of using GError, GError transition is planned for 2.1 2002-11-25 Szalay Attila * src/streamline.c (z_stream_line_read_callback): Bugfix. Sctricting the states, when calling user callback. 2002-11-21 Balazs Scheidler * src/streamfd.c: removed poll timeout implementation * src/stream.c: poll timeout is now implemented in StreamSource instead of in ZStreamFD, so poll timeout can be specified to any of the streams * src/stream.c, src/streamfd.c, src/streambuf.c, src/streamssl.c: changed _ctrl message handling 2002-11-18 Balazs Scheidler * configure.in: changed to 4 digit version number, currently 2.0.0.0 fixes bug id 11 2002-11-20 Szalay Attila * src/poll.c (z_poll_iter_timeout): Return from z_poll_inter_timeout when EINTR occured. 2002-11-18 Szalay Attila * Move core.session here from zorp-core. 2002-11-15 Szalay Attila * src/streamline.c (z_stream_line_watch_check): Rewrite source check conditions. (Doesn't try to call callback, when buffer is full. It's not guessable in every state. It will called when next character coming from network.) 2002-11-14 Szalay Attila * src/streamline.c (z_stream_line_watch_check): Bugfix. Check if self->pos is at end of buffer, becouse when this occur, there are no full line. 2002-11-13 Balazs Scheidler * src/misc.c (z_zorplib_version_info): return a string describing zorplibll configure options, used by zorp to display its version information * configure.in: prefixed all ENABLE_ macros with ZORPLIB_, thus ENABLE_MEMTRACE became ZORPLIB_ENABLE_MEMTRACE * src/zorp/zorplib.h: removed CORE_POLICY macro, as it was moved to zorp-core 2002-11-12 Balazs Scheidler * configure.in: bumped version number to 1.5.53, binary age 0 * lib/sockaddr.c: added a new parameter wildcard_clone to z_sockaddr_clone functions, it is used to generate an address suitable for binding with random port number selection (this avoids having to explicitly reference SockAddrInet attributes) 2002-11-11 Szalay Attila * src/log.c (z_log_source_new): Unset channel encoding. Close: #242 2002-11-11 Balazs Scheidler * lib/zorp/log.h (z_log): added explicit '(' and ')' to ensure precedence * lib/streamfd.c: interpret poll_timeout in milliseconds instead of in seconds 2002-11-08 Balazs Scheidler * src/streamssl.c (z_stream_ssl_read_method & z_stream_ssl_write_method): have a separate switch case for SSL_ERROR_SYSCALL, and handle the case where errno is 0, as it can be caused by server EOF, so take it as an EOF 2002-11-08 Kishazi Daniel * configure.in: bumped version number to 1.5.51 binary age 2 * src/parser.c (z_parser_check): new function * src/parser.h: change ZParserTag structure 2002-11-06 Balazs Scheidler * configure.in: bumped version number to 1.5.50 binary age 1 * src/zorp/streamfd.h (z_stream_set_nonblock): moved to stream.h * src/zorp/stream.h (z_stream_set_nonblock): moved here 2002-11-05 Balazs Scheidler * src/sockaddr.c (z_inet_aton): readded #ifdef HAVE_INET_ATON, and alternative implementation (it was removed on Windows) * src/log.c: cast the result of getpid() to int as it caused warning on Solaris, cast the argument of isalnum() from char to guchar as isalnum() is implemented as an array lookup on solaris 2002-10-28 Balazs Scheidler * configure.in: bumped version number to 1.5.49 binary age 0 * src/socket.c (z_getdestname): new function, implementing 'transparent get original destination) * src/socket.h (z_ll_getdestname): new function, calls the function pointer socket_funcs->getdestname * configure.in: bumped version number to 1.5.48 binary age 4 2002-10-28 Szalay Attila * src/zorp/stream.h: Move SET_NONBLLOCK ctrl function to stream.h from streamfd.h 2002-10-25 Balazs Scheidler * src/ssl.c: initialize ZSSLSession->ref_cnt to 1 2002-10-24 Balazs Scheidler * src/ssl.c (ZSSLSession): changed ZSSLSession to be reference counted, (z_ssl_session_ref, z_ssl_session_unref): new functions, (z_ssl_session_destroy): made a static private function 2002-10-24 Szalay Attila * src/streamssl.c (z_stream_ssl_read_method): Do ssl renegotiation transparent if needed. 2002-10-22 Szalay Attila * src/streambuf.c (z_stream_buf_write_callback): Bugfix. Return TRUE default. 2002-10-10 Balazs Scheidler * src/poll.c (z_poll_iterm_timeout): call g_main_context_dispatch() even in timeout, otherwise sources which do not really poll have no chance to dispatch their events 2002-10-10 Szalay Attila * Bumped to version 1.5.43 (AGE: 0) * configure.in: Remove enable-packet-trace. * src/streamssl.c: Use new callback function * src/streamline.c: Use new callback function * src/stream.h New callback function ctrl 2002-10-09 Szalay Attila * src/stream.c (z_stream_source_finalize): use self->stream instead of uninitialized stream 2002-10-09 Balazs Scheidler * src/memtrace.c: increased temporary heap to 64k, implicitly initialize the block hash on every malloc call, support realloc() during initialization, verified that static programs do not work with memtrace * src/sockaddr.c (z_sockaddr_clone): new function, implemented as a function pointer in sa_funcs, (z_sockaddr_new_copy): obsolete function, removed * src/poll.c: destroy the wakeup source * src/listen.c: changes similar to what connect.c had, support GDestroyNotify, added z_io_listen_cancel function * src/connect.c: removed the use of free queues, as they are not needed anymore 2002-10-07 Balazs Scheidler * configure.in: bumped version number to 1.5.42 * src/sockaddr.c: changed z_sockaddr_inet_get_port to support ZSockAddrInetRange and return 0 as port number in this case, (z_sockaddr_inet_check): new function to check whether a ZSockAddr is compatible with ZSockAddrInet * src/connect.c: added the possibility to assign a destroy notify function to user_data, (ZIOConnect): to avoid circular references the GSource is not referenced by pointer, instead it is referenced by the id (NOTE: glib does not handle the case when ids wrap around!, though it's a 32 bit unsigned number) * src/memtrace.c: added the define REALLY_TRACE_BT, which if defined causes the addblock/delblock messages to include a backtrace (makes zorp-memtrace.log huge!!) 2002-10-02 Balazs Scheidler * src/zorp/log.h: added new macros z_session_enter, z_session_leave, z_session_cp * src/connect.c: changed the way ZIOConnect references itself. Earlier it was assumed that the caller 'knows' when to drop reference. (this caused quite a lot of problems in pyconnect.c). Now connect references itself as long as its source is registered in the main loop. Thus it is not possible any more to cancel the connection by calling z_io_connect_unref. To cancel a connection a new function called z_io_connect_cancel was introduced, and the caller is free to free ZIOConnect anytime it wishes to. (it can also drop the reference immediately after initialization) * src/listen.c: changed refcounting similar to ZIOConnect 2002-10-02 Szalay Attila * Bumped to version 1.5.41 2002-10-01 Szalay Attila * src/streamline.c (z_stream_line_read_callback): Bugfix. Call readline callbacks, when error occured. * src/streamssl.c (z_stream_ssl_watch_check): Set streamssl source to work, because ssl may buffer readed data. 2002-09-30 Szalay Attila * src/streamline.c (z_stream_line_read_method): Bugfix. Move to first position, if no data in buffer. 2002-09-27 Szalay Attila * Bumped to version 1.5.40. Set Age to 0. * src/memtrace.c (z_malloc): Remove * before raw_ptr and user_ptr. * streambuf.c: streambuf set enable_write itself. 2002-09-25 Balazs Scheidler * src/memtrace.c (z_free, z_realloc): first check if the block exists, and then check canaries * src/zorp/log.h: changed z_enter/z_leave messages (made them shorter) 2002-09-23 Balazs Scheidler * src/memtrace.c: support temporary heap on initial malloc() calls (bugzilla id 1 & PR972) 2002-09-20 Balazs Scheidler * src/streamfd.c: readded z_stream_set_nonblock (FIXME: needs to be changed so every stream implementation has a chance to implement non-blocking I/O) * src/streamfd.c: added support for poll_timeout * src/stream.c (z_stream_set_timeout_method): set s->poll_timeout if Z_STREAM_TIMEOUT_POLL is specified 2002-09-18 Balazs Scheidler * stream.c: moved z_stream_set_cond_method and z_stream_set_callback_method here as they can be used by any ZStream implementation, (z_stream_set_timeout_method): new function to set poll & block timeouts for streams, (z_stream_set_timeout_forward): new function, forwards timeout set requests to stream->parent * streambuf.c: changed read, write & pri callback references to read_cb, write_cb and pri_cb, (z_stream_buf_set_cond_method): use z_stream_set_cond_method to perform default actions of z_stream_set_cond, (z_stream_buf_set_callback_method): -"- * streamfd.c: -"- * streamssl.c: -"- * streamline.c: -"-, don't check readability if the user doesn't want reading (check self->want_read) * stream.h: added set_timeout callback * ------ * src/Makefile.am: added streamfd.c * src/poll.c (z_poll_stream_unref): call z_stream_detach_source instead of z_source_stream_remove (renamed function), (z_poll_add_stream): call z_stream_attach_source instead of z_source_stream_new (renamed function) * src/stream.c: split into stream.c & streamfd.c, stream.c contains implementation independent functions only, streamfd implements the ZStream interface for unix fds, (ZStreamSource): doesn't free associated GPollFD list when the object is destroyed, the only place which was relying on this behaviour has been changed * src/streamfd.c: renamed ZStreamBase to ZStreamFD, now uses ZStreamFuncs & don't touch source->poll_fds directly, don't rely on ZStreamSource to free the registered GPollFD struct, use an inline struct in ZStreamFD instead (no need to free it) * src/streambuf.c: ported to ZStreamFuncs * src/streamline.c: ported to ZStreamFuncs * src/streamssl.c: ported to ZStreamFuncs * src/stream.h: merged ZIOFuncs and function pointers in ZStream into a single ZStreamFuncs structure, cleaned up naming (z_source_stream_new & z_source_stream_remove changed to z_stream_source_attach & z_stream_source_detach) 2002-09-16 Szalay Attila * Bumped to version 1.5.36 * src/streamline.c, src/streambuf.c, src/streamssl.c: Bugfix. Put parent to super. 2002-09-12 Balazs Scheidler * src/stream.c (z_stream_init): new function to initialize common attributes of a stream * src/streamssl.c, src/streambuf.c, src/streamline.c: use the new z_stream_init function instead of initializing common attributes directly 2002-09-12 Szalay Attila * Remove log facility define from c files. 2002-09-10 Szalay Attila * src/memtrace.c (z_mem_trace_init): New parameter, set the name of memtrace file * src/random.c: Handle if genrated random number bigger than max. * src/memtrace.c (z_mem_trace_dump): Check canaries in every pointer * src/memtrace.c (z_mem_trace_check_canaries): Log if canay broken. * Set the correct log facility and level in all log message 2002-09-10 Balazs Scheidler * src/stream.c, src/streambuf.c, src/streamline.c, src/streamssl.c: applied to the changed dispatch interface * src/zorp/stream.h: killed the last two arguments of the dispatch callback (callback and user_data) as we don't use the callbacks stored in our source, but have our own function pointers (in ZStream) * src/stream.c (z_stream_init): new function to initialize the base fields in a ZStream, this function is to be called from descendant ZStream implementations * src/zorp/stream.h: moved a couple of member fields from ZStreamBase to the general ZStream structure (time_open, bytes_recvd and bytes_sent) as those are needed in descendants as well 2002-09-09 Balazs Scheidler * src/stream.c: the open duration of a stream is calculated using difftime() instead of simply substracting the two numbers * configure.in: bumped version number to 1.5.33 (age 0) * src/zorp/stream.h (ZStreamFuncs): killed get_type method, use a simple member of ZStream instead, z_stream_get_type is converted to an inline function, this change has been applied to all stream implementations 2002-09-09 Szalay Attila * src/random.c (z_random_sequence_get_bounded): Bugfix. Use g_static_private correctly. 2002-09-05 Szalay Attila * Bumped to version 1.5.33 * src/log.c (z_log_init): Bugfix. If ZLF_THREAD is not set, doesn't start new thread. 2002-09-04 Balazs Scheidler * configure.in: integrated win32 support * src/error.c, src/zorp/error.h: platform independent error support, it works for sockets on Win32 as well on Unix * src/connect.c: use error functions from error.c, use Z_SOCKEVENT_* constants instead of G_IO_* directly * src/listen.c: use the error functions from error.c, use Z_SOCKEVENT_* constants instead of G_IO_* directly * src/io.c: limited support for Win32 sockets * src/log.c: we don't use logging on Win32, therefore most of this code is commented out on that platform * src/misc.c (z_process_daemonize): win32 version * src/parser.c: include instead of "parser.h" * src/poll.c: use the new error functions, limited win32 support * src/sockaddr.c: use the new error functions, limited win32 support * src/socket.c: use the new error functions, limited win32 support (new function z_socket_init is to be called on startup for programs which support win32) * src/socketsource.c: win32 support * src/ssl.c: don't use dirent functions directly, use the portable g_dir_* functions from glib instead * src/stream.c: win32 support, NOTE: there are two win32 implementations for z_stream_wait_fd, why? * src/stream.h (ZStream): added watch_finalize function pointer (needed on Win32) 2002-08-30 Szalay Attila * Bumped to version 1.5.31 * src/streambuf.c, src/streamline.c: Stacked streams now try to search for their instance in the stream chain. 2002-08-30 Balazs Scheidler * src/memtrace.c: updated memtrace implementation to use before and after canaries, the backtrace is stored in a gpointer array, and the log output includes a '0x' prefix (for Dani :) 2002-08-28 Balazs Scheidler * src/log.c: fixed yet another bug in logging code, unified z_log_init & log_log_init_thread, changed z_log_init parameters 2002-08-27 Balazs Scheidler * src/log.c: fixed a couple of bugs in Sasa's new logthreading code * configure.in: Bumped version number to 1.5.29 * src/streamline.c: changed z_stream_line_set_cond_method to invoke z_stream_set_cond_method instead of duplicating work here. NOTE: it might be possible to the same change in every ZStream implementation * src/stream.c: published two functions z_stream_set_cond_method & z_stream_set_callback_method as they are useful for other stream implementations as well 2002-08-23 Balazs Scheidler * src/zorp/registry.h: changed registry constants to reflect changes in Zorp (ZR_SPROXY is renamed back to ZR_PROXY, ZR_DPROXY was removed, and ZR_DTRACK is renamed to ZR_CONNTRACK) 2002-08-21 Balazs Scheidler * src/log.c, src/zorp/log.h: use thread private variable to fetch current session id and use it if none is specified 2002-08-21 Szalay Attila * Bumped to version 1.5.26 * Implement modifications for new UDP Core. 2002-08-08 Szalay Attila * Bumped to version 1.5.25 * Rewrite random function. 2002-07-31 Szalay Attila * src/connect.c (z_io_connect_start): Bugfix. Test to self->local in log message. (May be NULL) 2002-07-31 Balazs Scheidler * configure.in: bumped version number to 1.5.24, binary age 5 * src/socketsource.c: implemented self->suspended, z_socket_source_suspend and z_socket_source_resume * src/connect.c, src/listen.c: self->watch became a GSource * instead of guint, because source lookup by id is slow 2002-07-29 Balazs Scheidler * src/connect.c, src/listen.c: implemented timeout possibility * src/socketsource.c, src/zorp/socketsource.h: moved ZSource out of source.c, and renamed to ZSocketSource, implemented timeout possibility 2002-07-26 Balazs Scheidler * lib/ssl.c: if verify_mode == SSL_VERIFY_NONE then do not verify certificate (makes a lot of junk in log output) 2002-07-24 Szalay Attila * src/memtrace.c: New entry point z_memtrace_init_file. 2002-07-12 Szalay Attila * New flag. ENABLE_HEAP_TRACE, to detect off-by-one bugs and heap corruptions. 2002-07-01 Balazs Scheidler * src/socket.c (z_accept): handle EAGAIN by returning G_IO_STATUS_AGAIN 2002-06-26 Balazs Scheidler * src/listen.c: forward ported multi accept feature (accept as many connections at once as possible) * configure.in: bumped version number to 1.5.19 binary age 0 * src/stream.c, src/streamline.c, src/streamssl.c: renamed z_stream_set_way to z_stream_set_cond 2002-06-25 Szalay Attila * src/log.c (z_fetch_stderr): Bugfix. Remove stderr from poll if closed. 2002-06-13 Szalay Attila * Bugfix: Close random string with 0. (chaoron) 2002-06-12 Balazs Scheidler * src/connect.c: added an error message when z_io_connect_start is called twice * src/stream.c (z_stream_shutdown_method): handle the case when errno is set to EINTR initially and is not touched by the successful shutdown call 2002-06-10 Balazs Scheidler * configure.in: version bumped to 1.5.16, binary age 1 * src/poll.c: do not ref self->context twice4 * configure.in: version bumped to 1.5.15, binary age 0 * lib/connect.c: added a new debug message about connection initiation 2002-06-07 Balazs Scheidler * lib/socket.c: reorganized for transparent proxying 2002-06-07 Szalay Attila * poll.c: Bugfix. Free pollfd pointer vector. 2002-06-02 Balazs Scheidler * configure.in: version bumped to 1.5.14, binary age 1 * src/listen.c: change listen() to z_socket_listen() 2002-05-30 Balazs Scheidler * src/sockaddr.c: moved z_bind, z_accept and z_connect into socket.c * src/socket.c, src/zorp/socket.h: new files * src/listen.c, src/connect.c: changed to use ZSocket internally so Zorp can hook into socket related functions and provide transparency, changed self->sock to ZSocket, self->sock was renamed to self->poll and instead of allocating GPollFD dynamically, include it in the structure * src/Makefile.am: socket.c added 2002-05-24 Balazs Scheidler * configure.in: cleaned up (hope it doesn't break anything) * src/sysdep.c: removed, and moved to zorp-core 2002-05-16 Balazs Scheidler * src/thread.c: remove SSL error state when a thread exits 2002-05-10 Szalay Attila * src/source.c: New source, z_threshold_source 2002-05-07 Balazs Scheidler * src/log.c: added more robust reopening of log socket (fixes woody logging problems) 2002-04-25 Balazs Scheidler * src/misc.c: added an implementation for strlcpy if one is not present * configure.in: added check for strlcpy 2002-04-24 Szalay Attila * Rewrite poll to unref sources when quit. 2002-04-05 Kishazi Daniel * src/misc: New functions z_random_sequence_get and z_random_sequence_get_bounded. 2002-04-04 Kishazi Daniel * src/zorp/streamline.h: Added flag ZRL_PARTIAL_READ * src/streamline.c (z_stream_line_watch_prepare): Handling ZRL_PARTIAL_READ flag. (z_stream_line_watch_check): Handling ZRL_PARTIAL_READ flag. * ChangeLog: some typos corrected and a false entry removed. 2002-04-02 Szalay Attila * src/stream.c (z_stream_read_method): Bugfix: Don't try to dump readed data, if read failed. (z_stream_write_method): Same for writted data. * src/poll.c (_ZPollSource): Enhance z_poll_wakeup with a source. (Wakeup poll, even if not in poll _yet_. 2002-03-29 Szalay Attila * src/log.c (z_logv): Normal messages logging with INFO level. 2002-03-12 Szalay Attila * src/streamline.c (z_stream_line_unget_line): New function. Used mainly in http proxy. 2002-03-11 Szalay Attila * New function: z_poll_get_context * API: API is now semistable. 2001-10-24 Kishazi Daniel * Upgrade: use GLib 1.3.9 except in io.[ch] and giossl.[ch] libzorpll-3.9.4.1/archived-changelogs/3.0/VERSION000066400000000000000000000000111224546767600211570ustar00rootroot000000000000003.0.6.5.1libzorpll-3.9.4.1/archived-changelogs/3.1/000077500000000000000000000000001224546767600201205ustar00rootroot00000000000000libzorpll-3.9.4.1/archived-changelogs/3.1/ChangeLog000066400000000000000000001571571224546767600217120ustar00rootroot000000000000002008-09-11 Szalay Attila * VERSION: Bumped to version 3.1.8.4 2008-09-08 Szalay Attila * VERSION: Bumped to 3.1.8.3.2 * src/stream.c (z_stream_set_child_method): Fixed a possible use-after-free. umbrella state was set regardless of the situation, but self may be freed here. (fixes: #nobug) 2008-09-05 Szalay Attila * src/stackdump.c (z_write_minidump): Fixed some compilation problem in windows. (fixes: #nobug) * VERSION: Bumped to version 3.1.8.3.1 * src/stackdump.c (z_write_minidump): Changed MiniDumpWrite calling to use pointers instead of linking because windows-2000 does not have this function. (fixes: #nobug) 2008-08-22 Szalay Attila * VERSION: Bumped to 3.1.8.3 2008-08-17 SZALAY Attila * VERSION: Bumped to 3.1.8.2.2 2008-08-15 SZALAY Attila * src/listen.c (z_listener_accept): Limit accept loop to 1 sec time. (fixes: #12798) 2008-08-15 Szalay Attila * src/stream.c (z_stream_set_child_method): Fixed a compilation problem in windows platform. (fixes: #nobug) (z_stream_set_keepalive): Fixed a compilation problem in windows platform. (fixes: #nobug) 2008-08-14 SZALAY Attila * VERSION: Bumped to 3.1.8.2.1 2008-08-10 Laszlo Attila Toth * src/connect.c (z_connector_connected): removed: set keepalive to 1 * src/listen.c (z_listener_accept): removed: set keepalive which was dead code. * src/stream.c: added z_stream_set_keepalive function. If socket fd is valid, the keepalive option of fd is set (to the value of the parameter) and the stream's keepalive member is also set, but if fd == -1 both of them are untouched. * src/streamfd.c: added gint keepalive member of _ZStreamFD. (z_stream_fd_ctrl_method): added getter and setter for keepalive member of the stream. (z_stream_fd_new): initalizing keepalive member to 0. * src/zorp/stream.h: added ZST_CTRL_GET_KEEPALIVE and ZST_CTRL_SET_KEEPALIVE constants; z_stream_get_keepalive function. 2008-08-10 Viktor Hercinger * src/zorp/socket.h: added ZSF_TRANSPARENT socket flag (fixes #14329) 2008-07-29 Balazs Scheidler * lib/stream.c (z_stream_source_grab_ref): instead of grabbing struct reference on the current stream, search the top stream and grab that, this ensures that by the time the user callback returns a reference to the top_stream and its source is still available (fixes: #14404), (z_stream_source_prepare, _check, _dispatch): adapt to the changes in z_stream_source_ref, (z_stream_set_child_method): make sure the child/parent members are NULLed out before _unref is called as otherwise an assertion may fail in z_stream_free() 2008-06-18 Szalay Attila * VERSION: Bumped to 3.1.8.2 2008-06-09 Balazs Scheidler * src/stream.c (z_stream_source_dispatch): ref top_stream before calling z_stream_detach_source() as top_stream is only a borrowed reference in this case which might trigger an abort/crash during destruction as functions expect it to be a proper reference. (fixes: #13944) 2008-05-29 Balazs Scheidler * src/stream.c (z_stream_set_child_method): make the old child drop all callbacks as they still contain references to self (fixes: #13944), (z_stream_drop_callbacks): new function, drops all read/write/pri callbacks and associated user_data, (z_stream_free_method): also use z_stream_drop_callbacks, (z_stream_restore_context): -"- 2008-04-14 SZALAY Attila * tests/test_sockaddr.c: Added stdlib include for exit decalaration. (fixes: #nobug) * VERSION: Bumped to 3.1.8.1 2008-04-10 Laszlo Attila Toth * src/process.c: added notify_interval to process_opts; (z_process_perform_supervise): limiting count of sent notificatications, by default one / 10 mins. Count of supressed notifications is also sent. (fixes: #13048) * src/process.c (z_process_perform_supervise): always check the restarts no matter what was the reason. Log when necessary. (fixes: #13048) * src/process.c: process_opts is extended with 2 additional fields: restart_max and restart_interval. In the specified interval (which is in seconds) the process restarts are limitid to restart_max. The z_process_option is also extended by this values. z_process_perform_supervise: checking the new options for valid values and using them. (fixes: #13048) 2008-04-10 Tevesz Andras * src/stackdump.c: added win32 exception handler, added minidump writer * src/zorp/stackdump.h: added z_enable_write_dump_file * src/stackdump.c: added z_write_minidump, z_enable_write_dump_file 2008-04-10 MOLDVAI Dezso E. * configure.in: Re-added enable_debug configuration parameter handling (fixes: #13470) 2008-04-10 Laszlo Attila Toth * configure.in: -Werror-implicit-function-declaration added to cflags. (fixes: #13470) 2008-04-07 Szalay Attila * VERSION: Bumped to 3.1.8.0.3 2008-04-07 Simon Gabor * src/connect.c: (z_connector_start_in_context) now tolerates NULL as context argument (fixes: #12845) 2008-03-03 Szalay Attila * VERSION: Bumped to 3.1.8.0.2 2008-03-03 Laszlo Attila Toth * src/zorp/process.h: changed parameters of z_process_set_argv_space: it gets argc, argv of main() function. It *must* be called before any changes on argc, argv (for instance by g_option* functions). (fixes: #8941) * src/process.c: multiple changes. (fixes: #8941) (z_process_perform_supervise): process title change by a new function z_process_setproctitle, z_process_strlcpy functions for process title changes. (fixes: #8941) (z_process_set_argv_space): prepare for process title changes in process_opts: new members as needed. (fixes: #8941) 2008-02-25 Simon Gabor * src/ssl.c: code duplication eliminated (fixes: #12548) * src/ssl.c: inline constructor added to streamssl (fixes: #12548) 2008-02-21 SZALAY Attila * src/blob.c (z_blob_system_swap_in): Fixed a possible memory corruption with allocating the right amount of memory. (fixes: #11361) 2008-02-21 Szalay Attila * src/blob.c: Made some error fatal. (fixes: #11361) * tests/test_readline.c: Fixed 64 bit problem. (fixes: #nobug) 2008-02-21 Balazs Scheidler * src/streambuf.c (z_stream_buf_space_avail): return TRUE when flush_error is set to avoid deadlock in the application code which does not do I/O when space_avail returns FALSE (fixes: #12950) 2008-02-21 Szalay Attila * src/process.c (z_process_perform_supervise): Added a log message if could not kill zorp after it deadlocked. (fixes: #12799) 2008-02-20 Szalay Attila * VERSION: Bumped to 3.1.8.0.1 because of an incompatible ABI and API change. 2008-02-20 Simon Gabor * src/packetbuf.c: endianness arg removed from byte-sized pktbuf operations (fixes: #11909) 2008-02-19 Szalay Attila * VERSION: Bumped to 3.1.7.1.1 2008-01-13 Simon Gabor * src/zorp/log.h: msvc-specific warning about excess macro args disabled (fixes: #11688) 2007-12-25 Simon Gabor * src/zorp/log.h: definition of z_return added (fixes: #11688) * src/*: 'z_leave+return' constructs replaced by z_return, violations of coding style policy fixed (fixes: #11688) 2007-10-01 SZALAY Attila * VERSION: Bumped to 3.1.7.1 2007-09-14 Szalay Attila * VERSION: Bumped to 3.1.7.0.2 2007-08-21 Laszlo Attila Toth * src/process.c: starting notifier detached from the original process. (fixes #11285) 2007-08-21 Simon Gabor * src/poll.c, socket.c, streambuf.c, streamfd.c, streamssl.c, blob.c: log indentation bugs fixed (fixes: #11688) * src/stream.c: (z_stream_search_stack) an indentation bug fixed (fixes: #11688) * src/packetbuf.c: getters now work on const instances (fixes: #11543) * scripts/failure_notify.in: missing fields added (fixes: #11279) * scripts/failure_notify.conf: default admin address changed (fixes: #11279) 2007-07-23 Szalay Attila * src/memtrace.c (z_mem_trace_bt): Fixed frame base pointer detection. (fixes: #nobug) 2007-05-30 Szalay Attila * VERSION: Bumped to 3.1.7.0.1 2007-05-14 Szalay Attila * VERSION: Bumped to 3.1.7.0 because of incompatible changes. 2007-05-09 Simon Gabor * src/source.c, src/zorp/source.h (z_timeout_source_set_time): absolute timing added to ZTimeoutSource (fixes: #9956) * src/packetbuf.c: addressing bug fixed in ZPktBuf (fixes: #11145) * src/misc.c (z_format_data_dump): offset printout added to raw hexdump format (fixes: #9956) * src/packetbuf.c, src/zorp/packetbuf.h (z_pktbuf_part): assertion removed from the case of taking part of dynamic buffers - use this with caution! (z_pktbuf_put_boolean, z_pktbuf_get_boolean16): added functions for handling boolean values (fixes: #9956) * src/zorp/packetbuf.h (z_pktbuf_size): fixed a typo in the macro name (fixes: #9956) * src/zorp/misc.h, src/zorp/log.h, src/misc.c (z_log_text_dump): added for logging bulk data in textual form instead of the hexdump (fixes: #9956) * src/packetbuf.c (z_pktbuf_set_available): made public, (z_pktbuf_get_boolean): added (fixes: #10779) * src/zorp/packetbuf.h (z_pktbuf_current, z_pktbuf_end): added (fixes: #10779) * src/packetbuf.c: now p_pktbuf_put_*() works on dynamic buffers as well (fixes: #10779) * src/packetbuf.c, src/zorp/packetbuf.h (z_pktbuf_put_Xs): data block writer functions now take const pointers (fixes: #10779) * src/packetbuf.c: packet buffer facility improved by adding position-related and data manipulating functions, nomeclature shortened and clarified (fixes: #10779) * src/stream.c, src/streambuf.c, src/streamline.c: changes in packet buffer nomenclature committed (fixes: #10779) * src/misc.c (z_log_data_dump): dumping of non-printable characters fixed 2007-05-04 Szalay Attila * src/process.c (z_process_perform_supervise): Changed deadlock detection to not wait check_period amount of time between two waitpid calling. (fixes: #nobug) 2007-05-03 Krisztian Kovacs * src/makefile.msc: redirect to NUL device instead of NULL file (fixes: #nobug) * src/io.c (z_fd_set_nonblock): disable asynchronous events on Win32 before trying to set socket to blocking mode (fixes: #11323) * src/streamfd.c (z_stream_fd_ctrl_method): because blocking/non-blocking I/O channel settings are unsupported in GLib on Win32, we have to call z_fd_set_nonblock() directly on Win32 (fixes: #11323) * src/log.c (z_log): insert session id in log message (fixes: #nobug) 2007-04-23 Krisztian Kovacs * {arch}/=tagging-method: add Windows build prerequisites and output as precious * src/log.c (z_log_win32_syslogmsg): prepend time stamp to log message (fixes: #nobug) 2007-04-05 Szalay Attila * VERSION: Bumped to 3.1.6.2 2007-04-02 Szalay Attila * VERSION: Bumped to 3.1.6.1.2 2007-04-02 Pal Tamas * debian/libzorpll.install.in: Removed etc/libzorpll.conf * src/process.c: failure notify script's name contains the ZORPLIB_COMPAT_BRANCH. * configure.in: configure defines ZORPLIB_COMPAT_BRANCH in zorpconfig.h. * debian/libzorpll.postinst.in: Modified postinst to install the /etc/libzorpll.conf if missing or modify it if present. * scripts/Makefile.am: failure_notify going to be installed with a version. 2007-03-22 Pal Tamas * debian/libzorpll.config.in: Added config script to get admin email from zorp-utils' template and/or from the user. * debian/libzorpll.postinst.in: Added postinst script to set the email address for the failure notify script. * debian/libzorpll.templates.in: Added template file containing the zorplib/admin-email template * debian/Makefile.am: Added the new files and the ones created from them to EXTRA_DIST and noinst_SCRIPTS. * debian/libzorpll.install.in: Added etc/libzorpll.conf to libzorpll package's files. * debian/rules.in: Enabled dh_installdebconf. * src/process.c: Added an access call to test the existence of the preconfigured failure notify script, before trying to fork and execute it. * scripts/Makefile.am: Administrated the renaming of failure_notify.conf to libzorpll.conf. * scripts/failure_notify.in: Administrated conffile renaming. Only sends emails if ADMIN_EMAIL is a non-empty string. * scripts/libzorpll.conf: ADMIN_EMAIL's default value is a blank string. * scripts/failure_notify.conf: renamed to scripts/libzorpll.conf 2007-03-22 Simon Gabor * debian/libzorpll.install.in, debian/rules.in, Makefile.am, configure.in: variable 'libexecdir' added in order to support the dynamic placement of the failure notification handler script and its configuration file (fixes: #8560) * scripts/failure_notify.in: the location of the config file isn't hardwired anymore (fixes: #8560) * src/process.c: the location of the failure handler isn't hardwired anymore (fixes: #8560) * scripts/failure_notification: script added (fixes: #8560) * scripts/failure_notification.conf : config added (fixes: #8560) * src/zorp/process.h, src/process.c: (check_period, check_fn) two new members for process_opts added, (z_process_set_check) setter function for them added, (z_process_perform_supervise) if process_opts.check_fn is set, then it is used to detect process lockups/exits instead of a plain waitpid, Z_PROCESS_FAILURE_NOTIFICATION is executed on failure, called with instance name, chroot dir, pidfile dir, pidfile name, working dir, capabilities, exit reason (signalled or exited), exit argument (signal number or exit code) and performed action (restarting or not_restarting) as arguments. 2007-03-22 Balazs Scheidler * src/stream.c (z_stream_write): don't dump data to the message log if a write error occurs (fixes: #10882) 2007-02-20 Szalay Attila * VERSION: Bumped to 3.1.6.1 2007-02-12 SZALAY Attila * VERSION: Bumped to version 3.1.6.0.1 2007-02-05 Balazs Scheidler * src/zorp/misc.h (G_GNUC_WARN_UNUSED_RESULT): renamed from __warn_unused, define only if glib did not define it, better detection of gcc versions * src/zorp/listen.h: changed warn_unused references to G_GNUC_WARN_UNUSED_RESULT 2007-02-01 Krisztian Kovacs * src/misc.h: add __warn_unused macro, expands to warn_unused_result attribute on GCC versions with this feature (fixes: #10852) * src/zorp/listen.h (z_listener_start): change result type to gboolean, mark as __warn_unused so that we get a warning for callers not checking the new return value (fixes: #10852) (z_listener_start_in_context): add missing declaration for this function (fixes: #nobug) (z_listener_open): new function, opens the fd for a listener which has not been started yet, this is necessary in some cases where we'd like to get the local address before actually attaching our accept callback (fixes: #10852) * src/listen.c (z_listener_open): implement this new function (fixes: #10852) (z_listener_start): call the open callback if self->fd is not initialized yet (fixes: #10852) (z_listener_new): don't call the open_listener() virtual function, initialize self->fd to -1 (fixes: #10852) 2007-01-08 Balazs Scheidler * VERSION: bumped to 3.1.5.5 2007-01-08 Balazs Scheidler * src/listen.c (z_stream_listener_open_listener): always call z_listen() with 255 as backlog to work around a libzorpll problem that can only be solved by a binary incompatible change (fixes: #10873) 2007-01-08 Attila SZALAY * src/thread.c: Removed threadpool implementation. (fixes: #nobug) * src/blob.c (z_blob_system_report_usage): New function to print some statistics about blob system. (fixes: #10326) (z_blob_system_threadproc): Call z_blob_system_report_usage in every 5 minutes. (fixes: #10326) 2007-01-04 Simon Gabor * src/stream.c: possible error when casting from bool to int fixed 2006-12-14 Balazs Scheidler * VERSION: Bumped to 3.1.5.4 2006-12-08 Balazs Scheidler * VERSION: Bumped to 3.1.5.3.1 2006-12-08 Simon Gabor * src/streamblob.c: fixed handling of zero-timeout operation on blob streams (fixes: #10245) 2006-11-07 SZALAY Attila * VERSION: Bumped to 3.1.5.3 2006-10-04 SZALAY Attila * VERSION: Bumped to 3.1.5.2.1 * src/source.c (z_timeout_source_set_timeout): Add new_timeout divided by 1000 to tv_sec and use new_timeout module 1000 in g_time_val_add to avoid long overflow. (fixes: #10170) 2006-09-25 SZALAY Attila * VERSION: Bumped to 3.1.5.2 2006-09-20 SZALAY Attila * VERSION: Bumped to 3.1.5.1.1 2006-09-19 Simon Gabor * src/log.c: Default extremal values set for cmdline log options (fixes: #9889) 2006-09-18 Simon Gabor * src/log.c: setting SIGPIPE action to ignore in z_log_init if there isn't any handler installed (fixes: #9751) 2006-08-28 Balazs Scheidler * src/streamgzip.c (z_stream_gzip_shutdown_method): only call write_trailer if res == G_IO_STATUS_NORMAL (fixes: #9742) 2006-08-24 SZALAY Attila * src/ssl.c (z_ssl_session_new): Reverted too lazy crl dir verifing code. (fixes: #7643) 2006-07-21 SZALAY Attila * VERSION: Bumped to version 3.1.5.1 2006-07-20 Simon Gabor * src/blob.c: (z_blob_system_swap_in) the swap logic now also consideres recently used blobs as fetch-in candidates, (z_blob_unref) to-be-freed blobs are prevented from occasional and unnecessary fetching in * tests/test_blob.c: testcase for storage lock added, timeouts for swap-in tests decreased 2006-07-18 SZALAY Attila * VERSION: Bumped to version 3.1.5.0.3 2006-07-18 Simon Gabor * src/zorp/blob.h, src/blob.c: new attribute 'storage_locked' of blobs inhibits changing the storage media, prevents swapping in/out to ensure that the blob is accessible by the requested way, (z_blob_storage_lock) is the setter function for this (fixes: #9621) 2006-07-05 Balazs Scheidler * VERSION: bumped to version 3.1.5.0.2 2006-07-03 Attila SZALAY * src/stream.c (z_stream_set_child_method): Added a struct reference to child stream. (fixes: #9572) 2006-06-26 SZALAY Attila * VERSION: Bumped to version 3.1.5.0.1 2006-06-26 Krisztian Kovacs * src/stream.c (z_stream_restore_context): call destroy notifiers before overwriting current user_data pointers with the ones saved in the context (fixes: #7998) 2006-06-22 Simon Gabor * src/process.c: (z_process_start) setting of fd limit made optional, it shall be enabled by z_process_set_use_fdlimit() first (fixes: #9005) 2006-06-16 SZALAY Attila * VERSION: Bumped to version 3.1.4.1 2006-06-16 Balazs Scheidler * src/streamline.c (z_stream_line_get_copy): don't try to return a line if the passed buffer size is 0, previously this caused a line to be dropped (fixes: #9339), fixed position calculation when the complete buffer is part of a single line which does not fit the target buffer (fixes: #9339), * src/zorp/streamline.h (z_stream_line_set_truncate): new function, set the truncate bit in flags after construction 2006-06-16 Balazs Scheidler * src/process.c (z_process_startup_failed): don't remove the pidfile as it might not have been created yet (fixes: #9287) 2006-06-16 Simon Gabor * src/streamline.c: line buffer length added to the log message about too long lines (fixes: #9363) 2006-06-16 Balazs Scheidler * src/stream.c (z_stream_read_chunk): changed prototype to return GIOStatus and added a bytes_read argument to make it possible to return partial reads (fixes: #9371), (z_stream_write_chunk): -"- * src/streamgzip.c (z_stream_gzip_read_gzip_header): adapted to z_stream_read_chunk changes 2006-06-16 Simon Gabor * src/misc.c, src/zorp/misc.h: localtime_r added for win32 platform * src/log.c: misc.h included for the def of localtime_r * src/misc.c: missing declaration of z_log_add_option_group added (fixes #9452) * src/log.c: (z_log_init) when setting the logspec, only the default one and the one parsed from the (optional) config were considered * src/log.c: (z_log_func_nosyslog) GLog handler added for logging with timestamp, (z_log_init) installing z_log_func_nosyslog added (fixes #9270) 2006-06-14 Balazs Scheidler * VERSION: bumped to 3.1.4.0.2 2006-06-07 Simon Gabor * src/blob.c: (z_blob_unref) the blob is removed from the blobsystems list in advance to actually destroying the blob resources * src/process.c: pidfile is created only on successful startup (fixes #9287) 2006-06-06 Simon Gabor * src/log.c: commandline options got a separate ZLogOpts structure, so they can override the values coming from config files, all ZLogOpts members got a getter function (z_log_get_*) that handle this overriding, log_opts is no more publicly accessible. (fixes: #8044) 2006-06-06 SZALAY Attila * VERSION: Bumped to version 3.1.4.0.1 2006-06-06 Simon Gabor * src/zorp/log.h, src/log.c: ZLogOpts, z_log_add_option_group added, option-related arguments of z_log_init moved to z_log_set_defaults * src/zorp/misc.h, src/misc.c: Z_OG_LOG added, so z_libzorpll_add_option_groups doesn't necessarily adds option group for log options 2006-06-02 Simon Gabor * src/streamline.c: Previously when the end of the input stream wasn't terminated by an EOL character, G_IO_STATUS_EOF was returned, and so that last line was lost. Now this is fixed, the last line is returned with G_IO_STATUS_NORMAL, however the fact that the trailing EOL is missing can be detected only when the stream was created with the ZRL_RETURN_EOL (return the EOL in the result) flag. (fixes: #9244) * src/source.c: Now ZTimeoutSource keeps track of time using GTimeVal instead of plain second count. However, for keeping it consistent with g_timeout_source, on the interface, all time values are counted in milliseconds. (fixes: #7748) * src/misc.c (g_time_val_compare, g_time_val_diff): New functions added. 2006-05-29 Balazs Scheidler * VERSION: bumped to 3.1.3.1.1 * src/stream.c (z_stream_source_grab_ref): new function, grabs a stream reference when the stream callbacks should be called, (z_stream_source_prepare, z_stream_source_check, z_stream_source_dispatch): use z_stream_source_grab_ref instead of z_stream_struct_ref() directly (fixes: #8118), (z_stream_detach_source_method): protect the source destruction by the detach_lock mutex * src/stream.c (z_stream_source_prepare, z_stream_source_dispatch): bail out if the source is being processed from within its own dispatch callback (fixes: #7346) 2006-05-19 Balazs Scheidler * VERSION: bumped version to 3.1.3.1 2006-05-19 SZALAY Attila * src/stream.c (z_stream_read): Call z_stream_data_dump only if read returned with normal status. (fixes: #nobug) 2006-05-19 Balazs Scheidler * src/process.c (z_process_startup_failed): also close the stdio fds when may_exit is FALSE (fixes: #8838) 2006-05-19 Simon Gabor * src/process.c: (z_process_start) closing of stderr by detach_stdio moved to z_process_startup_ok, so the started daemon may use it until it reports its status (fixes #8838) * lib/blob.c: (z_blob_release_file) filesize check is now done on the fd to handle the case when the file was renamed (fixes #9115) * src/blob.c: (z_blob_alloc, z_blob_truncate, z_blob_add_copy, z_blob_get_ptr, z_blob_read_from_stream, z_blob_write_to_stream) checks for non-negativeness of position value added, (z_blob_get_copy, z_blob_get_ptr) check for positioning beyond blob size added, (z_blob_release_file) re-reading file size added, (z_blob_read_from_stream) when reading into a swapped-out blob, file expanding to the requested position fixed, (z_blob_write_to_stream) check for the result of get_ptr added (fixes #9115) * lib/blob.c: (z_blob_unref, z_blob_system_unref) an assertion occured when the mutex of the blob/blobsystem was destroyed while someone held a lock on it. (fixes #8942) * tests/test_blob.c: (main) testcase added for destroying the blob system while still holding a lock on one of its blobs 2006-05-19 Balazs Scheidler * src/process.c (z_process_change_limits): temporarily remove the fdlimit error message, we should somehow decide when to actually increase the number of fds (fixes: #9005) 2006-05-09 Balazs Scheidler * src/streamline.c (z_stream_line_watch_dispatch): only call the pri callback if dispatch is called _AND_ want_read was FALSE, fixes a data connection establishment problem in FTP * src/stream.c (z_stream_detach_source_method): added locking around checking and destroying self->source (fixes: #9124) * src/stream.c (z_stream_detach_source_method): don't call z_stream_struct_unref unless the stream also had an associated source, added an internal error message when detach is called without stream->source set * src/poll.c (ZRealPoll): removed streams hashtable as it was never used, (z_poll_stream_unref): removed, (z_poll_new): don't initialize self->streams, (z_poll_remove_stream): don't remove the stream from self->streams, * src/stream.c: lot of changes in reference counting, the new refcounting scheme is documented in the code, it would be too long to list all changes here. Also added function docstrings, (z_stream_attach_source_method, z_stream_detach_source_method, z_stream_close_method): new functions, refactorized from descendant stream types * src/streamblob.c, src/streambuf.c, src/streamfd.c, src/streamline.c, src/streamssl.c, src/streamtee.c: use inherited methods instead of reinventing them in every descendant stream types 2006-04-27 SZALAY Attila * Bumped to version 3.1.2.2.1 2006-04-11 Balazs Scheidler * src/streamline.c (z_stream_line_have_line): define avail as gsize, (z_stream_line_get_from_buf): -"- (fixes: #8437) 2006-03-31 SZALAY Attila * Bumped to version 3.1.2.2 2006-03-31 Balazs Scheidler * src/ssl.c (z_ssl_init): set CRYPTO_id_callback to use g_thread_self() as the thread id instead of getpid() (fixes: #8097) 2006-03-30 Holczer Szilard * src/streambuf.c (z_stream_write_packet_internal): Fixed null-pointer dereference. (fixed: #8783) 2006-03-28 SZALAY Attila * Forward ported patches from v3.0 (Up to zorp-lib--mainline--3.0--patch-126)(fixes: #nobug) 2006-03-27 SZALAY Attila * src/process.c (z_process_change_limits): Fixed error message about file number limit raising. (fixes: #8734) 2006-03-24 SZALAY Attila * Bumped to version 3.1.2.1 2006-03-24 Balazs Scheidler * src/process.c (z_process_enable_core): removed HAVE_PR_SET_DUMPABLE condition as it is not defined by the configure script 2006-03-24 SZALAY Attila * Bumped to version 3.1.2.0.1 2006-03-23 Balazs Scheidler * src/process.c (z_process_set_*): don't override values set by the user * src/streamline.c: stream line error messages are logged with a more descriptive message (fixes: #8461) 2006-03-23 Simon Gabor * src/streamline.c: ZStreamLine errors are logged (fixes #8461) 2006-03-23 Balazs Scheidler * src/misc.c (z_libzorpll_add_option_groups): don't use ZProcess API on Windows as it is not compiled on that platform * src/zorp/blob.h (ZBlob, ZBlobSystem): use ZRefCount for reference counting * src/blob.c: use z_refcount_{inc,dec} functions, (z_blob_system_default_init): removed 2006-03-23 Simon Gabor * src/blob.c: a reference to a variable preceded the assignment of it (fixes #7168) * src/misc.c, src/zorp/misc.h: Macro YES_NO_STR added, ON_OFF_STR made public (fixes #8616) * src/blob.c, src/zorp/blob.h: Concurrent access support for blobs removed (there is no nned for it) Communication between blob user thread and management thread optimised: only unsatisfiable requests are passed and waited for Allocated- and used-size counters mixup cleaned. * tests/test_blob.c: testcase for blobs added 2006-03-23 Balazs Scheidler * VERSION: 3.1.1.1.5 * src/process.c (z_process_start): removed umask(0) (fixes: #8691) * src/thread.c: fixed bad negation in max_stack_size parsing 2006-03-22 Balazs Scheidler * VERSION: 3.1.1.1.4 * src/thread.c: fixed max_stack_size parsing * src/memtrace.c (TMP_ALLOCATED): changed to unsigned comparison as it erroneously returned TRUE for pointers which were in fact not on the temp heap 2006-03-21 Balazs Scheidler * VERSION: 3.1.1.1.3 * src/process.c (max_threads): added as an extern as it is used in fd limit calculation, (z_process_change_limit): new function, sets fd limit (fixes: #8186), (z_process_option_entries): added fd-limit-min and fd-limit-threshold options, (process_opts): set fd_limit_min to 1024, fd_limit_threshold to 64 * src/thread.c (max_threads): removed static 2006-03-17 SZALAY Attila * src/misc.c (z_libzorpll_add_option_groups): Added disable_groups parameter to disable adding some of the groups to GoptionContext. (fixes: #nobug) 2006-03-17 Pal Tamas * src/makefile.msc: pdbfile's name modified from default to one under $(COMPILE_ENV)\deb\debug. Added commands to copy this $(COMPILE_ENV)\out\debug. * winbuild/build.bat.in: Modifeid zip's parameter list to archive the contents of the debug dir too. * makefile.msc: Added insttruction to create $(COMPILE_ENV)\deb\debug dir. 2006-03-17 Balazs Scheidler * src/process.c (z_process_change_dir): only change directory if process_opts.mode is not Z_PM_FOREGROUND, (z_process_option_entries): added arg_data to -F (fixes: #8186) * src/cap.c (zorp_caps): default to NULL, it is going to be set by the process API code later on, * src/misc.c (z_libzorpll_add_option_groups): new function, adds the libzorpll defined option groups to an application defined GOptionContext * src/process.c (process_opts): initialize mode to Z_PM_SAFE_BACKGROUND, removed flags member (z_process_set_mode): removed flags argument, use separate gboolean values instead, (z_process_set_argv_space): renamed from the misleading z_process_set_proc_title, (z_process_detach_tty): always detach the terminal if we are in the background, (z_process_enable_core): use process_opts.core instead of Z_PF_CORE, (z_process_format_pidfile_name): pidfile is relative if it does not start with '/', (z_process_change_caps): set the zorp_caps global variable, (z_process_change_dir): use process_opts.core instead of Z_PF_CORE, (z_process_perform_supervise): follow the rename of proc_title to argv_space, (z_process_add_option_group): new function, adds the 'process' GOptionGroup to the application context (fixes: #8186) * src/thread.c (z_pt_thread_init): removed getrlimit call as it is not needed in 3.1, (z_thread_add_option_group): new function, adds the 'thread' GOptionGroup to the application context (fixes: #8623) * src/thread.c (z_thread_init): set the value for RLIMIT_STACK and use g_thread_create_full() to specify stack size, it does not work for thread pools (fixes: #8623), (use_threadpools, max_threads, idle_threads): removed these global variables, (z_thread_set_max_threads, z_thread_set_max_stack_size, z_thread_enable_threadpools): new functions to set various ZThread parameters before calling z_thread_init (fixes: #8623), added docstrings * src/stream.c (z_stream_ctrl_method): do not derefere self->source if it is NULL (fixes: #8118), (z_stream_set_child_method): removed an unneeded g_return_if_fail() * src/stream.c (ZStreamSource): added dispatch_lock member, (z_stream_source_dispatch): lock SET_COND messages, (z_stream_set_child_method): disable child stream callbacks, handle new_child == NULL case, (z_stream_pop): use z_stream_set_child(NULL) instead of manipulating self->child directly, (z_stream_free_method): -"-, * src/streambuf.c (z_stream_buf_set_child): handle new_child == NULL case * src/streamgzip.c (z_stream_gzip_set_child): -"-, * src/streamline.c (z_stream_line_set_child): -"-, * src/streamssl.c (z_stream_ssl_set_child): -"-, * src/streamtee.c (z_stream_tee_set_child): -"-, 2006-03-14 Balazs Scheidler * configure.in: added checks for prctl, sys/prctl.h, added ZORPLIB_PIDFILE_DIR (currently hard-wired) * src/misc.c, src/zorp/misc.h: moved z_resolve_{user,group} to process.h * src/process.c: new API for z_process that handles, user/group change, chroot, core dumping, tty detach. The API is easily extendably and the 'auto-restart' feature described in #8186 should be addable easily, however it is not yet implemented. The change is incompatible. (fixes: #8186) * src/process.c (z_process_set_proc_title): new function, sets the address of the argv space, (z_process_message): new function, emits a message within the ZProcess implementation using stderr if possible, but falling back to syslog if not, (z_process_detach_stdio): new function split off from z_process_detach_tty() to close stdin/out/err, (z_process_send_result): moved upwards to make it available to other parts of the code, changed to transparently support the communication of startup/supervisor/daemon processes, (z_process_recv_result): new function, retrieves a return code sent by _send_result(), (z_process_perform_startup): new function, represents the 'startup' process, (z_process_perform_supervise): new function, represents the 'supervisor' process, (z_process_start): added support for Z_PM_SAFE_BACKGROUND, (*): changed all fprintf() calls to z_process_message, updated docstrings 2006-02-21 Balazs Scheidler * Bumped to version 3.1.1.1.2 2006-02-21 Balazs Scheidler * src/packetbuf.h (ZPacketBuffer): changed reference count to ZRefCount (fixes: #8464) * src/packetbuf.c (z_packet_buffer_ref, z_packet_buffer_unref): changed to use ZRefCount (fixes: #8464) * src/streambuf.c (z_stream_buf_write_method): create ZPacketBuffer locally to make it possible to incref the packet buffer for logging (fixes: #8464), (z_stream_write_buf_internal): removed and used open-coding instead, each caller function requires a reference to the packetbuffer itself (fixes: #8464), (z_stream_write_buf): incref packet buffer for logging (fixes: #8464) 2006-02-20 SZALAY Attila * Bumped to version 3.1.1.1.1 2006-02-20 SZALAY Attila * src/streamline.c (z_stream_line_read_method): Fixed a 64bit issue when reading bytes from a streamline. (fixes: #8437) (z_stream_line_read_method): Added data dump when reading bytes from a streamline. (fixes: #8437) * src/memtrace.c: Fixed pointer usage. Do not cast them to guint32. (fixes: #8437) 2006-02-16 Balazs Scheidler * forward-ported changes from 3.0 up to patch-122, for details see archives-changelogs/3.0/ChangeLog 2006-02-03 Balazs Scheidler * src/misc.c, src/misc.h: fixed compilation issues on win32 2006-02-03 SZALAY Attila * src/memtrace.c (z_mem_trace_bt): Implement sparc version and a dummy one. (fixes: #8191) 2006-02-03 Pal Tamas * debian/control.in: Added -memtrace package description. * debian/rules.in: Re-enabled the former -dbg package generation as -memtrace. * debian/rules.in: removed old dbg package creating code. Compat level changed to 4. Uses dh_install instead of dh_movefiles. * debian/Makefile.am: Administered file renames. * debian/control.in: changed -dbg package's description. * debian/libzorpll-dev.files.in: renamed to debian/libzorpll-dev.install.in * debian/libzorpll.files.in: renamed to debian/libzorpll.install.in * debian/rules.in: Enabled the binary-independent package generation. 2006-01-28 Balazs Scheidler * src/stream.c (z_stream_read): free the ungot packet buffer (fixes: #nobug) 2006-01-26 Attila SZALAY * src/misc.c: Added some include. (fixes: #nobug) * src/zorp/misc.h: Define the two new function, z_resolve_user and z_resolve_group. (fixes: #nobug) * src/misc.c (z_resolve_group): New function resolve the group to gid_t. (fixes: #nobug) * src/misc.c (z_resolve_user): New function resolve the user to uid_t. (fixes: #nobug) * src/zorp/blob.h: Change the define of the z_bob_get_file, because of the 3 new parameter. (fixes: #nobug) * src/blob.c (z_blob_get_file): Set the owner and the group of the file if needed. Also change the mode. (fixes: #nobug) 2006-01-18 SZALAY Attila * src/blob.c (z_blob_alloc): Change function type to void. (fixes: #nobug) (z_blob_alloc): Fixed usage of self->size and self->alloc_size (fixes: #nobug) (z_blob_alloc): Fixed a wrong error message, when truncating the full blob (fixes: #nobug) (z_blob_alloc): Fixed self->size if blob was shrinked. (fixes: #nobug) 2006-01-18 Balazs Scheidler * src/zorp/socket.h (z_socket_type_to_str): new function, returns a string representation of a socket type (dgram or stream) * src/connect.c (z_connector_open_socket): fixed socket type in log message, enable SO_REUSEADDR 2006-01-17 Balazs Scheidler * src/zorp/streamgzip.h (GZIP_MAGIC_LEN, GZIP_IS_GZIP_MAGIC): new macros to test for gzip magic numbers (fixes: #7661) * src/streamgzip.c: use gzip magic macros instead of static variables 2006-01-16 SZALAY Attila * tests/test_sockaddr.c (test_assert): Exit if error happened. (fixes: #7950) 2006-01-14 Balazs Scheidler * src/streamgzip.c (ZStreamGzip): removed flush, err, eof_before & eof_after members, use a bitfield called 'state' for these values, (z_stream_gzip_flush): removed this function as nothing used it (!?!?!) and seemed to duplicate a lot of code, (z_stream_gzip_read_gzip_header, z_stream_gzip_write_gzip_header): new functions to read/write GZip file headers, (z_stream_gzip_reset_gzip_header): reset the allocated memory used for gzip headers, (z_stream_gzip_write_gzip_trailer): new function to write the crc32 value of the compressed data, called from _shutdown, (z_stream_gzip_{set,get}_header_fields): changed the prototype and implementation to only touch the fields stored in self, (z_stream_gzip_fetch_header): new function, triggers an explicit header fetch, without actually reading compressed data, the header is automatically read by _read_method as well, but for cases where the header is needed earlier than the first byte of data this function is useful (z_stream_gzip_is_gzip_stream): removed as it is not related to ZStreamGzip in any way * tests/test_streams.c: added testcase for ZStreamGzip both using a gzip header and without a gzip header 2006-01-14 Balazs Scheidler * src/stream.c (z_stream_read_chunk, z_stream_write_chunk): cleaned up, added docstring and a notice about non-blocking usage 2006-01-13 Simon Gabor * src/stream.c, src/streamgzip.c, src/zorp/stream.h, src/zorp/streamgzip.h: code cleanup and on-demand header writing implemented (fixes #7661) * src/streamgzip.c, src/zorp/streamgzip.h: gzip header support added (fixes #7661) Constructor argument for flush mode converted to flag-set. 2006-01-13 Balazs Scheidler * src/streamtee.c (z_stream_tee_shutdown_method, z_stream_tee_close_method): new functions, close/shutdown methods for ZStreamTee (fixes: #7962) * src/zorp/stream.h (z_stream_shutdown): make shutdown method optional by returning a silent success if it does not exist, ZStreamBlob does not have a shutdown callback and there's no point implementing one (fixes: #7962) 2006-01-04 Balazs Scheidler * src/zorp/sockaddr.h (_ZSockAddrFuncs): added sa_equal func (fixes: #7950) * src/sockaddr.c (z_sockaddr_inet_equal, z_sockaddr_inet6_equal, z_sockaddr_unix_equal): implemented separate equal checking functions for various ZSockAddr types, (z_sockaddr_equal): call the sockaddr type specific equal function (fixes: #7950) * tests/test_sockaddr.c: new unit test program to test z_sockaddr_equal for various ZSockAddr construction cases (fixes: #7950) 2005-12-30 Balazs Scheidler * VERSION: bumped to 3.1.0.2 (alpha2) 2005-12-22 Balazs Scheidler * src/log.c (z_log_source_new): return the GSource instance instead of attaching it directly to the main context, (z_log_run): make sure a reference remains with z_log_run even if the destruction routine finishes, moved the attachment of ZLogSource to the main context here from z_log_source_new (fixes: #7839), (z_log_destroy): free the log_context reference here instead at the end of the log thread as we might need it to signal wakeup, fixes a possible deadlock during exit (fixes: #7839) 2005-12-21 Balazs Scheidler * src/misc.c (z_libzorpll_version_info): renamed from z_zorplib_version_info, increased buf size 2005-12-13 Krisztian Kovacs * autogen.sh: set executable bit(s) * {arch}/=tagging-method: add cscope and Emacs semantic files as precious 2005-12-13 Balazs Scheidler * src/packetbuf.c (z_packet_buffer_insert_data): new function to insert data in a ZPacketBuf at the specified location * src/stream.c (z_stream_source_*): fixed a possible race between finalize and other stream callbacks, also added a detailed note on how the locking inside ZStreamSource works (fixes: #7705) * src/streamline.c (z_stream_line_get_from_buf): return the EOL marker if ZRL_RETURN_EOL is enabled (fixes: #1761) * tests/test_streams.c (test_streamline): new function, tests the new ZRL_RETURN_EOL flag for ZStreamLine (fixes: #1761) * src/socket.c (z_bind): one of the error cases did not contain an error message, added that 2005-12-12 Simon Gabor * lib/blob.c: now the blobs can map from any position, not just from a multiple of pagesize 2005-12-07 Balazs Scheidler * src/blob.c (many functions): instead of using gsize for the size of the blobs, use gint64, (z_blob_alloc): forward ported fix from zorp-core--dev-fules--3.0--patch-213, (z_blob_read_from_stream): new function, forward ported z_blob_read_from_stream from, zorp-core--dev-fules--3.0--patch-213, changed prototype to match ZStream-like semantics, (z_blob_write_to_stream): new function, writes the blob to the stream specified without copying data (e.g. uses mmap) 2005-12-05 Balazs Scheidler * src/blob.c (z_blob_system_default_max_disk_usage): changed to gint64 2005-12-01 SZALAY Attila * Bumped to version 3.1.0.1.2 * Fixed some 64bit issues. 2005-11-30 SZALAY Attila * Bumped to version 3.1.0.1.1 2005-11-29 Simon Gabor * src/blob.c, src/streamtee.c: uninitialised variables fixed 2005-11-29 Balazs Scheidler * src/blob.c (z_blob_system_default_destroy): set z_blob_system_default to NULL after deinitialization, (z_blob_get_ptr): added an invariant to check if self->mapped_ptr is NULL, (z_blob_free_ptr): fixed docstring by removing req_datalen, * src/zorp/misc.h (Z_REFCOUNT_INIT): new macro to initialize a reference counter * src/zorp/zobject.h (z_object_ref, z_object_unref): converted to inline functions, use the new ZRefCount functions, (Z_OBJECT_INIT): new macro to initialize a statically allocated ZObject instance (e.g. ZClass), (Z_CLASS_INIT): new macro to initialize a statically allocated ZClass instance * src/sockaddr.c (z_sockaddr_ref, z_sockaddr_unref): use the new z_refcount_inc & _dec functions * src/misc.h: added ZRefCount and associated inline functions which uses the atomic functions in GLib to provide atomic reference counting which is way cheaper than using a real mutex * src/poll.c (z_poll_iter_timeout): do not call dispatch unless _check returned TRUE, fixes a possible assertion failure in ZCV * src/blob.c (z_blob_system_swap_in): do not start swapping in blob unless disk is over hiwat * src/blob.c: fixed log messages * src/streamtee.c, src/zorp/streamtee.c: new files, contains ZStreamTee class * src/blob.c (z_blob_unref): added code to handle NULL values * src/log.c (z_log_change_verbose_level): handle if new_value == NULL 2005-11-02 SZALAY Attila * src/blob.c, src/streamblob.c, src/zorp/blob.h, src/zorp/streamblob.h: Files added. (moved from zorp) * src/parser.c, src/zorp/parser.h: Removed (moved to libzmisc) 2005-11-02 Balazs Scheidler * src/log.c (z_log_change_logspec): handle when new_spec is NULL, as the caller might not be interested in the new logspec 2005-10-31 Balazs Scheidler * src/connect.c (z_connector_connected): fixed error reporting when the connection failed (introduced by the feature-sip changes) 2005-10-14 SZALAY Attila * Bumped to version 3.1.0.1 2005-10-13 SZALAY Attila * Bumped to version 3.1.0.0.6 2005-10-07 SZALAY Attila * Bumped to version 3.1.0.0.5 2005-10-06 SZALAY Attila * Bumped to version 3.1.0.0.4 * Upported som bugfix from v3.0. 2005-10-05 SZALAY Attila * src/streamline.c (z_stream_line_get_internal): Move self->end back with readed len if ZRL_IGNORE_TILL_EOL is set. (fixes: nobug) * Bumped to version 3.1.0.0.3 2005-09-28 Balazs Scheidler * src/log.c: change default session_id to "nosession", change stderr thread name to "stderr" * src/streamfd.c (z_stream_fd_read_method): fixed fd-level data logging * src/stream.c (z_stream_set_child_method): iterate umbrella state updates up to the last child, (z_stream_read, z_stream_write): call z_stream_data_dump * src/zorp/stream.h (z_stream_data_dump): new function to produce an I/O dump, (z_stream_set_name): iterate name change for all child streams * src/streambuf.c: make sure z_stream_data_dump is called for non-standard, ZStreamBuf specific entry points * src/streamline.c: make sure z_stream_data_dump is called for non-standard, ZStreamLine specific entry points * src/packetbuf.c: renamed self pointers to 'self', (z_packet_buffer_append_data): new function * src/packetbuf.c, src/zorp/packetbuf.h: new files, moved the implementation ZStreamBuffer as ZPacketBuffer here * src/*.c: changed all references to ZStreamBuffer 2005-09-28 Krisztian Kovacs * src/stackdump.c: don't compile stackdump-related functions unless ZORPLIB_ENABLE_STACKDUMP is true (fixes: #6979) 2005-09-28 Simon Gabor * src/sockaddr.c: a remaining reference to z_sockaddr_inet_range_new_inaddr fixed (fixes nobug) * src/source.c, src/zorp/source.h: z_timeout_source_disable() added src/sockaddr.c, src/zorp/sockaddr.h: z_sockaddr_inet_range_new_inaddr() added 2005-08-31 ABONYI Balint * fixed compiling under windows, removed C99 usage * added LIBZORPLL_EXTERN define * removed all warnings from type casts 2005-08-23 SZALAY Attila * src/zorp/misc.h (Z_STRING_SAFE): New macro. Check that string is null or not. (fixes: nobug) 2005-08-19 Balazs Scheidler * src/sockaddr.c (z_sockaddr_unix_check): new function, (z_sockaddr_inet_get_port): moved to sockaddr.h and made inline, (z_sockaddr_inet_get_address): moved to sockaddr.h and made inline, return a struct in_addr instead of a plain guint32 * src/sockaddr.h: moved some functions from sockaddr.c and made inline, (z_sockaddr_get_sa, z_sockaddr_inet_get_sa, z_sockaddr_inet_set_port, z_sockaddr_inet_set_address, z_sockaddr_unix_get_path): new inline functions for easier ZSockAddr manipulation 2005-07-29 Balazs Scheidler * src/log.c, src/zorp/log.h: removed z_llog2() mess, forwardported 3.0 fix which cannot go in there, as it is binary incompatible (fixes: #6397) 2005-07-28 SZALAY Attila * Bumped to version 3.1.0.0.2 2005-07-21 Balazs Scheidler * src/sockaddr.c: removed braindamaged options storing (did not belong here anyway), forward ported ipv6 sockaddr support from ancient sources, removed ENABLE_IP_OPTIONS and ENABLE_IPV6 defines (always compiled with ipv6 support) 2005-07-21 Balazs Scheidler * src/random.c: get rid of ZRandom completely, use SSL random generator functions, (z_random_sequence_get_bounded): fixed get_bounded value generation problem, (z_random_sequence_get): separate function to generate raw random sequence 2005-07-21 Balazs Scheidler * src/stream.c (z_stream_free_method): fixed memory leak, free self->name 2005-07-21 Balazs Scheidler * src/streambuf.c (z_stream_buf_shutdown_method): flush buffers in SHUT_RDWR as well 2005-07-21 Balazs Scheidler * src/streambuf.c (ZStreamBuf): use ZStreamPacket instead of ZStreamBufNode as the internal data buffer, (z_stream_write_packet): new function, expects a ZStreamPacket which is automatically consumed by the stream 2005-07-21 Balazs Scheidler * src/streambuf.c, src/streamline.c (z_stream_*_new): handle if child is NULL 2005-07-21 Balazs Scheidler * src/stream.c (z_stream_set_child_method): count the number of streams in a stack * src/streambuf.c: ZStreamBuf now finally behaves like a ZStream should, it is both source/binary incompatible * src/streamline.c (z_stream_line_attach_source_method): use the calculated stack_depth value instead of walking the stack for every z_stream_attach_source() invocation * tests/test_streams.c: added small testprogram for ZStreamBuf 2005-07-15 Balazs Scheidler * src/stream.c (z_stream_packet_ref): new function, (z_stream_packet_free): use reference counter, and only free if it becomes 0 * src/stream.c (z_stream_packet_set_size): new function to ensure properly sized data field, (z_stream_packet_set_data): do not leak if called multiple times * src/stream.c (z_stream_packet_replace_data): new function to replace the packet data without copying 2005-07-15 Krisztian Kovacs * src/stream.c (z_stream_read): don't copy more data than the length of the packet 2005-06-15 SZALAY Attila * debian/libzorpll.shlibs.in.in: Change the name of the package. 2005-06-01 SZALAY Attila * Bumped to version 3.1.0.0.1 2005-05-13 Balazs Scheidler * src/connect.c, src/listen.c: call z_object_free() from z_listener_free and z_connector_free * src/zorp/log.h (z_logv2, z_llog): make session_id const * src/memtrace.c: fixed a couple of shadowed variable * src/misc.c (z_format_data_dump): added const to session_id argument * src/stream.c (z_stream_read): use memmove instead of memcpy when reading from unget buffers, (z_stream_new): make name const parameter * src/stream.h (ZStream): make name member const, (z_stream_set_name): warn if new_name is NULL * src/test_streams.c: new file to test basic ZStream functionality 2005-05-13 Balazs Scheidler * src/stream.c, src/stream.h: moved ZPacket from zorp-core here under the name of ZStreamPacket, (z_stream_unget, z_stream_unget_line): new functions to push back data to the stream, (z_stream_free_method): free remaining unget bufs, 2005-05-13 Balazs Scheidler * src/zorp/log.h (z_log_enabled_len): make tag const gchar *, (z_log_data_dump): new inline function, first checks z_log_enabled, then calls z_data_dump(), * src/misc.c (z_format_data_dump): renamed from z_data_dump, new log class and level parameters * src/stream.c (z_stream_read, z_stream_write): stream operations are always logged from here (error, datadump), added GError support * src/streambuf.c, src/streambuf.c (error_callback): added GError parameter * src/streamfd.c: in addition to ZStream logging, also log low-level fd specific logging at a higher log level if ZStreamFD is not the toplevel stream (levels: 8/10 instead of 7/9) * src/streamgzip.c, src/streamline.c, src/streamline.c, src/streamssl.c: use GError everywhere to report problems 2005-05-13 Balazs Scheidler * src/stream.c: made ZStreamSource and ZStreamSetCb private, (z_stream_set_cond, z_stream_set_callback): do not inline these, implementation moved to stream.c, (z_stream_set_child): new virtual function to set a stream's child stream, used to implement dynamic stream stacking, (z_stream_push, z_stream_pop): new functions to manipulate the stream stack, (z_stream_read, z_stream_write): do not inline these, logging removed from ZStreamFd and moved here, * src/streamfd.c, src/streamgzip.c, src/streamline.c, src/streamssl.c, src/streambuf.c: adapted to ZStream changes * tests/test_ssl.c: test program for ZStreamSsl 2005-05-13 Balazs Scheidler * tests/test_conns.c: adapt to the latest changes in listener/connector 2005-05-13 Balazs Scheidler * src/connect.c (z_connector_connected): instead of passing the fd directly, pass a newly created ZStreamFD to the user callback, (z_connector_free): do not free self it is done by the ZObject destructor * src/listen.c (z_listener_accept): also pass the original destination address to the callback, (z_listener_free): do not free self, as it is done by the ZObject destructor * src/sockaddr.c (z_sockaddr_equal): new function to compare to ZSockAddr values 2005-05-13 Balazs Scheidler * src/connect.c: renamed ZIOConnect to ZConnector, made it socket-type independent, * src/zorp/connect.h (ZStreamConnector): created ZStreamConnector compatible with ZIOConnect * src/listen.c: renamed ZIOListen to ZListener, made it socket-type independent, (ZStreamListener): new class, compatible with ZIOListen * tests/test_conns.c: updated to reflect changes in ZIOListen and ZIOConnect 2005-05-13 Balazs Scheidler * src/listen.c, src/connect.c: ZIOListen and ZIOConnect converted to ZObject, ZIOListen generalized a bit to make it possible to use a common codebase for UDP * tests/test_conns.c: new test program for ZIOListen and ZIOConnect libzorpll-3.9.4.1/archived-changelogs/3.1/VERSION000066400000000000000000000000101224546767600211570ustar00rootroot000000000000003.1.8.4 libzorpll-3.9.4.1/archived-changelogs/3.3/000077500000000000000000000000001224546767600201225ustar00rootroot00000000000000libzorpll-3.9.4.1/archived-changelogs/3.3/ChangeLog000066400000000000000000000317201224546767600216770ustar00rootroot000000000000002009-05-25 Szalay Attila * VERSION: Bumped to 3.3.0.9 2009-05-17 SZALAY Attila * VERSION: Bumped to 3.3.0.8.1 2009-05-07 Szalay Attila * src/zorp/memtrace.h: Including glib.h which needed because of the changes in zorplib.h. (fixes: #nobug) * src/process.c, src/zorp/process.h (z_process_get_check_enable): Added void parameter statement. (fixes: #nobug) * src/zorp/misc.h: Added glib.h include statement needed because of the changes in zorplib.h. (fixes: #nobug) 2009-05-06 Czilly Gergely * src/zorp/zorplib.h: Moved the inclusion of zorplibconfig.h before the inclusion of glib.h so that enabling large file support can take full effect. (fixes: #14008) * configure.in: Enabled large file support. (fixes: #14008) * src/blob.c: Switched from gint to off_t for the purpose of storing large-file-related return values. (fixes: #14008) 2009-04-25 Czilly Gergely * configure.in: Made --enable-debug use -O0 because the default is not this. (fixes: #nobug) * src/process.c: Added access functions to toggle and get enabled/disabled state of deadlock checker. (fixes: #13315) * src/zorp/process.h: Added prototypes for access functions. (fixes: #13315) 2009-04-25 Laszlo Attila Toth * src/process.c (z_process_perform_supervise): always call waitpid, which didn't happen in the last iteration due to the lazy evaluation of '&&' operator (fixes #13596) 2009-04-16 Simon Gabor * configure.in: locating of ssl headers/libs improved (fixes: #18487) * src/blob.c: blob seek error fixed (fixes: #18480) 2009-04-04 Balazs Scheidler * src/streamssl.c (z_stream_ssl_shutdown_method): handle SSL_shutdown properly by setting the child stream in nonblocking mode and giving SSL 1 second to actually finish the two-way shutdown sequence (fixes: #18060) 2009-04-03 Szalay Attila * src/streamssl.c (z_stream_ssl_shutdown_method): Added the calling of child's shutdown method. (fixes: #18060) 2009-03-16 Szalay Attila * VERSION: Bumped to 3.3.0.8 2009-03-03 Szalay Attila * VERSION: Bumped to 3.3.0.7 2009-03-03 Laszlo Attila Toth * src/thread.c (z_thread_stack_size_arg): log error to stderr instead of calling z_log because log system not yet initialized (fixes #16207) * src/thread.c (z_thread_stack_size_arg): if the requested stack size is larger then 256 kiB, set it to 256 kiB and log it as an error (fixes #16207) 2009-02-26 SZALAY Attila * src/streamgzip.c, src/stream.c: Fixed linxu compilation errors created by the windows compilation error fixes. (fixes: #nobug) * src/streamgzip.c (z_stream_gzip_write_callback,z_stream_gzip_write_method,z_stream_gzip_shutdown_method): Cast self->buffer_encode_out_p to gchar because we do some char arithmetic with it. (fixes: #nobug) * src/stream.c (z_stream_read_chunk, z_stream_write_chunk): Cast buf to gchar becouse we do some char arithmetic with it. (fixes: #nobug) * src/sockaddr.c (z_sockaddr_inet_new_hostname): Remove this function from windows build. (fixes: #nobug) 2008-12-02 Szalay Attila * VERSION: Bumped to 3.3.0.6. (This version bump is needed because of an update release. The update release is needed becouse of the Windows GUI.) 2008-11-22 SZALAY Attila * Forward-ported patches from v3.1. (239-241,243-254) 2008-11-03 Balazs Scheidler * configure.in: don't check the existence of openssl/ts.h (fixes: #nobug) 2008-10-20 Balazs Scheidler * src/sockaddr.c (z_sockaddr_inet_new_hostname): renamed from z_sockaddr_inet_hostname_new, removed Solaris specific ifdefs, added docstring (fixes: #nobug) 2008-10-19 Laszlo Attila Toth * src/ssl.c (z_ssl_get_error_str): gets the last error. If there were others, a 'supressed %d messages' string is appended to the error msg (fixes #14644) 2008-10-18 Laszlo Attila Toth * src/sockaddr.c, src/zorp/sockaddr.h: added z_sockaddr_inet_hostname_new(hostname, port) to create a SockAddrInet object by hostname and port. If the hostname can't be resolved, the result is a NULL pointer (fixes #nobug) * src/Makefile.am, src/zorp/Makefile.am: filename changes (fixes #14644) * src/misc.c, src/zorp/misc.h (g_time_val*): const parameters; added z_timeval_subtract with non-negative result (fixes #14644) * src/zorp/gurl.h: renamed to src/zorp/zurlparse.h g_url* renamed to z_url* (fixes #14644) * src/gurl.c: renamed to src/zurlparse.c g_url* renamed to z_url* (fixes #14644) * src/gurl.c, src/zorp/gurl.h: URL parser code from syslog-ng-pe v3.0 (fixes #14644) * src/Makefile.am, src/zorp/Makefile.am: added gurl.[ch] (fixes #14644) 2008-10-18 Balazs Scheidler * src/zorp/packetbuf.h, src/packetbuf.c: changed prototypes to use "void *" instead of "guchar *" to avoid signedness warnings at call sites 2008-10-18 Balazs Scheidler * src/socket.c: fixed gcc-4.2 generated warnings * src/log.c: -"- * src/stackdump.c: -"- * src/packetbuf.c: -"- * src/blob.c: -"- * src/misc.c, src/zorp/misc.h, src/zorp/log.h: -"- 2008-10-18 Balazs Scheidler * src/zorp/stream.h: changed read/write methods to void *, as that solves a large number of signedness warnings * src/stream*.c: changed stream read/write method prototypes to use void * 2008-10-18 SZALAY Attila * test/portrandom.c, tests/randtest.c, tests/randtest.h: Added randomized port allocation check functions. (fixes: #15718) * src/socket.c (z_do_ll_bind): Lowlevel implementation of source port randomization support. (fixes: #15718) * src/streamline.c (z_stream_line_get_internal): Made ZStreamLine count bytes received on line-oriented reads. (fixes: #8393) * src/zorp/zobject.h, src/cap.c, src/connect.c, src/crypt.c, src/error.c, src/io.c, src/listen.c, src/log.c, src/memtrace.c, src/misc.c, src/poll.c, src/process.c, src/random.c, src/registry.c, src/sockaddr.c, src/socket.c, src/socketsource.c, src/source.c, src/ssl.c, src/stackdump.c, src/stream.c, src/streambuf.c, src/streamfd.c, src/streamgzip.c, src/streamline.c, src/streamssl.c, src/thread.c, src/zobject.c, src/zorp/connect.h, src/zorp/listen.h, src/zorp/log.h, src/zorp/misc.h, src/zorp/poll.h, src/zorp/random.h, src/zorp/sockaddr.h, src/zorp/socket.h, src/zorp/socketsource.h, src/zorp/ssl.h, src/zorp/stackdump.h, src/zorp/stream.h, src/zorp/streambuf.h, src/zorp/streamgzip.h, src/zorp/streamline.h, src/zorp/thread.h, src/packetbuf.c, src/zorp/packetbuf.h, src/streamtee.c, src/blob.c, src/zorp/blob.h, src/streamblob.c, src/code_base64.c, src/code.c, src/code_cipher.c, src/code_gzip.c, src/zorp/code.h: Added and fixed Doxygen comments. (fixes: #nobug) 2008-10-18 Balazs Scheidler * src/streamline.c (z_stream_line_ctrl_method): added support for ZST_LINE_GET_NUL_NONFATAL (fixes; #13874) 2008-10-18 Balazs Scheidler * src/memtrace.c: only report memtrace summary once per second instead of once per 1000 allocations (fixes: #nobug) 2008-10-18 Balazs Scheidler * configure.in: use pkg-config to detect openssl instead of the handcrafted detection routine, fixes openssl detection if it is installed in zwa install directory (fixes: #nobug) 2008-09-16 Szalay Attila * VERSION: Bumped to 3.3.0.5 2008-08-28 Szalay Attila * VERSION: Bumped to version 3.3.0.4.1 * Forward-ported patches from version 3.1 (238, 242) 2008-08-08 Szalay Attila * VERSION: Bumped to 3.3.0.4 2008-07-21 SZALAY Attila * tests/test_base64.c, tests/test_codecipher.c, tests/test_codegzip.c: Added some include statement. (fixes: #nobug) * VERSION: Bumped to 3.3.0.3.1 2008-07-15 Szalay Attila * Forward-ported patches from version 3.1 (227-237) 2008-07-14 Laszlo Attila Toth * src/zorp/packetbuf.h: Added z_pkt_buf_{get,set}_c8 functions for gchar type and z_pkt_buf_{get,set}_c8s for gchar * types 2008-07-14 Szalay Attila * src/stream.c (z_stream_ctrl_method): Changed stream behaviour to call destroy notify if user data would be overwritten. (fixes: #12876) 2008-06-11 Szalay Attila * VERSION: Bumped to 3.3.0.3 2008-06-11 Laszlo Attila Toth * src/zorp/socket.h: added ZSF_TRANSPARENT socket flag (fixes #14029) 2008-03-26 Szalay Attila * VERSION: Bumped to 3.3.0.2 2008-03-21 Szalay Attila * tests/test_codegzip.c: Added stdlib include because it's needed for realloc. (fixes: #nobug) 2008-03-20 Szalay Attila * VERSION: Bumped to 3.3.0.1.3 2008-03-12 Szalay Attila * src/process.c (z_process_change_limits): Fixed a type in two message. (fixes: #13038) * src/process.c: Obsolated fd-limit-threshold and raised fd-limit-min to 256000. (fixes: #13038) 2008-03-05 Szalay Attila * Forward-ported patches from version 3.1 (215-226) 2008-02-08 SZALAY Attila * tests/test_codegzip.c: Added stdio including to made it able to compile. (fixes: #nobug) * VERSION: Bumped to 3.3.0.1.2 2008-02-01 Szalay Attila * tests/Makefile.am: Added test_base64 test_codegzip test_codecipher tests. (fixes: #nobug) 2008-01-31 Szalay Attila * VERSION: Bumped to version 3.3.0.1.1 2008-01-24 Szalay Attila * src/code.c, src/code_base64.c, src/code_cipher.c, src/code_gzip.c, src/zorp/code.h, src/zorp/code_base64.h, src/zorp/code_cipher.h, src/zorp/code_gzip.h: Moved ZCode related file here to be able to use from zcv. (fixes: #12253) * src/io.c (z_fd_set_our_tos): Removed confusing message when stacking a proxy. (fixes: #12852) * src/io.c (z_fd_get_peer_tos): Do not try to set socket option in getsockopt failed. (fixes: #12852) 2007-10-18 Balazs Scheidler * VERSION: bumped to 3.3.0.1 2007-09-29 SZALAY Attila * Forward-ported patches from version 3.1 (207-214) 2007-08-24 Pal Tamas * winbuild/libzorpll.la: Added ersatz libtool la file help waf or other libtool using builder to link libzorpll-X.Xs.lib. * src/makefile.msc: - installs .la file into $(ROOT)\lib - installs .pc file into $(ROOT)\lib\pkgconfig. (also used by waf) - Added MAJORVESION variable to more easier filename changes during version bumping. * winbuild/Makefile.am: Added winbuild/libzorpll.la to EXTRA_DIST 2007-07-09 Szalay Attila * Bumped to version 3.3.0.0.1 2007-06-18 Szalay Attila * Merged patches from version 3.1 from patch-194 to patch-206 2007-03-28 Pfeiffer Szilard * VERSION: Initial version number change. (fixes: #nobug) 2007-02-22 Szalay Attila * Forward ported patches (185-193) from 3.1. (fixes: #nobug) 2007-02-22 Krisztian Kovacs * src/connect.c (z_connector_set_tos): instead of simply storing the tos value in self we now also set the ToS value on the file descriptor (fixes: #10946) (z_connector_open_socket): as we are called from z_connector_new() it's not possible that (self->tos != -1), so there's no point in setting the ToS value on our brand new shiny fd (fixes: #10946) * src/zorp/connect.h (z_connector_set_tos): z_connector_set_tos() is not inlined anymore (fixes: #10946) 2007-01-24 Balazs Scheidler * src/poll.c: removed unneeded core.debug(0) messages 2006-12-18 Balazs Scheidler * forward-ported patches from 3.1 to sync with 3.1.5.4 2006-10-30 SZALAY Attila * VERSION: Bumped to 3.2.0.1 2006-09-06 SZALAY Attila * tests/test_conns.c: Adapted testcase to the new connector API. * Bumped to version 3.2.0.0.2 2006-09-06 Balazs Scheidler * src/connect.c (z_connector_source_destroy_cb): set user_data to NULL, (z_connector_start_internal): return gboolean to indicate success, return the local address through a pointer, (z_connector_start): -"-, (z_connector_start_in_context): -"-, (z_connector_start_block): -"-, merged win32 and unix implementation, (z_connector_set_destroy_notify): removed, (z_connector_new): added destroy notify argument, set default timeout to 30 seconds, * src/connect.c (z_connector_new): removed tos argument, * src/zorp/connect.h (z_connector_set_tos): new inline function to set the target ToS before connecting * src/io.c: removed error handling from tos query/set functions as it is never handled anyway 2006-08-29 SZALAY Attila * Initial log entry for 3.2 libzorpll-3.9.4.1/autogen.sh000077500000000000000000000003771224546767600157320ustar00rootroot00000000000000#!/bin/sh # # $Id: autogen.sh,v 1.5 2004/08/18 11:25:39 bazsi Exp $ # # Run this script to generate Makefile skeletons and configure # scripts. # libtoolize -f --copy aclocal $* autoheader automake --add-missing --force-missing --copy --foreign autoconf libzorpll-3.9.4.1/configure.in000066400000000000000000000274721224546767600162470ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. dnl dnl There are a couple of environment defined variables which this script dnl makes use of in addition to the standard CFLAGS/LDFLAGS/etc. These are: dnl dnl RELEASE_TAG - Debian release tag which is put to debian/changelog dnl SNAPSHOT_VERSION - snapshot version to add to version number dnl SOURCE_REVISION - Revision of the source-tree, will added to the version string dnl AC_INIT(src/log.c) dnl *************************************************************************** dnl Definitions PACKAGE=libzorpll VERSION=`cat $srcdir/VERSION` dnl *************************************************************************** dnl Dependencies GLIB_MIN_VERSION=2.2.3 OPENSSL_MIN_VERSION=0.9.8 dnl *************************************************************************** dnl Initial setup # We want an absolute path to the source-dir. case "$srcdir" in /*) top_srcdir=$srcdir ;; *) oldsrcdir="$srcdir" top_srcdir="`cd \"$srcdir\"; pwd`" ;; esac if test -r $srcdir/dist.conf; then # read defaults, dist.conf does not change # values for parameters that are already set source $srcdir/dist.conf fi AC_CONFIG_MACRO_DIR([m4]) if test -n "$SNAPSHOT_VERSION"; then VERSION=$VERSION+$SNAPSHOT_VERSION fi if test -z "$RELEASE_TAG"; then RELEASE_TAG=zorp30dbg fi if test -z "$libexecdir" || test "x${libexecdir}" = "xNONE"; then libexecdir=${libdir}/libzorpll fi AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) ZORPLIBLL_VERSION=$VERSION AM_CONFIG_HEADER(src/zorp/zorplibconfig.h) dnl check for arguments AC_ARG_ENABLE(debug, [ --enable-debug Enable debug information & messages (default: no)],, enable_debug=no) AC_ARG_ENABLE(trace, [ --enable-trace Enable trace information & messages (default: no)],, enable_trace=no) AC_ARG_ENABLE(werror, [ --enable-werror When enabled, treat compiler warnings as errors (default: yes)],, enable_werror=yes) AC_ARG_ENABLE(mem-trace, [ --enable-mem-trace Enable memory trace (default: no)],, enable_mem_trace=no) AC_ARG_ENABLE(caps, [ --enable-caps Enable using POSIX 1003.e capabilities (default: autodetect)],, enable_caps=auto) AC_ARG_ENABLE(stackdump, [ --enable-stackdump Enable stackdump when a fatal signal is encountered (default: auto)],, enable_stackdump=auto) AC_ARG_ENABLE(ssl-engine, [ --enable-ssl-engine Enable OpenSSL engine support (default: auto)],, enable_ssl_engine=auto) AC_ARG_ENABLE(tos, [ --enable-tos Enable ToS manipulation routines (default: auto)],, enable_tos=auto) dnl *************************************************************************** dnl Argument processing which might affect detection if test "x$enable_debug" = "xyes"; then CFLAGS="$CFLAGS -O0" else CFLAGS="$CFLAGS -O2" fi dnl Checks for programs. AC_PROG_CC AM_PROG_LIBTOOL dnl *************************************************************************** dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_CHECK_HEADERS(fcntl.h sys/ioctl.h sys/time.h syslog.h unistd.h sys/capability.h dlfcn.h crypt.h pwd.h grp.h sys/prctl.h sys/resource.h) dnl locating zlib1g headers AC_CHECK_HEADER(zlib.h,,AC_MSG_ERROR([You don't seem to have zlib1g-dev installed])) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T AC_TYPE_UID_T AC_STRUCT_TM PKG_CHECK_MODULES(OPENSSL, openssl >= $OPENSSL_MIN_VERSION,, AC_MSG_ERROR(Cannot find OpenSSL library version >= $OPENSSL_MIN_VERSION: is pkg-config in path?)) save_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS $OPENSSL_CFLAGS" AC_CHECK_HEADER(openssl/ssl.h, [], [AC_MSG_ERROR([OpenSSL header file is missing])]) CPPFLAGS=$save_CPPFLAGS if test "x$ac_cv_header_openssl_des_h" = "xno"; then AC_ERROR(OpenSSL headers required) fi AC_CACHE_CHECK(for PR_SET_KEEPCAPS, blb_cv_keepcaps, [AC_EGREP_CPP(PR_SET_KEEPCAPS, [ #include PR_SET_KEEPCAPS ], blb_cv_keepcaps=no, blb_cv_keepcaps=yes)]) if test "x$blb_cv_keepcaps" = "xyes"; then AC_DEFINE(HAVE_PR_SET_KEEPCAPS, 1, [have PR_SET_KEEPCAPS]) fi AC_CACHE_CHECK(for SOL_IP, blb_cv_sol_ip, [AC_EGREP_CPP(SOL_IP, [ #include #include #include SOL_IP ], blb_cv_sol_ip=no, blb_cv_sol_ip=yes)]) if test "x$blb_cv_sol_ip" = "xyes"; then AC_DEFINE(HAVE_SOL_IP, 1, [have SOL_IP]) fi AC_CACHE_CHECK(for IP_PKTOPTIONS, blb_cv_ip_pktoptions, [AC_EGREP_CPP(IP_PKTOPTIONS, [ #include #include #include IP_PKTOPTIONS ], blb_cv_ip_pktoptions=no, blb_cv_ip_pktoptions=yes)]) if test "x$blb_cv_ip_pktoptions" = "xyes"; then AC_DEFINE(HAVE_PKTOPTIONS, 1, [have IP_PKTOPTIONS]) fi AC_CACHE_CHECK(for IP_RECVTOS, blb_cv_ip_recvtos, [AC_EGREP_CPP(IP_RECVTOS, [ #include #include #include IP_RECVTOS ], blb_cv_ip_recvtos=no, blb_cv_ip_recvtos=yes)]) if test "x$blb_cv_ip_recvtos" = "xyes"; then AC_DEFINE(HAVE_IP_RECVTOS, 1, [have IP_RECVTOS]) fi dnl *************************************************************************** dnl Checks for library functions. AC_FUNC_ALLOCA AC_PROG_GCC_TRADITIONAL AC_FUNC_MEMCMP AC_FUNC_STRFTIME AC_CHECK_LIB(cap, cap_set_proc) AC_CHECK_LIB(pthread, pthread_create) AC_CHECK_LIB(resolv, inet_aton) AC_CHECK_LIB(socket, socket) if test "x$ac_cv_header_crypt_h" = "xyes"; then AC_CHECK_LIB(crypt, crypt) fi AC_CHECK_LIB(z, gzread) AC_CHECK_FUNCS(socket strtol strtoul strlcpy backtrace prctl setrlimit) AC_CHECK_FUNCS(inet_aton inet_addr localtime_r) if test "x$ac_cv_header_crypt_h" = "xyes"; then AC_CHECK_FUNCS(crypt) fi AM_PATH_GLIB_2_0($GLIB_MIN_VERSION,, AC_MSG_ERROR(Cannot find GLIB version >= $GLIB_MIN_VERSION: is pkg-config in path?), gthread) dnl *************************************************************************** dnl Misc checks dnl enable support for files over 2GB AC_SYS_LARGEFILE os=`uname -s` if test "x$os" = "xLinux"; then AC_DEFINE(HAVE_BUGGY_SYSLOG_IN_LIBC, 1, [have buggy syslog() in libc]) AC_DEFINE(HAVE_MD5_CRYPT, 1, [Have transparent md5 support in crypt()]) fi if test "x$enable_caps" = "xauto" ; then AC_MSG_CHECKING(whether to enable POSIX 1003.1e capability support) if test "x$ac_cv_header_sys_capability_h" = "xyes" -a "x$ac_cv_lib_cap_cap_set_proc" = "xyes"; then AC_MSG_RESULT(yes) enable_caps=yes else AC_MSG_RESULT(no) enable_caps=no fi fi if test "x$enable_stackdump" = "xauto"; then enable_stackdump=no AC_MSG_CHECKING(whether to enable stack dumping (only in i386 Linux)) proc=`uname -m | sed -e 's/i.86/i386/'` os=`uname -s` if test "x$proc" = "xi386"; then if test "x$os" = "xLinux"; then AC_MSG_RESULT(yes) enable_stackdump=yes else AC_MSG_RESULT(no) fi else AC_MSG_RESULT(no) fi fi if test "x$enable_ssl_engine" = "xauto"; then AC_MSG_CHECKING(whether to enable SSL crypto engine support) if test "x$ac_cv_func_ENGINE_by_id" = "xyes"; then AC_MSG_RESULT(yes) enable_ssl_engine=yes else AC_MSG_RESULT(no) enable_ssl_engine=no fi fi if test "x$enable_tos" = "xauto"; then AC_MSG_CHECKING(whether to enable ToS manipulation support) if test "x$blb_cv_sol_ip" = "xyes" -a "x$blb_cv_ip_pktoptions" = "xyes" -a "x$blb_cv_ip_recvtos" = "xyes"; then AC_MSG_RESULT(yes) enable_tos=yes else AC_MSG_RESULT(no) enable_tos=no fi fi dnl *************************************************************************** dnl Export detected settings to Makefiles and Zorp enable_value() { if test "x$1" = "xyes" ; then echo 1 else echo 0 fi } LIBZORPLL_COMPAT_VERSION="`echo $VERSION | cut -d '.' -f 1-3`" dnl Library versioning, the resulting shared object is named: dnl libzorpll-.so. dnl VERSION_NOSNAPSHOT="`echo $VERSION | cut -d '+' -f 1`" VERSION_MAJOR=`echo $VERSION_NOSNAPSHOT | cut -d '.' -f 1` VERSION_MINOR=`echo $VERSION_NOSNAPSHOT | cut -d '.' -f 2` VERSION_COMPAT=`echo $VERSION_NOSNAPSHOT | cut -d '.' -f 3` VERSION_AGE=`echo $VERSION_NOSNAPSHOT | cut -d '.' -f 4` LIBZORPLL_LT_RELEASE="$VERSION_MAJOR.$VERSION_MINOR" LIBZORPLL_LT_CURRENT=$@<:@ $VERSION_COMPAT + $VERSION_AGE @:>@ LIBZORPLL_LT_COMPAT_BRANCH="$VERSION_MAJOR.$VERSION_MINOR-$VERSION_COMPAT" LIBZORPLL_LT_COMPAT_PL="$VERSION_COMPAT" LIBZORPLL_LT_AGE="$VERSION_AGE" ZORPLIBLL_WIN_VERSION="$VERSION_MAJOR,$VERSION_MINOR,$VERSION_COMPAT,$VERSION_AGE" set -x if test -z "${exec_prefix}" -o "x${exec_prefix}" = "xNONE"; then exec_prefix="${prefix}" fi set -x expand_recursive() { expd=`eval echo $1` if test "$1" = "$expd"; then echo $expd; else expand_recursive $expd fi; } libexecdir="`expand_recursive ${libexecdir}`" sysconfdir="`expand_recursive ${sysconfdir}`" ZORPLIB_PIDFILE_DIR="`eval echo ${localstatedir}/run/zorp`" ZORPLIB_TEMP_DIR="`eval echo ${localstatedir}/lib/zorp/tmp`" set +x AC_DEFINE_UNQUOTED(ZORPLIBLL_PACKAGE, "$PACKAGE", [Zorp low level library package name] ) AC_DEFINE_UNQUOTED(ZORPLIBLL_VERSION, "$ZORPLIBLL_VERSION", [Zorp low level library version] ) AC_DEFINE_UNQUOTED(ZORPLIBLL_REVISION, "$SOURCE_REVISION", [Zorp low level library, source revision]) AC_DEFINE_UNQUOTED(ZORPLIB_ENABLE_DEBUG, `enable_value $enable_debug`, [enable debug]) AC_DEFINE_UNQUOTED(ZORPLIB_ENABLE_TRACE, `enable_value $enable_trace`, [enable trace]) AC_DEFINE_UNQUOTED(ZORPLIB_ENABLE_MEM_TRACE, `enable_value $enable_mem_trace`, [enable memtrace]) AC_DEFINE_UNQUOTED(ZORPLIB_ENABLE_CAPS, `enable_value $enable_caps`, [enable caps]) AC_DEFINE_UNQUOTED(ZORPLIB_ENABLE_SSL_ENGINE, `enable_value $enable_ssl_engine`, [enable ssl engine]) AC_DEFINE_UNQUOTED(ZORPLIB_ENABLE_STACKDUMP, `enable_value $enable_stackdump`, [enable stack dump]) AC_DEFINE_UNQUOTED(ZORPLIB_ENABLE_TOS, `enable_value $enable_tos`, [enable ToS manipulation]) AC_DEFINE_UNQUOTED(ZORPLIB_PIDFILE_DIR, "$ZORPLIB_PIDFILE_DIR", [default PID file directory]) AC_DEFINE_UNQUOTED(ZORPLIB_LIBEXECDIR, "`eval echo ${libexecdir}`", [libexecdir]) AC_DEFINE_UNQUOTED(ZORPLIB_COMPAT_BRANCH,"`eval echo ${LIBZORPLL_LT_COMPAT_BRANCH}`", [Binary compatibility version]) AC_DEFINE_UNQUOTED(ZORPLIB_TEMP_DIR, "$ZORPLIB_TEMP_DIR", [default temporary directory]) cat < #include #include #include #include #include #include #include #include #include #include #include #include #include /** * @file * * Some words about the locking semantics of blobs * * - Blob system needn't be locked, because only the management thread accesses * the enclosed data * - Communication between blob and blob system is managed by the async queue of * the blob system: * - pushes itself into the systems async queue * - waits until the management thread notifies it about the completion of * the request by signalling the blobs cond_reply **/ /** Temporary buffer size for reading from streams */ #define Z_BLOB_COPY_BUFSIZE 8192 /** Default blob system instance */ ZBlobSystem *z_blob_system_default = NULL; /* And its default attributes * (Don't worry about the names, they will be used only 3 times...)*/ const gchar *z_blob_system_default_tmpdir = ZORPLIB_TEMP_DIR; /**< directory to store the blobs in */ gint64 z_blob_system_default_max_disk_usage = 1024*0x100000; /**< max disk usage = 1 GB */ gsize z_blob_system_default_max_mem_usage = 256*0x100000; /**< max mem usage = 256 MB */ gsize z_blob_system_default_lowat = 96*0x100000; /**< lowat = 96 MB */ gsize z_blob_system_default_hiwat = 128*0x100000; /**< hiwat = 128 MB */ gsize z_blob_system_default_noswap_max = 16384; /**< noswap_max = 16 kB */ /** local functions of blobs */ static void z_blob_alloc(ZBlob *self, gint64 req_size); /** Dummy magic pointer to signal that the management thread should exit */ static void Z_BLOB_THREAD_KILL(void) { /* dummy */ } /** Dummy magic pointer to signal that some memory is freed up and the management thread should check its waiting list */ static void Z_BLOB_MEM_FREED(void) { /* dummy */ } /** * Writes a blob out to disk, called only from z_blob_system_threadproc() * * @param[in] self this * * @warning Caller must hold a lock BOTH on the blob AND the blob system! **/ static void z_blob_swap_out(ZBlob *self) { off_t err; gssize written, remain; z_enter(); g_assert(self); if (!self->storage_locked && !self->is_in_file && self->system) { err = lseek(self->fd, 0, SEEK_SET); if (err < 0) { z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } remain = self->size; while (remain > 0) { written = write(self->fd, self->data, remain); if (written < 0) { if (errno == EINTR) { continue; } else { z_log(NULL, CORE_ERROR, 0, "Blob error, write() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } } remain -= written; } self->is_in_file = 1; g_free(self->data); self->data = NULL; self->stat.swap_count++; self->stat.last_accessed = time(NULL); self->system->mem_used -= self->alloc_size; self->system->disk_used += self->size; self->alloc_size = self->size; } z_return(); } /** * Signal the completion of a request. Called only from z_blob_system_threadproc(). * * @param[in] self this **/ static void z_blob_signal_ready(ZBlob *self) { g_mutex_lock(self->mtx_reply); g_cond_signal(self->cond_reply); self->replied = TRUE; g_mutex_unlock(self->mtx_reply); } /** * Checks if a blob may allocate self->alloc_req additional bytes. * * @param[in] self this * * @returns TRUE if req granted, FALSE if denied **/ static gboolean z_blob_check_alloc(ZBlob *self) { gsize disk_available, mem_available; gsize req_total; gboolean success = FALSE, on_disk = FALSE; mem_available = self->system->mem_max - self->system->mem_used; disk_available = self->system->disk_max - self->system->disk_used; req_total = self->alloc_size + self->alloc_req; /* FIXME: Need more sophisticated way to allocating. * * 1. blob is in memory free space in memory => allocate in memory * 2. in memory in disk !storage_locked => swap out + allocate * 3. in memory in disk storage_locked => ??? * 4. in disk in memory !storage locked => swap in (maybe) * 5. in disk in memory storage locked => ??? * 6. in disk in disk => allocate in disk * * But in this function not all situation handled. (I think.) */ if (self->is_in_file) { self->system->disk_used += self->alloc_req; success = TRUE; on_disk = TRUE; } else if ((self->alloc_req < 0) || ((gsize)self->alloc_req <= mem_available)) { self->system->mem_used += self->alloc_req; success = TRUE; on_disk = FALSE; } else if (!self->storage_locked && (req_total <= disk_available)) /* don't fit in mem but fits on disk */ { /* FIXME: !!! FOR TESTING ONLY !!! * The current swapping policy is definitely quite lame, it must * be replaced with some more intelligent algorithm. * Now, if the blob can't be kept in memory, it goes directly to disk. * Then, if any self gets freed, we try to find the most appropriate * one on disk that would fit in the available ram, and fetch it in. * The decision factor is the number of accesses divided by the * time elapsed since the last access. Ummm, it cries for some * refinement, but should work for now :)... */ z_log(NULL, CORE_DEBUG, 7, "Blob does not fit, swapping out; self_size='%" G_GINT64_FORMAT "'", self->size); z_blob_swap_out(self); self->system->disk_used += self->alloc_req; success = TRUE; on_disk = TRUE; } else if (req_total < (disk_available + mem_available)) /* we have the space for it, but partly on disk */ { /* Premise: if we had anything to fetch in, it would have been already * done. (Not quite true, best-fit candidate is fetched in. There may * be a better alignment, but finding it is an NP-strong problem - * analogous to the 'backpack' problem). * Now, treat this case as if there weren't enough space...*/ ; } else /* impossible to allocate */ { ; } if (self->alloc_req < 0) g_async_queue_push(self->system->req_queue, Z_BLOB_MEM_FREED); z_log(NULL, CORE_DEBUG, 7, "Blob allocation result; result='%s', store='%s', requested_size='%" G_GSSIZE_FORMAT "', mem_avail='%" G_GSIZE_FORMAT "', disk_avail='%" G_GSIZE_FORMAT "'", success ? "granted" : "denied", on_disk ? "disk" : "mem", req_total, mem_available, disk_available); return success; } /** * Try to fetch in blobs if there is enough space. * * @param[in] self this * * Try to fetch in blobs if there is enough space for that. * Called only from threadproc(), so exclusive access to all memory and blob * management data is implicitly granted. **/ void z_blob_system_swap_in(ZBlobSystem *self) { gint64 space_available; gdouble dec_factor, dec_factor_best; GList *cur; ZBlob *blob, *best; time_t now, elapsed; gint swap_count; gint64 swap_bytes; off_t err; gssize rd; /** * @todo FIXME: find and define a better swap algorithm and implement it * in a less scattered way **/ /** * Swap-in algorithm is as follows: * - memory store is preferred * - when the amount in RAM is less than lowat AND the amount on * disk is more than hiwat, swap-in is started * - the best blob is selected and it is swapped in **/ if (self->mem_used >= self->lowat || self->disk_used < self->hiwat) return; z_log(NULL, CORE_DEBUG, 7, "Starting blob swap-in; mem_used='%" G_GSIZE_FORMAT "', disk_used='%" G_GINT64_FORMAT "', lowat='%" G_GSIZE_FORMAT "'", self->mem_used, self->disk_used, self->lowat); swap_count = 0; swap_bytes = 0; do { time(&now); space_available = self->hiwat - self->mem_used; dec_factor_best = -1; best = NULL; for (cur = self->blobs; cur; cur = cur->next) { blob = (ZBlob *) cur->data; if (z_blob_lock(blob, 0)) /* zero timeout -> trylock */ { if (!blob->storage_locked && blob->is_in_file && (blob->alloc_size <= space_available)) { elapsed = now - blob->stat.last_accessed; dec_factor = (elapsed > 0) ? (blob->stat.req_rd + blob->stat.req_wr) / elapsed : 0; if (dec_factor > dec_factor_best) { dec_factor_best = dec_factor; best = blob; } } z_blob_unlock(blob); } } if (best) { z_log(NULL, CORE_DEBUG, 8, "Swapping in blob; blob_size='%" G_GINT64_FORMAT "'", best->size); if (z_blob_lock(best, 0)) /* zero timeout -> trylock */ { if (!best->storage_locked && best->is_in_file && (best->alloc_size <= space_available)) { gssize remain; err = lseek(best->fd, 0, SEEK_SET); if (err == (off_t)-1) { z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", best->filename, g_strerror(errno)); g_assert(0); } best->data = g_new0(gchar, best->alloc_size); remain = best->size; while (remain > 0) { rd = read(best->fd, best->data, remain); if (rd < 0) { if (errno == EINTR) { continue; } else { z_log(NULL, CORE_ERROR, 0, "Blob error, read() failed; file='%s', error='%s'", best->filename, g_strerror(errno)); g_assert(0); } } else if (rd == 0) break; remain -= rd; } best->is_in_file = 0; err = ftruncate(best->fd, 0); if (err < 0) z_log(NULL, CORE_DEBUG, 7, "Blob error, ftruncate() failed; file='%s', error='%s'", best->filename, g_strerror(errno)); best->stat.last_accessed = time(NULL); best->system->disk_used -= best->alloc_size; best->system->mem_used += best->alloc_size; swap_count++; swap_bytes += best->size; } z_blob_unlock(best); } } } while (best); z_log(NULL, CORE_INFO, 5, "Blob swap-in complete; swap_count='%d', swap_bytes='%" G_GINT64_FORMAT "'", swap_count, swap_bytes); } /** * Report disk and memory usage and other statistics on a ZBlobSystem to the log. * * @param[in] self this **/ void z_blob_system_report_usage(ZBlobSystem *self) { /** * @todo FIXME: * * - Prettier format * - Counter for blobs in disk and blobs in memory * * - Average/min/max blob size * - Average/min/max blob lifetime * - Average/min/max moving count (to/from swap) of blobs. * - Average/min/max length of waiting queue. * **/ z_log(NULL, CORE_INFO, 4, "Blob system usage: Disk used: %" G_GINT64_FORMAT " from %" G_GINT64_FORMAT ". Mem used: %" G_GSIZE_FORMAT " from %" G_GSIZE_FORMAT ". Blobs in use: %d. Waiting queue length: (cur/max/min/avg) %d/%d/%d/%d", self->disk_used, self->disk_max, self->mem_used, self->mem_max, g_list_length(self->blobs), g_list_length(self->waiting_list), -1, -1, -1); } /** * Thread procedure of ZBlobSystem. * * @param[in] self this * * Performs the swapping/storage maintenance tasks described in the spec. * * @returns Currently just self **/ static gpointer z_blob_system_threadproc(ZBlobSystem *self) { ZBlob *blob; GList *cur, *del; gssize blob_alloc_req; GTimeVal next_time, now; glong interval = 300; /* 5 min. */ z_enter(); g_assert(self); g_mutex_lock(self->mtx_blobsys); g_cond_signal(self->cond_thread_started); g_mutex_unlock(self->mtx_blobsys); g_get_current_time(&next_time); next_time.tv_sec += interval; while (1) { #if GLIB_MINOR_VERSION >= 32 blob = g_async_queue_timeout_pop(self->req_queue, interval * 1000000); /* blocks until there is a requesting blob in the queue */ #else blob = g_async_queue_timed_pop(self->req_queue, &next_time); /* blocks until there is a requesting blob in the queue */ #endif if (blob == NULL) { g_get_current_time(&next_time); next_time.tv_sec += interval; z_blob_system_report_usage(self); continue; } g_get_current_time(&now); if (now.tv_sec > next_time.tv_sec) { z_blob_system_report_usage(self); } if (blob == (ZBlob*)Z_BLOB_THREAD_KILL) break; g_mutex_lock(self->mtx_blobsys); if (blob == (ZBlob*)Z_BLOB_MEM_FREED) { /* check the waiting queue - it is enough to check on successful negative alloc requests, * because this is the only case when memory is freed up */ cur = self->waiting_list; while (cur) { blob = (ZBlob*) cur->data; del = NULL; blob->approved = z_blob_check_alloc(blob); if (blob->approved) { del = cur; z_blob_signal_ready(blob); } cur = cur->next; if (del) self->waiting_list = g_list_delete_link(self->waiting_list, del); } /* try to swap in blobs - makes sence only on negative alloc reqs, too */ z_blob_system_swap_in(self); } else { blob_alloc_req = blob->alloc_req; blob->approved = z_blob_check_alloc(blob); if (!blob->approved) /* In case of denial, move the blob to the waiting queue */ { z_log(NULL, CORE_INFO, 4, "Blob storage is full, adding allocate request to the waiting list; size='%" G_GSIZE_FORMAT "'", blob_alloc_req); self->waiting_list = g_list_append(self->waiting_list, blob); } else /* send back the result to the blob */ { z_blob_signal_ready(blob); } } g_mutex_unlock(self->mtx_blobsys); } z_leave(); g_thread_exit(self); z_return(self); } /** * Initialize the default blob system. **/ void z_blob_system_default_init(void) { z_enter(); z_blob_system_default = z_blob_system_new(z_blob_system_default_tmpdir, z_blob_system_default_max_disk_usage, z_blob_system_default_max_mem_usage, z_blob_system_default_lowat, z_blob_system_default_hiwat, z_blob_system_default_noswap_max); z_return(); } /** * Destroy the default blob system. **/ void z_blob_system_default_destroy(void) { z_enter(); if (z_blob_system_default) { z_blob_system_unref(z_blob_system_default); z_blob_system_default = NULL; } z_return(); } /** * Create a new blob system using the given parameters. * * @param[in] dir directory to put the swapped blobs into * @param[in] dmax max disk usage size * @param[in] mmax max mem usage size * @param[in] low low water mark * @param[in] hiw high water mark * @param[in] nosw maximal size that wont't be swapped * * @returns The new blob system instance **/ ZBlobSystem* z_blob_system_new(const char *dir, gint64 dmax, gsize mmax, gsize low, gsize hiw, gsize nosw) { ZBlobSystem *self; z_enter(); self = g_new0(ZBlobSystem, 1); z_refcount_set(&self->ref_cnt, 1); self->dir = strdup(dir); self->disk_max = dmax; self->mem_max = mmax; self->disk_used = self->mem_used = 0; if (mmax <= low) low = mmax - 1; self->lowat = low; if (mmax <= hiw) hiw = mmax - 1; self->hiwat = hiw; self->noswap_max = nosw; self->blobs = NULL; self->mtx_blobsys = g_mutex_new(); self->cond_thread_started = g_cond_new(); self->req_queue = g_async_queue_new(); self->waiting_list = NULL; g_mutex_lock(self->mtx_blobsys); self->thr_management = g_thread_create((GThreadFunc)z_blob_system_threadproc, (gpointer)self, TRUE, &self->thread_error); g_cond_wait(self->cond_thread_started, self->mtx_blobsys); g_mutex_unlock(self->mtx_blobsys); self->active = TRUE; z_return(self); } /** * Increase reference count of a blob system. * * @param[in] self the blob system object **/ void z_blob_system_ref(ZBlobSystem *self) { z_enter(); z_refcount_inc(&self->ref_cnt); z_return(); } /** * Decrease reference count of a blob system; destroy it if the count reaches zero. * * @param[in] self the blob system object * * This function decreases the reference count of the blob system * object given. If the reference count reaches zero, the blob system * will be destroyed. If there were pending requests in a to-be-destroyed * blob system, this fact will be logged. **/ void z_blob_system_unref(ZBlobSystem *self) { ZBlob *blob; GList *cur, *next; gint n; z_enter(); g_assert(self); if (z_refcount_dec(&self->ref_cnt)) { self->active = FALSE; /** @todo FIXME: itt lockolni kell */ g_async_queue_push(self->req_queue, Z_BLOB_THREAD_KILL); g_thread_join(self->thr_management); n = 0; for (cur = self->waiting_list; cur; cur = next) { next = cur->next; blob = (ZBlob*) cur->data; blob->approved = FALSE; z_blob_signal_ready(blob); self->waiting_list = g_list_delete_link(self->waiting_list, cur); n++; } if (n) z_log(NULL, CORE_INFO, 5, "Pending requests found for a to-be-destroyed blob system; num_requests='%d'", n); n = 0; for (cur = self->blobs; cur; cur = next) { next = cur->next; blob = (ZBlob*)cur->data; z_blob_unref(blob); n++; } if (n) z_log(NULL, CORE_INFO, 5, "Active blobs found in a to-be-destroyed blob system; num_blobs='%d'", n); if (self->dir) g_free(self->dir); if (g_mutex_trylock(self->mtx_blobsys)) { g_mutex_unlock(self->mtx_blobsys); g_mutex_free(self->mtx_blobsys); } else { /* Some blob operations are in progress: z_blob_new, _unref, _alloc, _get_file */ } g_cond_free(self->cond_thread_started); g_async_queue_unref(self->req_queue); g_list_free(self->waiting_list); g_free(self); } z_return(); } /****************************************************************************** * ZBlobStatistic ******************************************************************************/ /** * Initialize a ZBlobStatistic instance. * * @param[in] self this **/ void z_blob_statistic_init(ZBlobStatistic *self) { g_assert(self); self->req_rd = self->req_wr = self->swap_count = self->alloc_count = 0; self->total_rd = self->total_wr = 0; self->created = self->last_accessed = time(NULL); } /****************************************************************************** * ZBlob ******************************************************************************/ /** * Create a new blob. * * @param[in] sys Blob system to create the blob into * @param[in] initial_size Initial size to allocate. * * This function creates a new blob. If sys is NULL, z_blob_system_default will be used. * * @returns The new blob instance **/ ZBlob* z_blob_new(ZBlobSystem *sys, gsize initial_size) { ZBlob *self; z_enter(); if (!sys) sys = z_blob_system_default; if (!sys || !sys->active) z_return(NULL); self = g_new0(ZBlob, 1); self->system = sys; self->filename = g_strdup_printf("%s/blob_XXXXXX", self->system->dir); self->fd = mkstemp(self->filename); if (self->fd < 0) { z_log(NULL, CORE_ERROR, 2, "Error creating blob file: file='%s', error='%s'", self->filename, strerror(errno)); g_free(self->filename); g_free(self); z_return(NULL); } z_refcount_set(&self->ref_cnt, 1); self->size = 0; self->alloc_size = 0; self->data = NULL; self->is_in_file = FALSE; self->mtx_reply = g_mutex_new(); self->cond_reply = g_cond_new(); self->mapped_ptr = NULL; self->mapped_length = 0; self->storage_locked = FALSE; z_blob_statistic_init(&self->stat); self->mtx_lock = g_mutex_new(); g_mutex_lock(self->system->mtx_blobsys); self->system->blobs = g_list_append(self->system->blobs, self); g_mutex_unlock(self->system->mtx_blobsys); if (initial_size > 0) z_blob_alloc(self, initial_size); z_return(self); } /** * Increase reference count of blob and return a reference to it. * * @param[in] self this * * @returns self **/ ZBlob * z_blob_ref(ZBlob *self) { z_enter(); z_refcount_inc(&self->ref_cnt); z_return(self); } /** * Decrease reference count of blob; destroy it if the count reaches zero. * * @param[in] self this **/ void z_blob_unref(ZBlob *self) { z_enter(); if (self && z_refcount_dec(&self->ref_cnt)) { g_mutex_lock(self->system->mtx_blobsys); self->alloc_req = -self->alloc_size; self->system->blobs = g_list_remove(self->system->blobs, self); z_blob_check_alloc(self); g_mutex_unlock(self->system->mtx_blobsys); if (self->data) g_free(self->data); if (self->fd >= 0) close(self->fd); if (self->filename) { if (unlink(self->filename)) z_log(NULL, CORE_ERROR, 3, "Error removing blob file, unlink() failed; file='%s', error='%s'", self->filename, strerror(errno)); g_free(self->filename); self->filename = NULL; } g_mutex_free(self->mtx_reply); g_cond_free(self->cond_reply); if (g_mutex_trylock(self->mtx_lock)) { g_mutex_unlock(self->mtx_lock); g_mutex_free(self->mtx_lock); } else { z_log(NULL, CORE_ERROR, 3, "Error while destroying blob, someone still has a lock on it;"); /* someone has locked the blob by z_blob_get_file or _get_ptr, and forgot to release it */ } g_free(self); } z_return(); } /** * Lock a blob. * * @param[in] self this * @param[in] timeout Timeout for locking. A negative value means infinite and thus blocking mode. Zero means nonblocking mode. * * @returns TRUE if successfully locked. **/ gboolean z_blob_lock(ZBlob *self, gint timeout) { gboolean res; struct timeval tvnow, tvfinish; z_enter(); g_assert(self); if (timeout < 0) /* infinite timeout -> blocking mode */ { g_mutex_lock(self->mtx_lock); res = TRUE; } else if (timeout == 0) /* zero timeout -> nonblocking mode */ { res = g_mutex_trylock(self->mtx_lock); } else /* positive timeout */ { gettimeofday(&tvfinish, NULL); tvfinish.tv_sec += (timeout / 1000); tvfinish.tv_usec += 1000 * (timeout % 1000); tvfinish.tv_sec += (tvfinish.tv_usec / 1000000); tvfinish.tv_usec %= 1000000; /* FIXME: maybe g_cond_wait_timed_wait ? */ do { res = FALSE; if (g_mutex_trylock(self->mtx_lock)) { res = TRUE; break; } usleep(1000); gettimeofday(&tvnow, NULL); } while ((tvnow.tv_sec < tvfinish.tv_sec) || ((tvnow.tv_sec == tvfinish.tv_sec) && (tvnow.tv_usec < tvfinish.tv_usec))); } z_return(res); } /** * Unlock a blob. * * @param self[in] this **/ void z_blob_unlock(ZBlob *self) { z_enter(); g_assert(self); g_mutex_unlock(self->mtx_lock); z_return(); } static inline gint64 z_blob_calculate_allocation_size(gint64 req_size, gint64 allocated, gboolean in_file) { gint64 req_alloc_size; /* determine the allocation size */ if ((allocated <= 0) || in_file) { req_alloc_size = req_size; } else { /* First run (if shrinking reqd): go just below the requested size */ req_alloc_size = allocated; while (req_alloc_size > req_size) { req_alloc_size >>= 1; } /* Second run: find next available size */ while (req_alloc_size < req_size) { req_alloc_size <<= 1; } } return req_alloc_size; } /** * Allocate space for the blob (not necessarily in memory!) * * @param[in] self this * @param[in] req_size required space * * @warning Caller shall hold a write lock on the blob! **/ static void z_blob_alloc(ZBlob *self, gint64 req_size) { gchar *newdata; gint err; gint64 alloc_req; gboolean alloc_granted; z_enter(); g_assert(self); g_assert(req_size >= 0); /* just return if the allocation needn't change */ if (z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file) == self->alloc_size) z_return(); alloc_req = z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file) - self->alloc_size; g_mutex_lock(self->system->mtx_blobsys); self->alloc_req = alloc_req; alloc_granted = z_blob_check_alloc(self); g_mutex_unlock(self->system->mtx_blobsys); if (!alloc_granted) { self->approved = FALSE; self->replied = FALSE; g_mutex_lock(self->mtx_reply); g_async_queue_push(self->system->req_queue, self); while (!self->replied) g_cond_wait(self->cond_reply, self->mtx_reply); g_mutex_unlock(self->mtx_reply); alloc_granted = self->approved; } g_assert(alloc_granted); if (self->is_in_file) { err = ftruncate(self->fd, z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file)); if (err < 0) z_log(NULL, CORE_ERROR, 3, "Error truncating blob file, ftruncate() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); } else { newdata = g_renew(gchar, self->data, z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file)); if (self->alloc_size < z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file) && newdata) memset(newdata + self->alloc_size, 0, z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file) - self->alloc_size); self->data = newdata; } self->alloc_size = z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file); if (self->size > z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file)) self->size = z_blob_calculate_allocation_size(req_size, self->alloc_size, self->is_in_file); self->stat.alloc_count++; self->stat.last_accessed = time(NULL); z_return(); } /** * Truncates/expands a blob. * * @param[in] self this * @param[in] pos position to truncate at * @param[in] timeout timeout * * @returns TRUE on success **/ gboolean z_blob_truncate(ZBlob *self, gint64 pos, gint timeout) { gboolean res = FALSE; z_enter(); g_assert(self); g_assert(pos >= 0); if (z_blob_lock(self, timeout)) { z_blob_alloc(self, pos); z_blob_unlock(self); res = TRUE; } z_return(res); } /** * Write some data into the given position of the blob, expanding it if necessary. * * @param[in] self this * @param[in] pos position to write to * @param[in] data data to write * @param[in] req_datalen length of data * @param[in] timeout timeout * * @returns The amount of data written. **/ gsize z_blob_add_copy(ZBlob *self, gint64 pos, const gchar* data, gsize req_datalen, gint timeout) { off_t err; gssize written = 0; z_enter(); g_assert(self); g_assert(data); g_assert(pos >= 0); if (z_blob_lock(self, timeout)) { if (self->alloc_size < (pos + (gssize) req_datalen)) z_blob_alloc(self, pos + req_datalen); if (self->is_in_file) { gssize remain; err = lseek(self->fd, pos, SEEK_SET); if (err < 0) { z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } remain = req_datalen; while (remain > 0) { written = write(self->fd, data, remain); if (written < 0) { if (errno == EINTR) { continue; } else { z_log(NULL, CORE_ERROR, 0, "Blob error, write() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } } remain -= written; } } else { memmove(self->data + pos, data, req_datalen); written = req_datalen; } if (self->size < (pos + written)) self->size = pos + written; self->stat.req_wr++; self->stat.total_wr += written; self->stat.last_accessed = time(NULL); z_blob_unlock(self); } z_return(written); } /** * Reads some data from the blob into a buffer. * * @param[in] self this * @param[in] pos position to read from * @param[in] data buffer to read into * @param[in] req_datalen bytes to read * @param[in] timeout timeout * * @returns The amount of data actually read. **/ gsize z_blob_get_copy(ZBlob *self, gint64 pos, gchar* data, gsize req_datalen, gint timeout) { off_t err; gssize rd = 0; z_enter(); g_assert(self); g_assert(data); g_assert(pos >= 0); if (pos < self->size) { if (req_datalen > (guint64) (self->size - pos)) req_datalen = self->size - pos; if (z_blob_lock(self, timeout)) { if (self->is_in_file) { gssize remain; err = lseek(self->fd, pos, SEEK_SET); if (err < 0) { z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } remain = req_datalen; while (remain > 0) { rd = read(self->fd, data, remain); if (rd < 0) { if (errno == EINTR) { continue; } else { z_log(NULL, CORE_ERROR, 0, "Blob error, read() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } } remain -= rd; } } else { memmove(data, self->data + pos, req_datalen); rd = req_datalen; } self->stat.req_rd++; self->stat.total_rd += rd; self->stat.last_accessed = time(NULL); z_blob_unlock(self); } } z_return(rd); } /** * Get the (absolute) filename assigned to the blob. * * @param[in] self this * @param[in] user Owner of the created file or NULL * @param[in] group Group of the created file or NULL * @param[in] mode Mode of the created file of -1 * @param[in] timeout timeout * * @returns The filename **/ const gchar * z_blob_get_file(ZBlob *self, const gchar *user, const gchar *group, gint mode, gint timeout) { const gchar *res = NULL; z_enter(); g_assert(self); if (!self->filename || !self->system) z_return(NULL); if (z_blob_lock(self, timeout)) { if (!self->is_in_file) { if (self->storage_locked) goto exit; g_mutex_lock(self->system->mtx_blobsys); /* swap_out() accesses the blob systems data directly, so it needs to be locked */ z_blob_swap_out(self); g_mutex_unlock(self->system->mtx_blobsys); } if (group || user) { uid_t user_id = -1; gid_t group_id = -1; if (user && !z_resolve_user(user, &user_id)) { z_log(NULL, CORE_ERROR, 3, "Cannot resolve user; user='%s'", user); goto exit; } if (group && !z_resolve_group(group, &group_id)) { z_log(NULL, CORE_ERROR, 3, "Cannot resolve group; group='%s'", group); goto exit; } if (chown(self->filename, user_id, group_id) == -1) goto exit; } if ((mode != -1) && (chmod(self->filename, mode) == -1)) goto exit; res = self->filename; exit: if (res == NULL) z_blob_unlock(self); } z_return(res); } /** * Release the lock on the blob after z_blob_get_file. * * @param[in] self this * * Besides releasing the lock itself, this function also updates the * blob size from the file size. **/ void z_blob_release_file(ZBlob *self) { struct stat st; z_enter(); g_assert(self); if (!fstat(self->fd, &st)) self->size = self->alloc_size = st.st_size; else z_log(NULL, CORE_ERROR, 3, "Cannot stat file on release, blob size may be incorrect from now;"); z_blob_unlock(self); z_return(); } /** * Obtains a pointer to a subrange of the blob. * * @param[in] self this * @param[in] pos start of the range to get ptr for * @param[in, out] req_datalen length of the range: in=requested, out=mapped * @param[in] timeout timeout * * This function obtains a pointer to a specified subrange of the blob. * Until the pointer is freed by 'z_blob_free_ptr()', the blob will be locked for * reading, that means read operations are still possible, but writes and * swapping is disabled and will block! * * @returns The pointer on success, NULL on error **/ gchar * z_blob_get_ptr(ZBlob *self, gint64 pos, gsize *req_datalen, gint timeout) { gchar *data = NULL; gint offset_in_page; z_enter(); g_assert(self); g_assert(req_datalen); g_assert(self->mapped_ptr == NULL); g_assert(pos >= 0); if ((pos < self->size) && (self->size > 0) && z_blob_lock(self, timeout)) { if (self->size < (pos + (gssize) *req_datalen)) *req_datalen = self->size - pos; if (self->is_in_file) { offset_in_page = pos % getpagesize(); data = (gchar*)mmap(NULL, *req_datalen + offset_in_page, PROT_READ | PROT_WRITE, MAP_SHARED, self->fd, pos - offset_in_page); if (data == (gchar*)-1) data = NULL; else data += offset_in_page; } else { data = self->data + pos; } self->mapped_ptr = data; self->mapped_length = *req_datalen; if (!data) z_blob_unlock(self); } z_return(data); } /** * Unlocks a blob locked by 'z_blob_get_ptr()'. * * @param[in] self this * @param[in] data Pointer to a range, obtained by 'z_blob_get_ptr()' **/ void z_blob_free_ptr(ZBlob *self, gchar *data) { guint offset_in_page; z_enter(); g_assert(self); g_assert(self->mapped_ptr); g_assert(self->mapped_ptr == data); g_assert(self->mapped_length > 0); if (self->is_in_file) { offset_in_page = GPOINTER_TO_UINT(data) % getpagesize(); munmap(data - offset_in_page, self->mapped_length + offset_in_page); } self->mapped_ptr = NULL; self->mapped_length = 0; z_blob_unlock(self); z_return(); } /** * Write data read from a stream into a blob. * * @param[in] self this * @param[in] pos position to write to * @param[in] stream stream to read from * @param[in] count length of data to read * @param[in] timeout timeout * @param[out] error stream error if return value is G_IO_STATUS_ERROR * * Write some data into the given position of the blob, expanding it if * necessary. The function takes multiple passes and supports copying gint64 * chunks and ensures that all the requested data be copied unless an error * occurs, thus there is no bytes_read argument. * * @returns GLib I/O status **/ GIOStatus z_blob_read_from_stream(ZBlob *self, gint64 pos, ZStream *stream, gint64 count, gint timeout, GError **error) { off_t err; GIOStatus res = G_IO_STATUS_NORMAL; guchar *copybuf; GError *local_error = NULL; gsize left; z_enter(); g_assert(self); g_assert(pos >= 0); g_return_val_if_fail((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (z_blob_lock(self, timeout)) { if (self->is_in_file) { if (self->size < pos) z_blob_alloc(self, pos); err = lseek(self->fd, pos, SEEK_SET); if (err < 0) { z_log(NULL, CORE_ERROR, 0, "Blob error, lseek() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } copybuf = g_new(guchar, Z_BLOB_COPY_BUFSIZE); left = count; while (left != 0) { gsize br; gssize bw; gsize bytes; gssize remain; bytes = MIN(left, Z_BLOB_COPY_BUFSIZE); if (self->alloc_size < (pos + (gssize) bytes)) z_blob_alloc(self, pos + bytes); res = z_stream_read(stream, copybuf, bytes, &br, &local_error); if (res != G_IO_STATUS_NORMAL) goto exit_stats; left -= br; pos += br; if (self->size < pos) self->size = pos; remain = br; while (remain > 0) { bw = write(self->fd, copybuf, remain); if (bw < 0) { if (errno == EINTR) { continue; } else { z_log(NULL, CORE_ERROR, 0, "Blob error, write() failed; file='%s', error='%s'", self->filename, g_strerror(errno)); g_assert(0); } } remain -= bw; } } g_free(copybuf); } else { left = count; while (left != 0) { gsize br; gsize bytes; bytes = MIN(left, Z_BLOB_COPY_BUFSIZE); if (self->alloc_size < (pos + (gssize) bytes)) z_blob_alloc(self, pos + count); res = z_stream_read(stream, self->data + pos, bytes, &br, &local_error); if (res != G_IO_STATUS_NORMAL) goto exit_stats; left -= br; pos += br; if (self->size < pos) self->size = pos; } } exit_stats: self->stat.req_wr++; self->stat.total_wr += count; self->stat.last_accessed = time(NULL); z_blob_unlock(self); } else { /* FIXME: how to map this error ? */ res = G_IO_STATUS_ERROR; g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Error acquiring blob lock"); } if (local_error) g_propagate_error(error, local_error); z_return(res); } /** * Write data from a blob to a stream. * * @param[in] self this * @param[in] pos position to write to * @param[in] stream stream to read from * @param[in] count length of data to read * @param[in] timeout timeout * @param[out] error stream error if one occurs * * Write some data from the given position of the blob to the stream. The * function takes multiple passes thus it supports copying gint64 sized * chunks. It also ensures that the complete requested chunk is written * unless an error occurs, thus there is no bytes_written argument. * * @returns GLib I/O status **/ GIOStatus z_blob_write_to_stream(ZBlob *self, gint64 pos, ZStream *stream, gint64 count, gint timeout, GError **error) { gint64 end_pos = pos + count; GIOStatus res = G_IO_STATUS_NORMAL; g_assert(self); g_assert(pos >= 0); g_return_val_if_fail((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); while (pos < end_pos) { gsize mapped_length, mapped_pos, bw; gchar *d; mapped_length = MIN(Z_BLOB_COPY_BUFSIZE, end_pos - pos); mapped_pos = 0; d = z_blob_get_ptr(self, pos, &mapped_length, timeout); if (!d) { res = G_IO_STATUS_ERROR; break; } if (z_stream_write_chunk(stream, d + mapped_pos, mapped_length, &bw, NULL) != G_IO_STATUS_NORMAL) { res = G_IO_STATUS_ERROR; z_blob_free_ptr(self, d); goto exit; } z_blob_free_ptr(self, d); pos += mapped_length; } exit: return res; } /** * Sets the blob's storage_locked field to st. * * @param[in] self this * @param[in] st the value to set storage_locked to. * * @todo FIXME-DOC: this might need better documentation. **/ void z_blob_storage_lock(ZBlob *self, gboolean st) { self->storage_locked = st; } /** * @file * * @todo optimisation of pre-allocation * * Reason: simply doubling of pre-allocated space wastes the address range: * *
 * |- x -|
 *       |--- 2x ---|
 *                  |-------- 4x --------|
 * 
* * etc. There's no way to use the deallocated address space, because, for * example the next allocation of 8x can't fit in the x+2x = 3x hole. * * To achieve this, a growth factor less than 2 must be used: * *
 * |- x -|
 *       |- (p^1)*x -|
 *                   |---- (p^2)*x ----|
 * |---- (p^3)*x ----|
 * 
* * The exact value of p is the solution of the equation * *
 *             p^3 = p + 1
 *     p^3 - p - 1 = 0
 * 
* * which is (cbrt(x) ::= the cubic root of x) * *
 *    p <= cbrt( (1+sqrt(23/27))/2 ) + cbrt( (1-sqrt(23/27))/2 ) 
 *    p =~= 1.3247179572447458
 * 
* * This can be approximated quite well by *
 *     p = 1 + 1/3 - 1/116 
 * 
* and its reciprocal can be approximated by *
 *   1/p = 1 - 1/4 - 1/205
 * 
* * Unfortunately, using integers the rounding error accumulates, and this has * two bad side-effects: * - sometimes the calculated next allocation size is off the range by one * - growing and shrinking back is also off by one in some cases * * Because this optimisation affects only allocations comparable to the size of * the address space (>= 4 GB), currently I use simple doubling, but this must * be fixed some time. **/ libzorpll-3.9.4.1/src/cap.c000066400000000000000000000041501224546767600154200ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: cap.c,v 1.9 2003/09/10 11:46:58 bazsi Exp $ * * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #if ZORPLIB_ENABLE_CAPS const gchar *zorp_caps = NULL; /** * This function modifies the current permitted set of capabilities by * enabling or disabling the capability specified in capability. * * @param[in] capability capability to turn off or on * @param[in] onoff specifies whether the capability should be enabled or disabled * * @returns whether the operation was successful. **/ gboolean cap_modify(int capability, int onoff) { cap_t caps; z_enter(); if (!zorp_caps) z_return(TRUE); caps = cap_get_proc(); if (!caps) z_return(FALSE); if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &capability, onoff) == -1) { cap_free(caps); z_return(FALSE); } if (cap_set_proc(caps) == -1) { cap_free(caps); z_return(FALSE); } cap_free(caps); z_return(TRUE); } /** * Save the set of current capabilities and return it. * * @returns the current set of capabilities * * This function saves the set of current capabilities and returns it. * The caller might restore the saved set of capabilities by using cap_restore(). **/ cap_t cap_save(void) { z_enter(); if (!zorp_caps) z_return(NULL); z_return(cap_get_proc()); } /** * Restore the set of current capabilities specified by r. * * @param[in] r capability set saved by cap_save() * * @returns whether the operation was successful. **/ gboolean cap_restore(cap_t r) { gboolean rc; z_enter(); if (!zorp_caps) z_return(TRUE); rc = cap_set_proc(r) != -1; cap_free(r); z_return(rc); } #endif libzorpll-3.9.4.1/src/code.c000066400000000000000000000115511224546767600155720ustar00rootroot00000000000000// #include #include #include #include /** * @file * * @todo * - use ZPacketBuffer as destination * - the possibility to fetch the results as an allocated memory block * taking ownership (e.g. compress into ZCode's buffer and use it for * other purposes without memory moves **/ /** * Resizes the buffer by a factor of n**2 until it reaches the desired size. * * @param[in] self ZCode instance * @param[in] reqlen requested buffer length * * @todo FIXME: no error handling yet * * @returns TRUE on success **/ gboolean z_code_grow(ZCode *self, gint reqlen) { gint newlen; z_enter(); newlen = self->buf_len; if (newlen <= 0) { newlen = 1; } while (newlen < reqlen) { newlen *= 2; } self->buf = g_realloc(self->buf, newlen); self->buf_len = newlen; z_leave(); return TRUE; } /** * Pushes back data to the buffer. * * @param[in] self this * @param[in] from source buffer * @param[in] fromlen number of bytes to push back to the buffer * * After this function runs, the data will be available for reading. * * @returns The number of bytes pushed back **/ void z_code_unget_result(ZCode *self, const void *from, gsize fromlen) { z_enter(); if (fromlen > 0) { z_code_grow(self, self->buf_used + fromlen); g_memmove(self->buf + fromlen, self->buf, self->buf_used); g_memmove(self->buf, from, fromlen); self->buf_used += fromlen; } z_leave(); } /** * Returns and removes a chunk of transformed bytes. * * @param[in] self this * @param[in] to destination buffer -- the results are returned here * @param[in] tolen length of the destination buffer * * @returns The number of bytes returned. **/ gsize z_code_get_result(ZCode *self, void *to, gsize tolen) { gsize res; z_enter(); res = (tolen < self->buf_used) ? tolen : self->buf_used; if (res > 0) { z_log(NULL, CORE_DUMP, 8, "Reading ZCode data; len='%" G_GSIZE_FORMAT "', used='%" G_GSIZE_FORMAT "', partial='0x%02x'", res, self->buf_used, self->buf[self->buf_used]); z_log_data_dump(NULL, CORE_DEBUG, 8, self->buf, res); g_memmove(to, self->buf, res); self->buf_used -= res; g_memmove(self->buf, self->buf + res, self->buf_used + 1); z_log(NULL, CORE_DUMP, 8, "Remaining ZCode data; len='%" G_GSIZE_FORMAT "', used='%" G_GSIZE_FORMAT "', partial='0x%02x'", res, self->buf_used, self->buf[self->buf_used]); } z_leave(); return res; } /** * Returns a pointer to the transformed data. * * @param[in] self this * * Returns a pointer to the transformed data (Non-destructive read * support). The length of the data returned by this function is * available by calling the z_code_get_result_length() function. * * @returns Pointer to the data **/ const void * z_code_peek_result(ZCode *self) { guchar *res; z_enter(); res = self->buf; z_leave(); return res; } /** * How much data is available in the internal buffer, e.g.\ how much * output the coder has generated so far. * * @param[in] self this * * @returns The amount of available data in bytes **/ gsize z_code_get_result_length(ZCode *self) { gsize res; z_enter(); res = self->buf_used; z_leave(); return res; } /** * Flush the specified number of bytes from the result buffer as if it * had been read using z_code_get_result() * * @param[in] self this * @param[in] flush_length the number of bytes to flush **/ void z_code_flush_result(ZCode *self, gsize flush_length) { if (flush_length == 0 || self->buf_used < flush_length) { self->buf_used = 0; } else if (self->buf_used >= flush_length) { g_memmove(self->buf, self->buf + flush_length, self->buf_used - flush_length); self->buf_used -= flush_length; } } /** * Initialize a caller-allocated ZCode structure with default values * for ZCode. * * @param[out] self ZCode instance * @param[in] bufsize initial bufsize * * Usually used by actual ZCode implementations. **/ void z_code_init(ZCode *self, gint bufsize) { z_enter(); self->buf_len = (bufsize <= 0) ? ZCODE_BUFSIZE_DEFAULT : bufsize; self->buf = g_new0(guchar, self->buf_len); self->buf_used = 0; self->error_counter = 0; z_leave(); } /** * Constructor, creates a ZCode around the specified codec. * * @param[in] bufsize Initial buffer size. If this is <= 0, then * ZCODE_BUFSIZE_DEFAULT is used instead. * * @returns The new instance **/ ZCode* z_code_new(gint bufsize) { ZCode *self; z_enter(); self = g_new0(ZCode, 1); z_code_init(self, bufsize); z_leave(); return self; } /** * Free a ZCode instance by calling the virtual free_fn function. * * @param[in] self this **/ void z_code_free(ZCode *self) { z_enter(); if (self) { if (self->free_fn) self->free_fn(self); g_free(self->buf); g_free(self); } z_leave(); } libzorpll-3.9.4.1/src/code_base64.c000066400000000000000000000401241224546767600167340ustar00rootroot00000000000000// #include #include #include /** * ZCode-derived class to encode binary data to base64. **/ typedef struct ZCodeBase64Encode { ZCode super; gint phase; gint linepos; gint linelen; } ZCodeBase64Encode; /** * ZCode-derived class to decode base64-encoded data to binary form. **/ typedef struct ZCodeBase64Decode { ZCode super; gint phase; gboolean error_tolerant; } ZCodeBase64Decode; /** * @file * * Base64: 3 x 8-bit -> 4 x 6-bit (in ascii representation) * *
 * |               |               |               |
 *  . . . . . . . . . . . . . . . . . . . . . . . . 
 * |           |           |           |           |
 * 
* * 6-bit values mapped to ascii: *
 * 0x00..0x19 -> 'A'..'Z' (0x41..0x5a)
 * 0x1a..0x33 -> 'a'..'z' (0x61..0x7a)
 * 0x34..0x3d -> '0'..'9' (0x30..0x39)
 *    0x3e    ->   '+'       (0x2b)
 *    0x3f    ->   '/'       (0x2f)
 * 
* * If the length of the binary isn't a multiplicate of 3, unspecified bits are * treated as 0 in the specified output bytes, the other output bytes (of the * last quadruple) are represented as '='. * *
 * (xxxxxxxx, yyyyyyyy, zzzzzzzz) -> (xxxxxx, xxyyyy, yyyyzz, zzzzzz)
 * (xxxxxxxx, yyyyyyyy), EOS      -> (xxxxxx, xxyyyy, yyyy00, '=')
 * (xxxxxxxx), EOS                -> (xxxxxx, xx0000, '=',    '=')
 * EOS                            -> nothing
 * 
* * Ascii output may be formatted to lines of any width, terminated by CRLF. * * During decoding spaces, tabs, CRs and LFs shall be ignored, any other char * may be treated as error or ignored as well. **/ /** * Used internally by z_code_base64_encode_finish() to encode the remaining bits * and add padding. * * @param[in] self ZCodeBase64Encode instance * @param[in] closure TRUE to write padding, FALSE to encode the remaining bits * * First it's called with closure=TRUE with the remaining bits written to the buffer * and the rest of the bits in that byte zeroed. Then it's called with closure=FALSE * as many times as many '='-s need to be written. * * Line breaks are written when necessary. **/ static void z_code_base64_encode_fix(ZCodeBase64Encode *self, gboolean closure) { static const char xlat[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U' ,'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; self->super.buf[self->super.buf_used] = closure ? '=' : xlat[self->super.buf[self->super.buf_used] & 0x3f]; self->super.buf_used++; if (self->linelen) { if (self->linepos++ >= self->linelen) { self->super.buf[self->super.buf_used++] = '\r'; self->super.buf[self->super.buf_used++] = '\n'; self->linepos = 0; } } } /** * Used internally to find out how big the buffer should be. * * @param[in] old_size size of data already encoded in the buffer * @param[in] orig_size size of new data to be encoded (before encoding) * @param[in] line_length length of lines in encoded output * * @returns the new size the buffer should be grown to **/ static inline gsize z_code_calculate_growing(gsize old_size, gsize orig_size, gsize line_length) { gsize new_size; gsize new_coded_size; new_size = old_size; /* original content length */ new_coded_size = (orig_size*4 + 2) / 3; /* base64 create 4 octet from every 3 octet */ new_size += new_coded_size; if (line_length) { new_size += 2*(new_size + line_length - 1) / line_length; /* Add newlines */ } return new_size; } /** * binary -> base64 conversion * * @param[in] s this * @param[in] from_ source buffer * @param[in] fromlen source buffer length * * @returns Whether conversion succeeded **/ static gboolean z_code_base64_encode_transform(ZCode *s, const void *from_, gsize fromlen) { ZCodeBase64Encode *self = (ZCodeBase64Encode *) s; gsize pos, buf_used_orig; const guchar *from = from_; z_enter(); z_code_grow((ZCode*)self, z_code_calculate_growing(self->super.buf_used, fromlen, self->linelen)); /* This may allocate 4 excess bytes - but requires no further realloc()s. * Since the calculation uses buf_used, these 4 bytes won't accumulate, but * will be used in the future write()s, so the extra 4 is a grand total. */ z_log(NULL, CORE_DUMP, 8, "Encoding base64 data; len='%" G_GSIZE_FORMAT"', phase='%d', used='%" G_GSIZE_FORMAT "', partial='0x%02x'", fromlen, self->phase, self->super.buf_used, self->super.buf[self->super.buf_used]); z_log_data_dump(NULL, CORE_DEBUG, 8, from, fromlen); buf_used_orig = self->super.buf_used; for (pos = 0; pos < fromlen; pos++) { switch (self->phase) { case 0: /* no previous partial content, (00.. ...., 00.. ....) -> (00xx xxxx, 00xx ....) */ self->super.buf[self->super.buf_used] = from[pos] >> 2; z_code_base64_encode_fix(self, FALSE); self->super.buf[self->super.buf_used] = (from[pos] & 0x03) << 4; break; case 1: /* 2 upper bits already set, (00yy ...., 00.. ....) -> (00yy xxxx, 00xx xx..) */ self->super.buf[self->super.buf_used] |= from[pos] >> 4; z_code_base64_encode_fix(self, FALSE); self->super.buf[self->super.buf_used] = (from[pos] & 0x0f) << 2; break; case 2: /* 4 upper bits already set, (00yy yy.., 00.. ....) -> (00yy yyxx, 00xx xxxx) */ self->super.buf[self->super.buf_used] |= from[pos] >> 6; z_code_base64_encode_fix(self, FALSE); self->super.buf[self->super.buf_used] = from[pos] & 0x3f; z_code_base64_encode_fix(self, FALSE); break; } self->phase = (self->phase + 1) % 3; } z_log(NULL, CORE_DUMP, 8, "Encoded base64 data; len='%" G_GSIZE_FORMAT "', phase='%d', used='%" G_GSIZE_FORMAT "', partial='0x%02x'", self->super.buf_used - buf_used_orig, self->phase, self->super.buf_used, self->super.buf[self->super.buf_used]); z_log_data_dump(NULL, CORE_DEBUG, 8, self->super.buf + buf_used_orig, self->super.buf_used - buf_used_orig); z_leave(); return TRUE; } /** * Finish encoding to Base64. * * @param[in] s ZCodeBase64Encode instance. * * Finishes encoding, including adding padding and newline if necessary. * * @returns always TRUE **/ static gboolean z_code_base64_encode_finish(ZCode *s) { ZCodeBase64Encode *self = (ZCodeBase64Encode *) s; z_enter(); switch (self->phase) { case 0: /* no previous partial content, (00.. ....) -> nothing */ break; case 1: /* upper 2 bits already set, (00yy ....) -> (00yy 0000)== */ self->super.buf[self->super.buf_used] &= 0x30; z_code_base64_encode_fix(self, FALSE); z_code_base64_encode_fix(self, TRUE); z_code_base64_encode_fix(self, TRUE); break; case 2: /* upper 4 bits already set, (00yy yy..) -> (00yy yy00)= */ self->super.buf[self->super.buf_used] &= 0x3c; z_code_base64_encode_fix(self, FALSE); z_code_base64_encode_fix(self, TRUE); break; } if (self->linepos != 0) { self->super.buf[self->super.buf_used++] = '\r'; self->super.buf[self->super.buf_used++] = '\n'; } self->linepos = 0; self->phase = 0; z_leave(); return TRUE; } /** * Initialize ZCodeBase64Encode instance. * * @param[in] self ZCodeBase64Encode instance * @param[in] bufsize initial buffer size * @param[in] linelen line length in output **/ static void z_code_base64_encode_init(ZCodeBase64Encode *self, gint bufsize, gint linelen) { z_enter(); z_code_init(&self->super, bufsize); self->super.transform = z_code_base64_encode_transform; self->super.finish = z_code_base64_encode_finish; self->phase = 0; self->linepos = 0; self->linelen = linelen; z_leave(); } /** * Create a new ZCodeBase64Encode instance. * * @param[in] bufsize initial buffer size * @param[in] linelen line length in output * * @returns new object **/ ZCode* z_code_base64_encode_new(gint bufsize, gint linelen) { ZCodeBase64Encode *self; z_enter(); self = g_new0(ZCodeBase64Encode, 1); z_code_base64_encode_init(self, bufsize, linelen); z_leave(); return &self->super; } /* ---------------------------------------------------------------------- */ /** * base64 -> binary conversion * * @param[in] s this * @param[in] from_ source buffer * @param[in] fromlen source buffer length * * @returns FALSE if it aborted because of an error (if self->error_tolerant is unset); TRUE otherwise. **/ static gboolean z_code_base64_decode_transform(ZCode *s, const void *from_, gsize fromlen) { ZCodeBase64Decode *self = (ZCodeBase64Decode *) s; static const int xlat[256] = /* -3=error, -2=end of stream, -1=ignore, other=value */ { -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3, /* 0x00 - 0x0f */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x10 - 0x1f */ -1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0x3e, -3, -3, -3, 0x3f, /* 0x20 - 0x2f */ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, -3, -3, -3, -2, -3, -3, /* 0x30 - 0x3f */ -3, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* 0x40 - 0x4f */ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -3, -3, -3, -3, -3, /* 0x50 - 0x5f */ -3, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 0x60 - 0x6f */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, -3, -3, -3, -3, -3, /* 0x70 - 0x7f */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x80 - 0x8f */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x90 - 0x9f */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xa0 - 0xaf */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xb0 - 0xbf */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xc0 - 0xcf */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xd0 - 0xdf */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xe0 - 0xef */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3 /* 0xf0 - 0xff */ }; gsize pos, buf_used_orig; gint value; const guchar *from = from_; z_enter(); z_code_grow(s, self->super.buf_used + /* original content */ ((fromlen*3 + 3) / 4) + /* resulting data */ 16); /* This may allocate an excess of 3 bytes plus 0.75 for each non-base64 * character, but they won't accumulate, see z_code_base64_write() for * details. */ z_log(NULL, CORE_DUMP, 8, "Decoding base64 data; len='%" G_GSIZE_FORMAT "'", fromlen); z_log_data_dump(NULL, CORE_DEBUG, 8, from, fromlen); buf_used_orig = self->super.buf_used; value = -1; for (pos = 0; pos < fromlen; pos++) { value = xlat[(guchar)from[pos]]; if (value == -1) /* ignore */ continue; else if (value == -2) /* end of stream */ { switch (self->phase) { case 0: /* (=...) may not happen */ case 1: /* (x=..) may not happen */ z_log(NULL, CORE_ERROR, 3, "Base64 closing character in illegal phase; phase='%d', pos='0x%06" G_GSIZE_MODIFIER "x'", self->phase, pos); if (!self->error_tolerant) { self->super.error_counter++; z_leave(); return FALSE; } break; case 2: /* (..=.) */ self->phase = 4; break; case 3: /* (...=) */ case 4: /* (..==) */ self->phase = 0; break; } continue; } else if ((value < 0) || (0x3f < value)) /* invalid char */ { z_log(NULL, CORE_ERROR, 3, "Illegal base64 character; char='%c', pos='0x%06" G_GSIZE_MODIFIER "x'", from[pos], pos); if (self->error_tolerant) { continue; } else { self->super.error_counter++; z_leave(); return FALSE; } } if (self->phase == 4) /* special case: (yy=) already happened */ { z_log(NULL, CORE_ERROR, 3, "Base64 character in closing phase; char='%c', pos='0x%06" G_GSIZE_MODIFIER "x'", from[pos], pos); if (self->error_tolerant) { self->phase = 0; /* reset and try to go on */ } else { self->super.error_counter++; z_leave(); return FALSE; } } switch (self->phase) { case 0: /* no previous partial content, (.... ....) -> (xxxx xx..) */ self->super.buf[self->super.buf_used] = value << 2; break; case 1: /* upper 6 bits already set, (yyyy yy.., .... ....) -> (yyyy yyxx, xxxx ....) */ self->super.buf[self->super.buf_used++] |= value >> 4; self->super.buf[self->super.buf_used] = value << 4; break; case 2: /* upper 4 bits already set, (yyyy ...., .... ....) -> (yyyy xxxx, xx.. ....) */ self->super.buf[self->super.buf_used++] |= value >> 2; self->super.buf[self->super.buf_used] = value << 6; break; case 3: /* upper 2 bits already set, (yy.. ....) -> (yyxx xxxx) */ self->super.buf[self->super.buf_used++] |= value; break; } self->phase = (self->phase + 1) % 4; } z_log(NULL, CORE_DUMP, 8, "Decoded base64 data; len='%" G_GSIZE_FORMAT "'", self->super.buf_used - buf_used_orig); z_log_data_dump(NULL, CORE_DEBUG, 8, self->super.buf + buf_used_orig, self->super.buf_used - buf_used_orig); z_leave(); return TRUE; } /** * Finalize Base64 decoding. * * @param[in] s ZCodeBase64Decode instance * * Checks if the input was complete (if so, we returned to phase 0). * If it wasn't, the error is logged; and if we're not error_tolerant, * the return value also indicates this error condition. * * @return always TRUE if error_tolerant; otherwise FALSE if the input was incomplete **/ static gboolean z_code_base64_decode_finish(ZCode *s) { ZCodeBase64Decode *self = (ZCodeBase64Decode *) s; z_enter(); if (self->phase != 0) { z_log(NULL, CORE_ERROR, 3, "Unfinished base64 encoding; phase='%d'", self->phase); self->phase = 0; if (!self->error_tolerant) { z_leave(); return FALSE; } } z_leave(); return TRUE; } /** * Initialize ZCodeBase64Decode instance. * * @param[in] self ZCodeBase64Decode instance * @param[in] bufsize initial buffer size * @param[in] error_tolerant whether to be tolerant of errors in input **/ static void z_code_base64_decode_init(ZCodeBase64Decode *self, gint bufsize, gboolean error_tolerant) { z_enter(); z_code_init(&self->super, bufsize); self->super.transform = z_code_base64_decode_transform; self->super.finish = z_code_base64_decode_finish; self->phase = 0; self->error_tolerant = error_tolerant; z_leave(); } /** * Create a new ZCodeBase64Decode instance. * * @param[in] bufsize initial buffer size * @param[in] error_tolerant whether to be tolerant of errors in input * * @returns new object **/ ZCode * z_code_base64_decode_new(gint bufsize, gboolean error_tolerant) { ZCodeBase64Decode *self; z_enter(); self = g_new0(ZCodeBase64Decode, 1); z_code_base64_decode_init(self, bufsize, error_tolerant); z_leave(); return &self->super; } libzorpll-3.9.4.1/src/code_cipher.c000066400000000000000000000044361224546767600171300ustar00rootroot00000000000000#include /** * ZCode-derived class to encrypt/decrypt data using the OpenSSL EVP library. **/ typedef struct _ZCodeCipher { ZCode super; EVP_CIPHER_CTX *cipher_ctx; } ZCodeCipher; static void z_code_cipher_free(ZCode *s); /** * Transform the contents of buf into the buffer of the ZCode instance using an EVP cipher. * * @param[in] s ZCode instance * @param[in] buf input buffer * @param[in] buflen length of buf * * @returns TRUE on success **/ static gboolean z_code_cipher_transform(ZCode *s, const void *buf, gsize buflen) { ZCodeCipher *self = (ZCodeCipher *) s; gint out_length; gboolean result = TRUE; if (buflen) { z_code_grow(s, s->buf_used + ((buflen / self->cipher_ctx->cipher->block_size) + 1) * self->cipher_ctx->cipher->block_size); out_length = s->buf_len - s->buf_used; result = !!EVP_CipherUpdate(self->cipher_ctx, s->buf + s->buf_used, &out_length, buf, buflen); s->buf_used += out_length; } return result; } /** * Do the final step of transformation via the EVP cipher -- that is, deal with padding. * * @param[in] s ZCode instance * * @returns TRUE on success **/ static gboolean z_code_cipher_finish(ZCode *s) { ZCodeCipher *self = (ZCodeCipher *) s; gboolean result; gint out_length; z_code_grow(s, s->buf_used + self->cipher_ctx->cipher->block_size); out_length = s->buf_len - s->buf_used; result = !!EVP_CipherFinal(self->cipher_ctx, s->buf + s->buf_used, &out_length); s->buf_used += out_length; return result; } /** * Create a new ZCodeCipher instance using the specified EVP cipher context. * * @param[in] cipher_ctx the cipher context * * @returns the new ZCodeCipher instance **/ ZCode * z_code_cipher_new(EVP_CIPHER_CTX *cipher_ctx) { ZCodeCipher *self; self = g_new0(ZCodeCipher, 1); z_code_init(&self->super, 0); self->super.transform = z_code_cipher_transform; self->super.finish = z_code_cipher_finish; self->super.free_fn = z_code_cipher_free; self->cipher_ctx = cipher_ctx; return &self->super; } /** * Destroy a ZCodeCipher instance. * * @param[in] s ZCodeCipher instance * * The cipher context also gets cleaned up. **/ static void z_code_cipher_free(ZCode *s) { ZCodeCipher *self = (ZCodeCipher *) s; EVP_CIPHER_CTX_cleanup(self->cipher_ctx); } libzorpll-3.9.4.1/src/code_gzip.c000066400000000000000000000073561224546767600166330ustar00rootroot00000000000000#include // #include #include #include /** * ZCode-derived class to facilitate gzip compression/decompression. **/ typedef struct ZCodeGzip { ZCode super; gboolean encode; z_stream gzip; gboolean end_of_stream; } ZCodeGzip; /* decoder */ /** * Transform (gzip compress/encode or decompress/decode) the contents of buf into the buffer of the ZCodeGzip instance. * * @param[in] s ZCodeGzip instance * @param[in] buf input buffer * @param[in] buflen length of buf * * @return TRUE on success **/ static gboolean z_code_gzip_transform(ZCode *s, const void *buf, gsize buflen) { ZCodeGzip *self = (ZCodeGzip *) s; gint rc; if (!buflen) return TRUE; if (self->end_of_stream) { z_log(NULL, CORE_ERROR, 3, "Error during GZip transformation, data after EOF; mode='%d'", self->encode); return FALSE; } self->gzip.next_in = (guchar *) buf; self->gzip.avail_in = buflen; do { guint needed = self->encode ? self->gzip.avail_in : self->gzip.avail_in * 2; if ((s->buf_len - s->buf_used) < needed) z_code_grow(s, s->buf_len + needed); self->gzip.next_out = s->buf + s->buf_used; self->gzip.avail_out = s->buf_len - s->buf_used; rc = self->encode ? deflate(&self->gzip, Z_SYNC_FLUSH) : inflate(&self->gzip, Z_NO_FLUSH); if (rc < 0) { z_log(NULL, CORE_ERROR, 3, "Error in GZip transformation data; rc='%d', error='%s', avail_in='%d', avail_out='%d'", rc, Z_STRING_SAFE(self->gzip.msg), self->gzip.avail_in, self->gzip.avail_out); return FALSE; } if (rc == Z_STREAM_END) self->end_of_stream = TRUE; s->buf_used = s->buf_len - self->gzip.avail_out; } while (self->gzip.avail_in != 0); return TRUE; } /** * Destroy the ZCodeGzip instance. * * @param[in] s ZCodeGzip instance **/ static void z_code_gzip_free(ZCode *s) { ZCodeGzip *self = (ZCodeGzip *) s; if (self->encode) deflateEnd(&self->gzip); else inflateEnd(&self->gzip); } /** * Finalize the transformation. * * @param[in] s ZCodeGzip instance. * * @returns TRUE if the transformation has consumed all data available * (it should have by the end) **/ static gboolean z_code_gzip_finish(ZCode *s) { ZCodeGzip *self = (ZCodeGzip *) s; return self->gzip.avail_in == 0; } /** * Creates a new ZCodeGzip instance. * * @param[in] bufsize buffer size * @param[in] encode TRUE if encoding/compression is desired, FALSE if decoding/decompression is desired * @param[in] compress_level compression level (ignored for decoding) * * @returns ZCodeGzip instance **/ static ZCode * z_code_gzip_init(gint bufsize, gboolean encode, gint compress_level) { ZCodeGzip *self; z_enter(); self = g_new0(ZCodeGzip, 1); z_code_init(&self->super, bufsize); self->super.transform = z_code_gzip_transform; self->super.finish = z_code_gzip_finish; self->super.free_fn = z_code_gzip_free; self->encode = encode; if (encode) g_assert(deflateInit(&self->gzip, compress_level) == Z_OK); else g_assert(inflateInit(&self->gzip) == Z_OK); z_leave(); return &self->super; } /** * Creates a new ZCodeGzip instance set up for encoding/compression. * * @param[in] bufsize buffer size * @param[in] compress_level compression level (ignored for decoding) * * @returns ZCodeGzip instance **/ ZCode * z_code_gzip_encode_new(gint bufsize, gint compress_level) { return z_code_gzip_init(bufsize, TRUE, compress_level); } /** * Creates a new ZCodeGzip instance set up for decoding/decompression. * * @param[in] bufsize buffer size * * @returns ZCodeGzip instance **/ ZCode * z_code_gzip_decode_new(gint bufsize) { return z_code_gzip_init(bufsize, FALSE, 0); } libzorpll-3.9.4.1/src/connect.c000066400000000000000000000411571224546767600163160ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: connect.c,v 1.52 2004/10/05 14:06:37 chaoron Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef G_OS_WIN32 # include #include /* NOTE: on windows handles opened with socket() must call closesocket() and must NOT call any other close that triggers undefined behavior... */ #define close closesocket #else # include # include # include #endif /** * Private callback function, registered to a #ZSocketSource to be called * when the socket becomes writeable, e.g.\ when the connection is * established. * * @param[in] timed_out specifies whether the operation timed out * @param[in] data user data passed by socket source, assumed to point to #ZConnector instance * * @returns always FALSE to indicate that polling the socket should end **/ static gboolean z_connector_connected(gboolean timed_out, gpointer data) { ZConnector *self = (ZConnector *) data; int error_num = 0; const gchar * error_num_str = NULL; socklen_t errorlen = sizeof(error_num); ZConnectFunc callback; GError *err = NULL; gint fd; z_enter(); if (!self->callback) z_return(FALSE); /* we have been called */ fd = self->fd; if (timed_out) { error_num = ETIMEDOUT; error_num_str = "connection timed out"; } else if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)(&error_num), &errorlen) == -1) { /*LOG This message indicates that getsockopt(SOL_SOCKET, SO_ERROR) failed for the given fd. This system call should never fail, so if you see this please report it to the Zorp QA. */ z_log(self->session_id, CORE_ERROR, 0, "getsockopt(SOL_SOCKET, SO_ERROR) failed for connecting socket, ignoring; fd='%d', error='%s'", self->fd, g_strerror(errno)); } if (error_num) { char buf1[MAX_SOCKADDR_STRING], buf2[MAX_SOCKADDR_STRING]; if (!error_num_str) error_num_str = g_strerror(error_num); /*LOG This message indicates that the connection to the remote end failed for the given reason. It is likely that the remote end is unreachable. */ z_log(self->session_id, CORE_ERROR, 2, "Connection to remote end failed; local='%s', remote='%s', error='%s'", self->local ? z_sockaddr_format(self->local, buf1, sizeof(buf1)) : "NULL", z_sockaddr_format(self->remote, buf2, sizeof(buf2)), error_num_str); /* self->poll.fd is closed when we are freed */ fd = -1; } else { #ifdef G_OS_WIN32 WSAEventSelect(fd, 0, 0); #endif z_fd_set_nonblock(fd, 0); /* don't close our fd when freed */ self->fd = -1; } g_static_rec_mutex_lock(&self->lock); if (self->watch) { if (error_num) g_set_error(&err, G_IO_CHANNEL_ERROR, error_num, "%s", error_num_str); callback = self->callback; self->callback = NULL; callback(fd >= 0 ? z_stream_fd_new(fd, "") : NULL, err, self->user_data); g_clear_error(&err); } else { /*LOG This message reports that the connection was cancelled, and no further action is taken. */ z_log(self->session_id, CORE_DEBUG, 6, "Connection cancelled, not calling callback; fd='%d'", fd); close(fd); } g_static_rec_mutex_unlock(&self->lock); /* don't poll again, and destroy associated source */ z_return(FALSE); } /** * This function is registered as the destroy notify function of self when * the associated #ZSocketSource source is destroyed. * * @param[in] self ZConnector instance * * It calls our destroy_notify callback, and unrefs self. **/ static void z_connector_source_destroy_cb(ZConnector *self) { if (self->destroy_data && self->user_data) { self->destroy_data(self->user_data); self->user_data = NULL; } z_connector_unref(self); } /** * This function is used by the different z_connector_start_*() functions, * it contains the common things to do when a connection is initiated. * * @param[in] self ZConnector instance * @param[out] local_addr if not NULL, the local address where we are bound will be returned here * * @returns TRUE if the connection succeeded. **/ static gboolean z_connector_start_internal(ZConnector *self, ZSockAddr **local_addr) { ZSockAddr *local = NULL; gchar buf1[MAX_SOCKADDR_STRING], buf2[MAX_SOCKADDR_STRING]; z_enter(); /*LOG This message reports that a new connection is initiated from/to the given addresses. */ z_log(self->session_id, CORE_DEBUG, 7, "Initiating connection; from='%s', to='%s'", self->local ? z_sockaddr_format(self->local, buf1, sizeof(buf1)) : "NULL", z_sockaddr_format(self->remote, buf2, sizeof(buf2))); if (z_connect(self->fd, self->remote, self->sock_flags) != G_IO_STATUS_NORMAL && !z_errno_is(EINPROGRESS)) { /*LOG This message indicates that the connection to the remote end failed for the given reason. It is likely that the remote end is unreachable. */ z_log(self->session_id, CORE_ERROR, 2, "Connection to remote end failed; local='%s', remote='%s', error='%s'", self->local ? z_sockaddr_format(self->local, buf1, sizeof(buf1)) : "NULL", z_sockaddr_format(self->remote, buf2, sizeof(buf2)), g_strerror(errno)); z_return(FALSE); } if (z_getsockname(self->fd, &local, self->sock_flags) == G_IO_STATUS_NORMAL) { ZSockAddr *l; /* it contained the bind address, we now have an exact value */ l = self->local; self->local = NULL; z_sockaddr_unref(l); self->local = local; z_sockaddr_ref(local); } if (local_addr) *local_addr = local; else z_sockaddr_unref(local); return TRUE; } /** * Start initiating the connection. * * @param[in] self ZConnector instance * @param[out] local_addr if not NULL, the local address where we are bound will be returned here * * It will fail if this function has been called on this ZConnector already. * * @returns TRUE if the connection was successful **/ gboolean z_connector_start(ZConnector *self, ZSockAddr **local_addr) { z_enter(); if (self->watch) { /*LOG This message indicates that the connection was started twice. Please report this error to the Balabit QA Team (devel@balabit.com). */ z_log(self->session_id, CORE_ERROR, 3, "Internal error, z_connector_start was called twice;"); z_return(FALSE); } if (z_connector_start_internal(self, local_addr)) { self->watch = z_socket_source_new(self->fd, Z_SOCKEVENT_CONNECT, self->timeout); g_source_set_callback(self->watch, (GSourceFunc) z_connector_connected, z_connector_ref(self), (GDestroyNotify) z_connector_source_destroy_cb); if (!g_source_attach(self->watch, self->context)) g_assert_not_reached(); z_leave(); return TRUE; } z_return(FALSE); } /** * Initiate the connection and block while it either succeeds or fails. * * @param[in] self ZConnector instance * @param[out] local_addr if not NULL, the local address where we are bound will be returned here * @param[out] stream if not NULL, a stream wrapped around self->fd will be returned here * * @returns TRUE to indicate success and a reference of the local address in local_addr **/ gboolean z_connector_start_block(ZConnector *self, ZSockAddr **local_addr, ZStream **stream) { gint res; gboolean success = FALSE; z_enter(); if (z_connector_start_internal(self, local_addr)) { z_connector_ref(self); #ifndef G_OS_WIN32 { struct pollfd pfd; time_t timeout_target, timeout_left; pfd.fd = self->fd; pfd.events = POLLOUT; pfd.revents = 0; timeout_target = time(NULL) + self->timeout; do { timeout_left = timeout_target - time(NULL); res = poll((struct pollfd *) &pfd, 1, timeout_left < 0 ? 0 : timeout_left * 1000); if (res == 1) break; } while (res == -1 && errno == EINTR); } #else { fd_set rf; TIMEVAL to; to.tv_sec = 0; to.tv_usec = self->timeout * 1000; FD_ZERO(&rf); FD_SET(self->fd, &rf); do { res = select(0,&rf,&rf,&rf,&to); // ((struct pollfd *) &pfd, 1, self->timeout); if (res == 1) break; } while (res == -1 && errno == EINTR); } #endif z_fd_set_nonblock(self->fd, 0); z_fd_set_keepalive(self->fd, 1); success = TRUE; *stream = z_stream_fd_new(self->fd, ""); z_connector_source_destroy_cb(self); self->fd = -1; } z_leave(); return success; } /** * Same as z_connector_start() but using the context specified in context. * * @param[in] self ZConnector instance * @param[in] context GMainContext to use for polling * @param[out] local_addr if not NULL, the the local address where we are bound will be returned here * * @returns TRUE if successful. **/ gboolean z_connector_start_in_context(ZConnector *self, GMainContext *context, ZSockAddr **local_addr) { gboolean success; z_enter(); if (context) { g_main_context_ref(context); self->context = context; } success = z_connector_start(self, local_addr); z_leave(); return success; } /** * Cancel connection after _start was called. * * @param[in] self ZConnector instance * * It is guaranteed that no user callbacks will be called after * z_connector_cancel() returns. **/ void z_connector_cancel(ZConnector *self) { z_enter(); g_static_rec_mutex_lock(&self->lock); if(self->watch) { /* Must unlock self->lock before call g_source_destroy, * because in another thread we may be hold context lock * (inside the glib) and wait for this lock. (For example if * the client stop the download in exactly the same time, when * the connection failed. */ GSource *watch = self->watch; self->watch = NULL; g_static_rec_mutex_unlock(&self->lock); g_source_destroy(watch); g_source_unref(watch); } else { g_static_rec_mutex_unlock(&self->lock); } z_return(); } /** * Set the connection timeout of a #ZConnector. * * @param[in] self ZConnector instance * @param[in] timeout timeout in seconds * * Set connection timeout. The connection establishment may not exceed the * time specified in timeout. **/ void z_connector_set_timeout(ZConnector *self, gint timeout) { self->timeout = timeout; } void z_connector_set_tos(ZConnector *self, gint tos) { if ((self->fd != -1) && tos > 0) z_fd_set_our_tos(self->fd, tos); } void z_connector_set_mark(ZConnector *self, int mark) { if ((self->fd != -1) && mark > 0) z_fd_set_our_mark(self->fd, mark); } /** * This function opens a new socket and returns the newly created fd. * * @param[in] self ZConnector instance * * @returns the newly created fd **/ static gint z_connector_open_socket(ZConnector *self) { gint fd; gint on = 1; gchar buf[MAX_SOCKADDR_STRING]; fd = socket(z_map_pf(self->remote->sa.sa_family), self->socket_type, 0); if (fd == -1) { /*LOG This message indicates that Zorp failed to create a socket for establishing a connection with the indicated remote endpoint. */ z_log(self->session_id, CORE_ERROR, 1, "Creating socket for connecting failed; family='%d', type='%s', remote='%s', error='%s'", self->remote->sa.sa_family, z_socket_type_to_str(self->socket_type), z_sockaddr_format(self->remote, buf, sizeof(buf)), g_strerror(errno)); z_return(-1); } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { z_log(self->session_id, CORE_ERROR, 1, "Enabling SO_REUSEADDR on connect socket failed; family='%d', type='%s', error='%s'", self->remote->sa.sa_family, z_socket_type_to_str(self->socket_type), g_strerror(errno)); } if (self->local && z_bind(fd, self->local, self->sock_flags) != G_IO_STATUS_NORMAL) { z_log(self->session_id, CORE_ERROR, 1, "Error binding socket; local='%s', error='%s'", z_sockaddr_format(self->local, buf, sizeof(buf)), g_strerror(errno)); z_leave(); return -1; } if (!z_fd_set_nonblock(fd, TRUE)) { /* z_fd_set_nonblock sends log message for failure */ z_leave(); return -1; } z_leave(); return fd; } /** * This function creates a new ZConnector instance. * * @param[in] class the class of the new object, must be compatible with #ZConnector. * @param[in] session_id session id used for logging * @param[in] socket_type socket type * @param[in] local local address to bind to. * @param[in] remote remote address to connect to. * @param[in] sock_flags socket flags * @param[in] callback function to call when the connection is established. * @param[in] user_data opaque pointer to pass to callback. * @param[in] destroy_data destroy callback for user_data * * @returns The allocated instance. **/ ZConnector * z_connector_new(ZClass *class_, const gchar *session_id, gint socket_type, ZSockAddr *local, ZSockAddr *remote, guint32 sock_flags, ZConnectFunc callback, gpointer user_data, GDestroyNotify destroy_data) { ZConnector *self; z_enter(); self = Z_NEW_COMPAT(class_, ZConnector); self->refcnt = 1; self->local = z_sockaddr_ref(local); self->remote = z_sockaddr_ref(remote); self->session_id = session_id ? g_strdup(session_id) : NULL; self->callback = callback; self->user_data = user_data; self->destroy_data = destroy_data; self->timeout = 30; self->sock_flags = sock_flags; self->socket_type = socket_type; self->fd = z_connector_open_socket(self); if (self->fd < 0) { z_connector_unref(self); self = NULL; } z_return((ZConnector *) self); } /** * Free the contents of s. * * @param[in] s ZConnector instance to free * * This function is called by z_connector_unref() when the reference count * of s goes down to zero. It frees the contents of s. **/ static void z_connector_free(ZObject *s) { ZConnector *self = Z_CAST(s, ZConnector); z_enter(); self->callback = NULL; if (self->destroy_data && self->user_data) { self->destroy_data(self->user_data); self->user_data = NULL; } if (self->fd != -1) close(self->fd); if (self->watch) { /* self->watch might still be present when the destruction of this * object is done by the FALSE return value of our callback. * 1) connected returns FALSE * 2) GSource calls our destroy notify, which drops the reference * held by the source * 3) when our ref_cnt goes to 0, this function is called, but * self->watch might still be present * * Otherwise the circular reference is broken by _cancel or right in * _start when the error occurs. */ g_source_destroy(self->watch); g_source_unref(self->watch); self->watch = NULL; } z_sockaddr_unref(self->local); z_sockaddr_unref(self->remote); if (self->context) g_main_context_unref(self->context); g_free(self->session_id); z_object_free_method(s); z_return(); } /** * ZConnector virtual methods. **/ ZConnectorFuncs z_connector_funcs = { { Z_FUNCS_COUNT(ZObject), z_connector_free }, }; /** * ZConnector class descriptor. **/ #ifdef G_OS_WIN32 LIBZORPLL_EXTERN #endif Z_CLASS_DEF(ZConnector, ZObject, z_connector_funcs); /** * ZStreamConnector virtual methods. **/ ZConnectorFuncs z_stream_connector_funcs = { { Z_FUNCS_COUNT(ZObject), NULL } }; /** * ZStreamConnector class descriptor. **/ #ifdef G_OS_WIN32 LIBZORPLL_EXTERN #endif ZClass ZStreamConnector__class = { Z_CLASS_HEADER, Z_CLASS(ZConnector), // super_class "ZStreamConnector", // name sizeof(ZConnector), // size &z_stream_connector_funcs.super //funcs }; libzorpll-3.9.4.1/src/crypt.c000066400000000000000000000131661224546767600160250ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id$ * * Author : bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #if HAVE_CRYPT_H #include #endif #if HAVE_CRYPT /** mutex protecting crypt() invocation */ G_LOCK_DEFINE_STATIC(crypt_lock); #else #include #endif #ifdef G_OS_WIN32 #define snprintf _snprintf #endif #if !HAVE_MD5_CRYPT #include #define CRYPT_MD5_MAGIC "$1$" #define CRYPT_MD5_MAGIC_LEN 3 static unsigned char md5_crypt_b64t[] = /**< 0 to 63 => ascii - 64 */ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; /** * Encode MD5 hash to the ASCII-based encoding defined by md5_crypt_b64t * * @param[out] s buffer where the result will be returned * @param[in] v the MD5 hash to be encoded * @param[in] n the size of the buffer * * @note This function won't write a terminating null to the buffer. * However, it will always write n bytes, even writing 0-s if v runs out. **/ static inline void md5_crypt_to64(char *s, unsigned int v, int n) { while (--n >= 0) { *s++ = md5_crypt_b64t[v & 0x3f]; v >>= 6; } } /** * MD5 version of crypt(3) -- generates an MD5-based hash string (with salt) of the password. * * @param[in] pw the password * @param[in] salt the salt * @param[out] result buffer for the result * @param[in] result_len size of the buffer **/ void md5_crypt(const char *pw, const char *salt, char *result, size_t result_len) { const char *sp, *ep; char *p; unsigned char final[16]; int i, sl, pwl; unsigned int l; MD5_CTX ctx, alt_ctx; /* Refine the salt first */ sp = salt; /* If it starts with the magic string, then skip that */ if (strncmp(sp, CRYPT_MD5_MAGIC, CRYPT_MD5_MAGIC_LEN) == 0) sp += CRYPT_MD5_MAGIC_LEN; /* It stops at the first '$', max 8 chars */ for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++) continue; /* get the length of the true salt */ sl = ep - sp; pwl = strlen(pw); MD5_Init(&ctx); MD5_Update(&ctx, pw, pwl); MD5_Update(&ctx, CRYPT_MD5_MAGIC, CRYPT_MD5_MAGIC_LEN); MD5_Update(&ctx, sp, sl); MD5_Init(&alt_ctx); MD5_Update(&alt_ctx, pw, pwl); MD5_Update(&alt_ctx, sp, sl); MD5_Update(&alt_ctx, pw, pwl); MD5_Final(final, &alt_ctx); for (i = pwl; i > 0; i -= 16) MD5_Update(&ctx, final, (i > 16 ? 16 : i)); /* Then something really weird... */ final[0] = 0; for (i = pwl; i != 0; i >>= 1) if ((i & 1) != 0) MD5_Update(&ctx, final, 1); else MD5_Update(&ctx, pw, 1); MD5_Final(final, &ctx); for (i = 0; i < 1000; i++) { MD5_Init(&ctx); if ((i & 1) != 0) MD5_Update(&ctx, pw, pwl); else MD5_Update(&ctx, final, 16); if ((i % 3) != 0) MD5_Update(&ctx, sp, sl); if ((i % 7) != 0) MD5_Update(&ctx, pw, pwl); if ((i & 1) != 0) MD5_Update(&ctx, final, 16); else MD5_Update(&ctx, pw, pwl); MD5_Final(final, &ctx); } /* Now make the output string */ i = snprintf(result, result_len, "%s%.*s$", CRYPT_MD5_MAGIC, sl, sp); if (i > 0 && result_len > (unsigned int) i) { p = result + i; if (result_len > 23) { l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; md5_crypt_to64(p,l,4); p += 4; l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; md5_crypt_to64(p,l,4); p += 4; l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; md5_crypt_to64(p,l,4); p += 4; l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; md5_crypt_to64(p,l,4); p += 4; l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; md5_crypt_to64(p,l,4); p += 4; l = final[11]; md5_crypt_to64(p,l,2); p += 2; *p = '\0'; } /* Don't leave anything around in vm they could use. */ memset(final, 0, sizeof(final)); } } #endif /** * This function is a reentrant version of crypt(3), ensuring thread * synchronization using a global mutex. * * @param[in] key password to crypt * @param[in] salt salt value * @param[out] result result is stored here * @param[in] result_len length of the result buffer **/ /* based on actual crypt(3) */ #if HAVE_CRYPT && HAVE_MD5_CRYPT void z_crypt(const char *key, const char *salt, char *result, size_t result_len) { G_LOCK(crypt_lock); g_strlcpy(result, crypt(key, salt), result_len); G_UNLOCK(crypt_lock); } #elif HAVE_CRYPT /* have crypt, but no md5 in crypt */ void z_crypt(const char *key, const char *salt, char *result, size_t result_len) { if (strncmp(salt, CRYPT_MD5_MAGIC, CRYPT_MD5_MAGIC_LEN) == 0) { /* need md5 crypt */ md5_crypt(key, salt, result, result_len); } else { /* ok, call libc crypt */ G_LOCK(crypt_lock); g_strlcpy(result, crypt(key, salt), result_len); G_UNLOCK(crypt_lock); } } #else /* does not have crypt at all */ void z_crypt(const char *key, const char *salt, char *result, size_t result_len) { if (strncmp(salt, CRYPT_MD5_MAGIC, CRYPT_MD5_MAGIC_LEN) == 0) { /* need md5 crypt */ md5_crypt(key, salt, result, result_len); } else { g_assert(result_len >= 14); DES_fcrypt(key, salt, result); } } #endif libzorpll-3.9.4.1/src/error.c000066400000000000000000000035711224546767600160140ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: error.c,v 1.2 2003/04/08 13:32:28 sasa Exp $ * * Author : void * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #ifdef G_OS_WIN32 /** * Translate Unix error code to Windows error code. * * @param[in] e Unix error code * * It's not complete... only contains error codes used somewhere. **/ static int z_errno_translate(int e) { switch (e) { case EAGAIN: /* a.k.a. EWOULDBLOCK */ case EINPROGRESS: return WSAEWOULDBLOCK; case ENOTSOCK: return WSAENOTSOCK; case EINTR: /* WSAEINTR does exist, but has a different meaning */ return 0; default: return e; } } #endif /** * Check if errno/WSAGetLastError() is equal to e, compensating for platform differences. * * @param[in] e Unix error code * * @returns TRUE if the compared error values are equivalent. **/ gboolean z_errno_is(int e) { #ifdef G_OS_WIN32 int err; err = WSAGetLastError(); if (err == z_errno_translate(e)) return TRUE; #endif return (errno == e); } /** * Get the error value, using WSAGetLastError() on Windows and errno elsewhere. * * @returns the error value **/ int z_errno_get(void) { #ifdef G_OS_WIN32 return WSAGetLastError(); #else return errno; #endif } /** * Set the error value, using WSASetLastError() on Windows and errno elsewhere. * * @param[in] e the error value **/ void z_errno_set(int e) { #ifdef G_OS_WIN32 WSASetLastError(e); #endif errno = e; } libzorpll-3.9.4.1/src/headerset.c000066400000000000000000000053741224546767600166320ustar00rootroot00000000000000#include #include static void z_header_set_destroy_chain(GList *list) { ZHeader *header; z_enter(); while (list) { header = (ZHeader *)list->data; g_string_free(header->key, TRUE); g_string_free(header->value, TRUE); g_free(header); list = g_list_delete_link(list, list); } z_return(); } static void z_header_set_destroy_foreach(gpointer key G_GNUC_UNUSED, gpointer value, gpointer user_data G_GNUC_UNUSED) { z_enter(); z_header_set_destroy_chain((GList *)value); z_return(); } static gint z_header_compare(ZHeader *h1, ZHeader *h2) { return strcmp(h2->key->str, h1->key->str); } static void z_header_set_append_foreach(gpointer key G_GNUC_UNUSED, gpointer value, gpointer user_data) { GList **ret = (GList **) user_data; GList *list; ZHeader *header; list = (GList *) value; while (list) { header = list->data; *ret = g_list_insert_sorted(*ret, header, (GCompareFunc) z_header_compare); list = g_list_next(list); } } GList * z_header_set_get_all_headers(ZHeaderSet *self) { GList *ret = NULL; z_enter(); g_hash_table_foreach(self->headers, z_header_set_append_foreach, &ret); ret = g_list_reverse(ret); z_return(ret); } ZHeader * z_header_set_iterate(ZHeaderSet *self, const gchar *key, gpointer *opaque) { ZHeader *res; GList *value = opaque ? (GList *) *opaque : NULL; z_enter(); if (value == NULL) value = (GList *) g_hash_table_lookup(self->headers, key); else value = g_list_next(value); if (value == NULL) z_return(NULL); res = value->data; if (opaque) *opaque = value; z_return(res); } gboolean z_header_set_add(ZHeaderSet *self, GString *key, GString *value, gboolean multiple) { ZHeader *header; GList *hlist; z_enter(); header = g_new0(ZHeader, 1); header->key = key; header->value = value; hlist = g_hash_table_lookup(self->headers, header->key->str); if (!hlist || (header->key->str[0] == 'X') || multiple) { self->headers_count++; hlist = g_list_append(hlist, header); g_hash_table_insert(self->headers, header->key->str, hlist); z_return(TRUE); } z_return(FALSE); } void z_header_set_init(ZHeaderSet *self) { self->headers = g_hash_table_new(g_str_hash, g_str_equal); } void z_header_set_destroy(ZHeaderSet *self) { g_hash_table_foreach(self->headers, z_header_set_destroy_foreach, NULL); g_hash_table_destroy(self->headers); self->headers = NULL; } libzorpll-3.9.4.1/src/io.c000066400000000000000000000160751224546767600152750ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: io.c,v 1.18 2004/05/22 14:04:16 bazsi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef G_OS_WIN32 # include #else # include # include #endif /** * This function enables or disables the non-blocking mode of operation on * the given fd. * * @param[in] fd file descriptor to change * @param[in] enable specifies whether to enable or disable O_NONBLOCK * * @returns whether the operation was successful **/ gboolean z_fd_set_nonblock(int fd, gboolean enable) { #ifdef G_OS_WIN32 /* Note: this assumes the fd is a socket. */ unsigned long argp; argp = enable; if (!enable) { if (WSAEventSelect(fd, (WSAEVENT) NULL, 0) == SOCKET_ERROR) { z_log(NULL, CORE_ERROR, 3, "Disabling socket events failed; fd='%d', error='%08x'", fd, z_errno_get()); return FALSE; } } if (ioctlsocket(fd, FIONBIO, &argp) == SOCKET_ERROR) { /*LOG This message indicates that changing the blocking state on the given fd failed for the given reason. Please report this event to the Zorp QA team. */ z_log(NULL, CORE_ERROR, 3, "Changing blocking mode failed; fd='%d', enable='%d', error='%08x'", fd, enable, z_errno_get()); return FALSE; } #else int flags; if ((flags = fcntl(fd, F_GETFL)) == -1) return FALSE; if (enable) flags |= O_NONBLOCK; else flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { /*LOG This message indicates that changing the blocking state on the given fd failed for the given reason. Please report this event to the Zorp QA team. */ z_log(NULL, CORE_ERROR, 3, "Changing blocking mode failed; fd='%d', enable='%d', error='%s'", fd, enable, g_strerror(errno)); return FALSE; } #endif return TRUE; } /** * This function enables or disables the TCP keepalive feature for socket * specified by fd. * * @param[in] fd file descriptor of a socket * @param[in] enable whether to enable or disable TCP keepalive * * @returns whether the operation was successful **/ gboolean z_fd_set_keepalive(int fd, gboolean enable) { if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)(&enable), sizeof(enable)) == -1) { /*LOG This message indicates that changing the keep-alive state on the given fd failed for the given reason. Please report this event to the Zorp QA team. */ z_log(NULL, CORE_ERROR, 4, "setsockopt(SOL_SOCKET, SO_KEEPALIVE) failed; fd='%d', enable='%d', error='%s'", fd, enable, g_strerror(errno)); return FALSE; } return TRUE; } /** * This function enables or disables the TCP SO_OOBINLINE feature for socket * specified by fd. * * @param[in] fd file descriptor of a socket * @param[in] enable whether to enable or disable TCP SO_OOBINLINE * * @returns whether the operation was successful **/ gboolean z_fd_set_oobinline(int fd, gboolean enable) { if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char *)(&enable), sizeof(enable)) == -1) { /*LOG This message indicates that changing the OOBINLINE state on the given fd failed for the given reason. Please report this event to the Zorp QA team. */ z_log(NULL, CORE_ERROR, 4, "setsockopt(SOL_SOCKET, SO_OOBINLINE) failed; fd='%d', enable='%d', error='%s'", fd, enable, g_strerror(errno)); return FALSE; } return TRUE; } #ifndef SO_MARK /* In kernel 2.6.25 the SO_MARK has value 36 if architecture is x86/x86_64 */ #define SO_MARK 36 #endif void z_fd_set_our_mark(int fd, int mark) { int res; cap_t saved_caps; static gboolean logged = FALSE; saved_caps = cap_save(); cap_enable(CAP_NET_ADMIN); res = setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); cap_restore(saved_caps); if (res == -1 && !logged) { logged = TRUE; /*LOG This message indicates that an error occurred while Zorp attempted to change the SO_MARK value of the specified fd. This message will appear only once and is probably caused by missing kernel support. Check your kernel whether it includes support for changing MARKs from userspace. */ z_log(NULL, CORE_ERROR, 3, "Error changing MARK; fd='%d', mark='%08x', error='%s'", fd, mark, g_strerror(errno)); } } #if ZORPLIB_ENABLE_TOS void z_fd_get_peer_tos(gint fd, guint8 *tos) { gint tmp; gchar buf[256]; gboolean tos_found = FALSE; socklen_t buflen, len; z_enter(); *tos = 0; tmp = 1; if (setsockopt(fd, SOL_IP, IP_RECVTOS, &tmp, sizeof(tmp)) < 0) { z_log(NULL, CORE_ERROR, 8, "Error in setsockopt(SOL_IP, IP_RECVTOS); fd='%d', error='%s'", fd, g_strerror(errno)); z_leave(); return; } buflen = sizeof(buf); if (getsockopt(fd, SOL_IP, IP_PKTOPTIONS, &buf, &buflen) >= 0) { struct msghdr msg; struct cmsghdr *cmsg; msg.msg_controllen = buflen; msg.msg_control = buf; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TOS) { *tos = *(guchar *) CMSG_DATA(cmsg); tos_found = TRUE; break; } } } if (!tos_found) { len = sizeof(*tos); if (getsockopt(fd, SOL_IP, IP_TOS, tos, &len) == -1) { z_log(NULL, CORE_ERROR, 2, "Error in getsockopt(SOL_IP, IP_PKTOPTIONS) || getsockopt(SOL_IP, IP_TOS); fd='%d', error='%s'", fd, g_strerror(errno)); *tos = 0; } } z_leave(); } void z_fd_set_our_tos(gint fd, guint8 tos) { socklen_t len; #if ZORPLIB_ENABLE_CAPS cap_t saved_caps; saved_caps = cap_save(); #endif len = sizeof(tos); cap_enable(CAP_NET_ADMIN); if (setsockopt(fd, SOL_IP, IP_TOS, &tos, len) < 0) { if (errno != ENOTSOCK && errno != EOPNOTSUPP) { z_log(NULL, CORE_ERROR, 3, "Error setting ToS value on socket; fd='%d', tos='%d', error='%s', errno='%d'", fd, tos, g_strerror(errno), errno); } } else { z_log(NULL, CORE_DEBUG, 6, "Setting socket ToS value; fd='%d', tos='%d'", fd, tos); } cap_restore(saved_caps); } void z_fd_get_our_tos(gint fd, guint8 *tos) { socklen_t len; *tos = 0; len = sizeof(*tos); if (getsockopt(fd, SOL_IP, IP_TOS, tos, &len) < 0) { z_log(NULL, CORE_ERROR, 2, "Error in getsockopt(SOL_IP, IP_TOS); fd='%d', error='%s'", fd, g_strerror(errno)); } } #endif libzorpll-3.9.4.1/src/libzorpll.def000066400000000000000000000073041224546767600172060ustar00rootroot00000000000000LIBRARY LIBZORPLL EXPORTS z_stream_write z_stream_read z_stream_set_callback z_stream_set_cond z_listener_start z_listener_start_in_context z_listener_suspend z_listener_resume z_listener_cancel z_listener_new z_stream_listener_new z_connector_start z_connector_start_block z_connector_start_in_context z_connector_cancel z_connector_set_timeout z_connector_new z_errno_is z_errno_get z_errno_set z_fd_set_nonblock z_fd_set_keepalive z_fd_set_oobinline z_close_syslog z_log z_fetch_stderr z_log_source_new z_log_session_id z_log_run z_log_init z_log_destroy z_logv z_llog z_mem_trace_init z_mem_trace_stats z_mem_trace_dump g_string_assign_len z_str_escape z_str_compress z_port_enabled z_poll_new z_poll_ref z_poll_unref z_poll_add_stream z_poll_remove_stream z_poll_iter_timeout z_poll_wakeup z_poll_is_running z_poll_quit z_poll_get_context z_random_sequence_get z_random_sequence_get_bounded z_registry_init z_registry_destroy z_registry_add z_registry_get_one z_registry_get z_registry_has_key z_registry_foreach z_inet_ntoa z_inet_aton z_sockaddr_format z_sockaddr_ref z_sockaddr_unref z_sockaddr_inet_free z_sockaddr_inet_new z_sockaddr_inet_new2 z_sockaddr_inet_check z_sockaddr_inet_range_new z_sockaddr_new z_bind z_accept z_connect z_disconnect z_listen z_getsockname z_getpeername z_getdestname z_do_ll_bind z_do_ll_accept z_do_ll_connect z_do_ll_listen z_do_ll_getsockname z_do_ll_getpeername z_socket_init z_socket_done z_socket_source_finalize z_socket_source_suspend z_socket_source_resume z_socket_source_new z_threshold_source_new z_threshold_source_set_threshold z_timeout_source_set_timeout z_timeout_source_new z_ssl_get_error_str z_ssl_init z_ssl_destroy z_ssl_verify_crl z_ssl_verify_callback z_ssl_crl_store_create z_ssl_set_trusted_ca_list z_ssl_session_new z_ssl_session_new_ssl z_ssl_session_ref z_ssl_session_unref z_stream_bio_write z_stream_bio_read z_stream_bio_puts z_stream_bio_ctrl z_stream_bio_create z_stream_bio_destroy z_ssl_bio_new z_stream_source_new z_stream_free_method z_stream_ctrl_method z_stream_new z_stream_search_stack z_stream_write_buf z_stream_buf_new z_stream_buf_space_avail z_stream_fd_write_pri_method z_stream_fd_new z_stream_line_get z_stream_line_get_copy z_stream_line_new z_stream_ssl_new z_thread_self z_thread_register_start_callback z_thread_register_stop_callback z_thread_new z_thread_init z_thread_destroy z_object_free_method z_object_is_subclass z_object_is_compatible z_object_is_instance z_object_new z_object_new_compatible z_crypt z_stream_gzip_new ZConnector__class ZStreamConnector__class ZStream__class ZStreamLine__class ZClass__class ZObject__class libzorpll-3.9.4.1/src/libzorpll.rc.in000066400000000000000000000021231224546767600174530ustar00rootroot00000000000000#include "winver.h" VS_VERSION_INFO VERSIONINFO FILEVERSION @ZORPLIBLL_WIN_VERSION@ PRODUCTVERSION @ZORPLIBLL_WIN_VERSION@ FILEFLAGSMASK 0x0L #ifdef DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "\0" VALUE "CompanyName", "BalaBit IT Ltd.\0" VALUE "FileDescription", "Low level library for Zorp\0" VALUE "FileVersion", "@ZORPLIBLL_VERSION@\0" VALUE "InternalName", "@PACKAGE@-@VERSION@\0" VALUE "LegalCopyright", "Copyright © 2000-2005 BalaBit IT Ltd.\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "libzorpll.dll\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "ZorpLib\0" VALUE "ProductVersion", "@ZORPLIBLL_VERSION@\0" VALUE "SpecialBuild", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END libzorpll-3.9.4.1/src/listen.c000066400000000000000000000263361224546767600161650ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: listen.c,v 1.41 2004/10/05 14:06:37 chaoron Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef G_OS_WIN32 # include # include #else # include # include #endif #define MAX_ACCEPTS_AT_A_TIME 50 /** * Private callback used as the callback of #ZSocketSource which * calls us when the listening socket becomes readable. * * @param[in] timed_out specifies whether the operation was timed out (unused) * @param[in] data user pointer pointing to self * * This function accepts the connection using z_accept() and calls the callback supplied * by our user. * * @todo FIXME: timed_out is unused. Why? * * @returns whether further callbacks should be delivered **/ static gboolean z_listener_accept(gboolean timed_out G_GNUC_UNUSED, gpointer data) { ZListener *self = (ZListener *) data; ZSockAddr *client, *dest; gboolean rc = TRUE; ZStream *newstream; gint accepts = 0; GIOStatus res; time_t start; z_enter(); /* NOTE: self->lock protects cancellation, _cancel grabs self->lock thus * we either execute first and accept all fds, or self->watch will be * NULL and we return */ g_static_rec_mutex_lock(&self->lock); if (!self->watch) { g_static_rec_mutex_unlock(&self->lock); z_return(TRUE); } z_listener_ref((ZListener *) self); start=time(NULL); while (!z_socket_source_is_suspended(self->watch) && rc && accepts < MAX_ACCEPTS_AT_A_TIME && start == time(NULL)) { res = Z_FUNCS(self, ZListener)->accept_connection(self, &newstream, &client, &dest); if (res == G_IO_STATUS_NORMAL) { #ifdef G_OS_WIN32 //FIXMEEEEEEEEEEEE // WSAEventSelect(newfd, 0, 0); #endif z_stream_set_nonblock(newstream, 0); } else if (res == G_IO_STATUS_AGAIN) { break; } else { newstream = NULL; client = NULL; } rc = self->callback(newstream, client, dest, self->user_data); accepts++; if (self->sock_flags & ZSF_ACCEPT_ONE) rc = FALSE; if (!self->watch) break; } z_listener_unref((ZListener *) self); g_static_rec_mutex_unlock(&self->lock); /*LOG This message reports the number of accepted connections in one poll cycle. If this value is continually high then it is likely that the computer can not handle the incoming connection rate. */ z_log(self->session_id, CORE_DEBUG, 7, "Accept count; accepts='%d'", accepts); z_return(rc); } /** * Open the listener through calling the open_listener virtual * function and store the file descriptor in the ZListener structure. * * @param[in] self ZListener instance * * @returns the new fd if successful, -1 if failed **/ gboolean z_listener_open(ZListener *self) { gint fd; gboolean res; z_enter(); g_assert(Z_FUNCS(self, ZListener)->open_listener != NULL); fd = Z_FUNCS(self, ZListener)->open_listener(self); if (fd == -1) res = FALSE; else { self->fd = fd; res = TRUE; } z_return(res); } /** * Start polling to the listening socket in the main context. * * @param[in] s ZListener instance * * @returns TRUE if successful, FALSE if it isn't open yet or the connection was started already. **/ gboolean z_listener_start(ZListener *s) { ZListener *self = (ZListener *) s; gchar buf[MAX_SOCKADDR_STRING]; z_enter(); if (self->watch) { /*LOG This message indicates that the connection was started twice and this second attempt is ignored. */ z_log(self->session_id, CORE_ERROR, 4, "Internal error z_listener_start called twice, ignoring;"); z_return(FALSE); } if (self->fd == -1) { /* the open callback has not been called yet, so we don't yet have an fd */ if (!z_listener_open(self)) z_return(FALSE); } /*LOG This message reports that listening on the given address is successfully started. */ z_log(self->session_id, CORE_DEBUG, 7, "Start to listen; fd='%d', address='%s'", self->fd, z_sockaddr_format(self->local, buf, sizeof(buf))); /* our callback might be called immediately, which in turn may free us, thus the incremented reference here. */ z_listener_ref(s); self->watch = z_socket_source_new(self->fd, Z_SOCKEVENT_ACCEPT, -1); g_source_set_callback(self->watch, (GSourceFunc) z_listener_accept, self, (GDestroyNotify) z_listener_unref); g_source_attach(self->watch, self->context); z_return(TRUE); } /** * Start listening to the socket in the specified context. * * @param[in] s ZListener instance * @param[in] context GMainContext to use for polling * * @returns TRUE on success **/ gboolean z_listener_start_in_context(ZListener *s, GMainContext *context) { gboolean res; ZListener *self = (ZListener *) s; z_enter(); g_main_context_ref(context); self->context = context; res = z_listener_start(s); z_return(res); } /** * Temporarily suspend listening on the socket. * * @param[in] s ZListener instance * * Further callbacks will not be delivered until z_listener_resume() is called. **/ void z_listener_suspend(ZListener *s) { ZListener *self = (ZListener *) s; z_enter(); if (self->watch) z_socket_source_suspend(self->watch); z_return(); } /** * Resume a suspended listener. * * @param[in] self ZListener instance **/ void z_listener_resume(ZListener *self) { z_enter(); if (self->watch) z_socket_source_resume(self->watch); z_return(); } /** * Cancel listening. * * @param[in] self ZListener instance * * No user callbacks will be called after returning from * z_listener_cancel(). **/ void z_listener_cancel(ZListener *self) { z_enter(); if (self->watch) { GSource *watch; /* NOTE: this locks out our accepted callback. We either accept all * pending fds, or we NULL out self->watch and our accepted callback * won't call any user callbacks. It is therefore guaranteed that no * user callbacks will be called after cancellation */ g_static_rec_mutex_lock(&self->lock); watch = self->watch; self->watch = NULL; g_static_rec_mutex_unlock(&self->lock); g_source_destroy(watch); g_source_unref(watch); } z_return(); } /** * This function creates a new ZListener instance. * * @param[in] class the class of the new object, must be compatible with #ZListener. * @param[in] session_id session id * @param[in] bind_addr address to bind to. * @param[in] sock_flags a combination of socket flags (ZSF_*) * @param[in] callback function to call, when an incoming connection is accepted. * @param[in] user_data opaque pointer passed to callback. * * Listening to the socket will not be started until z_listener_start() is called. * * @returns the new ZListener instance **/ ZListener * z_listener_new(ZClass *class, const gchar *session_id, ZSockAddr *bind_addr, guint32 sock_flags, ZAcceptFunc callback, gpointer user_data) { ZListener *self; z_enter(); self = Z_NEW_COMPAT(class, ZListener); self->session_id = session_id ? g_strdup(session_id) : NULL; self->callback = callback; self->user_data = user_data; self->sock_flags = sock_flags; self->bind_addr = z_sockaddr_ref(bind_addr); self->fd = -1; z_return(self); } /** * A private function called when the reference count of the ZListener * instance goes down to zero. * * @param[in] s ZListener instance * * It frees all instance variables and the structure itself. **/ static void z_listener_free(ZObject *s) { ZListener *self = Z_CAST(s, ZListener); z_enter(); self->callback = NULL; if (self->fd != -1) { #ifdef G_OS_WIN32 closesocket(self->fd); #else close(self->fd); #endif } if (self->context) g_main_context_unref(self->context); z_sockaddr_unref(self->bind_addr); z_sockaddr_unref(self->local); g_free(self->session_id); z_object_free_method(s); z_return(); } /** * ZListener virtual methods. **/ ZListenerFuncs z_listener_funcs = { { Z_FUNCS_COUNT(ZListener), z_listener_free, }, NULL, NULL }; /** * ZListener class descriptor. **/ Z_CLASS_DEF(ZListener, ZObject, z_listener_funcs); /** * Stream listener. **/ typedef struct _ZStreamListener { ZListener super; gint backlog; } ZStreamListener; ZClass ZStreamListener__class; /** * Create the listener socket. * * @param[in] s ZStreamListener instance * * @returns the new fd if successful, -1 if failed **/ static gint z_stream_listener_open_listener(ZListener *s) { ZStreamListener *self = Z_CAST(s, ZStreamListener); gint fd; z_enter(); fd = socket(z_map_pf(s->bind_addr->sa.sa_family), SOCK_STREAM, 0); if (fd == -1) { /*LOG This message indicate that the creation of a new socket failed for the given reason. It is likely that the system is running low on memory, or the system is running out of the available fds. */ z_log(s->session_id, CORE_ERROR, 2, "Cannot create socket; error='%s'", g_strerror(errno)); z_return(-1); } z_fd_set_nonblock(fd, 1); if ((s->bind_addr && z_bind(fd, s->bind_addr, s->sock_flags) != G_IO_STATUS_NORMAL) || (z_listen(fd, self->backlog, s->sock_flags) != G_IO_STATUS_NORMAL) || (z_getsockname(fd, &s->local, s->sock_flags) != G_IO_STATUS_NORMAL)) { close(fd); z_return(-1); } z_return(fd); } static GIOStatus z_stream_listener_accept_connection(ZListener *self, ZStream **fdstream, ZSockAddr **client, ZSockAddr **dest) { gint newfd; GIOStatus res; res = z_accept(self->fd, &newfd, client, self->sock_flags); if (res != G_IO_STATUS_NORMAL) { return res; } *fdstream = z_stream_fd_new(newfd, ""); *dest = NULL; z_getdestname(newfd, dest, self->sock_flags); return res; } ZListener * z_stream_listener_new(const gchar *session_id, ZSockAddr *local, guint32 sock_flags, gint backlog, ZAcceptFunc callback, gpointer user_data) { ZStreamListener *self; self = Z_CAST(z_listener_new(Z_CLASS(ZStreamListener), session_id, local, sock_flags, callback, user_data), ZStreamListener); if (self) { self->backlog = backlog; } return &self->super; } /** * ZListener virtual methods. **/ ZListenerFuncs z_stream_listener_funcs = { { Z_FUNCS_COUNT(ZListener), z_listener_free, }, z_stream_listener_open_listener, z_stream_listener_accept_connection }; /** * ZListener class descriptor. **/ Z_CLASS_DEF(ZStreamListener, ZListener, z_stream_listener_funcs); libzorpll-3.9.4.1/src/log.c000066400000000000000000001077751224546767600154570ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: log.c,v 1.76 2004/09/28 17:14:48 bazsi Exp $ * * Author : Bazsi * Auditor : kisza * Last audited version: 1.7 * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #ifdef G_OS_WIN32 # include # include # include # include # define close _close # define open _open #else # include # include # include #endif #ifdef G_OS_WIN32 //Windows exception handler needs this LONG WINAPI z_unhandled_exception_filter(PEXCEPTION_POINTERS); typedef LONG WINAPI z_unhandled_exception_filter_function(PEXCEPTION_POINTERS); z_unhandled_exception_filter_function *z_setup_unhandled_exception_filter = &z_unhandled_exception_filter; #endif #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "Zorp" /** * Extremal dummy value for booleans for detecting whether they are changed. * Rationale: FALSE is 0, TRUE is some unknown value, none of 255, 256, 65535, * 65536, (1L<<32)-1, (1L<<32) is divisible by 7, so this formula will yield * a value different from both 0 and TRUE, even considering a byte, word or * doubleword wrap-around :) **/ #define Z_EXTREMAL_BOOLEAN ((gboolean)(7*(int)TRUE + 1)) /** * Per-thread GHashTable based logtag cache. **/ typedef struct _ZLogTagCache { gboolean empty_hash; gboolean used; GHashTable *tag_hash; } ZLogTagCache; /** * Parsed item of a ZLogSpec, pattern and verbosity_level. **/ typedef struct _ZLogSpecItem { gchar *pattern; gint verbose_level; } ZLogSpecItem; /** * Complete logspec with a list of ZLogSpecItems. **/ typedef struct _ZLogSpec { GSList *items; gint verbose_level; } ZLogSpec; /** * Logging options. **/ typedef struct _ZLogOpts { gint verbose_level; /**< verbosity level */ gboolean use_syslog; /**< whether to use syslog */ gboolean log_tags; /**< whether to include message tag and verbosity level in log messages */ const gchar *log_spec; /**< logspec specification */ } ZLogOpts; ZLogOpts log_opts = {0, FALSE, FALSE, NULL}; ZLogOpts log_opts_cmdline = {-1, Z_EXTREMAL_BOOLEAN, Z_EXTREMAL_BOOLEAN, NULL}; /** Protects logtag_caches array when grabbing and releasing a thread specific log cache */ G_LOCK_DEFINE_STATIC(logtag_cache_lock); static GStaticPrivate current_logtag_cache = G_STATIC_PRIVATE_INIT; static GPtrArray *logtag_caches; /** Protects log_spec/log_spec_str */ G_LOCK_DEFINE_STATIC(log_spec_lock); static ZLogSpec log_spec; static gchar *log_spec_str; static gboolean log_escape_nonprintable_chars = FALSE; static ZLogMapTagFunc log_map_tag; static gint log_mapped_tags_count; static guchar *log_mapped_tags_verb; static gboolean stderr_syslog = FALSE; static gboolean log_tags = FALSE; gchar fake_session_id[256] = "nosession"; static GMainContext *log_context = NULL; #ifndef G_OS_WIN32 /* * This is a private reimplementation of syslog() as that one had a * mysterious bug in it and my bug reports were ignored. */ #if HAVE_BUGGY_SYSLOG_IN_LIBC #define SYSLOG_SOCKET "/dev/log" const gchar *syslog_tag = NULL; int syslog_fd = -1; /** * Analogous to openlog(), open the syslog() connection to local syslogd. * * @param[in] tag program name used in log messages * * @returns TRUE when the operation succeeds **/ gboolean z_open_syslog(const gchar *tag) { struct sockaddr_un s_un; syslog_tag = tag; syslog_fd = socket(PF_UNIX, SOCK_STREAM, 0); if (syslog_fd == -1) { return FALSE; } s_un.sun_family = AF_UNIX; g_strlcpy(s_un.sun_path, SYSLOG_SOCKET, sizeof(s_un.sun_path)); if (connect(syslog_fd, (struct sockaddr *) &s_un, sizeof(s_un)) == -1) { close(syslog_fd); syslog_fd = socket(PF_UNIX, SOCK_DGRAM, 0); if (connect(syslog_fd, (struct sockaddr *) &s_un, sizeof(s_un)) == -1) { close(syslog_fd); syslog_fd = -1; return FALSE; } } return TRUE; } /** * Close the connection to the local syslogd. * * @param[in] fd syslog connection to close * * The syslog connection is specified by the fd argument to avoid races when reopening * connections. * * @returns whether the operation was successful **/ gboolean z_close_syslog_internal(int fd) { if (fd != -1) { close(fd); return TRUE; } return FALSE; } /** * Close the connection to the global syslogd. * * @returns TRUE to indicate success. **/ gboolean z_close_syslog(void) { return z_close_syslog_internal(syslog_fd); } /** * Send the specified message to syslog. * * @param[in] pri syslog priority * @param[in] msg syslog message **/ gboolean z_send_syslog(gint pri, const gchar *msg) { /* * NOTE: We limit the log message size to 8192 now. Hope it will be enough. * IIRC syslog-ng can only handle 8k long messages. */ gchar buf[8192]; const guchar *p; gchar timestamp[32]; time_t now; struct tm t; guint len, attempt = 0; gint rc = 0; int sfd = syslog_fd; G_LOCK_DEFINE_STATIC(lock); now = time(NULL); localtime_r(&now, &t); strftime(timestamp, sizeof(timestamp), "%h %e %H:%M:%S", &t); g_snprintf(buf, sizeof(buf), "<%d>%s %s[%d]: ", pri, timestamp, syslog_tag, (int) getpid()); if (log_escape_nonprintable_chars) { len = strlen(buf); for (p = (guchar *) msg; *p && len < sizeof(buf) - 5; p++) { if (*p >= 0x20 && *p <= 0x7F) { buf[len++] = *p; } else { g_snprintf(&buf[len], 5, "<%02X>", (guchar) *p); len += 4; } } } else { g_strlcat(buf, msg, sizeof(buf) - 1); len = strlen(buf); } buf[len++] = '\n'; buf[len] = 0; do { attempt++; if (sfd != -1) rc = write(sfd, buf, len); if (sfd == -1 || (rc == -1 && errno != EINTR && errno != EAGAIN)) { G_LOCK(lock); if (sfd == syslog_fd) { z_open_syslog(syslog_tag); z_close_syslog_internal(sfd); } sfd = syslog_fd; G_UNLOCK(lock); } } while (rc == -1 && attempt <= 1); return TRUE; } #else /* use the syslog implementation in libc */ /** * Open a connection to the local system logging process. * * @param[in] tag program name to display in log messages * * This function uses the native syslog() implementation in libc to offer syslog functions. * * @returns always TRUE. **/ gboolean z_open_syslog(const gchar *tag) { openlog(tag, LOG_NDELAY | LOG_PID, 0); return TRUE; } /** * Close the connection to the local syslog process. * * @returns always TRUE. **/ gboolean z_close_syslog(void) { closelog(); return TRUE; } /** * Send a message to syslogd. It uses the syslog() function in libc. * * @param[in] pri priority of the message * @param[in] msg message itself * * @returns always TRUE. **/ gboolean z_send_syslog(gint pri, const gchar *msg) { syslog(pri, "%s", msg); return TRUE; } #endif #else int syslog_fd = -1; /** * Analogous to openlog(), open the syslog() connection to local syslogd. * * @param[in] tag program name used in log messages * * Windows implementation. * * @returns TRUE when the operation succeeds **/ gboolean z_open_syslog(const gchar *tag) { char fn[256]; g_strlcpy(fn, getenv("windir"), sizeof(fn)); g_strlcat(fn, "\\debug\\", sizeof(fn)); g_strlcat(fn, tag, sizeof(fn)); if((syslog_fd = open(fn, _O_APPEND | _O_RDWR | _O_CREAT, _S_IREAD | _S_IWRITE )) == -1) { close(syslog_fd); syslog_fd = -1; return FALSE; } return TRUE; } /** * Close the connection to the local syslog process. **/ gboolean z_close_syslog(void) { if (syslog_fd != -1) { close(syslog_fd); return TRUE; } return FALSE; } #endif /* logspec parsing and evaluation handling */ /** * Check when the pattern in a logspec matches the specified tag. * * @param[in] glob pattern to match tag against * @param[in] tag message tag **/ static gboolean z_log_spec_glob_match(const gchar *glob, const gchar *tag) { gchar *p1, *p2; gint len1, len2; p1 = strchr(glob, '.'); p2 = strchr(tag, '.'); while (p1 && p2) { len1 = p1 - glob; len2 = p2 - tag; if (((len1 != 1) || (memcmp(glob, "*", 1) != 0)) && ((len1 != len2) || memcmp(glob, tag, len1) != 0)) return FALSE; glob = p1 + 1; tag = p2 + 1; p1 = strchr(glob, '.'); p2 = strchr(tag, '.'); } if (p1) len1 = p1 - glob; else len1 = strlen(glob); if (p2) len2 = p2 - tag; else len2 = strlen(tag); if (((len1 != 1) || (memcmp(glob, "*", 1) != 0)) && ((len1 != len2) || memcmp(glob, tag, len1) != 0)) return FALSE; glob += len1; tag += len2; if (strlen(glob) > strlen(tag)) return FALSE; return TRUE; } /** * Evaluate the currently parsed logspec in self and return the verbosity level * associated with tag. * * @param[in] self ZLogSpec structure * @param[in] tag message to return verbosity for * * @returns the verbosity level associated with tag **/ static gint z_log_spec_eval(ZLogSpec *self, const gchar *tag) { GSList *l; ZLogSpecItem *lsi; l = self->items; while (l) { lsi = (ZLogSpecItem *) l->data; if (z_log_spec_glob_match(lsi->pattern, tag)) { return lsi->verbose_level; } l = g_slist_next(l); } return self->verbose_level; } /** * Free all resources associated with self. * * @param[in] self ZLogSpec instance * * Does not free self as it is assumed to be allocated statically. **/ static void z_log_spec_destroy(ZLogSpec *self) { GSList *l, *l_next; ZLogSpecItem *lsi; l = self->items; while (l) { l_next = g_slist_next(l); lsi = (ZLogSpecItem *) l->data; g_free(lsi->pattern); g_free(lsi); g_slist_free_1(l); l = l_next; } self->items = NULL; } /** * Parse a user-specified logspec into self. * * @param[in] self ZLogSpec instance * @param[in] logspec_str logspec specification * @param[in] default_verbosity global verbosity level * * @returns sdf **/ static gboolean z_log_spec_init(ZLogSpec *self, const gchar *logspec_str, gint default_verbosity) { ZLogSpecItem *item; gchar *tmp = g_strdup(logspec_str ? logspec_str : ""), *src; gint new_level; src = tmp; self->items = NULL; self->verbose_level = default_verbosity; while (*src) { const gchar *glob, *num; gchar *end; while (*src == ',' || *src == ' ') src++; glob = src; while (isalnum((guchar) (*src)) || *src == '.' || *src == '*') src++; if (*src != ':') { /* invalid log spec */ goto invalid_logspec; } *src = 0; src++; num = src; new_level = strtoul(num, &end, 10); item = g_new(ZLogSpecItem, 1); item->pattern = g_strdup(glob); item->verbose_level = new_level; self->items = g_slist_prepend(self->items, item); src = end; while (*src && *src != ',') src++; } self->items = g_slist_reverse(self->items); g_free(tmp); return TRUE; invalid_logspec: z_log_spec_destroy(self); g_free(tmp); return FALSE; } /* log tag cache * * Each thread has its own dedicated logtag cache to avoid locking. Caches are shared * which means that once a thread terminates it releases its cache which can be reused * by an independent thread. * */ /** * Clear all thread specific caches. It is called after changing the * verbosity level or the logspec. **/ void z_log_clear_caches(void) { guint i; G_LOCK(logtag_cache_lock); for (i = 0; i < logtag_caches->len; i++) { ZLogTagCache *lc = g_ptr_array_index(logtag_caches, i); lc->empty_hash = TRUE; } G_UNLOCK(logtag_cache_lock); if (log_mapped_tags_verb) { memset(log_mapped_tags_verb, 0, log_mapped_tags_count * sizeof(log_mapped_tags_verb[0])); } } /** * Grab a thread specific log-tag cache. **/ void z_log_grab_cache(void) { guint i; ZLogTagCache *lc = NULL; G_LOCK(logtag_cache_lock); for (i = 0; i < logtag_caches->len; i++) { lc = g_ptr_array_index(logtag_caches, i); if (!lc->used) break; else lc = NULL; } if (!lc) { lc = g_new0(ZLogTagCache, 1); lc->tag_hash = g_hash_table_new(g_str_hash, g_str_equal); g_ptr_array_add(logtag_caches, lc); } lc->used = 1; g_static_private_set(¤t_logtag_cache, lc, NULL); G_UNLOCK(logtag_cache_lock); } /** * Release a thread specific log-tag cache to make it usable by other threads. **/ void z_log_release_cache(void) { ZLogTagCache *lc; G_LOCK(logtag_cache_lock); lc = g_static_private_get(¤t_logtag_cache); if (lc) lc->used = 0; G_UNLOCK(logtag_cache_lock); } /** * Thread startup function called at thread startup time to allocate a logtag cache. * * @param thread (unused) * @param user_data (unused) **/ static void z_log_thread_started(ZThread *thread G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { z_log_grab_cache(); } /** * Thread startup function called at thread shutdown time to release the logtag cache. * * @param thread (unused) * @param user_data (unused) **/ static void z_log_thread_stopped(ZThread *thread G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { z_log_release_cache(); } /* global log state manipulation */ /** * This function changes the global verbosity level as specified by the * direction and value parameters. * * @param[in] direction specifies the change direction (-1 decrease, 0 set, 1 increase) * @param[in] value change with this value (or set to this value if direction == 0) * @param[out] new_value if not NULL, the resulting verbosity level is returned here * * @returns always TRUE. **/ gboolean z_log_change_verbose_level(gint direction, gint value, gint *new_value) { gint old_verbose_level = log_spec.verbose_level; G_LOCK(log_spec_lock); if (direction < 0) log_spec.verbose_level -= value; else if (direction == 0) log_spec.verbose_level = value; else log_spec.verbose_level += value; if (log_spec.verbose_level < 0) log_spec.verbose_level = 0; if (log_spec.verbose_level > 10) log_spec.verbose_level = 10; G_UNLOCK(log_spec_lock); if (old_verbose_level != log_spec.verbose_level) { z_log_clear_caches(); /*LOG This message reports that Zorp changed its verbosity level. */ z_log(NULL, CORE_INFO, 0, "Changing verbosity level; verbose_level='%d'", log_spec.verbose_level); } if (new_value) *new_value = log_spec.verbose_level; return TRUE; } /** * Change the logspec value and return the new setting. * * @param[in] new_log_spec_str change the logspec to this value, leave it unchanged if set to NULL * @param[out] new_value if not NULL, the new logspec will be returned here * * @return TRUE on success **/ gboolean z_log_change_logspec(const gchar *new_log_spec_str, const gchar **new_value) { if (new_log_spec_str) { ZLogSpec new_spec; if (z_log_spec_init(&new_spec, new_log_spec_str, log_spec.verbose_level)) { G_LOCK(log_spec_lock); z_log_spec_destroy(&log_spec); log_spec = new_spec; if (log_spec_str) g_free(log_spec_str); log_spec_str = g_strdup(new_log_spec_str); G_UNLOCK(log_spec_lock); z_log_clear_caches(); /*LOG This message reports that Zorp changed its logspec. */ z_log(NULL, CORE_INFO, 0, "Changing logspec; verbose_level='%d', logspec='%s'", log_spec.verbose_level, new_log_spec_str); } else { z_log(NULL, CORE_ERROR, 0, "Invalid logspec, reverting to old logspec; new_logspec='%s'", new_log_spec_str); return FALSE; } } if (new_value) *new_value = log_spec_str; return TRUE; } /** * This function enables the "tag_map cache" which makes tag caching very * efficient by using an array based lookup instead of GHashTable. * * @param[in] map_tags function to map message tags to IDs * @param[in] max_tag maximum ID value assigned to tags * * @note this function can only be called once, at startup time. **/ void z_log_enable_tag_map_cache(ZLogMapTagFunc map_tags, gint max_tag) { g_assert(!log_map_tag); log_map_tag = map_tags; log_mapped_tags_count = max_tag; log_mapped_tags_verb = g_new0(guchar, max_tag); } /** * Checks if a message with a given class/level combination would actually * be written to the log. * * @param[in] tag log message tag * @param[in] tag_len length of tag * @param[in] level log message level * * It can be used prior to constructing complex log * messages to decide whether the messages need to be constucted at all. * All results are cached, thus the second invocation will not parse the * log specifications again. * * @returns TRUE if the log would be written, FALSE otherwise **/ gboolean z_log_enabled_len(const gchar *tag, gsize tag_len, gint level) { return level <= z_log_get_tag_loglevel(tag ,tag_len); } gint z_log_get_tag_loglevel(const gchar *tag, gsize tag_len) { gint verbose; ZLogTagCache *lc; GHashTable *tag_hash; if (G_LIKELY(!log_spec.items)) { /* fastpath, no logspec, decision is simple */ return log_spec.verbose_level; } if (G_LIKELY(log_map_tag)) { /* somewhat less fast path, map_tag is defined, use it for caching */ gint tag_ndx = log_map_tag(tag, tag_len); if (G_LIKELY(tag_ndx != -1)) { /* known keyword, use id indexed array to lookup tag specific verbosity */ verbose = log_mapped_tags_verb[tag_ndx]; if (G_LIKELY(verbose)) verbose--; else { G_LOCK(log_spec_lock); verbose = z_log_spec_eval(&log_spec, tag); log_mapped_tags_verb[tag_ndx] = (guchar) (verbose & 0xFF) + 1; G_UNLOCK(log_spec_lock); } return verbose; } } /* check slow ghashtable based cache */ lc = ((ZLogTagCache *) g_static_private_get(¤t_logtag_cache)); if (!lc) { return log_spec.verbose_level; } if (lc->empty_hash) { g_hash_table_destroy(lc->tag_hash); lc->tag_hash = g_hash_table_new(g_str_hash, g_str_equal); lc->empty_hash = FALSE; } tag_hash = lc->tag_hash; verbose = GPOINTER_TO_INT(g_hash_table_lookup(tag_hash, (gconstpointer) tag)); if (!verbose) { /* slooooww path, evaluate logspec */ G_LOCK(log_spec_lock); verbose = z_log_spec_eval(&log_spec, tag); G_UNLOCK(log_spec_lock); g_hash_table_insert(tag_hash, (gchar *) tag, GUINT_TO_POINTER(verbose + 1)); } else verbose--; return verbose; } /* Main entry points for logging */ /** * Get the current session id. * * @param[in] session_id default session_id * * This helper function is used by the z_log() macro (or function, in * the case of Win32) to get the current session id. * * @returns If the argument is NULL, the session_id assigned to the * current thread, otherwise the value of the argument is returned. **/ const gchar * z_log_session_id(const gchar *session_id) { if (session_id == NULL || session_id[0] == 0) { ZThread *thread = z_thread_self(); if (thread == NULL) return fake_session_id; else return thread->name; } return session_id; } /** * This function sends a message formatted as printf format string and * arguments to the syslog. * * @param[in] class log message class * @param[in] level log message verbosity level * @param[in] format log message format specified in printf form * @param[in] ap format arguments va_list * * The associated class/level pair is checked * whether the message really needs to be written. **/ void z_logv(const gchar *class, int level, const gchar *format, va_list ap) { int saved_errno = errno; if (log_tags) { gchar *msgbuf; msgbuf = g_strdup_vprintf(format, ap); #if ZORPLIB_ENABLE_TRACE g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%p -> %s(%d): %s", g_thread_self(), class, level, msgbuf); #else g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s(%d): %s", class, level, msgbuf); #endif g_free(msgbuf); } else { g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format, ap); } errno = saved_errno; } /** * This message is the same as z_logv() but format string and arguments * are specified directly. * * @param[in] class log message class * @param[in] level log message verbosity level * @param[in] format log message format specified in printf form * * @see z_log() in log.h **/ void z_llog(const gchar *class, int level, const gchar *format, ...) { va_list l; va_start(l, format); z_logv(class, level, format, l); va_end(l); } #ifdef G_OS_WIN32 /** * Win32 implementation of z_log(). * * @param[in] session_id session id * @param[in] class log message class * @param[in] level log message verbosity level * @param[in] format log message format specified in printf form * * This function checks if the message would be logged; if so, sends * a message formatted as printf format string and * arguments (including session id) to the syslog. * * @see z_log() in log.h **/ void z_log(const gchar *session_id, const gchar *class, int level, const gchar *format, ...) { va_list l; gchar msgbuf[2048]; if (!z_log_enabled(class, level)) return; va_start(l, format); g_vsnprintf(msgbuf, sizeof(msgbuf), format, l); g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%p -> %s(%d): (%s): %s", g_thread_self(), class, level, z_log_session_id(session_id), msgbuf); va_end(l); } #endif /* G_OS_WIN32 */ /** * This function is registered as a GLib log handler and sends all GLIB * messages to stderr. * * @param log_domain not used * @param log_flags not used * @param[in] message message * @param user_data not used **/ static void z_log_func_nosyslog(const gchar *log_domain G_GNUC_UNUSED, GLogLevelFlags log_flags G_GNUC_UNUSED, const gchar *message, gpointer user_data G_GNUC_UNUSED) { gchar timestamp[32]; time_t now; struct tm tmnow; /* prepend timestamp */ time(&now); strftime(timestamp, sizeof(timestamp), "%b %d %H:%M:%S", localtime_r(&now, &tmnow)); fprintf(stderr, "%s %s\n", timestamp, message); } #ifndef G_OS_WIN32 /** * This function is registered as a GLib log handler and sends all GLIB * messages to messages to syslog. * * @param log_domain GLIB log domain (unused) * @param[in] log_flags GLIB log flags * @param[in] message message * @param user_data not used * * Zorp itself does not use GLIB logging, it calls z_log() directly. **/ static void z_log_func(const gchar *log_domain G_GNUC_UNUSED, GLogLevelFlags log_flags, const gchar *message, gpointer user_data G_GNUC_UNUSED) { int pri = LOG_INFO; if (log_flags & G_LOG_LEVEL_DEBUG) pri = LOG_DEBUG; else if (log_flags & G_LOG_LEVEL_WARNING) pri = LOG_WARNING; else if (log_flags & G_LOG_LEVEL_ERROR) pri = LOG_ERR; z_send_syslog(pri | ZORP_SYSLOG_FACILITY, message); } #else G_LOCK_DEFINE_STATIC(win32_log_handler_mutex); /** * Log handler function to send Win32 debug message. * * @param log_domain unused * @param log_flags unused * @param[in] message debug message to send * @param user_data unused **/ static void z_log_win32_debugmsg(const gchar *log_domain, GLogLevelFlags log_flags, const gchar *message, gpointer user_data) { G_LOCK(win32_log_handler_mutex); OutputDebugString(message); OutputDebugString("\n"); G_UNLOCK(win32_log_handler_mutex); } /** * Log handler function to send Win32 syslog message. * * @param log_domain unused * @param log_flags unused * @param[in] message syslog message to send * @param user_data unused **/ static void z_log_win32_syslogmsg(const gchar *log_domain, GLogLevelFlags log_flags, const gchar *message, gpointer user_data) { time_t now; struct tm *t; gchar tstamp[64]; gchar buf[2048]; int nchars; G_LOCK(win32_log_handler_mutex); now = time(NULL); t = localtime(&now); strftime(tstamp, sizeof(tstamp), "%Y %b %d %H:%M:%S", t); G_UNLOCK(win32_log_handler_mutex); nchars = g_snprintf(buf, sizeof(buf), "%s %s\n", tstamp, message); write(syslog_fd, buf, nchars); } #endif /** * Fetch messages line-by-line and send them to log via z_log(). * * @param[in] channel the read end of the STDERR pipe * @param condition the I/O condition triggering this callback (unused) * @param arg not used * * This function is registered as a read callback of the STDERR pipe to * fetch messages sent to stderr. It fetches messages line-by-line and * uses z_log() to send messages to log. * * @returns TRUE to indicate further reading is needed, FALSE otherwise **/ gboolean z_fetch_stderr(GIOChannel *channel, GIOCondition condition G_GNUC_UNUSED, gpointer arg G_GNUC_UNUSED) { gchar *line = NULL; GIOStatus status = G_IO_STATUS_NORMAL; GError *err = NULL; status = g_io_channel_read_line(channel, &line, NULL, NULL, &err); switch (status) { case G_IO_STATUS_NORMAL: /*NOLOG*/ z_log(NULL, CORE_STDERR, 3, "%s", line); break; case G_IO_STATUS_AGAIN: break; case G_IO_STATUS_EOF: /*LOG This message indicates that the program closed its stderr. No further message on the stderr will be logged. */ z_log(NULL, CORE_STDERR, 4, "The program closed its stderr. No further stderr logging is possible."); return FALSE; default: /*LOG This message indicates that an error occurred while reading from stderr. */ z_log(NULL, CORE_STDERR, 3, "Can not read from stderr; result='%s'", (err != NULL) ? ((err)->message) : ("Unknown error")); return FALSE; } g_free(line); return TRUE; } /** * Creates the source watching the stderr pipe. * * @param[in] fd read side of the stderr pipe **/ GSource * z_log_source_new(gint fd) { GIOChannel *channel; GSource *source; channel = g_io_channel_unix_new(fd); g_io_channel_set_encoding(channel, NULL, NULL); g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL); source = g_io_create_watch(channel, G_IO_IN); g_source_set_callback(source, (GSourceFunc) z_fetch_stderr, NULL, NULL); return source; } /** * STDERR reading thread function. * * @param[in] user_data thread data pointer, assumed to point to the stderr fd * * @returns always NULL. **/ void * z_log_run(gpointer user_data) { GMainContext *c, *old_context; gint *fd = (gint *)user_data; GSource *source; old_context = g_main_context_new(); g_main_context_ref(old_context); log_context = old_context; g_main_context_acquire(log_context); source = z_log_source_new(*fd); g_source_attach(source, log_context); g_source_unref(source); do { /* NOTE: although log_context might already be unrefed by the thread * running z_log_destroy() we still hold a reference through * old_context, therefore it is not a problem if we use a stale value * in log_context, at most we run another iteration */ c = log_context; if (c) g_main_context_iteration(c, TRUE); } while (c); g_main_context_release(old_context); g_main_context_unref(old_context); return NULL; } /** * This function can be called after z_log_init() to redirect internal * messages to syslog. * * @param[in] syslog_name syslog program name **/ void z_log_enable_syslog(const gchar *syslog_name) { z_open_syslog(syslog_name); #ifndef G_OS_WIN32 g_log_set_handler(G_LOG_DOMAIN, 0xff, z_log_func, NULL); #else g_log_set_handler(G_LOG_DOMAIN, 0xff, z_log_win32_syslogmsg, NULL); #endif } /** * This function can be called after z_log_init() to redirect stderr * messages messages to the system log. * * @param[in] threaded specifies whether to use a separate thread for stderr reading **/ void z_log_enable_stderr_redirect(gboolean threaded) { #ifndef G_OS_WIN32 static int grab[2]; if (pipe(grab) < 0) { /*LOG This message is indicates that pipe creation failed. It is likely that the system runs out of free fds. */ z_log(NULL, CORE_ERROR, 3, "Error creating stderr-syslog pipe;"); return; } stderr_syslog = TRUE; dup2(grab[1], 1); dup2(grab[1], 2); if (grab[1] != 2 && grab[1] != 1) close(grab[1]); if (threaded) { if (!z_thread_new("stderr", z_log_run, &grab[0])) threaded = FALSE; } if (!threaded) { log_context = g_main_context_default(); if (!g_main_context_acquire(log_context)) { log_context = g_main_context_new(); g_main_context_acquire(log_context); } g_main_context_ref(log_context); z_log_source_new(grab[0]); } #endif } /** * Initialize the logging subsystem according to the options * in specified in the flags parameter. * * @param[in] syslog_name the program name to appear in syslogs * @param[in] flags log flags (ZLF_* macros) * * @returns TRUE on success **/ gboolean z_log_init(const gchar *syslog_name, guint flags) { #ifndef G_OS_WIN32 struct sigaction sa; gint i; i = sigaction(SIGPIPE, NULL, &sa); if (i) { z_log(NULL, CORE_ERROR, 0, "Can't get SIGPIPE handler; error='%s'", strerror(errno)); } else if (sa.sa_handler == SIG_DFL) { sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL)) z_log(NULL, CORE_ERROR, 0, "Can't set SIGPIPE handler; error='%s'", strerror(errno)); } #endif if (!z_log_spec_init(&log_spec, z_log_get_log_spec(), z_log_get_verbose_level())) { z_log(NULL, CORE_ERROR, 0, "Invalid logspec; logspec='%s'", z_log_get_log_spec()); return FALSE; } log_spec_str = z_log_get_log_spec() ? g_strdup(z_log_get_log_spec()) : NULL; log_tags = z_log_get_log_tags(); logtag_caches = g_ptr_array_new(); z_log_grab_cache(); z_thread_register_start_callback((GFunc) z_log_thread_started, NULL); z_thread_register_stop_callback((GFunc) z_log_thread_stopped, NULL); if (z_log_get_use_syslog()) { z_log_enable_syslog(syslog_name); #ifndef G_OS_WIN32 if (flags & ZLF_STDERR) z_log_enable_stderr_redirect(flags & ZLF_THREAD); #endif } else { #ifdef G_OS_WIN32 if (flags & ZLF_WINDEBUG) { g_log_set_handler(G_LOG_DOMAIN, 0xff, z_log_win32_debugmsg, NULL); } else #endif { g_log_set_handler(G_LOG_DOMAIN, 0xff, z_log_func_nosyslog, NULL); } } if (flags & ZLF_ESCAPE) log_escape_nonprintable_chars = TRUE; return TRUE; } /** * Deinitialize the logging subsystem. **/ void z_log_destroy(void) { GMainContext *c; #ifndef G_OS_WIN32 if (stderr_syslog) { close(1); close(2); } #endif z_close_syslog(); /* NOTE: log_context is freed in the log thread */ c = log_context; log_context = NULL; if (c) { g_main_context_wakeup(c); g_main_context_unref(c); } } /** * Keep track of indentation level and return the appropriate number of spaces. * * @param[in] dir direction and amount to indent * * The indentation level has to be in [0, 128], changes beyond that won't be performed. * The indentation level is tracked separately per thread. * * @returns pointer to static array of a number of spaces equal to the indentation level **/ const gchar * z_log_trace_indent(gint dir) { static const gchar *spaces128 = " " " "; static GStaticPrivate current_indent_key = G_STATIC_PRIVATE_INIT; int *current_indent = g_static_private_get (¤t_indent_key); const gchar *res; if (!current_indent) { current_indent = g_new (int,1); *current_indent = 0; g_static_private_set (¤t_indent_key, current_indent, g_free); } if (dir > 0) { res = spaces128 + 128 - *current_indent; if (*current_indent < (128 - dir)) *current_indent += dir; } else { if (*current_indent >= -dir) *current_indent += dir; res = spaces128 + 128 - *current_indent; } return res; } /** * Command line options for logging. **/ static GOptionEntry z_log_option_entries[] = { { "verbose", 'v', 0, G_OPTION_ARG_INT, &log_opts_cmdline.verbose_level, "Set verbosity level", "" }, { "no-syslog", 'l', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &log_opts_cmdline.use_syslog, "Do not send messages to syslog", NULL }, { "log-spec", 's', 0, G_OPTION_ARG_STRING, &log_opts_cmdline.log_spec, "Set log specification", "" }, { "logspec", 's', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &log_opts_cmdline.log_spec, "Alias for log-spec", "" }, { "log-tags", 'T', 0, G_OPTION_ARG_NONE, &log_opts_cmdline.log_tags, "Enable logging of message tags", NULL }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; /** * Set default options in log_opts. * * @param[in] verbose_level verbosity level * @param[in] use_syslog whether to use syslog * @param[in] n_log_tags whether to include message tag and verbosity level in log messages * @param[in] n_log_spec logspec specification **/ void z_log_set_defaults(gint verbose_level, gboolean use_syslog, gboolean n_log_tags, const gchar *n_log_spec) { log_opts.verbose_level = verbose_level; log_opts.use_syslog = use_syslog; log_opts.log_tags = n_log_tags; log_opts.log_spec = n_log_spec; } /** * Add the logging-specific command line options to the option context. * * @param[in] ctx GOptionContext instance **/ void z_log_add_option_group(GOptionContext *ctx) { GOptionGroup *group; /* initialise commandline arg variables to extremal values to be able to detect * whether they are changed or not */ log_opts_cmdline.verbose_level = -1; log_opts_cmdline.use_syslog = Z_EXTREMAL_BOOLEAN; log_opts_cmdline.log_spec = NULL; log_opts_cmdline.log_tags = Z_EXTREMAL_BOOLEAN; group = g_option_group_new("log", "Log options", "Log options", NULL, NULL); g_option_group_add_entries(group, z_log_option_entries); g_option_context_add_group(ctx, group); } /** * Get verbose level setting in effect. * * @returns the setting from the command line option if one was given and the default otherwise. **/ gint z_log_get_verbose_level(void) { return (log_opts_cmdline.verbose_level == -1) ? log_opts.verbose_level : log_opts_cmdline.verbose_level; } /** * Get syslog setting in effect. * * @returns the setting from the command line option if one was given and the default otherwise. **/ gboolean z_log_get_use_syslog(void) { return (log_opts_cmdline.use_syslog == Z_EXTREMAL_BOOLEAN) ? log_opts.use_syslog : log_opts_cmdline.use_syslog; } /** * Get log tags setting in effect. * * @returns the setting from the command line option if one was given and the default otherwise. **/ const gchar * z_log_get_log_spec(void) { return (log_opts_cmdline.log_spec == NULL) ? log_opts.log_spec : log_opts_cmdline.log_spec; } /** * Get logspec string in effect. * * @returns the setting from the command line option if one was given and the default otherwise. **/ gboolean z_log_get_log_tags(void) { return (log_opts_cmdline.log_tags == Z_EXTREMAL_BOOLEAN) ? log_opts.log_tags : log_opts_cmdline.log_tags; } /** * Set the value of the use_syslog option. * * @param[in] use_syslog the new value **/ void z_log_set_use_syslog(gboolean use_syslog) { log_opts.use_syslog = use_syslog; } libzorpll-3.9.4.1/src/makefile.msc000066400000000000000000000047041224546767600167770ustar00rootroot00000000000000## Use: nmake -f makefile.msc !IFNDEF COMPILE_ENV COMPILE_ENV=c:\build !ENDIF !INCLUDE $(COMPILE_ENV)\dep\include\make.msc ROOT= $(COMPILE_ENV)\out ################################################################ INCLUDES = -FI$(TOP)\include\msvc_recommended_pragmas.h $(GLIB_CFLAGS) $(OPENSSL_CFLAGS) $(ZLIB_CFLAGS) -I . DEPCFLAGS = -Zm400 $(INTL_CFLAGS) $(LIBICONV_CFLAGS) $(DIRENT_CFLAGS) PDBFILE=$(COMPILE_ENV)\dep\debug\libzorpll-$(MAJORVERSION)s.pdb MAPFILE=$(COMPILE_ENV)\dep\debug\libzorpll-$(MAJORVERSION)s.map CFLAGS = $(CFLAGS) /D"COMPILING_LIBZORPLL" /Fd$(PDBFILE) /Z7 MAJORVERSION=3.3 all: install OUTPUTS = \ libzorpll-$(MAJORVERSION)s.lib OBJECTS = \ cap.obj \ connect.obj \ crypt.obj \ error.obj \ io.obj \ listen.obj \ log.obj \ memtrace.obj \ misc.obj \ packetbuf.obj \ poll.obj \ process.obj \ random.obj \ registry.obj \ sockaddr.obj \ socket.obj \ socketsource.obj \ source.obj \ ssl.obj \ stackdump.obj \ stream.obj \ streambuf.obj \ streamfd.obj \ streamgzip.obj \ streamline.obj \ streamssl.obj \ thread.obj \ win32_reg.obj \ zobject.obj DLLOBJECTS = libzorpll.res ################ zorp-lib #libzorpll.dll : zorplibconfig.h $(OBJECTS) $(DLLOBJECTS) # $(CC) $(CFLAGS) -LD -Fe$@ $(OBJECTS) $(DLLOBJECTS) $(GLIB_LIBS) $(OPENSSL_LIBS) $(LIBICONV_LIBS) $(INTL_LIBS) $(ZLIB_LIBS)\ # user32.lib advapi32.lib ws2_32.lib $(LDFLAGS) /out:libzorpll.dll /implib:libzorpll.lib /def:libzorpll.def /machine:I386 /MAP libzorpll-$(MAJORVERSION)s.lib: zorplibconfig.h $(OBJECTS) lib /out:libzorpll-$(MAJORVERSION)s.lib $(OBJECTS) zorplibconfig.h: #.\zorp\zorplibconfig.h.win32 @copy .\zorp\zorplibconfig.h-win32 .\zorp\zorplibconfig.h >NUL clean:: @del .\zorp\zorplibconfig.h install: zorplibconfig.h libzorpll-$(MAJORVERSION)s.lib @if not exist $(ROOT)\include\zorp mkdir $(ROOT)\include\zorp @copy /y .\zorp\*.h $(ROOT)\include\zorp >NUL @if not exist $(ROOT)\lib mkdir $(ROOT)\lib @if not exist $(ROOT)\lib\pkgconfig mkdir $(ROOT)\lib\pkgconfig @copy /y .\libzorpll-$(MAJORVERSION)s.lib $(ROOT)\lib >NUL @if not exist $(ROOT)\debug mkdir $(ROOT)\debug @rem ugly hack to add the pdb file to the package. @if exist $(PDBFILE) copy /y $(PDBFILE) $(ROOT)\debug >NUL @if exist $(MAPFILE) copy /y $(MAPFILE) $(ROOT)\debug >NUL @copy /y ..\zorplibll.pc $(ROOT)\lib\pkgconfig @copy /y ..\winbuild\libzorpll.la $(ROOT)\lib #@copy /y .\libzorpll.dll $(ROOT)\bin >NUL libzorpll-3.9.4.1/src/memtrace.c000066400000000000000000000547301224546767600164630ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: memtrace.c,v 1.38 2004/08/18 12:06:40 sasa Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #if ZORPLIB_ENABLE_MEM_TRACE #ifdef G_OS_WIN32 #include #endif #ifdef HAVE_DLFCN_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #if HAVE_BACKTRACE # include #else # define backtrace(a, b) {a[0]=NULL} #endif #define MEMTRACE_BACKTRACE_LEN 64 #define MEMTRACE_BACKTRACE_BUF_LEN (MEMTRACE_BACKTRACE_LEN * ((sizeof(gpointer) * 2) + 2 + 1) + 1) #define MEMTRACE_CANARY_SIZE 2 #define MEMTRACE_CANARY_FILL 0xcd #define MEMTRACE_CANARY_CHECK 0xcdcdcdcd #define MEMTRACE_CANARY_OVERHEAD sizeof(ZMemTraceCanary) * 2 /** * Trace the memory usage of the program using libzorpll * * @todo FIXME: May we use valgrind instead? **/ #define ZORP_ENV_MEMTRACE "ZORP_MEMTRACE" /** * Set some canaries before and after the allocated memory * and check it when a pointer deallocated. **/ #define ZORP_ENV_MEMTRACE_CANARIES "ZORP_MEMTRACE_CANARIES" /** * Don't deallocate pointers, just fill it with the canaries * It's useful when checking for heap corruption **/ #define ZORP_ENV_MEMTRACE_HARD "ZORP_MEMTRACE_HARD" /** * Log all allocation and deallocation events. **/ #define ZORP_ENV_MEMTRACE_FULL "ZORP_MEMTRACE_FULL" typedef struct _ZMemTraceCanary { gsize size; gsize neg_size; guint32 canary[MEMTRACE_CANARY_SIZE]; } ZMemTraceCanary; typedef struct _ZMemTraceEntry { guint32 next; gpointer ptr; gsize size; gpointer backtrace[MEMTRACE_BACKTRACE_LEN]; gboolean deleted; } ZMemTraceEntry; typedef struct _ZMemTraceHead { guint32 list; GStaticMutex lock; gulong size; } ZMemTraceHead; #define MEMTRACE_HASH_SIZE 32768 #define MEMTRACE_HASH_MASK (32767 << 3) #define MEMTRACE_HASH_SHIFT 3 /** * At most this amount of blocks can be allocated at the same time. * This preallocates MEMTRACE_HEAP_SIZE * sizeof(ZMemTraceEntry), * which is 268 bytes currently in i386. (17MB) **/ #define MEMTRACE_HEAP_SIZE 300000 #define MEMTRACE_TEMP_HEAP_SIZE 65536 /**< If not enough 131072 */ #define MEMTRACE_EOL ((guint32) -1) ZMemTraceHead mem_trace_hash[MEMTRACE_HASH_SIZE]; ZMemTraceEntry mem_trace_heap[MEMTRACE_HEAP_SIZE]; guint32 mem_trace_free_list = MEMTRACE_EOL; guint32 mem_block_count = 0, mem_allocated_size = 0, mem_alloc_count = 0; gboolean mem_trace_initialized = FALSE; static GStaticMutex mem_trace_lock = G_STATIC_MUTEX_INIT; gchar mem_trace_filename[1024] = ZORPLIB_TEMP_DIR "/zorp-memtrace.log"; gboolean mem_trace_canaries = FALSE; gboolean mem_trace_hard = FALSE; gboolean really_trace_malloc = FALSE; gboolean mem_trace = FALSE; gchar temp_heap[MEMTRACE_TEMP_HEAP_SIZE]; gint temp_brk = 0; gint mem_trace_recurse = 0; #define TMP_ALLOCATED(ptr) (((unsigned int )((char *) ptr - temp_heap)) < MEMTRACE_TEMP_HEAP_SIZE) void *(*old_malloc)(size_t size); void (*old_free)(void *ptr); void *(*old_realloc)(void *ptr, size_t size); void *(*old_calloc)(size_t nmemb, size_t size); static void z_mem_trace_printf(char *format, ...); /** * Save pointers to original free, realloc, calloc and malloc. **/ static void z_mem_trace_init_pointers(void) { dlerror(); old_free = dlsym(RTLD_NEXT, "free"); if (dlerror() != NULL) assert(0); old_realloc = dlsym(RTLD_NEXT, "realloc"); old_calloc = dlsym(RTLD_NEXT, "calloc"); old_malloc = dlsym(RTLD_NEXT, "malloc"); } /** * Internal function to initialize memtrace globals. * * Only the first call will have any effect (unless mem_trace_initialize * is somehow unset again). **/ static void z_mem_trace_init_internal(void) { int i; if (!mem_trace_initialized) { #if defined(__AMD64__) || defined(AMD64) || defined (__x86_64__) gpointer temp_buf[10]; #endif /* __amd64__ */ mem_trace_initialized = TRUE; #if defined(__AMD64__) || defined(AMD64) || defined (__x86_64__) backtrace(temp_buf, 5); #endif /* __amd64__ */ z_mem_trace_init_pointers(); if (getenv(ZORP_ENV_MEMTRACE)) { mem_trace = TRUE; if (getenv(ZORP_ENV_MEMTRACE_CANARIES)) mem_trace_canaries = TRUE; if (getenv(ZORP_ENV_MEMTRACE_HARD)) mem_trace_hard = TRUE; if (getenv(ZORP_ENV_MEMTRACE_FULL)) really_trace_malloc = TRUE; for (i = 0; i < MEMTRACE_HEAP_SIZE; i++) { mem_trace_heap[i].next = i + 1; } mem_trace_heap[MEMTRACE_HEAP_SIZE - 1].next = MEMTRACE_EOL; mem_trace_free_list = 0; for (i = 0; i < MEMTRACE_HASH_SIZE; i++) { mem_trace_hash[i].list = MEMTRACE_EOL; g_static_mutex_init(&mem_trace_hash[i].lock); } } } } /** * If the ZORP_ENV_MEMTRACE environment variable says memtrace is needed, * set mem_trace and set the trace file name with full path. * * @param[in] tracefile basename of the trace file. **/ void z_mem_trace_init(const gchar *tracefile_name) { z_mem_trace_init_internal(); if (tracefile_name && mem_trace) { g_snprintf(mem_trace_filename, sizeof(mem_trace_filename), ZORPLIB_TEMP_DIR "/%s", tracefile_name); z_mem_trace_printf("MemTrace initialized; memtrace='%s', canaries='%s', keep_deleted='%s', full_log='%s'\n", YES_NO_STR(mem_trace), YES_NO_STR(mem_trace_canaries), YES_NO_STR(mem_trace_hard), YES_NO_STR(really_trace_malloc)); } } static guint32 z_mem_trace_hash(gpointer ptr) { return (guint32)((gsize)ptr & MEMTRACE_HASH_MASK) >> MEMTRACE_HASH_SHIFT; } #if defined(__i386__) /** * Produce a backtrace from the stack into backtrace. * * @param[out] backtrace backtrace will be placed here. * * x86 version. **/ void z_mem_trace_bt(gpointer backt[]) { gpointer x; gpointer *ebp; gint i = 0; #if defined(__i386) __asm__("mov %%ebp, %0\n": "=r"(ebp)); #else #if defined(__AMD64__) || defined(AMD64) || defined(__x86_64__) __asm__("mov %%rbp, %0\n": "=r"(ebp)); #endif #endif while ((ebp > &x) && *ebp && *(ebp + 1) && i < MEMTRACE_BACKTRACE_LEN - 1) { gpointer value = *(ebp + 1); backt[i] = value; i++; ebp = *ebp; } backt[i] = NULL; } #else #if defined(__AMD64__) || defined(AMD64) || defined(__x86_64__) void z_mem_trace_bt(gpointer backt[]) { gpointer btrace[MEMTRACE_BACKTRACE_LEN + 1]; gint i = 0; gint length; length = backtrace(btrace, MEMTRACE_BACKTRACE_LEN); while (btrace[i] && i < length && i < MEMTRACE_BACKTRACE_LEN - 1) { backt[i] = btrace[i]; i++; } backt[i] = NULL; } #else #if defined(__sparc__) /** * Produce a backtrace from the stack into backtrace. * * @param[out] backt backtrace will be placed here. * * SPARC version. **/ void z_mem_trace_bt(gpointer backt[]) { gpointer x; gpointer *fp; gint i = 0; __asm__("mov %%fp, %0\n": "=r"(fp)); while ((fp > &x) && *fp && i < MEMTRACE_BACKTRACE_LEN - 1) { gpointer value = *(fp + 16); backt[i] = value; i++; fp = *(fp + 15); } backt[i] = NULL; } #else /* Stack is not known do dummy backtrace */ /** * Produce a backtrace from the stack into backt -- except stack is unknown so this is a dummy. * * @param[out] backt instead of backtrace, a single NULL will be placed here. * * Unknown architecture version. **/ void z_mem_trace_bt(gpointer backt[]) { backt[0] = NULL; } #endif /* __sparc__ */ #endif /* __x86_64__ */ #endif /* __i386__ */ /** * Format backtrace into a printable string format. * * @param[in] backt the backtrace * @param[out] buf buffer to receive the string * @param[in] buflen size of buffer * * @returns a pointer to the string (same as buf) **/ static char * z_mem_trace_format_bt(gpointer backt[], gchar *buf, guint buflen) { gchar *p = buf; gint i, len; p[0] = '\0'; for (i = 0; i < MEMTRACE_BACKTRACE_LEN && buflen >= (sizeof(gpointer) * 2) + 3 && backt[i]; i++) { len = g_snprintf(buf, buflen, "%p,", backt[i]); buf += len; buflen -= len; } return p; } /** * Write a line to the memtrace log if memtrace is enabled. * * @param[in] format printf-like format string * * The format string and the rest of the parameters are expected to be like those of *printf. **/ static void z_mem_trace_printf(char *format, ...) { gchar buf[1024]; gint len; va_list l; gint mem_trace_log_fd = -1; if (mem_trace) { va_start(l, format); len = vsnprintf(buf, sizeof(buf), format, l); va_end(l); mem_trace_log_fd = open(mem_trace_filename, O_CREAT | O_WRONLY | O_APPEND, 0600); if (mem_trace_log_fd != -1) { write(mem_trace_log_fd, buf, len); close(mem_trace_log_fd); } } } /** * Log statistics to the memtrace log. **/ void z_mem_trace_stats(void) { z_mem_trace_printf("time: %d, allocs: %ld, blocks: %ld, size: %ld\n", time(NULL), mem_alloc_count, mem_block_count, mem_allocated_size); } static gpointer z_mem_trace_check_canaries(gpointer ptr); void z_mem_trace_dump() { int i; if (mem_trace) { z_mem_trace_printf("memdump begins\n"); for (i = 0; i < MEMTRACE_HASH_SIZE; i++) { ZMemTraceHead *head = &mem_trace_hash[i]; ZMemTraceEntry *entry; guint32 cur; g_static_mutex_lock(&head->lock); cur = head->list; while (cur != MEMTRACE_EOL) { char backtrace_buf[MEMTRACE_BACKTRACE_BUF_LEN]; entry = &mem_trace_heap[cur]; z_mem_trace_printf("ptr=%p, size=%d, deleted=%s backtrace=%s\n", entry->ptr, entry->size, entry->deleted ? "TRUE" : "FALSE", z_mem_trace_format_bt(entry->backtrace, backtrace_buf, sizeof(backtrace_buf))); if (mem_trace_canaries) { z_mem_trace_check_canaries(entry->ptr); } if (mem_trace_hard && entry->deleted) { guint j; for (j = 0; j < entry->size; j++) { if (*((unsigned char *)(entry->ptr) + j) != MEMTRACE_CANARY_FILL) { z_mem_trace_printf("Using freed pointer; ptr=%p\n", entry->ptr); } } } cur = entry->next; } g_static_mutex_unlock(&head->lock); } } } /** * Fill areas before and after specified area with canary values. * * @param[in] ptr raw pointer * @param[in] size original size * * @returns the pointer to be returned **/ static gpointer z_mem_trace_fill_canaries(gpointer ptr, gint size) { if (!ptr) return ptr; if (mem_trace_canaries) { ZMemTraceCanary *p_before = (ZMemTraceCanary *) ptr; ZMemTraceCanary *p_after = (ZMemTraceCanary *)(((gchar *) ptr) + sizeof(ZMemTraceCanary) + size); memset(p_before->canary, MEMTRACE_CANARY_FILL, sizeof(p_before->canary)); memset(p_after->canary, MEMTRACE_CANARY_FILL, sizeof(p_after->canary)); p_before->size = p_after->size = size; p_before->neg_size = p_after->neg_size = -size; return (gpointer) (p_before + 1); } else return ptr; } /** * Aborts the process if the canaries are touched. * * @param[in] ptr user pointer * * @returns the pointer to be freed **/ static gpointer z_mem_trace_check_canaries(gpointer ptr) { if (!ptr) return ptr; if (mem_trace_canaries) { ZMemTraceCanary *p_before = ((ZMemTraceCanary *) ptr) - 1; ZMemTraceCanary *p_after; int i; if (p_before->size != -p_before->neg_size) { z_mem_trace_printf("Inconsistency in canaries; ptr=%p\n", ptr); abort(); } p_after = (ZMemTraceCanary *) (((gchar *) ptr) + p_before->size); if (p_after->size != p_before->size || p_after->neg_size != p_before->neg_size) { z_mem_trace_printf("Inconsistency in canaries; ptr=%p\n", ptr); abort(); } for (i = 0; i < MEMTRACE_CANARY_SIZE; i++) { if (p_before->canary[i] != p_after->canary[i] || p_before->canary[i] != MEMTRACE_CANARY_CHECK) { z_mem_trace_printf("Touched canary; ptr=%p\n", ptr); abort(); } } return (gpointer) p_before; } return ptr; } static gboolean z_mem_trace_add(gpointer ptr, gint size, gpointer backt[]) { guint32 hash, new_ndx; ZMemTraceEntry *new; ZMemTraceHead *head; static time_t prev_stats = 0, now; hash = z_mem_trace_hash(ptr); g_static_mutex_lock(&mem_trace_lock); if (mem_trace_free_list == MEMTRACE_EOL) { g_static_mutex_unlock(&mem_trace_lock); return FALSE; } mem_block_count++; mem_alloc_count++; now = time(NULL); if (now != prev_stats) { prev_stats = now; z_mem_trace_stats(); } mem_allocated_size += size; new_ndx = mem_trace_free_list; new = &mem_trace_heap[new_ndx]; mem_trace_free_list = mem_trace_heap[mem_trace_free_list].next; g_static_mutex_unlock(&mem_trace_lock); new->ptr = ptr; new->size = size; memmove(new->backtrace, backt, sizeof(new->backtrace)); head = &mem_trace_hash[hash]; g_static_mutex_lock(&head->lock); new->next = head->list; head->list = new_ndx; g_static_mutex_unlock(&head->lock); if (really_trace_malloc) { gchar buf[1024]; z_mem_trace_printf("memtrace addblock; ptr='%p', size='%d', bt='%s'\n", ptr, size, z_mem_trace_format_bt(backt, buf, sizeof(buf))); } return TRUE; } static gboolean z_mem_trace_del(gpointer ptr, gpointer bt[]) { guint32 hash, *prev, cur; ZMemTraceHead *head; ZMemTraceEntry *entry; hash = z_mem_trace_hash(ptr); head = &mem_trace_hash[hash]; g_static_mutex_lock(&head->lock); prev = &head->list; cur = head->list; while (cur != MEMTRACE_EOL && mem_trace_heap[cur].ptr != ptr) { prev = &mem_trace_heap[cur].next; cur = mem_trace_heap[cur].next; } if (cur == MEMTRACE_EOL) { g_static_mutex_unlock(&head->lock); return FALSE; } if (!mem_trace_hard) *prev = mem_trace_heap[cur].next; g_static_mutex_unlock(&head->lock); g_static_mutex_lock(&mem_trace_lock); entry = &mem_trace_heap[cur]; if (really_trace_malloc) { gchar buf[1024]; z_mem_trace_printf("memtrace delblock; ptr='%p', size='%d', bt='%s'\n", (void *) entry->ptr, entry->size, z_mem_trace_format_bt(bt, buf, sizeof(buf))); } if (!mem_trace_hard) { mem_trace_heap[cur].next = mem_trace_free_list; mem_trace_free_list = cur; mem_block_count--; mem_allocated_size -= mem_trace_heap[cur].size; } else { entry->deleted = TRUE; } g_static_mutex_unlock(&mem_trace_lock); return TRUE; } static inline guint32 z_mem_trace_lookup_chain(gpointer ptr, ZMemTraceHead *head) { guint32 cur = MEMTRACE_EOL; cur = head->list; while (cur != MEMTRACE_EOL && mem_trace_heap[cur].ptr != ptr) { cur = mem_trace_heap[cur].next; } return cur; } static int z_mem_trace_getsize(gpointer ptr) { guint32 hash, cur; int size; ZMemTraceHead *head; hash = z_mem_trace_hash(ptr); head = &mem_trace_hash[hash]; g_static_mutex_lock(&head->lock); cur = z_mem_trace_lookup_chain(ptr, head); if (cur != MEMTRACE_EOL) { size = mem_trace_heap[cur].size; g_static_mutex_unlock(&head->lock); return size; } g_static_mutex_unlock(&head->lock); return -1; } void * z_malloc(size_t size, gpointer backt[]) { gpointer raw_ptr, user_ptr; gchar buf[MEMTRACE_BACKTRACE_BUF_LEN]; guint backtrace_info = 0; z_mem_trace_init_internal(); if (old_malloc == NULL) { raw_ptr = &temp_heap[temp_brk]; temp_brk += size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD; if (temp_brk > MEMTRACE_TEMP_HEAP_SIZE) { backtrace_info = temp_brk; temp_brk = 0; assert(0); } } else raw_ptr = old_malloc(size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); if (mem_trace) { user_ptr = z_mem_trace_fill_canaries(raw_ptr, size); if (mem_trace_hard && z_mem_trace_getsize(user_ptr) != -1) { z_mem_trace_printf("Duplicate memory block; backtrace='%s'\n", z_mem_trace_format_bt(backt, buf, sizeof(buf))); abort(); } if (user_ptr && !z_mem_trace_add(user_ptr, size, backt)) { old_free(raw_ptr); z_mem_trace_printf("Out of free memory blocks; backtrace='%s'\n", z_mem_trace_format_bt(backt, buf, sizeof(buf))); z_mem_trace_stats(); z_mem_trace_dump(); return NULL; } } else user_ptr = raw_ptr; return user_ptr; } void z_free(void *user_ptr, gpointer backt[]) { gchar backtrace_buf[MEMTRACE_BACKTRACE_BUF_LEN]; gpointer raw_ptr; gint size; z_mem_trace_init_internal(); if (mem_trace) { size = z_mem_trace_getsize(user_ptr); if (user_ptr && !z_mem_trace_del(user_ptr, backt)) { z_mem_trace_printf("Trying to free a non-existing memory block; ptr=%p, backtrace='%s'\n", user_ptr, z_mem_trace_format_bt(backt, backtrace_buf, sizeof(backtrace_buf))); assert(0); } raw_ptr = z_mem_trace_check_canaries(user_ptr); if (size != -1) memset(user_ptr, MEMTRACE_CANARY_FILL, size); } else { raw_ptr = user_ptr; } if (!TMP_ALLOCATED(raw_ptr) && !mem_trace_hard) old_free(raw_ptr); } void * z_realloc(void *user_ptr, size_t size, gpointer backt[]) { void *new_ptr, *raw_ptr = NULL; size_t old_size = 0; gchar buf[MEMTRACE_BACKTRACE_BUF_LEN]; z_mem_trace_init_internal(); if (mem_trace) { if (user_ptr) { old_size = z_mem_trace_getsize(user_ptr); if (old_size == (size_t) -1 || !z_mem_trace_del(user_ptr, backt)) { z_mem_trace_printf("Trying to realloc a non-existing memory block; ptr=%p, size='%d', info='%s'", user_ptr, size, z_mem_trace_format_bt(backt, buf, sizeof(buf))); assert(0); } raw_ptr = z_mem_trace_check_canaries(user_ptr); } } else { raw_ptr = user_ptr; } if (old_realloc && old_malloc) { if (TMP_ALLOCATED(raw_ptr)) { /* this ptr was allocated on the temp heap, move it to real heap */ z_mem_trace_printf("reallocing space on the temp heap, moving..., ptr=%p, temp_heap=%p, diff=%d, old_size=%d\n", raw_ptr, temp_heap, (char *) raw_ptr-temp_heap, old_size); new_ptr = old_malloc(size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); if (new_ptr) { new_ptr = z_mem_trace_fill_canaries(new_ptr, size); /* copy user data */ memmove(new_ptr, user_ptr, old_size); } } else { if (!mem_trace_hard) { new_ptr = old_realloc(raw_ptr, size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); /* fill_canaries doesn't touch data, only fills the canary info */ new_ptr = z_mem_trace_fill_canaries(new_ptr, size); } else { new_ptr = old_malloc(size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); /* fill_canaries doesn't touch data, only fills the canary info */ new_ptr = z_mem_trace_fill_canaries(new_ptr, size); memmove(new_ptr, user_ptr, MIN(size, old_size)); if (old_size != (size_t) -1) memset(user_ptr, MEMTRACE_CANARY_FILL, old_size); } } } else { new_ptr = &temp_heap[temp_brk]; temp_brk += size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD; assert(temp_brk < MEMTRACE_TEMP_HEAP_SIZE); new_ptr = z_mem_trace_fill_canaries(new_ptr, size); /* copy user data */ memmove(new_ptr, user_ptr, old_size); } if (new_ptr) { z_mem_trace_add(new_ptr, size, backt); } return new_ptr; } void * z_calloc(size_t nmemb, size_t size, gpointer backt[]) { void *user_ptr, *raw_ptr; z_mem_trace_init_internal(); if (old_calloc == NULL) { raw_ptr = &temp_heap[temp_brk]; temp_brk += nmemb * size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD; assert(temp_brk < MEMTRACE_TEMP_HEAP_SIZE); } else raw_ptr = old_calloc(nmemb, size + mem_trace_canaries * MEMTRACE_CANARY_OVERHEAD); if (mem_trace) { user_ptr = z_mem_trace_fill_canaries(raw_ptr, nmemb * size); z_mem_trace_add(user_ptr, nmemb * size, backt); } else { user_ptr = raw_ptr; } return user_ptr; } #undef malloc #undef free #undef realloc #undef calloc /* look up return address */ void * malloc(size_t size) { gpointer backt[MEMTRACE_BACKTRACE_LEN]; if (mem_trace) z_mem_trace_bt(backt); else backt[0] = 0; return z_malloc(size, backt); } void free(void *ptr) { gpointer backt[MEMTRACE_BACKTRACE_LEN]; if (mem_trace) z_mem_trace_bt(backt); else backt[0] = 0; return z_free(ptr, backt); } void * realloc(void *ptr, size_t size) { gpointer backt[MEMTRACE_BACKTRACE_LEN]; if (mem_trace) z_mem_trace_bt(backt); else backt[0] = 0; return z_realloc(ptr, size, backt); } void * calloc(size_t nmemb, size_t size) { gpointer backt[MEMTRACE_BACKTRACE_LEN]; if (mem_trace) z_mem_trace_bt(backt); else backt[0] = 0; return z_calloc(nmemb, size, backt); } #else /** * Save pointers to original free, realloc, calloc and malloc -- dummy version for when memtrace is disabled. * * @param memtrace_file unused **/ void z_mem_trace_init(const gchar *memtrace_file G_GNUC_UNUSED) { } /** * Log statistics to the memtrace log -- dummy version for when memtrace is disabled. **/ void z_mem_trace_stats(void) { } void z_mem_trace_dump() { } #endif libzorpll-3.9.4.1/src/misc.c000066400000000000000000000340201224546767600156070ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: misc.c,v 1.43 2004/06/01 09:14:24 abi Exp $ * * Author : Bazsi, SaSa, Chaoron * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #define PARSE_STATE_START 0 #define PARSE_STATE_DASH 1 #define PARSE_STATE_END 2 #define PARSE_STATE_ESCAPE 3 /** * Initialize a ZCharSet by setting clearing the character set bitstring. * * @param[out] self ZCharSet instance to initialize **/ void z_charset_init(ZCharSet *self) { memset(self, 0, sizeof(*self)); } /** * This function parses an character set from its string representation. * * @param[in] self ZCharSet instance, previously initialized by z_charset_init * @param[in] interval_str string representation of the character set * * @returns true if interval_str parsed correctly (the parser didn't get into a * nonexistent state and the parser returned to its starting state at the end) **/ gboolean z_charset_parse(ZCharSet *self, gchar *interval_str) { guint i = 0; guchar j; guint state = PARSE_STATE_START; guint old_state = PARSE_STATE_START; guchar start_pos = 0; guchar end_pos = 0; z_enter(); while (interval_str[i]) { switch (state) { case PARSE_STATE_START: if (interval_str[i] == '\\' && old_state != PARSE_STATE_ESCAPE) { z_cp(); old_state = state; state = PARSE_STATE_ESCAPE; } else { z_cp(); start_pos = interval_str[i]; state = PARSE_STATE_DASH; old_state = PARSE_STATE_START; i++; } break; case PARSE_STATE_DASH: if (interval_str[i] == '\\' && old_state != PARSE_STATE_ESCAPE) { z_cp(); state = PARSE_STATE_END; i--; } else { z_cp(); state = PARSE_STATE_END; old_state = PARSE_STATE_DASH; if (interval_str[i] == '-') i++; else i--; } break; case PARSE_STATE_END: if (interval_str[i] == '\\' && old_state != PARSE_STATE_ESCAPE) { z_cp(); old_state = state; state = PARSE_STATE_ESCAPE; } else { z_cp(); end_pos = interval_str[i]; for (j = start_pos; j <= end_pos; j++) z_charset_enable(self, j); i++; state = PARSE_STATE_START; old_state = PARSE_STATE_END; } break; case PARSE_STATE_ESCAPE: z_cp(); i++; state = old_state; old_state = PARSE_STATE_ESCAPE; break; default: z_return(FALSE); } } if (state == PARSE_STATE_DASH) { z_cp(); z_charset_enable(self, start_pos); state = PARSE_STATE_START; } z_return(state == PARSE_STATE_START); } /** * This function checks whether the given string contains valid characters only. * * @param[in] self ZCharSet instance * @param[in] str string to check * @param[in] len string length * * @returns if the string contains valid characters only **/ gboolean z_charset_is_string_valid(ZCharSet *self, gchar *str, gint len) { gint i; if (len < 0) len = strlen(str); for (i = 0; i < len; i++) { if (!z_charset_is_enabled(self, str[i])) return FALSE; } return TRUE; } /** * This function assigns the given string/length value to the specified GString. * * @param[in] s GString instance * @param[in] val string pointer * @param[in] len length of string * * This function should be defined in GLib, however no such function exists. * * @returns the GString instance **/ GString * g_string_assign_len(GString *s, const gchar *val, gint len) { g_string_truncate(s, 0); if (val && len) g_string_append_len(s, val, len); return s; } /** * Compares t1 and t2 * * @param[in] t1 time value t1 * @param[in] t2 time value t2 * * @returns -1 if t1 is earlier than t2 * @returns 0 if t1 equals t2 * @returns 1 if t1 is later than t2 **/ gint g_time_val_compare(const GTimeVal *t1, const GTimeVal *t2) { g_assert(t1); g_assert(t2); if (t1->tv_sec < t2->tv_sec) return -1; else if (t1->tv_sec > t2->tv_sec) return 1; else if (t1->tv_usec < t2->tv_usec) return -1; else if (t1->tv_usec > t2->tv_usec) return 1; return 0; } /** * Calculates the time difference between t1 and t2 in microseconds. * * @param[in] t1 time value t1 * @param[in] t2 time value t2 * * The result is positive if t1 is later than t2. * * @returns Time difference in microseconds **/ glong g_time_val_diff(const GTimeVal *t1, const GTimeVal *t2) { g_assert(t1); g_assert(t2); return (t1->tv_sec - t2->tv_sec) * G_USEC_PER_SEC + (t1->tv_usec - t2->tv_usec); } /** * g_timeval_subtract: * @result: the value of x - y * @x: * @y: * * Subtract y from x. The value of x is always greater or equals to y. * The result is non-negative. * * It cannot be used to calculate a negative result. * */ void g_time_val_subtract(GTimeVal *result, const GTimeVal *x, const GTimeVal *y) { result->tv_usec = x->tv_usec; result->tv_sec = x->tv_sec; if (x->tv_usec < y->tv_usec) { result->tv_usec += 1000000; result->tv_sec -= 1; } result->tv_usec -= y->tv_usec; result->tv_sec -= y->tv_sec; } /** * Produces one line of hex dump of the specified part buf in line. * * @param[out] line where the result will appear * @param[in] linelen allocated length of line * @param[in] i index in buf to dump from * @param[in] buf raw binary data to dump * @param[in] len length of buf * * This function will hexdump up to 16 bytes of buf on one line. * This will be followed with a dump of the characters where * unprintable characters will be replaced with '.' * * @returns The number of characters that were actually dumped on this line **/ static guint z_hexdump(gchar *line, guint linelen, guint i, const char *buf, guint len) { guint j; char *end = line; for (j = 0; j < 16 && (i + j < len); j++) { g_snprintf(end, linelen - (end - line), "%02X ", (unsigned char) buf[i+j]); end += 3; } for (; j < 16; j++) { g_snprintf(end, linelen - (end - line), " "); end += 3; } g_snprintf(end, linelen - (end - line), " "); end++; for (j = 0; j < 16 && (i + j < len) && linelen > (guint)(end - line); j++) { *end = isprint(buf[i + j]) ? buf[i + j] : '.'; end++; } *end='\0'; return j; } /** * This function generates hexdumps of the specified buffer to the system * log using z_log(). * * @param[in] session_id session id to be used for the log messages * @param[in] class log message class * @param[in] level log message verbosity level * @param[in] buf buffer * @param[in] len buffer length * * Used internally by z_log_data_dump(). **/ void z_format_data_dump(const gchar *session_id, const char *class, gint level, const void *buf, guint len) { guint i, offs; gchar line[1024]; i = 0; while (i < len) { offs = i; i += z_hexdump(line, sizeof(line), i, buf, len); /*NOLOG*/ z_log((gchar *)session_id, class, level, "data line 0x%04x: %s", offs, line); } } /** * This function generates textual dumps of the specified buffer to the system * log using z_log(). * * @param[in] session_id session id to be used for the log messages * @param[in] class log message class * @param[in] level log message verbosity level * @param[in] buf buffer * @param[in] len buffer length * * Used internally by z_log_text_dump(). **/ void z_format_text_dump(const gchar *session_id, const char *class, gint level, const void *buf, guint len) { guint i, nl; gchar line[1024]; const gchar *bufc = buf; while (len > 0) { for (nl = 0; (nl < len) && bufc[nl] && (bufc[nl] != '\r') && (bufc[nl] != '\n'); nl++) ; i = (nl < len) ? nl : nl - 1; /* # of chars to dump */ if (i >= sizeof(line)) i = sizeof(line) - 1; memcpy(line, bufc, i); line[i] = '\0'; /*NOLOG*/ z_log((gchar *)session_id, class, level, "text line: %s", line); bufc += nl; len -= nl; if ((len > 0) && (bufc[0] == '\r')) { bufc++; len--; } if ((len > 0) && (bufc[0] == '\n')) { bufc++; len--; } } } /** * Escapes spaces to %_ and %-s to %% in s and returns the result. * * @param[in] s the string to escape characters in * @param[in] len length of s * * @returns the escaped string **/ gchar * z_str_escape(const gchar *s, gint len) { gchar *res; gint i = 0, j = 0;; z_enter(); if (len < 0) len = strlen(s) + 1; res = g_new0(gchar, len * 2); while (i < len && s[i] != '\0') { switch (s[i]) { case ' ': res[j++] = '%'; res[j++] = '_'; break; case '%': res[j++] = '%'; res[j++] = '%'; break; default: res[j++] = s[i]; } i++; } z_return(res); } /** * Undoes the escaping done by z_str_escape() on s and returns the result. * * @param[in] s the string to unescape characters in * @param[in] len length of s * * @returns the compressed string **/ gchar * z_str_compress(const gchar *s, gint len) { gchar *res; gint i = 0, j = 0;; z_enter(); if (len < 0) len = strlen(s) + 1; res = g_new0(gchar, len); while (i < len && s[i] != '\0') { if (s[i] == '%' && s[i+1] == '%') { i++; res[j++] = '%'; } else if (s[i] == '%' && s[i+1] == '_') { i++; res[j++] = ' '; } else { res[j++] = s[i]; } i++; } z_return(res); } /** * Parse port range and check if the port number is valid. * * @param[in] port_range port range specification * @param[in] port port number to check * * This function parses the given port_range and returns TRUE to indicate * whether the specified port number is valid. The port specification is in * the format: port1[-port2]([,port1[-port2]])* * * @returns TRUE when the port number is valid **/ gboolean z_port_enabled(gchar *port_range, guint port) { long int portl, porth; gchar *tmp; gchar *err; if (strlen(port_range) == 0 ) return FALSE; tmp = port_range; while (*tmp) { portl = strtol(tmp, &err, 10); tmp = err; if (*tmp == '-') { porth = strtol(tmp + 1, &err, 10); tmp = err; } else { porth = portl; } if (*tmp != 0 && *tmp != ',') return FALSE; if (*tmp) { tmp++; if (*tmp <= '0' && *tmp >= '9') return FALSE; } if ( portl <= (long int)port && (long int)port <= porth ) return TRUE; } return FALSE; } /** * GLib hashtable hash function for case insensitive hashtables. * * @param[in] key **/ guint z_casestr_hash(gconstpointer key) { const char *p = key; guint h = toupper(*p); if (h) for (p += 1; *p != '\0'; p++) h = (h << 5) - h + toupper(*p); return h; } /** * This function returns a static character string which includes version * information and compilation settings. This function is _NOT_ reentrant. * * @returns a static string of the version information to be displayed to * the user **/ const gchar * z_libzorpll_version_info(void) { static gchar buf[512]; g_snprintf(buf, sizeof(buf), "libzorpll %s\n" "Revision: %s\n" "Compile-Date: %s %s\n" "Trace: %s\n" "MemTrace: %s\n" "Caps: %s\n" "Debug: %s\n" "StackDump: %s\n", ZORPLIBLL_VERSION, ZORPLIBLL_REVISION, __DATE__, __TIME__, ON_OFF_STR(ZORPLIB_ENABLE_TRACE), ON_OFF_STR(ZORPLIB_ENABLE_MEM_TRACE), ON_OFF_STR(ZORPLIB_ENABLE_CAPS), ON_OFF_STR(ZORPLIB_ENABLE_DEBUG), ON_OFF_STR(ZORPLIB_ENABLE_STACKDUMP)); return buf; } /* NOTE: we deliberately do not define this function in a header file as we don't want these public */ void z_thread_add_option_group(GOptionContext *ctx); void z_process_add_option_group(GOptionContext *ctx); void z_log_add_option_group(GOptionContext *ctx); /** * This function put the library specific options to the program * option context. * * @param[in] ctx A #GoptionContext container for the options * @param[in] disable_groups Exclude these groups. **/ void z_libzorpll_add_option_groups(GOptionContext *ctx, guint disable_groups) { #ifndef G_OS_WIN32 /* we don't have process API on Windows */ if ((disable_groups & Z_OG_PROCESS) == 0) z_process_add_option_group(ctx); #endif if ((disable_groups & Z_OG_THREAD) == 0) z_thread_add_option_group(ctx); if ((disable_groups & Z_OG_LOG) == 0) z_log_add_option_group(ctx); } #ifndef HAVE_LOCALTIME_R /** * localtime_r replacement in case we don't have one. * * @param[in] timep time in seconds since epoch form to convert * @param[out] result tm struct to convert date/timestamp to * * localtime_r is implemented by locking and calling localtime. * * @returns a pointer to result **/ struct tm * localtime_r(const time_t *timep, struct tm *result) { static GStaticMutex mutex = G_STATIC_MUTEX_INIT; g_static_mutex_lock (&mutex); memcpy(result, localtime(timep), sizeof(struct tm)); g_static_mutex_unlock (&mutex); return result; } #endif libzorpll-3.9.4.1/src/packetbuf.c000066400000000000000000000475461224546767600166410ustar00rootroot00000000000000#include #include /** * Logs the contents of a buffer, prepended with a header if title is not NULL. * * @param[in] session_id parameter for z_log * @param[in] class parameter for z_log * @param[in] level parameter for z_log * @param[in] self this * @param[in] title optional title to prepend **/ void z_pktbuf_dump(const gchar *session_id, const gchar *class, int level, ZPktBuf *self, const gchar *title) { if (title) { z_log(session_id, class, level, "Packet buffer dump follows; title='%s', borrowed='%s', data='%p', " "allocated='%" G_GSIZE_FORMAT"', length='%" G_GSIZE_FORMAT "', " "pos='%" G_GSIZE_FORMAT "'", title, YES_NO_STR(self->flags & Z_PB_BORROWED), self->data, self->allocated, self->length, self->pos); } z_log_data_dump(session_id, class, level, (gchar *) self->data, self->length); } /** * Set the data/length fields of p to the specified data block by copying the * data to the internal buffer of ZPktBuf. * * @param[in] self 'this' * @param[in] data pointer to the data block * @param[in] length length of the data block * * @returns TRUE to be able to chain it. **/ gboolean z_pktbuf_copy(ZPktBuf *self, const void *data, gsize length) { z_pktbuf_resize(self, length); if (self->pos > length) self->pos = length; self->length = length; memcpy(self->data, data, length); return TRUE; } /** * Set the data/length fields of p to the specified data block without * copying and actually using data as a pointer. * * @param[in] self 'this' * @param[in] data pointer to the data block * @param[in] length length of the data block * @param[in] is_borrowed is data to be freed automatically or not * * If is_borrowed is set, then * it is assumed that data cannot be freed using g_free(). **/ void z_pktbuf_relocate(ZPktBuf *self, void *data, gsize length, gboolean is_borrowed) { if (self->data && !(self->flags & Z_PB_BORROWED)) g_free(self->data); if (self->pos > length) self->pos = length; self->data = data; self->length = self->allocated = length; if (is_borrowed) self->flags |= Z_PB_BORROWED; else self->flags &= ~Z_PB_BORROWED; } /** * Tries to ensure that at least size bytes is available in self. * * @param[in] self this * @param[in] size requested length in bytes * * @note This may fail if the buffer is initialised from an external * and not relocatable data. **/ void z_pktbuf_resize(ZPktBuf *self, gsize size) { if (size > self->allocated) { /* We don't have to realloc borrowed memory pointer. */ g_assert(!(self->flags & Z_PB_BORROWED)); self->data = g_realloc(self->data, size); self->allocated = size; } if (self->length > size) self->length = size; if (self->pos > size) self->pos = size; } /** * Tries to ensures that size bytes are available in self starting from the * current position. * * @param[in] self this * @param[in] size amount of bytes needed * * @todo FIXME: Why it's setting self->length? * * @returns TRUE on success **/ gboolean z_pktbuf_set_available(ZPktBuf *self, gsize size) { if (self->length >= self->pos + size) return TRUE; self->length = self->pos + size; z_pktbuf_resize(self, self->pos + size); return TRUE; } /** * Tries to append a byte array to self. * * @param[in] self this * @param[in] data buffer to append * @param[in] length length of data * * @returns TRUE **/ gboolean z_pktbuf_append(ZPktBuf *self, const void *data, gsize length) { z_pktbuf_resize(self, self->length + length); g_memmove(self->data + self->length, data, length); self->length += length; return TRUE; } /** * Tries to insert a byte array into self. * * @param[in] self this * @param[in] pos position to insert to * @param[in] data data to insert * @param[in] length length of data * * @returns TRUE on success **/ gboolean z_pktbuf_insert(ZPktBuf *self, gsize pos, const void *data, gsize length) { z_pktbuf_resize(self, self->length + length); g_memmove(self->data + pos + length, self->data + pos, self->length - pos); g_memmove(self->data + pos, data, length); self->length += length; return TRUE; } gboolean z_pktbuf_data_equal(ZPktBuf *lhs, ZPktBuf *rhs) { return lhs->length == rhs->length && !memcmp(lhs->data, rhs->data, rhs->length); } /** * Create a new ZPktBuf instance, set its length to 0 and its data ptr to NULL * * @returns ZPktBuf* pointer to the new instance **/ ZPktBuf * z_pktbuf_new(void) { ZPktBuf *self; z_enter(); self = g_new0(ZPktBuf, 1); z_refcount_set(&self->ref_cnt, 1); z_return(self); } /** * Create a new ZPktBuf instance pointing to a slice of another instance. * * @param[in] parent ZPktBuf instance to point to * @param[in] pos beginning of slice (offset from the beginning of parent->data) * @param[in] len length of slice * * @note The parent instance must hold a non-relocatable buffer, otherwise * it couldn't be guaranteed that a) the original instance won't get relocated * b) both ZPktBuf instances manipulate the same data. * * @note It turned out so that we must permit this - no way to * do it without hacking. * * @returns ZPktBuf* pointer to the new instance **/ ZPktBuf * z_pktbuf_part(ZPktBuf *parent, gsize pos, gsize len) { ZPktBuf *self = NULL; z_enter(); self = g_new0(ZPktBuf, 1); z_refcount_set(&self->ref_cnt, 1); self->data = parent->data + pos; self->allocated = self->length = MIN(len, parent->length - pos); self->flags = Z_PB_BORROWED; z_return(self); } /** * Split a ZPktBuf object into two at a specified position. * * @param[in] self ZPktBuf object to split. Will contain the first part of the buffer after the split * @param[in] at The position to split at * * @returns ZPktBuf* object with the second part of the buffer, starting with the character specified by the position */ ZPktBuf * z_pktbuf_split(ZPktBuf *self, gsize at) { ZPktBuf *ret; ret = z_pktbuf_new(); z_pktbuf_copy(ret, self->data+at, self->length-at); z_pktbuf_resize(self, at); return ret; } /** * Increment the reference counter for self. * * @param[in] self packet * * @returns Pointer to the instance **/ ZPktBuf * z_pktbuf_ref(ZPktBuf *self) { z_refcount_inc(&self->ref_cnt); return self; } /** * Decrements the reference counter for self and once it reaches 0, it * deallocates the buffer if present, then the instance itself. * * @param[in] self 'this' **/ void z_pktbuf_unref(ZPktBuf *self) { z_enter(); if (self && z_refcount_dec(&self->ref_cnt)) { if (self->data && !(self->flags & Z_PB_BORROWED)) g_free(self->data); g_free(self); } z_return(); } /** * Construct a new ZPktBuf and initialize it with the contents of a GString. * * @param[in] str GString instance containing the data to initialize the packet with. * **/ ZPktBuf * z_pktbuf_new_from_gstring(const GString * const str) { ZPktBuf *pkt = z_pktbuf_new(); z_pktbuf_put_u8s(pkt, str->len, (guint8 *) str->str); return pkt; } /** * Moves the current position in the buffer * * @param[in] self this * @param[in] whence seek type * @param[in] pos amount to seek * * @returns TRUE on success **/ gboolean z_pktbuf_seek(ZPktBuf *self, GSeekType whence, gssize pos) { switch (whence) { case G_SEEK_CUR: if ((self->pos + pos) > self->length || (((gssize)self->pos) + pos) < 0) return FALSE; self->pos += pos; break; case G_SEEK_SET: if (pos > (gssize)self->length || pos < 0) return FALSE; self->pos = pos; break; case G_SEEK_END: if ((pos > 0) || ((gssize)self->length < -pos)) return FALSE; self->pos = self->length + pos; break; } return TRUE; } /* * note on Doxygen comments: This is an ugly hack to avoid repetition, * but it's the best I could come up with. * * Brief descriptions appear twice because the brief description had * to be written explicitly, otherwise the entire text inserted by * @copydoc would be the "brief description". * * Perhaps this could be redone with DISTRIBUTE_GROUP_DOC. */ /** * Read an unsigned X-bit number from a ZPktBuf. * * @copydoc z_pktbuf_get_u16 **/ gboolean z_pktbuf_get_u8(ZPktBuf *self, guint8 *res) { if (z_pktbuf_available(self) < 1) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint8; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"'", self->length, self->pos); return FALSE; } if (res) res[0] = *(guint8*)(self->data + self->pos); self->pos++; return TRUE; } /** * Read an unsigned X-bit number from a ZPktBuf. * * @param[in] self this * @param[in] e endianness of the stored value (missing if X=8) * @param[out] res pointer to store the value to * * @note X is the number at the end of the function name. * * Reads an unsigned X-bit number from the current position of self and * stores it to res if it's not NULL, moving the current position pointer to * the next available position. * * @returns TRUE on success **/ gboolean z_pktbuf_get_u16(ZPktBuf *self, gint e, guint16 *res) { if (z_pktbuf_available(self) < 2) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint16; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"'", self->length, self->pos); return FALSE; } if (res) { if (e == G_HOST_ENDIAN) res[0] = *(guint16*)(self->data + self->pos); else res[0] = GUINT16_SWAP_LE_BE(*(guint16*)(self->data + self->pos)); } self->pos += 2; return TRUE; } /** * Read an unsigned X-bit number from a ZPktBuf. * * @copydoc z_pktbuf_get_u16 **/ gboolean z_pktbuf_get_u32(ZPktBuf *self, gint e, guint32 *res) { if (z_pktbuf_available(self) < 4) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint32; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"'", self->length, self->pos); return FALSE; } if (res) { if (e == G_HOST_ENDIAN) res[0] = *(guint32*)(self->data + self->pos); else res[0] = GUINT32_SWAP_LE_BE(*(guint32*)(self->data + self->pos)); } self->pos += 4; return TRUE; } /** * Read an unsigned X-bit number from a ZPktBuf. * * @copydoc z_pktbuf_get_u16 **/ gboolean z_pktbuf_get_u64(ZPktBuf *self, gint e, guint64 *res) { if (z_pktbuf_available(self) < 8) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint64; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"'", self->length, self->pos); return FALSE; } if (res) { if (e == G_HOST_ENDIAN) res[0] = *(guint64*)(self->data + self->pos); else res[0] = GUINT64_SWAP_LE_BE(*(guint64*)(self->data + self->pos)); } self->pos += 8; return TRUE; } /** * Write an unsigned X-bit number to a ZPktBuf. * * @copydoc z_pktbuf_put_u16 **/ gboolean z_pktbuf_put_u8(ZPktBuf *self, guint8 d) { z_pktbuf_set_available(self, 1); *(guint8*)(self->data + self->pos) = d; self->pos++; return TRUE; } /** * Write an unsigned X-bit number to a ZPktBuf. * * @param[in] self this * @param[in] e endianness to use for storing the value (missing if X=8) * @param[in] d value to store * * @note X is the number at the end of the function name. * * Writes an unsigned X-bit number to the current position of self, moving * the current position pointer to the next available position. * * @returns TRUE on success **/ gboolean z_pktbuf_put_u16(ZPktBuf *self, gint e, guint16 d) { z_pktbuf_set_available(self, 2); if (e == G_HOST_ENDIAN) *(guint16*)(self->data + self->pos) = d; else *(guint16*)(self->data + self->pos) = GUINT16_SWAP_LE_BE(d); self->pos += 2; return TRUE; } /** * Write an unsigned X-bit number to a ZPktBuf. * * @copydoc z_pktbuf_put_u16 **/ gboolean z_pktbuf_put_u32(ZPktBuf *self, gint e, guint32 d) { z_pktbuf_set_available(self, 4); if (e == G_HOST_ENDIAN) *(guint32*)(self->data + self->pos) = d; else *(guint32*)(self->data + self->pos) = GUINT32_SWAP_LE_BE(d); self->pos += 4; return TRUE; } /** * Write an unsigned X-bit number to a ZPktBuf. * * @copydoc z_pktbuf_put_u16 **/ gboolean z_pktbuf_put_u64(ZPktBuf *self, gint e, guint64 d) { z_pktbuf_set_available(self, 8); if (e == G_HOST_ENDIAN) *(guint64*)(self->data + self->pos) = d; else *(guint64*)(self->data + self->pos) = GUINT64_SWAP_LE_BE(d); self->pos += 8; return TRUE; } /** * Read an array of n unsigned X-bit numbers from a ZPktBuf. * * @copydoc z_pktbuf_get_u16s **/ gboolean z_pktbuf_get_u8s(ZPktBuf *self, gsize n, guint8 *res) { if (z_pktbuf_available(self) < n) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint8 array; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"', req_len='%" G_GSIZE_FORMAT"'", self->length, self->pos, n); return FALSE; } if (res) memcpy(res, self->data + self->pos, n); self->pos += n; return TRUE; } /** * Read an array of n unsigned X-bit numbers from a ZPktBuf. * * @param[in] self this * @param[in] e endianness of the stored value (missing if X=8) * @param[in] n number of values to read * @param[out] res pointer to store the value to * * @note X is the number at the end of the function name. * * Reads an array of n unsigned X-bit numbers from the current position of * self and stores them to res if it's not NULL, moving the current position * pointer to the next available position. * * @returns TRUE on success */ gboolean z_pktbuf_get_u16s(ZPktBuf *self, gint e, gsize n, guint16 *res) { guint i; n <<= 1; if (z_pktbuf_available(self) < n) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint16 array; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"', req_len='%" G_GSIZE_FORMAT"'", self->length, self->pos, n); return FALSE; } if (res) { if (e == G_HOST_ENDIAN) { memcpy(res, self->data + self->pos, n); } else { for (i = 0; i < n; i += 2) *(guint16*)((guint8*)res + i) = GUINT16_SWAP_LE_BE(*(guint16*)(self->data + self->pos + i)); } } self->pos += n; return TRUE; } /** * Read an array of n unsigned X-bit numbers from a ZPktBuf. * * @copydoc z_pktbuf_get_u16s **/ gboolean z_pktbuf_get_u32s(ZPktBuf *self, gint e, gsize n, guint32 *res) { guint i; n <<= 2; if (z_pktbuf_available(self) < n) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint32 array; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"', req_len='%" G_GSIZE_FORMAT"'", self->length, self->pos, n); return FALSE; } if (res) { if (e == G_HOST_ENDIAN) { memcpy(res, self->data + self->pos, n); } else { for (i = 0; i < n; i += 4) *(guint32*)((guint8*)res + i) = GUINT32_SWAP_LE_BE(*(guint32*)(self->data + self->pos + i)); } } self->pos += n; return TRUE; } /** * Read an array of n unsigned X-bit numbers from a ZPktBuf. * * @copydoc z_pktbuf_get_u16s **/ gboolean z_pktbuf_get_u64s(ZPktBuf *self, gint e, gsize n, guint64 *res) { guint i; n <<= 3; if (z_pktbuf_available(self) < n) { z_log(NULL, CORE_DEBUG, 7, "Error parsing uint64 array; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"', req_len='%" G_GSIZE_FORMAT"'", self->length, self->pos, n); return FALSE; } if (res) { if (e == G_HOST_ENDIAN) { memcpy(res, self->data + self->pos, n); } else { for (i = 0; i < n; i += 8) *(guint64*)((guint8*)res + i) = GUINT64_SWAP_LE_BE(*(guint64*)(self->data + self->pos + i)); } } self->pos += n; return TRUE; } /** * Write an array of n unsigned X-bit numbers into a ZPktBuf. * * @copydoc z_pktbuf_put_u16s **/ gboolean z_pktbuf_put_u8s(ZPktBuf *self, gsize n, const guint8 *res) { z_pktbuf_set_available(self, n); if (res) memcpy(self->data + self->pos, res, n); self->pos += n; return TRUE; } /** * Write an array of n unsigned X-bit numbers into a ZPktBuf. * * @param[in] self this * @param[in] e endianness to use for storing the values (missing if X=8) * @param[in] n number of values to write * @param[in] res array of values to write * * @note X is the number at the end of the function name. * * Writes an array of n unsigned X-bit numbers to the current position of * self, moving the current position pointer to the next available position. * * @returns TRUE on success */ gboolean z_pktbuf_put_u16s(ZPktBuf *self, gint e, gsize n, const guint16 *res) { guint i; n <<= 1; z_pktbuf_set_available(self, n); if (res) { if (e == G_HOST_ENDIAN) { memcpy(self->data + self->pos, res, n); } else { for (i = 0; i < n; i += 2) *(guint16*)(self->data + self->pos + i) = GUINT16_SWAP_LE_BE(*(guint16*)((guint8*)res + i)); } } self->pos += n; return TRUE; } /** * Write an array of n unsigned X-bit numbers into a ZPktBuf. * * @copydoc z_pktbuf_put_u16s **/ gboolean z_pktbuf_put_u32s(ZPktBuf *self, gint e, gsize n, const guint32 *res) { guint i; n <<= 2; z_pktbuf_set_available(self, n); if (res) { if (e == G_HOST_ENDIAN) { memcpy(self->data + self->pos, res, n); } else { for (i = 0; i < n; i += 4) *(guint32*)(self->data + self->pos + i) = GUINT32_SWAP_LE_BE(*(guint32*)((guint8*)res + i)); } } self->pos += n; return TRUE; } /** * Write an array of n unsigned X-bit numbers into a ZPktBuf. * * @copydoc z_pktbuf_put_u16s **/ gboolean z_pktbuf_put_u64s(ZPktBuf *self, gint e, gsize n, const guint64 *res) { guint i; n <<= 3; z_pktbuf_set_available(self, n); if (res) { if (e == G_HOST_ENDIAN) { memcpy(self->data + self->pos, res, n); } else { for (i = 0; i < n; i += 8) *(guint64*)(self->data + self->pos + i) = GUINT64_SWAP_LE_BE(*(guint64*)((guint8*)res + i)); } } self->pos += n; return TRUE; } /** * Read an 8-bit boolean value from a ZPktBuf. * * @param[in] self ZPktBuf instance * @param[out] res the value will be returned here * * @returns TRUE on success **/ gboolean z_pktbuf_get_boolean(ZPktBuf *self, gboolean *res) { if (z_pktbuf_available(self) < 1) { z_log(NULL, CORE_DEBUG, 7, "Error parsing boolean; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"'", self->length, self->pos); return FALSE; } if (res) res[0] = !!(*(guint8*)(self->data + self->pos)); self->pos++; return TRUE; } /** * Write an 8-bit boolean value to a ZPktBuf. * * @param[in] self ZPktBuf instance * @param[in] res value to write * * @returns TRUE on success **/ gboolean z_pktbuf_put_boolean(ZPktBuf *self, gboolean res) { if (!z_pktbuf_set_available(self, 1)) return FALSE; *(guint8*)(self->data + self->pos) = res ? 1 : 0; self->pos++; return TRUE; } /** * Read a 16-bit boolean value from a ZPktBuf. * * @param[in] self ZPktBuf instance * @param[out] res the value will be returned here * * @returns TRUE on success **/ gboolean z_pktbuf_get_boolean16(ZPktBuf *self, gboolean *res) { if (z_pktbuf_available(self) < 2) { z_log(NULL, CORE_DEBUG, 7, "Error parsing boolean16; length='%" G_GSIZE_FORMAT "', pos='%" G_GSIZE_FORMAT"'", self->length, self->pos); return FALSE; } if (res) res[0] = !!(*(guint16*)(self->data + self->pos)); self->pos += 2; return TRUE; } /** * @brief Append a string to the buffer, properly updating the position. * * @param[in] self ZPktBuf instance * @param[in] str the string to append * @return TRUE on success */ gboolean z_pktbuf_put_string(ZPktBuf *self, const gchar *str) { return z_pktbuf_put_u8s(self, strlen(str), (guint8 *) str); } /** * @brief Append a pktbuf while consuming it * @param[in] self ZPktBuf instance * @param[in] other ZPktBuf to append, will be consumed * @return self */ ZPktBuf * z_pktbuf_append_pktbuf(ZPktBuf *self, ZPktBuf *other) { z_pktbuf_append(self, other->data, other->length); z_pktbuf_unref(other); return self; } libzorpll-3.9.4.1/src/poll.c000066400000000000000000000217161224546767600156320ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: poll.c,v 1.46 2003/11/06 10:55:25 bazsi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #ifndef G_OS_WIN32 # include #endif #ifdef HAVE_UNISTD_H #include #endif #include /** * @file * * @todo FIXME: this module should be discarded and GMainContext should be used * directly instead. -- Bazsi, 2006.08.11. **/ /** * ZRealPoll is an implementation of the ZPoll interface defined in * poll.h. It's a callback based poll loop, which can be used by proxy * modules. It holds a collection of ZStream objects and calls their * callbacks when a requested I/O event occurs. ZPoll objects are * reference counted and are automatically freed when the number of * references to a single instance reaches zero. **/ typedef struct _ZRealPoll { guint ref_count; GMainContext *context; GPollFD *pollfd; guint pollfd_num; gboolean quit; GStaticMutex lock; GSource *wakeup; } ZRealPoll; /** * This class is a special source used to wake up a ZPoll loop from * different threads. **/ typedef struct _ZPollSource { GSource super; gboolean wakeup; } ZPollSource; /** * This is the prepare function of ZPollSource. * * @param[in] s ZPollSource instance * @param[out] timeout poll timeout * * This is the prepare function of ZPollSource, it basically checks whether * the loop was woken up by checking self->wakeup, and returns TRUE in that * case. * * @see GSourceFuncs documentation. * * @returns always -1 timeout value, e.g. infinite timeout **/ static gboolean z_poll_source_prepare(GSource *s, gint *timeout) { ZPollSource *self = (ZPollSource *)s; z_enter(); if (self->wakeup) z_return(TRUE); *timeout = -1; z_return(FALSE); } /** * This is the check function of ZPollSource. * * @param s ZPollSource instance (not used) * * As we poll nothing we always return FALSE. * * @see GSourceFuncs documentation. * * @returns FALSE * * @todo FIXME: I think this function should check the value of self->wakeup **/ static gboolean z_poll_source_check(GSource *s G_GNUC_UNUSED) { z_enter(); z_return(FALSE); } /** * This function simply sets self->wakeup to FALSE to allow the next poll loop * to run. * * @param[in] s ZPollSource instance * @param callback the callback for s (not used) * @param user_data the data to be passed to callback (not used) * * @see GSourceFuncs documentation. * * @returns TRUE **/ static gboolean z_poll_source_dispatch(GSource *s, GSourceFunc callback G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { ZPollSource *self = (ZPollSource *) s; z_enter(); self->wakeup = FALSE; z_return(TRUE); } /** * ZPollSource virtual methods. **/ GSourceFuncs z_poll_source_funcs = { z_poll_source_prepare, z_poll_source_check, z_poll_source_dispatch, NULL, NULL, NULL }; /** * This function creates a new ZPoll instance. * * @returns a pointer to the new instance **/ ZPoll * z_poll_new(void) { ZRealPoll *self = g_new0(ZRealPoll, 1); z_enter(); g_return_val_if_fail( self != NULL, NULL); self->ref_count = 1; self->quit = FALSE; self->pollfd_num = 4; self->pollfd = g_new(GPollFD, self->pollfd_num); self->context = g_main_context_default(); if (g_main_context_acquire(self->context)) { g_main_context_ref(self->context); } else { self->context = g_main_context_new(); assert(g_main_context_acquire(self->context)); } self->wakeup = g_source_new(&z_poll_source_funcs, sizeof(ZPollSource)); g_source_attach(self->wakeup, self->context); z_return((ZPoll *) self); } /** * Used internally to free up an instance when the reference count * reaches 0. * * @param[in] s ZPoll instance **/ static void z_poll_destroy(ZPoll *s) { ZRealPoll *self = (ZRealPoll *) s; z_enter(); if(self->wakeup) { g_source_destroy(self->wakeup); g_source_unref(self->wakeup); self->wakeup = NULL; } g_main_context_release(self->context); g_main_context_unref(self->context); g_free(self->pollfd); g_free(self); z_return(); } /** * Increment the reference count of the given ZPoll instance. * * @param[in] s ZPoll instance **/ void z_poll_ref(ZPoll *s) { ZRealPoll *self = (ZRealPoll *) s; z_enter(); self->ref_count++; z_return(); } /** * Decrement the reference count of the given ZPoll instance, and free it * using z_poll_destroy() if it reaches 0. * * @param[in] s ZPoll instance **/ void z_poll_unref(ZPoll *s) { ZRealPoll *self = (ZRealPoll *) s; z_enter(); if (self) { g_assert(self->ref_count > 0); self->ref_count--; if (self->ref_count == 0) z_poll_destroy(s); } z_return(); } /** * Register a ZStream to be monitored by a ZPoll instance. * * @param[in] s ZPoll instance * @param[in] stream stream instance **/ void z_poll_add_stream(ZPoll *s, ZStream *stream) { ZRealPoll *self = (ZRealPoll *) s; z_enter(); z_stream_attach_source(stream, self->context); z_return(); } /** * Remove a ZStream from a ZPoll instance. * * @param[in] s ZPoll instance * @param[in] stream stream to be removed **/ void z_poll_remove_stream(ZPoll *s G_GNUC_UNUSED, ZStream *stream) { z_enter(); z_stream_detach_source(stream); z_return(); } /** * Run an iteration of the poll loop. * * @param[in] s ZPoll instance * @param[in] timeout timeout value in milliseconds * * This function runs an iteration of the poll loop. Monitor filedescriptors of * registered Streams, and call appropriate callbacks. * * @returns TRUE if the iteration should be called again. **/ guint z_poll_iter_timeout(ZPoll *s, gint timeout) { ZRealPoll *self = (ZRealPoll *) s; gint max_priority = G_PRIORITY_LOW; gint polltimeout; gint fdnum = 0; GPollFunc pollfunc; gint rc; z_enter(); z_errno_set(0); if (self->quit) z_return(0); g_main_context_prepare (self->context, &max_priority); fdnum = g_main_context_query(self->context, max_priority, &polltimeout, self->pollfd, self->pollfd_num); while (fdnum > (gint)self->pollfd_num) { /*LOG This message reports that the polling fd structure is growing. */ z_log(NULL, CORE_DEBUG, 7, "Polling fd structure growing; old_num='%d'", self->pollfd_num); self->pollfd_num *= 2; self->pollfd = g_renew(GPollFD, self->pollfd, self->pollfd_num); fdnum = g_main_context_query(self->context, max_priority, &polltimeout, self->pollfd, self->pollfd_num); } if (polltimeout <= -1) polltimeout = timeout; else if (timeout > -1) polltimeout = MIN(polltimeout, timeout); pollfunc = g_main_context_get_poll_func(self->context); z_trace(NULL, "Entering poll;"); rc = pollfunc(self->pollfd, fdnum, polltimeout); z_trace(NULL, "Returning from poll;"); if (g_main_context_check(self->context, max_priority, self->pollfd, fdnum)) g_main_context_dispatch(self->context); if (rc == -1 && !z_errno_is(EINTR)) z_return(0); if (rc == 0 && polltimeout == timeout) { z_errno_set(ETIMEDOUT); z_return(0); } z_return(1); } /** * Wake up a running poll loop using its wakeup pipe. * * @param[in] s ZPoll instance **/ void z_poll_wakeup(ZPoll *s) { ZRealPoll *self = (ZRealPoll *) s; ZPollSource *src; z_enter(); src = (ZPollSource *)self->wakeup; src->wakeup = TRUE; g_main_context_wakeup(self->context); z_return(); } /** * Checks whether z_poll_quit was called earlier on this ZPoll object. * * @param[in] s ZPoll instance * * @returns TRUE if the poll is still running **/ gboolean z_poll_is_running(ZPoll *s) { ZRealPoll *self = (ZRealPoll *) s; z_enter(); z_return(!self->quit); } /** * Indicate that this poll loop is to be ended. * * @param[in] s ZPoll instance * * Can be called from thread different from the one running poll. **/ void z_poll_quit(ZPoll *s) { ZRealPoll *self = (ZRealPoll *) s; z_enter(); self->quit = TRUE; z_poll_wakeup(s); z_return(); } /** * Return the underlying GMainContext. * * @param[in] s ZPoll instance **/ GMainContext * z_poll_get_context(ZPoll *s) { ZRealPoll *self = (ZRealPoll *) s; z_enter(); z_return(self->context); } libzorpll-3.9.4.1/src/process.c000066400000000000000000001241511224546767600163370ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: process.c,v 1.7 2004/01/09 10:44:31 sasa Exp $ * * Author : Bazsi, SaSa, Chaoron * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #ifndef G_OS_WIN32 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_PRCTL_H # include #endif /** * @file * * @note * * - pidfile is created and removed by the daemon (e.g. the child) itself, * the parent does not touch that * * - we communicate with the user using stderr (using fprintf) as long as it * is available and using syslog() afterwards * * - there are 3 processes involved in safe_background mode (e.g. auto-restart) * - startup process which was started by the user (zorpctl) * - supervisor process which automatically restarts the daemon when it exits abnormally * - daemon processes which perform the actual task at hand * * The startup process delivers the result of the first startup to its * caller, if we can deliver a failure in this case then restarts will not * be performed (e.g. if the first startup fails, the daemon will not be * restarted even if auto-restart was enabled). After the first successful * start, the startup process exits (delivering that startup was * successful) and the supervisor process wait()s for the daemon processes * to exit. If they exit prematurely (e.g. they crash) they will be * restarted, if the startup is not successful in this case the restart * will be attempted again just as if they crashed. * * The processes communicate with two pairs of pipes, startup_result_pipe * is used to indicate success/failure to the startup process, * init_result_pipe (as in "initialization") is used to deliver success * reports from the daemon to the supervisor. **/ typedef enum { Z_PK_STARTUP, Z_PK_SUPERVISOR, Z_PK_DAEMON, } ZProcessKind; #define Z_PROCESS_FD_LIMIT_RESERVE 64 #define Z_PROCESS_FAILURE_NOTIFICATION ZORPLIB_LIBEXECDIR "/failure_notify" ZORPLIB_COMPAT_BRANCH /** pipe used to deliver the initialization result to the calling process */ static gint startup_result_pipe[2] = { -1, -1 }; /** pipe used to deliver initialization result to the supervisor */ static gint init_result_pipe[2] = { -1, -1 }; static ZProcessKind process_kind = Z_PK_STARTUP; static gboolean stderr_present = TRUE; extern gint max_threads; /** * Resolve a UNIX user name and store the associated uid in uid. * * @param[in] user username or numeric uid if there's no such username * @param[out] uid the uid of user * * @returns TRUE to indicate success **/ gboolean z_resolve_user(const gchar *user, uid_t *uid) { struct passwd pw; struct passwd *pw_p; gchar buf[1024]; *uid = 0; if (getpwnam_r(user, &pw, buf, sizeof(buf), &pw_p) == 0 && pw_p) { *uid = pw.pw_uid; } else { gchar *err; gulong tmp_uid; tmp_uid = strtol(user, &err, 0); if (*err != '\0') return FALSE; *uid = (uid_t)tmp_uid; } return TRUE; } /** * Resolve a UNIX group and store the associated gid in gid. * * @param[in] group groupname or numeric gid if there's no such groupname * @param[out] gid gid of group * * @returns TRUE to indicate success **/ gboolean z_resolve_group(const gchar *group, gid_t *gid) { struct group gr; struct group *gr_p; gchar buf[1024]; *gid = 0; if (getgrnam_r(group, &gr, buf, sizeof(buf), &gr_p) == 0 && gr_p) { *gid = gr.gr_gid; } else { gchar *err; gulong tmp_gid; tmp_gid = strtol(group, &err, 0); if (*err != '\0') return FALSE; *gid = (gid_t)tmp_gid; } return TRUE; } /** global variables */ static struct { ZProcessMode mode; const gchar *name; const gchar *user; const gchar *group; const gchar *chroot_dir; const gchar *pidfile; const gchar *pidfile_dir; const gchar *cwd; const gchar *caps; gint argc; gchar **argv; gchar *argv_start; size_t argv_env_len; gchar *argv_orig; gboolean core, use_fdlimit_settings; gint fd_limit_threshold; gint fd_limit_min; gint check_period; gboolean (*check_fn)(void); gint restart_max; gint restart_interval; gint notify_interval; gboolean pid_removed; } process_opts = { .mode = Z_PM_SAFE_BACKGROUND, .argc = 0, .argv = NULL, .argv_start = NULL, .argv_env_len = 0, .use_fdlimit_settings = FALSE, .fd_limit_threshold = -1, .fd_limit_min = 256000, .check_period = -1, .check_fn = NULL, .restart_max = 5, .restart_interval = 60, .notify_interval = 600, .pid_removed = FALSE, }; /** * This function should be called by the daemon to set the processing mode * as specified by mode. * * @param[in] mode an element from ZProcessMode **/ void z_process_set_mode(ZProcessMode mode) { process_opts.mode = mode; } /** * Called by the daemon to set the program name. * * @param[in] name the name of the process to be reported as program name * * This function should be called by the daemon to set the program name * which is present in various error message and might influence the PID * file if not overridden by z_process_set_pidfile(). **/ void z_process_set_name(const gchar *name) { process_opts.name = name; } /** * This function should be called by the daemon to set the user name. * * @param[in] user the name of the user the process should switch to during startup **/ void z_process_set_user(const gchar *user) { if (!process_opts.user) process_opts.user = user; } /** * This function should be called by the daemon to set the group name. * * @param[in] group the name of the group the process should switch to during startup **/ void z_process_set_group(const gchar *group) { if (!process_opts.group) process_opts.group = group; } /** * This function should be called by the daemon to set the chroot directory * * @param[in] chroot_dir the name of the chroot directory the process should switch to during startup **/ void z_process_set_chroot(const gchar *chroot_dir) { if (!process_opts.chroot_dir) process_opts.chroot_dir = chroot_dir; } /** * Called by the daemon to set the PID file name and store the PID. * * @param[in] pidfile the name of the complete pid file with full path * * This function should be called by the daemon to set the PID file name to * store the pid of the process. This value will be used as the pidfile * directly, neither name nor pidfile_dir influences the pidfile location if * this is set. **/ void z_process_set_pidfile(const gchar *pidfile) { if (!process_opts.pidfile) process_opts.pidfile = pidfile; } /** * This function should be called by the daemon to set the PID file * directory. * * @param[in] pidfile_dir name of the pidfile directory * * This value is not used if set_pidfile() was called. **/ void z_process_set_pidfile_dir(const gchar *pidfile_dir) { if (!process_opts.pidfile_dir) process_opts.pidfile_dir = pidfile_dir; } /** * This function should be called by the daemon to set the working * directory. * * @param[in] cwd name of the working directory * * The process will change its current directory to this value or * to pidfile_dir if it is unset. **/ void z_process_set_working_dir(const gchar *cwd) { if (!process_opts.cwd) process_opts.cwd = cwd; } /** * This function should be called by the daemon to set the initial * capability set. * * @param[in] caps capability specification in text form * * The process will change its capabilities to this value * during startup, provided it has enough permissions to do so. **/ void z_process_set_caps(const gchar *caps) { if (!process_opts.caps) process_opts.caps = caps; } /** * This function should be called by the daemon if it wants to enable * process title manipulation in the supervisor process. * * @param[in] argc Original argc, as received by the main function in its first parameter * @param[in] argv Original argv, as received by the main function in its second parameter **/ void z_process_set_argv_space(gint argc, gchar **argv) { extern char **environ; gchar *lastargv = NULL; gchar **envp = environ; gint i; if (process_opts.argv) return; process_opts.argv = argv; process_opts.argc = argc; for (i = 0; envp[i] != NULL; i++) ; environ = g_new(char *, i + 1); /* * Find the last argv string or environment variable within * our process memory area. */ for (i = 0; i < process_opts.argc; i++) { if (lastargv == NULL || lastargv + 1 == process_opts.argv[i]) lastargv = process_opts.argv[i] + strlen(process_opts.argv[i]); } for (i = 0; envp[i] != NULL; i++) { if (lastargv + 1 == envp[i]) lastargv = envp[i] + strlen(envp[i]); } process_opts.argv_start = process_opts.argv[0]; process_opts.argv_env_len = lastargv - process_opts.argv[0] - 1; process_opts.argv_orig = malloc(sizeof(gchar) * process_opts.argv_env_len); memcpy(process_opts.argv_orig, process_opts.argv_start, process_opts.argv_env_len); /* * Copy environment * XXX - will truncate env on strdup fail */ for (i = 0; envp[i] != NULL; i++) environ[i] = g_strdup(envp[i]); environ[i] = NULL; } /** * Enable (true) or disable (false) the usage of the fdlimit settings. * * @param[in] use value * * By default it's disabled. **/ void z_process_set_use_fdlimit(gboolean use) { process_opts.use_fdlimit_settings = use; } /** * Installs a checker function that is called at the specified rate. * * @param[in] check_period check period in seconds * @param[in] check_fn checker function * * The checked process is allowed to run as long as this function * returns TRUE. **/ void z_process_set_check(gint check_period, gboolean (*check_fn)(void)) { process_opts.check_period = check_period; process_opts.check_fn = check_fn; } /** * Turns deadlock checker function on or off, as specified. * * @param[in] new_state TRUE to enable, FALSE to disable * * Won't work if timeout was set to -1 originally (or if it gets set to -1 elsewhere at all). **/ void z_process_set_check_enable(gboolean new_state) { static gint old_value = -1; gint temp; if ((process_opts.check_period >= 0) && (new_state)) /* already on */ return; if ((process_opts.check_period < 0) && (!new_state)) /* already off */ return; /* requested state is not the current state -> toggle state */ temp = old_value; old_value = process_opts.check_period; process_opts.check_period = temp; } /** * Returns whether deadlock checking is enabled. * * @returns TRUE if enabled **/ gboolean z_process_get_check_enable(void) { if (process_opts.check_period >= 0) return TRUE; return FALSE; } /** * Send a message to the client using stderr as long as it's available and using * syslog() if it isn't. * * @param[in] fmt format string * @param[in] ... arguments to fmt * * This function sends a message to the client preferring to use the stderr * channel as long as it is available and switching to using syslog() if it * isn't. Generally the stderr channel will be available in the startup * process and in the beginning of the first startup in the * supervisor/daemon processes. Later on the stderr fd will be closed and we * have to fall back to using the system log. **/ void z_process_message(const gchar *fmt, ...) { gchar buf[2048]; va_list ap; va_start(ap, fmt); g_vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (stderr_present) fprintf(stderr, "%s: %s\n", process_opts.name, buf); else { gchar name[32]; g_snprintf(name, sizeof(name), "%s/%s", process_kind == Z_PK_SUPERVISOR ? "supervise" : "daemon", process_opts.name); openlog(name, LOG_PID, LOG_DAEMON); syslog(LOG_CRIT, "%s\n", buf); closelog(); } } /** * This function is called from z_process_start() to detach from the * controlling tty. **/ static void z_process_detach_tty(void) { if (process_opts.mode != Z_PM_FOREGROUND) { /* detach ourselves from the tty when not staying in the foreground */ if (isatty(STDIN_FILENO)) { ioctl(STDIN_FILENO, TIOCNOTTY, 0); setsid(); } } } /** * Set fd limit. **/ static void z_process_change_limits(void) { struct rlimit limit; if (process_opts.fd_limit_threshold != -1) z_process_message("Setting fd-limit-threshold is deprecated, use fd-limit-min directly;"); limit.rlim_cur = limit.rlim_max = process_opts.fd_limit_min; if (setrlimit(RLIMIT_NOFILE, &limit) < 0) z_process_message("Error setting file number limit; limit='%d'; error='%s'", process_opts.fd_limit_min, g_strerror(errno)); } /** * Use /dev/null as input/output/error. This function is idempotent, can be * called any number of times without harm. **/ static void z_process_detach_stdio(void) { gint devnull_fd; if (process_opts.mode != Z_PM_FOREGROUND && stderr_present) { devnull_fd = open("/dev/null", O_RDONLY); if (devnull_fd >= 0) { dup2(devnull_fd, STDIN_FILENO); close(devnull_fd); } devnull_fd = open("/dev/null", O_WRONLY); if (devnull_fd >= 0) { dup2(devnull_fd, STDOUT_FILENO); dup2(devnull_fd, STDERR_FILENO); close(devnull_fd); } stderr_present = FALSE; } } /** * Enable core file dumping by setting PR_DUMPABLE and changing the core * file limit to infinity. **/ static void z_process_enable_core(void) { struct rlimit limit; if (process_opts.core) { #if HAVE_PRCTL if (!prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { gint rc; rc = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); if (rc < 0) z_process_message("Cannot set process to be dumpable; error='%s'", g_strerror(errno)); } #endif limit.rlim_cur = limit.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_CORE, &limit) < 0) z_process_message("Error setting core limit to infinity; error='%s'", g_strerror(errno)); } } /** * Format the pid file name according to the settings specified by the * process. * * @param[out] buf buffer to store the pidfile name * @param[in] buflen size of buf **/ static const gchar * z_process_format_pidfile_name(gchar *buf, gsize buflen) { const gchar *pidfile = process_opts.pidfile; if (pidfile == NULL) { g_snprintf(buf, buflen, "%s/%s.pid", process_opts.pidfile_dir ? process_opts.pidfile_dir : ZORPLIB_PIDFILE_DIR, process_opts.name); pidfile = buf; } else if (pidfile[0] != '/') { /* complete path to pidfile not specified, assume it is a relative path to pidfile_dir */ g_snprintf(buf, buflen, "%s/%s", process_opts.pidfile_dir ? process_opts.pidfile_dir : ZORPLIB_PIDFILE_DIR, pidfile); pidfile = buf; } return pidfile; } /** * Write the pid to the pidfile. * * @param[in] pid pid to write into the pidfile **/ static void z_process_write_pidfile(pid_t pid) { gchar buf[256]; const gchar *pidfile; FILE *fd; pidfile = z_process_format_pidfile_name(buf, sizeof(buf)); process_opts.pid_removed = FALSE; fd = fopen(pidfile, "w"); if (fd != NULL) { fprintf(fd, "%d\n", (int) pid); fclose(fd); } else { z_process_message("Error creating pid file; file='%s', error='%s'", pidfile, g_strerror(errno)); } } /** * Read the pid from the pidfile * * @returns pid in the file or -1 in case of an error **/ static pid_t z_process_read_pidfile(const gchar *pidfile) { FILE *f; pid_t pid; f = fopen(pidfile, "r"); if (f) { if (fscanf(f, "%d", &pid) == 1) { fclose(f); return pid; } fclose(f); } return -1; } /** * Remove the pidfile. **/ static void z_process_remove_pidfile(void) { gchar buf[256]; const gchar *pidfile; pid_t fpid; if (process_opts.pid_removed) return; pidfile = z_process_format_pidfile_name(buf, sizeof(buf)); fpid = z_process_read_pidfile(pidfile); if (fpid == -1) { z_process_message("Error removing pid file; file='%s', error='Could not read pid file'", pidfile); } else if (fpid == getpid()) { if (unlink(pidfile) < 0) { z_process_message("Error removing pid file; file='%s', error='%s'", pidfile, g_strerror(errno)); } else { process_opts.pid_removed = TRUE; } } } /** * Change the current root to the value specified by the user, causes the * startup process to fail if this function returns FALSE. (e.g. the user * specified a chroot but we could not change to that directory) * * @returns TRUE to indicate success **/ static gboolean z_process_change_root(void) { if (process_opts.chroot_dir) { if (chroot(process_opts.chroot_dir) < 0) { z_process_message("Error in chroot(); chroot='%s', error='%s'\n", process_opts.chroot_dir, g_strerror(errno)); return FALSE; } } return TRUE; } /** * Change the current user/group/groups to the value specified by the user. * causes the startup process to fail if this function returns FALSE. (e.g. * the user requested the uid/gid to change we could not change to that uid) * * @returns TRUE to indicate success **/ static gboolean z_process_change_user(void) { uid_t uid = -1; gid_t gid = -1; #if HAVE_PRCTL && HAVE_PR_SET_KEEPCAPS if (process_opts.caps) prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); #endif if (process_opts.user && !z_resolve_user(process_opts.user, &uid)) { z_process_message("Error resolving user; user='%s'", process_opts.user); return FALSE; } if (process_opts.group && !z_resolve_group(process_opts.group, &gid)) { z_process_message("Error resolving group; group='%s'", process_opts.group); return FALSE; } if ((gint) gid != -1) { if (setgid(gid) < 0) { z_process_message("Error in setgid(); group='%s', error='%s'", process_opts.group, g_strerror(errno)); if (getuid() == 0) return FALSE; } if (process_opts.user && initgroups(process_opts.user, gid) < 0) { z_process_message("Error in initgroups(); user='%s', error='%s'", process_opts.user, g_strerror(errno)); if (getuid() == 0) return FALSE; } } if ((gint) uid != -1) { if (setuid(uid) < 0) { z_process_message("Error in setuid(); user='%s', error='%s'", process_opts.user, g_strerror(errno)); if (getuid() == 0) return FALSE; } } return TRUE; } /** * Change the current capset to the value specified by the user. causes the * startup process to fail if this function returns FALSE, but we only do * this if the capset cannot be parsed, otherwise a failure changing the * capabilities will not result in failure * * @returns TRUE to indicate success **/ static gboolean z_process_change_caps(void) { #if ZORPLIB_ENABLE_CAPS if (process_opts.caps) { cap_t cap = cap_from_text(process_opts.caps); if (cap == NULL) { z_process_message("Error parsing capabilities: %s", zorp_caps); return FALSE; } else { if (cap_set_proc(cap) == -1) { z_process_message("Error setting capabilities; error='%s'", g_strerror(errno)); } cap_free(cap); } zorp_caps = process_opts.caps; } #endif return TRUE; } /** * Change the current working directory to the value specified by the user * and verify that the daemon would be able to dump core to that directory * if that is requested. **/ static void z_process_change_dir(void) { const gchar *cwd = NULL; if (process_opts.mode != Z_PM_FOREGROUND) { if (process_opts.cwd) cwd = process_opts.cwd; else if (process_opts.pidfile_dir) cwd = process_opts.pidfile_dir; if (cwd) IGNORE_UNUSED_RESULT(chdir(cwd)); } /* this check is here to avoid having to change directory early in the startup process */ if ((process_opts.core) && access(".", W_OK) < 0) { gchar buf[256]; IGNORE_UNUSED_RESULT(getcwd(buf, sizeof(buf))); z_process_message("Unable to write to current directory, core dumps will not be generated; dir='%s', error='%s'", buf, g_strerror(errno)); } } /** * Notify our parent process about the result of the process startup phase. * * @param[in] ret_num exit code of the process * * This function is called to notify our parent process (which is the same * executable process but separated with a fork()) about the result of the * process startup phase. Specifying ret_num == 0 means that everything was * dandy, all other values mean that the initialization failed and the * parent should exit using ret_num as the exit code. The function behaves * differently depending on which process it was called from, determined by * the value of the process_kind global variable. In the daemon process it * writes to init_result_pipe, in the startup process it writes to the * startup_result_pipe. * * This function can only be called once, further invocations will do nothing. **/ static void z_process_send_result(guint ret_num) { gchar buf[10]; guint buf_len; gint *fd; if (process_kind == Z_PK_SUPERVISOR) fd = &startup_result_pipe[1]; else if (process_kind == Z_PK_DAEMON) fd = &init_result_pipe[1]; else g_assert_not_reached(); if (*fd != -1) { buf_len = g_snprintf(buf, sizeof(buf), "%d\n", ret_num); IGNORE_UNUSED_RESULT(write(*fd, buf, buf_len)); close(*fd); *fd = -1; } } /** * Retrieves an exit code value from one of the result pipes depending on * which process the function was called from. This function can be called * only once, further invocations will return non-zero result code. * * @returns the exit code **/ static gint z_process_recv_result(void) { gchar ret_buf[6]; gint ret_num = 1; gint *fd; /** @todo FIXME: use a timer */ if (process_kind == Z_PK_SUPERVISOR) fd = &init_result_pipe[0]; else if (process_kind == Z_PK_STARTUP) fd = &startup_result_pipe[0]; else g_assert_not_reached(); if (*fd != -1) { memset(ret_buf, 0, sizeof(ret_buf)); if (read(*fd, ret_buf, sizeof(ret_buf)) > 0) { ret_num = atoi(ret_buf); } else { /* the process probably crashed without telling a proper exit code */ ret_num = 1; } close(*fd); *fd = -1; } return ret_num; } /** * This function is the startup process, never returns, the startup process exits here. **/ static void z_process_perform_startup(void) { /* startup process */ exit(z_process_recv_result()); } #define SPT_PADCHAR '\0' /** * Put a new process title in argv[0] (for ps & co.). * * @param[in] proc_title new process title **/ static void z_process_setproctitle(const gchar* proc_title) { size_t len; g_assert(process_opts.argv_start != NULL); len = g_strlcpy(process_opts.argv_start, proc_title, process_opts.argv_env_len); for (; len < process_opts.argv_env_len; ++len) process_opts.argv_start[len] = SPT_PADCHAR; } #define PROC_TITLE_SPACE 1024 /** Maximum handled restart time */ #define PROC_RESTART_MAX 30 /** * Supervise process, returns only in the context of the daemon process, the * supervisor process exits here. **/ static void z_process_perform_supervise(void) { pid_t pid; gboolean first = TRUE, exited = FALSE; gchar proc_title[PROC_TITLE_SPACE]; size_t restart_time_count = 0; time_t restart_time[PROC_RESTART_MAX]; time_t last_notification_time = 0; time_t now, from; gint restart_interval_min; gint notify_count = 0; g_snprintf(proc_title, PROC_TITLE_SPACE, "supervising %s", process_opts.name); z_process_setproctitle(proc_title); /* The value of the checked restarts must be between 2 and PROC_RESTART_MAX. At least 2 samples are required for the checking of restarts */ if (process_opts.restart_max > PROC_RESTART_MAX) { z_process_message("Warning. The specified value of restart-max parameter is decreaased to '%d'", PROC_RESTART_MAX); process_opts.restart_max = PROC_RESTART_MAX; } if (process_opts.restart_max < 2) { z_process_message("Warning. The specified value of restart-max parameter < 2. Changed to default value '5'; restart_max='%d'", process_opts.restart_max); process_opts.restart_max = 5; } /* The supervisor process waits about 1 second before restarts the supervised process also * the interval should be at least restart_max * 3 seconds to let a longer period for the checking. * The restart itself takes about 3 seconds. * Also there is another lower limit, below it the checking may go wrong. The latter value is 5 (currently) */ restart_interval_min = MAX (5, 3 * process_opts.restart_max); if (process_opts.restart_interval < restart_interval_min) { z_process_message("Warning. The specified value of restart-interval parameter < %d. Changed to '%d'; restart_interval='%d'", restart_interval_min, restart_interval_min, process_opts.restart_interval); process_opts.restart_interval = 5; } while (1) { gint i = 0; gint restart_count = 1; now = time(0); from = now - process_opts.restart_interval; /* ensure there is at least one free slot */ if (restart_time_count == PROC_RESTART_MAX) { memmove(restart_time, restart_time + sizeof(time_t), sizeof(time_t) * (PROC_RESTART_MAX - 1)); --restart_time_count; } restart_time[restart_time_count] = time(NULL); ++restart_time_count; /* checking for restart count in an interval */ for (i = restart_time_count - 1; i>=0 && restart_time[i] >= from; --i) ++restart_count; if (pipe(init_result_pipe) != 0) { z_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno)); z_process_startup_failed(1, TRUE); } /* fork off a child process */ if ((pid = fork()) < 0) { z_process_message("Error forking child process; error='%s'", g_strerror(errno)); z_process_startup_failed(1, TRUE); } else if (pid != 0) { gint rc; gboolean deadlock = FALSE; /* this is the supervisor process */ /* shut down init_result_pipe write side */ close(init_result_pipe[1]); init_result_pipe[1] = -1; rc = z_process_recv_result(); if (first) { /* first time encounter, we have a chance to report back, do it */ z_process_send_result(rc); if (rc != 0) break; z_process_detach_stdio(); } first = FALSE; if (rc != 0) { i = 0; /* initialization failed in daemon, it will probably exit soon, wait and restart */ while (i < 6 && waitpid(pid, &rc, WNOHANG) == 0) { if (i > 3) kill(pid, i > 4 ? SIGKILL : SIGTERM); sleep(1); i++; } if (i == 6) { z_process_message("Initialization failed but the daemon did not exit, even when forced to, trying to recover; pid='%d'", pid); waitpid(pid, &rc, WNOHANG); } if (restart_count > process_opts.restart_max) { z_process_message("Daemon exited but not restarting; restart_count='%d'", restart_count); break; } else { continue; } } if (process_opts.check_fn && (process_opts.check_period >= 0)) { i = 1; while (!(exited = waitpid(pid, &rc, WNOHANG))) { if (i >= process_opts.check_period) { if (!process_opts.check_fn()) break; i = 0; } sleep(1); i++; } if (!exited) { gint j = 0; z_process_message("Daemon deadlock detected, killing process;"); deadlock = TRUE; while (j < 6 && waitpid(pid, &rc, WNOHANG) == 0) { if (j > 3) kill(pid, j > 4 ? SIGKILL : SIGABRT); sleep(1); j++; } if (j == 6) { z_process_message("The daemon did not exit after deadlock, even when forced to, trying to recover; pid='%d'", pid); waitpid(pid, &rc, WNOHANG); } } } else { waitpid(pid, &rc, 0); } if (deadlock || WIFSIGNALED(rc) || (WIFEXITED(rc) && WEXITSTATUS(rc) != 0)) { gchar argbuf[128]; if (!access(Z_PROCESS_FAILURE_NOTIFICATION, R_OK | X_OK)) { const gchar *notify_reason; pid_t npid; gint nrc; now = time(0); if (now - last_notification_time > process_opts.notify_interval) { last_notification_time = now; npid = fork(); switch (npid) { case -1: z_process_message("Could not fork for external notification; reason='%s'", strerror(errno)); break; case 0: switch(fork()) { case -1: z_process_message("Could not fork for external notification; reason='%s'", strerror(errno)); exit(1); break; case 0: if (deadlock) { notify_reason = "deadlock detected"; argbuf[0] = 0; } else { snprintf(argbuf, sizeof(argbuf), "%d; supressed_notifications=%d", WIFSIGNALED(rc) ? WTERMSIG(rc) : WEXITSTATUS(rc), notify_count); if (WIFSIGNALED(rc)) notify_reason = "signalled"; else notify_reason = "non-zero exit code"; } execlp(Z_PROCESS_FAILURE_NOTIFICATION, Z_PROCESS_FAILURE_NOTIFICATION, Z_STRING_SAFE(process_opts.name), Z_STRING_SAFE(process_opts.chroot_dir), Z_STRING_SAFE(process_opts.pidfile_dir), Z_STRING_SAFE(process_opts.pidfile), Z_STRING_SAFE(process_opts.cwd), Z_STRING_SAFE(process_opts.caps), notify_reason, argbuf, (deadlock || !WIFSIGNALED(rc) || WTERMSIG(rc) != SIGKILL) ? "restarting" : "not-restarting", (gchar*) NULL); z_process_message("Could not execute external notification; reason='%s'", strerror(errno)); break; default: exit(0); break; } /* child process */ default: waitpid(npid, &nrc, 0); break; } notify_count = 0; } else { notify_count++; } } if (deadlock || !WIFSIGNALED(rc) || WTERMSIG(rc) != SIGKILL) { if (restart_count > process_opts.restart_max) { z_process_message("Daemon exited due to a deadlock/signal/failure, not restarting; exitcode='%d', restart_count='%d'", rc, restart_count); break; } else z_process_message("Daemon exited due to a deadlock/signal/failure, restarting; exitcode='%d'", rc); sleep(1); } else { z_process_message("Daemon was killed, not restarting; exitcode='%d'", rc); break; } } else /* if not (deadlock || WIFSIGNALED(rc) || (WIFEXITED(rc) && WEXITSTATUS(rc) != 0)) */ { z_process_message("Daemon exited gracefully, not restarting; exitcode='%d'", rc); break; } } else /* pid == 0 */ { /* this is the daemon process, thus we should return to the caller of z_process_start() */ /* shut down init_result_pipe read side */ process_kind = Z_PK_DAEMON; close(init_result_pipe[0]); init_result_pipe[0] = -1; memcpy(process_opts.argv_start, process_opts.argv_orig, process_opts.argv_env_len); return; } } exit(0); } /** * Start the process as directed by the options set by various * z_process_set_*() functions. **/ void z_process_start(void) { pid_t pid; z_process_detach_tty(); if (process_opts.use_fdlimit_settings) z_process_change_limits(); if (process_opts.mode == Z_PM_BACKGROUND) { /* no supervisor, sends result to startup process directly */ if (pipe(init_result_pipe) != 0) { z_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno)); exit(1); } if ((pid = fork()) < 0) { z_process_message("Error forking child process; error='%s'", g_strerror(errno)); exit(1); } else if (pid != 0) { /* shut down init_result_pipe write side */ close(init_result_pipe[1]); /* connect startup_result_pipe with init_result_pipe */ startup_result_pipe[0] = init_result_pipe[0]; init_result_pipe[0] = -1; z_process_perform_startup(); /* NOTE: never returns */ g_assert_not_reached(); } process_kind = Z_PK_DAEMON; /* shut down init_result_pipe read side */ close(init_result_pipe[0]); init_result_pipe[0] = -1; } else if (process_opts.mode == Z_PM_SAFE_BACKGROUND) { /* full blown startup/supervisor/daemon */ if (pipe(startup_result_pipe) != 0) { z_process_message("Error daemonizing process, cannot open pipe; error='%s'", g_strerror(errno)); exit(1); } /* first fork off supervisor process */ if ((pid = fork()) < 0) { z_process_message("Error forking child process; error='%s'", g_strerror(errno)); exit(1); } else if (pid != 0) { /* this is the startup process */ /* shut down startup_result_pipe write side */ close(startup_result_pipe[1]); startup_result_pipe[1] = -1; /* NOTE: never returns */ z_process_perform_startup(); g_assert_not_reached(); } /* this is the supervisor process */ /* shut down startup_result_pipe read side */ close(startup_result_pipe[0]); startup_result_pipe[0] = -1; process_kind = Z_PK_SUPERVISOR; z_process_perform_supervise(); /* we only return in the daamon process here */ } else if (process_opts.mode == Z_PM_FOREGROUND) { process_kind = Z_PK_DAEMON; } else { g_assert_not_reached(); } /* daemon process, we should return to the caller to perform work */ setsid(); /* NOTE: we need to signal the parent in case of errors from this point. * This is accomplished by writing the appropriate exit code to * init_result_pipe, the easiest way doing so is calling z_process_startup_failed. * */ if (!z_process_change_root() || !z_process_change_user() || !z_process_change_caps()) { z_process_startup_failed(1, TRUE); } z_process_enable_core(); z_process_change_dir(); } /** * This is a public API function to be called by the user code when * initialization failed. * * @param[in] ret_num exit code * @param[in] may_exit whether to exit the process **/ void z_process_startup_failed(guint ret_num, gboolean may_exit) { z_process_send_result(ret_num); if (may_exit) { exit(ret_num); } else { z_process_detach_stdio(); } } /** * This is a public API function to be called by the user code when * initialization was successful, we can report back to the user. **/ void z_process_startup_ok(void) { z_process_write_pidfile(getpid()); z_process_send_result(0); z_process_detach_stdio(); } /** * This is a public API function to be called by the user code when the * daemon exits after properly initialized (e.g. when it terminates because * of SIGTERM). This function currently only removes the PID file. **/ void z_process_finish(void) { z_process_remove_pidfile(); } /** * This is a public API function to be called by the user code when the * daemon is about to exit. This function currently only removes the PID file. **/ void z_process_finish_prepare(void) { z_process_remove_pidfile(); } static gboolean z_process_process_mode_arg(const gchar *option_name G_GNUC_UNUSED, const gchar *value, gpointer data G_GNUC_UNUSED, GError **error) { if (strcmp(value, "foreground") == 0) { process_opts.mode = Z_PM_FOREGROUND; } else if (strcmp(value, "background") == 0) { process_opts.mode = Z_PM_BACKGROUND; } else if (strcmp(value, "safe-background") == 0) { process_opts.mode = Z_PM_SAFE_BACKGROUND; } else { g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Error parsing process-mode argument"); return FALSE; } return TRUE; } static GOptionEntry z_process_option_entries[] = { { "foreground", 'F', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &process_opts.mode, "Do not go into the background after initialization", NULL }, { "process-mode", 0, 0, G_OPTION_ARG_CALLBACK, z_process_process_mode_arg , "Set process running mode", "" }, { "user", 'u', 0, G_OPTION_ARG_STRING, &process_opts.user, "Set the user to run as", "" }, { "uid", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &process_opts.user, NULL, NULL }, { "group", 'g', 0, G_OPTION_ARG_STRING, &process_opts.group, "Set the group to run as", "" }, { "gid", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &process_opts.group, NULL, NULL }, { "chroot", 'R', 0, G_OPTION_ARG_STRING, &process_opts.chroot_dir, "Chroot to this directory", "" }, { "caps", 'C', 0, G_OPTION_ARG_STRING, &process_opts.caps, "Set default capability set", "" }, { "no-caps", 'N', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &process_opts.caps, "Disable managing Linux capabilities", NULL }, { "pidfile", 'P', 0, G_OPTION_ARG_STRING, &process_opts.pidfile, "Set path to pid file", "" }, { "enable-core", 0, 0, G_OPTION_ARG_NONE, &process_opts.core, "Enable dumping core files", NULL }, { "fd-limit-min", 0, 0, G_OPTION_ARG_INT, &process_opts.fd_limit_min, "The minimum required number of fds", NULL }, { "fd-limit-threshold", 0, 0, G_OPTION_ARG_INT, &process_opts.fd_limit_threshold,"The required fds per thread (OBSOLETE)", NULL }, { "restart-max", 0, 0, G_OPTION_ARG_INT, &process_opts.restart_max, "The maximum number of restarts within a specified interval", NULL }, { "restart-interval", 0, 0, G_OPTION_ARG_INT, &process_opts.restart_interval, "Set the length of the interval in seconds to check process restarts", NULL }, { "notify_interval", 0, 0, G_OPTION_ARG_INT, &process_opts.notify_interval, "Interval between sending 2 notifications in seconds", NULL }, { NULL, 0, 0, 0, NULL, NULL, NULL }, }; /** * Add the option group (items specified in z_process_option_entries) to the context. * * @param[in] ctx context **/ void z_process_add_option_group(GOptionContext *ctx) { GOptionGroup *group; group = g_option_group_new("process", "Process options", "Process options", NULL, NULL); g_option_group_add_entries(group, z_process_option_entries); g_option_context_add_group(ctx, group); } #endif libzorpll-3.9.4.1/src/random.c000066400000000000000000000077221224546767600161450ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: random.c,v 1.11 2003/05/30 14:13:13 sasa Exp $ * * Author : SaSa * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #define MASK_FOR_N_BITS(n) ((1 << (n)) - 1) /** * Generate random bytes via OpenSSL. * * @param[in] strength random strength * @param[out] target target buffer * @param[in] target_len size of target * * This function returns a sequence of random bytes generated by the PRNG * found in OpenSSL. Currently there's no difference between various random * strengths but they are defined as below: * * Z_RANDOM_STRONG -- key grade random numbers, might be used for * generating keys and/or checking authentication * information * * Z_RANDOM_BASIC -- anything that needs to be unpredictable but might * somewhat be less random, typical use is random padding * in cryptographic protocols * * Z_RANDOM_WEAK -- anything that needs to be something but does not really * need cryptographic strength, for example source port * selection. * * @returns TRUE on success **/ gboolean z_random_sequence_get(ZRandomStrength strength, guchar *target, gsize target_len) { g_return_val_if_fail(strength < Z_RANDOM_NUM_STRENGTHS, FALSE); return RAND_bytes(target, target_len); } /** * This function generates a random sequence where each value is in the * [min, max] range. * * @param[in] strength random strength * @param[out] target target buffer * @param[in] target_len size of target * @param[in] min minimum value * @param[in] max maximum value * * This is useful to strictly generate printable characters. * * @returns TRUE on success **/ gboolean z_random_sequence_get_bounded(ZRandomStrength strength, guchar *target, gsize target_len, guchar min, guchar max) { guint bound; guchar num_bits; guint needed_bytes; guchar *buf; guchar offset; guint i, j; guchar unused_bit_count = 0; guchar bit_buffer = 0; z_enter(); g_return_val_if_fail(strength < Z_RANDOM_NUM_STRENGTHS, FALSE); g_return_val_if_fail(min < max, FALSE); buf = alloca(target_len + 1); bound = max - min; num_bits = 0; while (bound) { num_bits++; bound >>= 1; } needed_bytes = ((num_bits * target_len) - unused_bit_count + 7) / 8; if (!z_random_sequence_get(strength, buf, needed_bytes)) z_return(FALSE); for (i = 0, j = 0; i < target_len; i++) { if (num_bits <= unused_bit_count) { /* we still have enough bits in the buffer */ target[i] = bit_buffer & MASK_FOR_N_BITS(num_bits); bit_buffer >>= num_bits; unused_bit_count -= num_bits; } else { /* we need some more bits */ /* buffered bits go in as the high order bits */ offset = num_bits - unused_bit_count; target[i] = bit_buffer << offset; /* new buffer */ bit_buffer = buf[j++]; unused_bit_count = 8; /* new bits go as the low order bits */ target[i] |= bit_buffer & MASK_FOR_N_BITS(offset); bit_buffer >>= offset; unused_bit_count -= offset; } /* ok, we now have num_bits in target[i] */ target[i] = ((((guint) target[i] * (max - min)) / MASK_FOR_N_BITS(num_bits)) + min) & 0xFF; g_assert(target[i] >= min && target[i] <= max); } z_return(TRUE); } libzorpll-3.9.4.1/src/registry.c000066400000000000000000000123511224546767600165270ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: registry.c,v 1.11 2004/08/18 11:46:46 bazsi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include static GHashTable *registry[MAX_REGISTRY_TYPE]; #define MAX_REGISTRY_NAME 32 /** * ZRegistryEntry is an entry in the registry hash. * * An entry in the registry. The registry is a hash table indexed by a * string and storing an opaque pointer and an integer type * value. */ typedef struct _ZRegistryEntry { gint type; gchar name[MAX_REGISTRY_NAME]; gpointer value; } ZRegistryEntry; /** * Initialize the registry. **/ void z_registry_init(void) { int i; for (i = 0; i < MAX_REGISTRY_TYPE; i++) registry[i] = g_hash_table_new(g_str_hash, g_str_equal); } /** * Deinitialize the registry subsystem. **/ void z_registry_destroy(void) { int i; for (i = 0; i= 0 && type < MAX_REGISTRY_TYPE); } /** * Add an entry to the registry with the given name and type. * * @param[in] name the key of this entry * @param[in] type the type of this entry * @param[in] value the pointer associated with this entry **/ void z_registry_add(const gchar *name, gint type, gpointer value) { ZRegistryEntry *ze = g_new0(ZRegistryEntry, 1); if (!z_registry_is_type_valid(type)) { /*LOG This message indicates that an internal error occurred, a buggy/incompatible loadable module wanted to register an unsupported module type. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 0, "Internal error, bad registry type; name='%s', type='%d'", name, type); return; } g_strlcpy(ze->name, name, sizeof(ze->name)); ze->value = value; ze->type = type; g_hash_table_insert(registry[type], ze->name, ze); } /** * Fetch an item from the registry with the given name returning its * type and pointer. * * @param[in] name name of the entry to fetch * @param[in] type type of the entry * * @returns NULL if the entry was not found, the associated pointer otherwise **/ static ZRegistryEntry * z_registry_get_one(const gchar *name, gint type) { ZRegistryEntry *ze = NULL; z_enter(); ze = g_hash_table_lookup(registry[type], name); z_return(ze); } /** * This function returns an entry from the registry autoprobing for * different types. * * @param[in] name name of the entry to fetch * @param[in, out] type contains the preferred entry type on input, contains the real type on output * * If type is NULL or the value pointed by type is 0, * then each possible entry type is checked, otherwise only the value * specified will be used. * * @returns the value stored in the registry or NULL if nothing is found **/ gpointer z_registry_get(const gchar *name, gint *type) { int i; ZRegistryEntry *ze = NULL; z_enter(); if (type && !z_registry_is_type_valid(*type)) z_return(NULL); if (type == NULL || *type == 0) { for (i = 0; i < MAX_REGISTRY_TYPE && ze == NULL; i++) { ze = z_registry_get_one(name, i); } } else { ze = z_registry_get_one(name, *type); } if (ze) { if (type) *type = ze->type; z_return(ze->value); } z_return(NULL); } /** * This function checks whether the given name is found in the registry at * all, and returns the accompanying type value if found. * * @param[in] name name to search for * * @return the type value **/ guint z_registry_has_key(const gchar *name) { int i; ZRegistryEntry *ze = NULL; for (i = 0; (i < MAX_REGISTRY_TYPE) && (ze == NULL); i++) { ze = z_registry_get_one(name, i); } if (ze) { return i; } else { return 0; } } typedef struct _ZRegistryForeachCallbackData { ZRFunc user_func; gpointer user_data; } ZRegistryForeachCallbackData; static void z_registry_foreach_invoke_callback(gpointer key G_GNUC_UNUSED, gpointer value, gpointer user_data) { ZRegistryForeachCallbackData *callback_data = (ZRegistryForeachCallbackData *)user_data; ZRegistryEntry *ze = (ZRegistryEntry *) value; if (ze) (*(callback_data->user_func))(ze->name, ze->type, ze->value, callback_data->user_data); } /** * This function iterates over the set of registry entries having the * type type. * * @param[in] type type of entries to iterate over * @param[in] func a ZRFunc function to call for elements **/ void z_registry_foreach(gint type, ZRFunc func, gpointer user_data) { ZRegistryForeachCallbackData helper_data; g_assert(z_registry_is_type_valid(type)); helper_data.user_func = func; helper_data.user_data = user_data; g_hash_table_foreach(registry[type], z_registry_foreach_invoke_callback, &helper_data); } libzorpll-3.9.4.1/src/sockaddr.c000066400000000000000000000575431224546767600164650ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: sockaddr.c,v 1.32 2004/08/18 11:46:46 bazsi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #ifndef G_OS_WIN32 # include #endif static ZSockAddrFuncs inet_range_sockaddr_funcs; #ifdef G_OS_WIN32 #endif /** * Thread friendly version of inet_ntoa(), converts an IP address to * human readable form. * * @param[out] buf store result in this buffer * @param[in] bufsize the available space in buf * @param[in] a address to convert. * * @returns the address of buf **/ gchar * z_inet_ntoa(gchar *buf, size_t bufsize, struct in_addr a) { unsigned int ip = ntohl(a.s_addr); g_snprintf(buf, bufsize, "%d.%d.%d.%d", (ip & 0xff000000) >> 24, (ip & 0x00ff0000) >> 16, (ip & 0x0000ff00) >> 8, (ip & 0x000000ff)); return buf; } /** * This function takes an IP address in text representation, parses it and * returns it in a. * * @param[in] buf buffer to parse * @param[out] a the parsed address * * @returns TRUE to indicate that parsing was successful. **/ gboolean z_inet_aton(const gchar *buf, struct in_addr *a) { #ifdef HAVE_INET_ATON return inet_aton(buf, a); #else a->s_addr = inet_addr(buf); return TRUE; #endif } /* general ZSockAddr functions */ /** * General function to allocate and initialize a ZSockAddr structure, * and convert a libc style sockaddr * pointer to our representation. * * @param[in] sa libc sockaddr * pointer to convert * @param[in] salen size of sa * * @returns new ZSockAddr instance **/ ZSockAddr * z_sockaddr_new(struct sockaddr *sa, gsize salen) { z_enter(); switch (sa->sa_family) { #ifndef G_OS_WIN32 case AF_INET6: if (salen >= sizeof(struct sockaddr_in6)) z_return(z_sockaddr_inet6_new2((struct sockaddr_in6 *) sa)); break; #endif case AF_INET: if (salen == sizeof(struct sockaddr_in)) z_return(z_sockaddr_inet_new2((struct sockaddr_in *) sa)); break; #ifndef G_OS_WIN32 case AF_UNIX: /* NOTE: the sockaddr_un structure might be less than struct sockaddr_un */ z_return(z_sockaddr_unix_new2((struct sockaddr_un *) sa, salen)); #endif default: /*LOG This message indicates an internal error, the program tried to use an unsupported address family. Please report this error to the Zorp QA team. */ z_log(NULL, CORE_ERROR, 3, "Unsupported socket family in z_sockaddr_new(); family='%d'", sa->sa_family); z_return(NULL); } z_return(NULL); } /** * Format a ZSockAddr into human readable form, calls the format * virtual method of ZSockAddr. * * @param[in] a instance pointer of a ZSockAddr * @param[out] text destination buffer * @param[in] n the size of text * * @returns text is filled with a human readable representation of a, and a * pointer to text is returned. **/ gchar * z_sockaddr_format(ZSockAddr *a, gchar *text, gulong n) { return a->sa_funcs->sa_format(a, text, n); } /** * This function compares two ZSockAddr structures whether their _value_ is * equal, e.g.\ same IP/port. * * @param[in] a first sockaddr to compare * @param[in] b second sockaddr to compare * * @returns TRUE if they're equal **/ gboolean z_sockaddr_equal(ZSockAddr *a, ZSockAddr *b) { return a->sa.sa_family == b->sa.sa_family && a->sa_funcs->sa_equal(a, b); } /** * Increment the reference count of a ZSockAddr instance. * * @param[in] a pointer to ZSockAddr instance * * @returns the same instance **/ ZSockAddr * z_sockaddr_ref(ZSockAddr *a) { if (a) z_refcount_inc(&a->refcnt); return a; } /** * Decrement the reference count of a ZSockAddr instance, and free if * the refcnt reaches 0. * * @param[in] a ZSockAddr instance **/ void z_sockaddr_unref(ZSockAddr *a) { if (a && z_refcount_dec(&a->refcnt)) { if (!a->sa_funcs->freefn) g_free(a); else a->sa_funcs->freefn(a); } } /* AF_INET socket address */ /** * ZSockAddrInet is an implementation of the ZSockAddr interface, * encapsulating an IPv4 host address and port number. **/ typedef struct _ZSockAddrInet { gint refcnt; guint32 flags; ZSockAddrFuncs *sa_funcs; int salen; struct sockaddr_in sin; } ZSockAddrInet; /** * This function is used as a bind_prepare callback for ZSockAddrInet * addresses. * * @param[in] sock fd of the socket to prepare for bind * @param addr address where we are binding to (unused) * @param[in] sock_flags socket flags (ZSF_*) * * It currently enables SO_REUSEADDR to permit concurrent * access to the same socket. * * @returns GIOStatus to indicate success/failure **/ static GIOStatus z_sockaddr_inet_bind_prepare(int sock, ZSockAddr *addr G_GNUC_UNUSED, guint32 sock_flags) { int tmp = 1; GIOStatus res = G_IO_STATUS_NORMAL; if ((sock_flags & ZSF_LOOSE_BIND) == 0) { if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof(tmp)) < 0) res = G_IO_STATUS_ERROR; } return res; } /** * This function is the clone callback for ZSockAddrInet sockets. * * @param[in] addr address to clone * @param[in] wildcard whether the port information is important * * It copies the sockaddr contents and nulls port if wildcard is TRUE. * * @returns the cloned address **/ static ZSockAddr * z_sockaddr_inet_clone(ZSockAddr *addr, gboolean wildcard) { ZSockAddrInet *self = g_new0(ZSockAddrInet, 1); memcpy(self, addr, sizeof(*self)); self->refcnt = 1; if (wildcard) self->sin.sin_port = 0; return (ZSockAddr *) self; } /** * This function is the format callback for ZSockAddrInet socket addresses * and returns the human readable representation of the IPv4 address. * * @param[in] addr ZSockAddrInet instance * @param[out] text buffer to format this address into * @param[in] n size of text * * @returns the start of the buffer **/ static gchar * z_sockaddr_inet_format(ZSockAddr *addr, gchar *text, gulong n) { ZSockAddrInet *self = (ZSockAddrInet *) addr; char buf[32]; g_snprintf(text, n, "AF_INET(%s:%d)", z_inet_ntoa(buf, sizeof(buf), self->sin.sin_addr), ntohs(self->sin.sin_port)); return text; } /** * This function is the free callback fro ZSockAddrInet sockets. * * @param[in] addr ZSockAddrInet instance * * It frees ZSockAddrInet specific information and the address structure itself. **/ void z_sockaddr_inet_free(ZSockAddr *addr) { g_free(addr); } /** * Checks whether two addresses of the AF_INET family are equal. * * @param[in] addr the first address * @param[in] o the second address * * @returns TRUE if both the IP address and port are equal. **/ static gboolean z_sockaddr_inet_equal(ZSockAddr *addr, ZSockAddr *o) { ZSockAddrInet *self = (ZSockAddrInet *) addr; ZSockAddrInet *other = (ZSockAddrInet *) o; g_assert(self->sin.sin_family == AF_INET); g_assert(other->sin.sin_family == AF_INET); return self->sin.sin_addr.s_addr == other->sin.sin_addr.s_addr && self->sin.sin_port == other->sin.sin_port; } /** * ZSockAddrInet virtual methods. **/ static ZSockAddrFuncs inet_sockaddr_funcs = { z_sockaddr_inet_bind_prepare, NULL, z_sockaddr_inet_clone, z_sockaddr_inet_format, z_sockaddr_inet_free, z_sockaddr_inet_equal }; /** * This constructor allocates and initializes an IPv4 socket address. * * @param[in] ip text representation of an IP address * @param[in] port port number in host byte order * * @returns the new instance **/ ZSockAddr * z_sockaddr_inet_new(const gchar *ip, guint16 port) { ZSockAddrInet *self; struct in_addr netaddr; if (!z_inet_aton(ip, &netaddr)) { return NULL; } self = g_new0(ZSockAddrInet, 1); self->refcnt = 1; self->flags = 0; self->salen = sizeof(struct sockaddr_in); self->sin.sin_family = AF_INET; self->sin.sin_addr = netaddr; self->sin.sin_port = htons(port); self->sa_funcs = &inet_sockaddr_funcs; return (ZSockAddr *) self; } /** * Alternate constructor for ZSockAddrInet which takes a (struct * sockaddr_in) structure instead of an ip+port. * * @param[in] sinaddr the sockaddr_in structure to convert * * @returns the allocated instance. **/ ZSockAddr * z_sockaddr_inet_new2(struct sockaddr_in *sinaddr) { ZSockAddrInet *self = g_new0(ZSockAddrInet, 1); self->refcnt = 1; self->flags = 0; self->salen = sizeof(struct sockaddr_in); self->sin = *sinaddr; self->sa_funcs = &inet_sockaddr_funcs; return (ZSockAddr *) self; } #ifndef G_OS_WIN32 /** * Alternate constructor for ZSockAddrInet which takes a hostname+port * instead of a struct sockaddr_in. * * @param[in] hostname name of the host to resolve * @param[in] port port number in host byte order * * @returns the allocated instance. **/ ZSockAddr * z_sockaddr_inet_new_hostname(const gchar *hostname, guint16 port) { struct hostent hes, *he; char hostbuf[1024]; char buf[32]; int err = 0; int rc; ZSockAddr *saddr = NULL; rc = gethostbyname_r(hostname, &hes, hostbuf, sizeof(hostbuf), &he, &err); if (rc == 0 && he && he->h_addr_list[0]) { z_inet_ntoa(buf, sizeof(buf), *((struct in_addr *) he->h_addr_list[0])); saddr = z_sockaddr_inet_new(buf, port); } return saddr; } #endif /** * This function checks whether the given ZSockAddr instance is in fact a * ZSockAddrInet instance. * * @param[in] s ZSockAddr instance * * @returns TRUE if s is a ZSockAddrInet **/ gboolean z_sockaddr_inet_check(ZSockAddr *s) { return (s->sa_funcs == &inet_sockaddr_funcs) || (s->sa_funcs == &inet_range_sockaddr_funcs); } /*+ Similar to ZSockAddrInet, but binds to a port in the given range +*/ /** * Class to store an IP address with a port range. * * @note it is assumed that it is safe to cast from ZSockAddrInetRange to * ZSockAddrInet **/ typedef struct _ZSockAddrInetRange { gint refcnt; guint32 flags; ZSockAddrFuncs *sa_funcs; int salen; struct sockaddr_in sin; guint16 min_port, max_port, last_port; } ZSockAddrInetRange; /** * This function is the bind callback of ZSockAddrInetRange. * * @param[in] sock socket to bind * @param[in] a address to bind to * @param[in] sock_flags socket flags (ZSF_*) * * It tries to allocate a port in the specified range. * * Returns: a GIOStatus value to indicate failure/success **/ static GIOStatus z_sockaddr_inet_range_bind(int sock, ZSockAddr *a, guint32 sock_flags) { ZSockAddrInetRange *self = (ZSockAddrInetRange *) a; guint16 port; if (self->min_port > self->max_port) { /*LOG This message indicates that SockAddrInetRange was given incorrect parameters, the allowed min_port is greater than max_port. */ z_log(NULL, CORE_ERROR, 3, "SockAddrInetRange, invalid range given; min_port='%d', max_port='%d'", self->min_port, self->max_port); return G_IO_STATUS_ERROR; } for (port = self->last_port; port <= self->max_port; port++) { /* attempt to bind */ self->sin.sin_port = htons(port); if (z_ll_bind(sock, (struct sockaddr *) &self->sin, self->salen, sock_flags) == 0) { /*LOG This message reports that the SockAddrInetRange was successfully bound to the given port in the dynamic port range. */ z_log(NULL, CORE_DEBUG, 6, "SockAddrInetRange, successfully bound; min_port='%d', max_port='%d', port='%d'", self->min_port, self->max_port, port); self->last_port = port + 1; return G_IO_STATUS_NORMAL; } } for (port = self->min_port; port <= self->max_port; port++) { /* attempt to bind */ self->sin.sin_port = htons(port); if (z_ll_bind(sock, (struct sockaddr *) &self->sin, self->salen, sock_flags) == 0) { /*NOLOG*/ /* the previous message is the same */ z_log(NULL, CORE_DEBUG, 6, "SockAddrInetRange, successfully bound; min_port='%d', max_port='%d', port='%d'", self->min_port, self->max_port, port); self->last_port = port + 1; return G_IO_STATUS_NORMAL; } } /*LOG This message reports that the SockAddRinetRange could not find any free port in the given range. */ z_log(NULL, CORE_ERROR, 3, "SockAddrInetRange, could not find free port to bind; min_port='%d', max_port='%d'", self->min_port, self->max_port); self->last_port = self->min_port; return G_IO_STATUS_ERROR; } /** * This function is the clone callback for ZSockAddrInetRange sockets. * * @param[in] addr address to clone * @param wildcard_clone whether the port information is important (unused) * * It copies the sockaddr contents. * * @returns the cloned address **/ static ZSockAddr * z_sockaddr_inet_range_clone(ZSockAddr *addr, gboolean wildcard_clone G_GNUC_UNUSED) { ZSockAddrInetRange *self = g_new0(ZSockAddrInetRange, 1); memcpy(self, addr, sizeof(*self)); self->refcnt = 1; if (self->max_port > self->min_port) { self->last_port = ((guint16) rand() % (self->max_port - self->min_port)) + self->min_port; } else if (self->max_port == self->min_port) { self->last_port = self->min_port; } return (ZSockAddr *) self; } /** * ZSockAddrInetRange virtual methods. **/ static ZSockAddrFuncs inet_range_sockaddr_funcs = { NULL, z_sockaddr_inet_range_bind, z_sockaddr_inet_range_clone, z_sockaddr_inet_format, z_sockaddr_inet_free, z_sockaddr_inet_equal }; /** * This constructor creates a new ZSockAddrInetRange instance with the * specified arguments. * * @param[in] ip ip address in text form * @param[in] min_port minimal port to bind to * @param[in] max_port maximum port to bind to * * @returns the new ZSockAddrInetRange instance **/ ZSockAddr * z_sockaddr_inet_range_new(const gchar *ip, guint16 min_port, guint16 max_port) { struct in_addr netaddr; if (!z_inet_aton(ip, &netaddr)) return NULL; return z_sockaddr_inet_range_new_inaddr(netaddr, min_port, max_port); } /** * This constructor creates a new ZSockAddrInetRange instance with the * specified arguments. * * @param[in] addr address * @param[in] min_port minimal port to bind to * @param[in] max_port maximum port to bind to * * @returns the new ZSockAddr instance **/ ZSockAddr * z_sockaddr_inet_range_new_inaddr(struct in_addr addr, guint16 min_port, guint16 max_port) { ZSockAddrInetRange *self; self = g_new0(ZSockAddrInetRange, 1); self->refcnt = 1; self->flags = 0; self->salen = sizeof(struct sockaddr_in); self->sin.sin_family = AF_INET; self->sin.sin_addr = addr; self->sin.sin_port = 0; self->sa_funcs = &inet_range_sockaddr_funcs; if (max_port > min_port) { self->last_port = (guint16)(rand() % (max_port - min_port)) + min_port; } else if (max_port == min_port) { self->last_port = min_port; } self->min_port = min_port; self->max_port = max_port; return (ZSockAddr *) self; } #ifndef G_OS_WIN32 /** * ZSockAddrInet6 is an implementation of the ZSockAddr interface, * encapsulating an IPv6 host address and port number. **/ typedef struct _ZSockAddrInet6 { gint refcnt; guint32 flags; ZSockAddrFuncs *sa_funcs; int salen; struct sockaddr_in6 sin6; } ZSockAddrInet6; /** * This function is the clonse callback for ZSockAddrInet sockets. * * @param[in] addr address to clone * @param[in] wildcard whether the port information is important * * It copies the sockaddr contents and nulls port if wildcard is TRUE. * * @returns the cloned address **/ static ZSockAddr * z_sockaddr_inet6_clone(ZSockAddr *addr, gboolean wildcard) { ZSockAddrInet6 *self = g_new0(ZSockAddrInet6, 1); memcpy(self, addr, sizeof(*self)); self->refcnt = 1; if (wildcard) self->sin6.sin6_port = 0; return (ZSockAddr *) self; } /** * Format an IPv6 address into human readable form. * * @param[in] addr the address * @param[out] text buffer to receive the result * @param[in] n length of buffer * * @returns a pointer to text **/ static gchar * z_sockaddr_inet6_format(ZSockAddr *addr, gchar *text, gulong n) { ZSockAddrInet6 *self = (ZSockAddrInet6 *) addr; char buf[64]; inet_ntop(AF_INET6, &self->sin6.sin6_addr, buf, sizeof(buf)); g_snprintf(text, n, "AF_INET6(%s:%d)", buf, htons(self->sin6.sin6_port)); return text; } /** * Frees a ZSockAddrInet6 (or ZSockAddr) instance. * * @param[in] addr ZSockAddr instance **/ static void z_sockaddr_inet6_free(ZSockAddr *addr) { g_free(addr); } /** * Checks whether two IPv6 addresses of are equal. * * @param[in] addr the first address * @param[in] o the second address * * @returns TRUE if both the IP address and port are equal. **/ static gboolean z_sockaddr_inet6_equal(ZSockAddr *addr, ZSockAddr *o) { ZSockAddrInet6 *self = (ZSockAddrInet6 *) addr; ZSockAddrInet6 *other = (ZSockAddrInet6 *) o; g_assert(self->sin6.sin6_family == AF_INET6); g_assert(other->sin6.sin6_family == AF_INET6); return memcmp(&self->sin6.sin6_addr, &other->sin6.sin6_addr, sizeof(self->sin6.sin6_addr)) == 0 && self->sin6.sin6_port == other->sin6.sin6_port; } /** * ZSockAddrInet6 virtual methods. **/ static ZSockAddrFuncs inet6_sockaddr_funcs = { z_sockaddr_inet_bind_prepare, NULL, z_sockaddr_inet6_clone, z_sockaddr_inet6_format, z_sockaddr_inet6_free, z_sockaddr_inet6_equal }; /** * Allocate and initialize an IPv6 socket address. * * @param[in] ip text representation of an IP address * @param[in] port port number in host byte order * * @returns ZSockAddrInet6 instance **/ ZSockAddr * z_sockaddr_inet6_new(gchar *ip, guint16 port) { ZSockAddrInet6 *addr = g_new0(ZSockAddrInet6, 1); addr->refcnt = 1; addr->flags = 0; addr->salen = sizeof(struct sockaddr_in6); addr->sin6.sin6_family = AF_INET6; inet_pton(AF_INET6, ip, &addr->sin6.sin6_addr); addr->sin6.sin6_port = htons(port); addr->sa_funcs = &inet6_sockaddr_funcs; return (ZSockAddr *) addr; } /** * Allocate and initialize an IPv6 socket address using libc sockaddr * * structure. * * @param[in] sin6 the sockaddr_in6 structure to convert * * @returns ZSockAddrInet6 instance **/ ZSockAddr * z_sockaddr_inet6_new2(struct sockaddr_in6 *sin6) { ZSockAddrInet6 *addr = g_new0(ZSockAddrInet6, 1); addr->refcnt = 1; addr->flags = 0; addr->salen = sizeof(struct sockaddr_in6); addr->sin6 = *sin6; addr->sa_funcs = &inet6_sockaddr_funcs; return (ZSockAddr *) addr; } /** * This function checks whether the given ZSockAddr instance is in fact a * ZSockAddrInet instance. * * @param[in] s ZSockAddr instance * * @returns TRUE if s is a ZSockAddrInet **/ gboolean z_sockaddr_inet6_check(ZSockAddr *s) { return (s->sa_funcs == &inet6_sockaddr_funcs); } #endif #ifndef G_OS_WIN32 /* AF_UNIX socket address */ /** * The ZSockAddrUnix class is an implementation of the ZSockAddr * interface encapsulating AF_UNIX domain socket names. **/ typedef struct _ZSockAddrUnix { gint refcnt; guint32 flags; ZSockAddrFuncs *sa_funcs; int salen; struct sockaddr_un saun; } ZSockAddrUnix; static GIOStatus z_sockaddr_unix_bind_prepare(int sock, ZSockAddr *addr, guint32 sock_flags); static gchar *z_sockaddr_unix_format(ZSockAddr *addr, gchar *text, gulong n); /** * This function is the clone callback for ZSockAddrUnix instances. * * @param[in] addr ZSockAddr instance to clone * @param wildcard_clone specifies whether the clone can be a wildcard (unused) * * It copies the address information and returns a newly constructed, independent copy. * * @returns the cloned instance **/ static ZSockAddr * z_sockaddr_unix_clone(ZSockAddr *addr, gboolean wildcard_clone G_GNUC_UNUSED) { ZSockAddrUnix *self = g_new0(ZSockAddrUnix, 1); memcpy(self, addr, sizeof(*self)); self->refcnt = 1; return (ZSockAddr *) self; } /** * Checks whether two UNIX addresses of are equal. * * @param[in] addr the first address * @param[in] o the second address * * @returns TRUE if the addresses are equal. **/ static gboolean z_sockaddr_unix_equal(ZSockAddr *addr, ZSockAddr *o) { ZSockAddrUnix *self = (ZSockAddrUnix *) addr; ZSockAddrUnix *other = (ZSockAddrUnix *) o; g_assert(self->saun.sun_family == AF_UNIX); g_assert(other->saun.sun_family == AF_UNIX); return strncmp(self->saun.sun_path, other->saun.sun_path, sizeof(self->saun.sun_path)) == 0; } /** * ZSockAddrUnix virtual methods. **/ static ZSockAddrFuncs unix_sockaddr_funcs = { z_sockaddr_unix_bind_prepare, NULL, z_sockaddr_unix_clone, z_sockaddr_unix_format, NULL, z_sockaddr_unix_equal }; /* anonymous if name == NULL */ /** * This function checks whether the given ZSockAddr instance is in fact a * ZSockAddrUnix instance. * * @param[in] s ZSockAddr instance * * @returns TRUE if s is a ZSockAddrUnix **/ gboolean z_sockaddr_unix_check(ZSockAddr *s) { return s->sa_funcs == &unix_sockaddr_funcs; } /** * Allocate and initialize a ZSockAddrUnix instance. * * @param[in] name filename * * @returns a ZSockAddrUnix instance **/ ZSockAddr * z_sockaddr_unix_new(const gchar *name) { ZSockAddrUnix *self = g_new0(ZSockAddrUnix, 1); self->refcnt = 1; self->flags = 0; self->sa_funcs = &unix_sockaddr_funcs; self->saun.sun_family = AF_UNIX; if (name) { g_strlcpy(self->saun.sun_path, name, sizeof(self->saun.sun_path)); self->salen = sizeof(self->saun) - sizeof(self->saun.sun_path) + strlen(self->saun.sun_path) + 1; } else { self->saun.sun_path[0] = 0; self->salen = 2; } return (ZSockAddr *) self; } /** * Allocate and initialize a ZSockAddrUnix instance, using libc * sockaddr_un structure. * * @param[in] saun sockaddr_un structure to convert * @param[in] sunlen size of saun * * @returns a ZSockAddrUnix instance **/ ZSockAddr * z_sockaddr_unix_new2(struct sockaddr_un *saun, int sunlen) { ZSockAddrUnix *self = g_new0(ZSockAddrUnix, 1); self->refcnt = 1; self->flags = 0; self->sa_funcs = &unix_sockaddr_funcs; memset(&self->saun, 0, sizeof(self->saun)); if (sunlen) { memcpy(&self->saun, saun, sunlen); } else { self->saun.sun_family = AF_UNIX; } self->salen = sizeof(struct sockaddr_un); return (ZSockAddr *) self; } /** * This function is used as a bind_prepare callback for ZSockAddrUnix * addresses. * * @param sock fd of the socket to prepare for bind (not used) * @param[in] addr address where we are binding to * @param sock_flags socket flags (ZSF_*) (unused) * * It currently unlinks the socket if it exists and is a socket. * * @returns GIOStatus to indicate success/failure **/ static GIOStatus z_sockaddr_unix_bind_prepare(int sock G_GNUC_UNUSED, ZSockAddr *addr, guint32 sock_flags G_GNUC_UNUSED) { ZSockAddrUnix *self = (ZSockAddrUnix *) addr; struct stat st; if (self->saun.sun_path[0] == 0) return G_IO_STATUS_ERROR; if (stat(self->saun.sun_path, &st) == -1 || !S_ISSOCK(st.st_mode)) return G_IO_STATUS_ERROR; unlink(self->saun.sun_path); return G_IO_STATUS_NORMAL; } /** * This function is the format callback for ZSockAddrUnix socket addresses * and returns the human readable representation of the unix domain socket * address. * * @param[in] addr ZSockAddrUnix instance * @param[out] text buffer to format this address into * @param[in] n size of text * * @returns the start of the buffer **/ gchar * z_sockaddr_unix_format(ZSockAddr *addr, gchar *text, gulong n) { ZSockAddrUnix *self = (ZSockAddrUnix *) addr; g_snprintf(text, n, "AF_UNIX(%s)", self->salen > 2 && self->saun.sun_path[0] ? self->saun.sun_path : "anonymous"); return text; } #endif libzorpll-3.9.4.1/src/socket.c000066400000000000000000000331641224546767600161540ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: socket.c,v 1.21 2004/05/22 14:04:16 bazsi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #define MAGIC_FAMILY_NUMBER 111 /** * A thin interface around bind() using a ZSockAddr structure for * socket address. * * @param[in] fd socket to bind * @param[in] addr address to bind * * It enables the NET_BIND_SERVICE capability (should be * in the permitted set). * * @returns GIOStatus instance **/ GIOStatus z_bind(gint fd, ZSockAddr *addr, guint32 sock_flags) { #if ZORPLIB_ENABLE_CAPS cap_t saved_caps; #endif GIOStatus rc; z_enter(); #if ZORPLIB_ENABLE_CAPS saved_caps = cap_save(); #endif cap_enable(CAP_NET_BIND_SERVICE); /* for binding low numbered ports */ cap_enable(CAP_NET_ADMIN); /* for binding non-local interfaces, transparent proxying */ if (addr->sa_funcs && addr->sa_funcs->sa_bind_prepare) addr->sa_funcs->sa_bind_prepare(fd, addr, sock_flags); if (addr->sa_funcs && addr->sa_funcs->sa_bind) rc = addr->sa_funcs->sa_bind(fd, addr, sock_flags); else { if (addr && z_ll_bind(fd, &addr->sa, addr->salen, sock_flags) < 0) { gchar buf[MAX_SOCKADDR_STRING]; /*LOG This message indicates that the low level bind failed for the given reason. */ z_log(NULL, CORE_ERROR, 3, "bind() failed; bind='%s', error='%s'", z_sockaddr_format(addr, buf, sizeof(buf)), g_strerror(errno)); cap_restore(saved_caps); z_return(G_IO_STATUS_ERROR); } rc = G_IO_STATUS_NORMAL; } cap_restore(saved_caps); z_return(rc); } /** * Accept a connection on the given fd, returning the newfd and the * address of the client in a Zorp SockAddr structure. * * @param[in] fd accept connection on this socket * @param[out] newfd fd of the accepted connection * @param[out] addr store the address of the client here * * @returns GIOStatus instance **/ GIOStatus z_accept(gint fd, gint *newfd, ZSockAddr **addr, guint32 sock_flags) { char sabuf[1024]; socklen_t salen = sizeof(sabuf); struct sockaddr *sa = (struct sockaddr *) sabuf; /* NOTE: workaround a Linux 2.4.20 kernel problem */ sa->sa_family = MAGIC_FAMILY_NUMBER; do { *newfd = z_ll_accept(fd, (struct sockaddr *) sabuf, &salen, sock_flags); } while (*newfd == -1 && z_errno_is(EINTR)); if (*newfd != -1) { if (sa->sa_family == MAGIC_FAMILY_NUMBER && salen == sizeof(sabuf)) { /* workaround the linux 2.4.20 problem */ sa->sa_family = AF_UNIX; salen = 2; } *addr = z_sockaddr_new((struct sockaddr *) sabuf, salen); } else if (z_errno_is(EAGAIN)) { return G_IO_STATUS_AGAIN; } else { /*LOG This message indicates that the low level accept of a connection failed for the given reason. */ z_log(NULL, CORE_ERROR, 3, "accept() failed; fd='%d', error='%s'", fd, g_strerror(errno)); return G_IO_STATUS_ERROR; } return G_IO_STATUS_NORMAL; } /** * Connect a socket using Zorp style ZSockAddr structure. * * @param[in] fd socket to connect * @param[in] remote remote address * @param[in] sock_flags socket flags * * @returns GIOStatus instance **/ GIOStatus z_connect(gint fd, ZSockAddr *remote, guint32 sock_flags) { int rc; z_enter(); do { rc = z_ll_connect(fd, &remote->sa, remote->salen, sock_flags); } while (rc == -1 && z_errno_is(EINTR)); if (rc != -1) z_return(G_IO_STATUS_NORMAL); if (!z_errno_is(EINPROGRESS)) { int saved_errno = z_errno_get(); /*LOG This message indicates that the low level connection establishment failed for the given reason. */ z_log(NULL, CORE_ERROR, 3, "connect() failed; fd='%d', error='%s'", fd, g_strerror(errno)); z_errno_set(saved_errno); } z_return(G_IO_STATUS_ERROR); } /** * Disconnect an already connected socket for protocols that support this * operation (for example UDP). * * @param[in] fd socket to disconnect * @param sock_flags socket flags (not used) * * @returns GIOStatus instance **/ GIOStatus z_disconnect(int fd, guint32 sock_flags G_GNUC_UNUSED) { gint rc; struct sockaddr sa; z_enter(); sa.sa_family = AF_UNSPEC; do { rc = connect(fd, &sa, sizeof(struct sockaddr)); } while (rc == -1 && errno == EINTR); if (rc != -1) z_return(G_IO_STATUS_NORMAL); /*LOG This message indicates that the low level disconnect failed for the given reason. */ z_log(NULL, CORE_ERROR, 3, "Disconnect failed; error='%s'", g_strerror(errno)); z_return(G_IO_STATUS_ERROR); } /** * Start listening on this socket given the underlying protocol supports it. * * @param[in] fd socket to listen * @param[in] backlog the number of possible connections in the backlog queue * @param accept_one whether only one connection is to be accepted (used as a hint) (unused) * * @returns GIOStatus instance **/ GIOStatus z_listen(gint fd, gint backlog, guint32 sock_flags) { if (z_ll_listen(fd, backlog, sock_flags) == -1) { /*LOG This message indicates that the low level listen failed for the given reason. */ z_log(NULL, CORE_ERROR, 3, "listen() failed; fd='%d', error='%s'", fd, g_strerror(errno)); return G_IO_STATUS_ERROR; } return G_IO_STATUS_NORMAL; } /** * Get the local address where a given socket is bound. * * @param[in] fd socket * @param[out] local_addr the local address is returned here * @param[in] sock_flags socket flags * * @returns GIOStatus instance **/ GIOStatus z_getsockname(gint fd, ZSockAddr **local_addr, guint32 sock_flags) { char sabuf[1500]; socklen_t salen = sizeof(sabuf); if (z_ll_getsockname(fd, (struct sockaddr *) sabuf, &salen, sock_flags) == -1) { /*LOG This message indicates that the getsockname() system call failed for the given fd. */ z_log(NULL, CORE_ERROR, 3, "getsockname() failed; fd='%d', error='%s'", fd, g_strerror(errno)); return G_IO_STATUS_ERROR; } *local_addr = z_sockaddr_new((struct sockaddr *) sabuf, salen); return G_IO_STATUS_NORMAL; } /** * Get the remote address where a given socket is connected. * * @param[in] fd socket * @param[out] peer_addr the address of the peer is returned here * * @returns GIOStatus instance **/ GIOStatus z_getpeername(gint fd, ZSockAddr **peer_addr, guint32 sock_flags) { char sabuf[1500]; socklen_t salen = sizeof(sabuf); if (z_ll_getpeername(fd, (struct sockaddr *) sabuf, &salen, sock_flags) == -1) { return G_IO_STATUS_ERROR; } *peer_addr = z_sockaddr_new((struct sockaddr *) sabuf, salen); return G_IO_STATUS_NORMAL; } /** * Get the original destination of a client represented by the socket. * * @param[in] fd socket * @param[out] dest_addr the address of the peer's original destination is returned here * @param[in] sock_flags socket flags * * @returns GIOStatus instance **/ GIOStatus z_getdestname(gint fd, ZSockAddr **dest_addr, guint32 sock_flags) { char sabuf[1500]; socklen_t salen = sizeof(sabuf); if (z_ll_getdestname(fd, (struct sockaddr *) sabuf, &salen, sock_flags) == -1) { return G_IO_STATUS_ERROR; } *dest_addr = z_sockaddr_new((struct sockaddr *) sabuf, salen); return G_IO_STATUS_NORMAL; } /* low level functions */ /** * Do the actual port binding. * * @param[in] fd FD of the socket to bind * @param[in, out] sa address to bind to * @param[in] salen length of sa * @param[in] sock_flags flags, see below * * If ZSF_LOOSE_BIND is enabled in sock_flags, the port will be allocated in the * same group ([1, 511], [512, 1023], [1024, 65535]). * * If ZSF_RANDOM_BIND is _also_ enabled in sock_flags, the port will be allocated * randomly in the same group using a cryptographically secure algorithm. * * @returns 0 on success, -1 on failure (like bind() ) **/ gint z_do_ll_bind(int fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags) { if ((sock_flags & ZSF_LOOSE_BIND) == 0 || sa->sa_family != AF_INET || ntohs(((struct sockaddr_in *) sa)->sin_port) == 0) { return bind(fd, sa, salen); } else { gint rc = -1; /* the port is sa is only a hint, the only requirement is that the * allocated port is in the same group, but we need to disable REUSE * address for this to work properly */ if ((sock_flags & ZSF_RANDOM_BIND) == 0) /* in the non-random case, try to bind to the given port */ rc = bind(fd, sa, salen); /* If we're supposed to bind to a random port or we couldn't bind to the specified port, * find another in the same group. */ if ((sock_flags & ZSF_RANDOM_BIND) || (rc < 0 && errno == EADDRINUSE)) { gint range; gint random_limit; /* stop trying to find an open port randomly after reaching this limit (see below) */ guint16 port_min, port_max; guint16 port; guint16 port_mask; /* for random number bounding */ port = ntohs(((struct sockaddr_in *) sa)->sin_port); if (port < 512) { port_min = 1; port_max = 511; port_mask = 0x01ff; } else if (port < 1024) { port_min = 512; port_max = 1023; port_mask = 0x01ff; } else { port_min = 1024; port_max = 65535; port_mask = 0xffff; } port++; range = port_max - port_min + 1; /* Try to select port randomly if required. * Per the current implementation, if the range is too small, we won't try at all. * (none of the above ranges are too small) */ if (sock_flags & ZSF_RANDOM_BIND) { /* try (range/8) ports randomly */ for (random_limit = range / 8; random_limit > 0; random_limit--) { /* get a random port number within the group. binary bounding won't always work * so it's not used */ do { z_random_sequence_get(Z_RANDOM_BASIC, (guchar *) &port, sizeof(port)); /* all ranges are at least 9 bits so we always ask for 16 bits */ port &= port_mask; /* mask bits we don't need */ port += port_min; /* port is normally 0-based, move it into the range */ /* NOTE: this may cause some values to be selected with greater probability with some ranges due to wraparound. * the current ranges are unaffected. */ } while((port < port_min) || (port > port_max)); ((struct sockaddr_in *) sa)->sin_port = htons(port); if (bind(fd, sa, salen) >= 0) { return 0; } else if (errno != EADDRINUSE) { rc = -1; break; } } /* if it wasn't successful, give up and try to find one sequentially. */ } /* try to find a port sequentially */ for (; range > 0; port++, range--) { if (port > port_max) port = port_min; ((struct sockaddr_in *) sa)->sin_port = htons(port); if (bind(fd, sa, salen) >= 0) { return 0; } else if (errno != EADDRINUSE) { rc = -1; break; } } } return rc; } } gint z_do_ll_accept(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags G_GNUC_UNUSED) { return accept(fd, sa, salen); } gint z_do_ll_connect(int fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags G_GNUC_UNUSED) { return connect(fd, sa, salen); } gint z_do_ll_listen(int fd, gint backlog, guint32 sock_flags G_GNUC_UNUSED) { return listen(fd, backlog); } gint z_do_ll_getsockname(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags G_GNUC_UNUSED) { return getsockname(fd, sa, salen); } gint z_do_ll_getpeername(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags G_GNUC_UNUSED) { return getpeername(fd, sa, salen); } /** * Table of socket-related functions. **/ ZSocketFuncs z_socket_funcs = { z_do_ll_bind, z_do_ll_accept, z_do_ll_connect, z_do_ll_listen, z_do_ll_getsockname, z_do_ll_getpeername, z_do_ll_getsockname }; ZSocketFuncs *socket_funcs = &z_socket_funcs; #ifdef G_OS_WIN32 #include gboolean z_socket_init(void) { WSADATA wsa; int res; res = WSAStartup(MAKEWORD(2,0), &wsa); if (res) { /*LOG This message indicates that Winsock startup failed for the given reason. */ z_log(NULL, CORE_DEBUG, 0, "WinSock startup failed; error_code='%d'", WSAGetLastError() ); return FALSE; } return TRUE; } void z_socket_done(void) { WSACleanup(); } #else gboolean z_socket_init(void) { return TRUE; } void z_socket_done(void) { } #endif libzorpll-3.9.4.1/src/socketsource.c000066400000000000000000000117051224546767600173720ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: socketsource.c,v 1.13 2004/05/22 14:04:16 bazsi Exp $ * * Author : bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #ifdef G_OS_WIN32 # include #endif /** * This is the prepare function of ZSocketSource. * * @param[in] s ZSocketSource instance * @param[out] timeout poll timeout * * @see GSourceFuncs documentation. * * @returns always FALSE **/ static gboolean z_socket_source_prepare(GSource *s, gint *timeout) { ZSocketSource *self = (ZSocketSource *) s; if (self->suspended) { self->poll.events = 0; self->poll.revents = 0; *timeout = -1; return FALSE; } else { #ifdef G_OS_WIN32 self->poll.events = G_IO_IN; z_trace(NULL, "WinSock: WSAEventSelect(%d,%d,%o) at %s line %d", self->fd, self->poll.fd, self->cond, __FILE__, __LINE__); if (WSAEventSelect(self->fd, self->poll.fd, self->cond) == SOCKET_ERROR) //(HANDLE) { /*LOG This message indicates that the WinSock setup event setup failed for the given reason. */ z_log(NULL, CORE_ERROR, 0, "Failed to setup WinSock event; error='%s'", g_strerror(errno)); *timeout = -1; return FALSE; } #else self->poll.events = self->cond; #endif } if (self->timeout_time != -1) { *timeout = (self->timeout_time - time(NULL)) * 1000; if (*timeout < 0) *timeout = 0; } else *timeout = -1; return FALSE; } /** * This is the check function of ZSocketSource * * @param[in] s ZSocketSource instance * * @see GSourceFuncs documentation for explanation * * @returns TRUE if it's ready to be dispatched **/ static gboolean z_socket_source_check(GSource *s) { ZSocketSource *self = (ZSocketSource *) s; #ifdef G_OS_WIN32 WSANETWORKEVENTS evs; #endif if (self->timeout_time > 0 && time(NULL) >= self->timeout_time) { self->timed_out = TRUE; return TRUE; } else self->timed_out = FALSE; #ifdef G_OS_WIN32 if (self->acceptevent) return TRUE; WSAEnumNetworkEvents(self->fd, self->poll.fd, &evs); // (HANDLE) self->poll.revents = (gushort)evs.lNetworkEvents; if(evs.lNetworkEvents != 0) self->acceptevent = TRUE; z_trace(NULL, "WinSock: Event %d on fd %d at %s line %d", self->poll.revents, self->poll.fd, __FILE__, __LINE__); #endif return !!self->poll.revents; } /** * This is the dispatch function of ZSocketSource * * @param[in] s ZSocketSource instance * @param[in] callback callback function we're supposed to call * @param[in] user_data parameter for the callback function * * @see GSourceFuncs documentation for explanation **/ static gboolean z_socket_source_dispatch(GSource *s, GSourceFunc callback, gpointer user_data) { ZSocketSource *self = (ZSocketSource *) s; z_trace(NULL, "Dispatching event for fd %d", self->poll.fd); if(!self->suspended) { #ifdef G_OS_WIN32 self->acceptevent = FALSE; #endif return ((ZSocketSourceFunc) callback)(self->timed_out, user_data); } return TRUE; } /** * ZSocketSource's finalize function, see GSourceFuncs documentation for explanation. **/ void z_socket_source_finalize(GSource *source G_GNUC_UNUSED) { #ifdef G_OS_WIN32 ZSocketSource *self = (ZSocketSource *) source; z_trace(NULL, "WinSock: Event #%d destroyed at %s line %d",self->poll.fd, __FILE__, __LINE__); WSACloseEvent( self->poll.fd); //(HANDLE) #endif } /** * ZSocketSource virtual methods. **/ GSourceFuncs z_socket_source_funcs = { z_socket_source_prepare, z_socket_source_check, z_socket_source_dispatch, z_socket_source_finalize, NULL, NULL }; void z_socket_source_suspend(GSource *s) { ZSocketSource *self = (ZSocketSource *) s; z_enter(); self->suspended = TRUE; z_return(); } void z_socket_source_resume(GSource *s) { ZSocketSource *self = (ZSocketSource *) s; z_enter(); self->suspended = FALSE; z_return(); } GSource * z_socket_source_new(gint fd, GIOCondition cond, gint timeout) { ZSocketSource *self; self = (ZSocketSource *) g_source_new(&z_socket_source_funcs, sizeof(ZSocketSource)); #ifdef G_OS_WIN32 self->fd = fd; self->poll.fd = (int)WSACreateEvent(); //by Abi #else self->poll.fd = fd; #endif self->cond = cond; g_source_add_poll(&self->super, &self->poll); g_source_set_can_recurse(&self->super, FALSE); if (timeout != -1) self->timeout_time = time(NULL) + timeout; else self->timeout_time = -1; return &self->super; } libzorpll-3.9.4.1/src/source.c000066400000000000000000000176061224546767600161670ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: source.c,v 1.27 2004/05/22 14:04:16 bazsi Exp $ * * Author : SaSa * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include /** * Miscellaneous source objects for use throughout the ZMS **/ typedef struct _ZThresholdSource { GSource super; guint idle_threshold; guint busy_threshold; time_t last_call; time_t start_time; } ZThresholdSource; /** * prepare() function for the threshold source * * @param[in] s source object * @param[out] timeout returns the calculated timeout here * * @returns always FALSE **/ static gboolean z_threshold_source_prepare(GSource *s, gint *timeout) { ZThresholdSource *self = (ZThresholdSource *)s; time_t now; now = time(NULL); self->start_time = now; *timeout = MIN(self->idle_threshold, self->busy_threshold + self->last_call - now) * 1000; return FALSE; } /** * check() function for the threshold source * * @param[in] s source object **/ static gboolean z_threshold_source_check(GSource *s) { ZThresholdSource *self = (ZThresholdSource *) s; time_t now; gboolean ret; z_enter(); now = time(NULL); ret = ((time_t)(self->start_time + self->idle_threshold) <= now); ret = ret || ((time_t)(self->last_call + self->busy_threshold) <= now); z_return(ret); } /** * dispatch() function for the threshold source * * @param[in] s source object * @param[in] callback callback function associated with the source * @param[in] user_data pointer to be passed to the callback function * * @returns FALSE if the callback function was not set; whatever the callback function returned otherwise. **/ static gboolean z_threshold_source_dispatch(GSource *s, GSourceFunc callback, gpointer user_data) { ZThresholdSource *self = (ZThresholdSource *)s; gboolean rc = FALSE; z_enter(); if (callback != NULL) { rc = (*callback) (user_data); self->last_call = time(NULL); } else { /*LOG This message indicates an internal error. Please report this error to the QA team. */ z_log(NULL, CORE_ERROR, 4, "Threshold callback function not set;"); } z_return(rc); } /** * ZThresholdSource virtual methods. **/ static GSourceFuncs z_threshold_source_funcs = { z_threshold_source_prepare, z_threshold_source_check, z_threshold_source_dispatch, NULL, NULL, NULL }; /** * Creates new ZThresholdSource instance. * * @param[in] idle_threshold idle threshold * @param[in] busy_threshold busy threshold * * @returns new ZThresholdSource instance **/ GSource * z_threshold_source_new(guint idle_threshold, guint busy_threshold) { ZThresholdSource *self; self = (ZThresholdSource *) g_source_new(&z_threshold_source_funcs, sizeof(ZThresholdSource)); self->idle_threshold = idle_threshold; self->busy_threshold = busy_threshold; return &self->super; } /** * This function changes the thresholds associated with the threshold source. * * @param[in] source the threshold source instance * @param[in] idle_threshold new idle threshold * @param[in] busy_threshold new busy threshold **/ void z_threshold_source_set_threshold(GSource *source, guint idle_threshold, guint busy_threshold) { ZThresholdSource *self = (ZThresholdSource *) source; self->idle_threshold = idle_threshold; self->busy_threshold = busy_threshold; } /** * GSource descendant class to generate an event on timeout. * * The timeout can be disabled by setting timeout_target.tv_sec = timeout_target.tv_usec = 0 **/ typedef struct _ZTimeoutSource { GSource super; GTimeVal timeout_target; /**< When the timeout will expire. */ } ZTimeoutSource; /** * Checks if the ZTimeoutSource instance is enabled. * * @param[in] self the ZTimeoutSource instance * * Disabled state is shown by setting timeout_target.tv_sec = timeout_target.tv_usec = 0 **/ static gboolean z_timeout_source_enabled(ZTimeoutSource *self) { if (self->timeout_target.tv_sec > 0) return TRUE; else if (self->timeout_target.tv_sec < 0) return FALSE; else return self->timeout_target.tv_usec > 0; } /** * prepare() function for the timeout source * * @param[in] s source object * @param[out] timeout returns the calculated timeout here **/ static gboolean z_timeout_source_prepare(GSource *s, gint *timeout) { ZTimeoutSource *self = (ZTimeoutSource *)s; GTimeVal now; if (!z_timeout_source_enabled(self)) return FALSE; g_get_current_time(&now); if (g_time_val_compare(&self->timeout_target, &now) <= 0) return TRUE; else if (timeout) *timeout = g_time_val_diff(&self->timeout_target, &now) / 1000; return FALSE; } /** * check() function for the timeout source * * @param[in] s source object **/ static gboolean z_timeout_source_check(GSource *s) { ZTimeoutSource *self = (ZTimeoutSource *) s; GTimeVal now; if (!z_timeout_source_enabled(self)) return FALSE; g_get_current_time(&now); return g_time_val_compare(&self->timeout_target, &now) <= 0; } /** * dispatch() function for the timeout source * * @param s source object (not used) * @param[in] callback callback function associated with the source * @param[in] user_data pointer to be passed to the callback function **/ static gboolean z_timeout_source_dispatch(GSource *s G_GNUC_UNUSED, GSourceFunc callback, gpointer user_data) { return (*callback)(user_data); } /** * ZTimeoutSource virtual methods. **/ static GSourceFuncs z_timeout_source_funcs = { z_timeout_source_prepare, z_timeout_source_check, z_timeout_source_dispatch, NULL, NULL, NULL }; /** * This function changes the timeout associated to the timeout source * pointed to by source. * * @param[in] source a reference to the timeout source * @param[in] new_timeout the new timeout value in milliseconds **/ void z_timeout_source_set_timeout(GSource *source, gulong new_timeout) { ZTimeoutSource *self = (ZTimeoutSource *) source; g_get_current_time(&self->timeout_target); self->timeout_target.tv_sec += new_timeout / 1000; g_time_val_add(&self->timeout_target, (new_timeout % 1000) * 1000); } /** * This function changes when the callback should be called next time. * * @param[in] source a reference to the timeout source * @param[in] nexttime the next time the callback should be called **/ void z_timeout_source_set_time(GSource *source, GTimeVal *nexttime) { ZTimeoutSource *self = (ZTimeoutSource *) source; self->timeout_target.tv_sec = nexttime->tv_sec; self->timeout_target.tv_usec = nexttime->tv_usec; } /** * This function disables the timeout source pointed to by source. * * @param[in] source a reference to the timeout source **/ void z_timeout_source_disable(GSource *source) { ZTimeoutSource *self = (ZTimeoutSource *) source; self->timeout_target.tv_sec = -1; } /** * This function creates and initializes a source which issues a callback * when a given timeout elapses. * * @param[in] initial_timeout the initial timeout value in milliseconds * * It does not matter how many times the poll() loop runs as the time is * saved as the target time instead of an interval which would start each * time the poll loop is run. **/ GSource * z_timeout_source_new(gulong initial_timeout) { ZTimeoutSource *self; self = (ZTimeoutSource *) g_source_new(&z_timeout_source_funcs, sizeof(ZTimeoutSource)); z_timeout_source_set_timeout((GSource*)self, initial_timeout); return &self->super; } libzorpll-3.9.4.1/src/ssl.c000066400000000000000000001024521224546767600154620ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: ssl.c,v 1.37 2004/05/22 14:04:16 bazsi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ /** * @file * interface between Zorp and the SSL library **/ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #undef X509_NAME #include #include #if ZORPLIB_ENABLE_SSL_ENGINE #include gchar *crypto_engine = NULL; #endif static int ssl_initialized = 0; #if GLIB_MINOR_VERSION >=32 static GMutex *ssl_mutexes; #else static GStaticMutex *ssl_mutexes; #endif static int mutexnum; /** * Fetch OpenSSL error code and generate a string interpretation of it. * * @param[out] buf buffer to put string into * @param[in] buflen size of buffer * * @returns buf **/ gchar * z_ssl_get_error_str(gchar *buf, int buflen) { const char *ls, *fs, *rs; unsigned long e, l, f, r; unsigned long new_error = 0; gint count = -1; do { e = new_error; new_error= ERR_get_error(); ++count; } while (new_error); l = ERR_GET_LIB(e); f = ERR_GET_FUNC(e); r = ERR_GET_REASON(e); ls = ERR_lib_error_string(e); fs = ERR_func_error_string(e); rs = ERR_reason_error_string(e); if (count) g_snprintf(buf, buflen, "error:%08lX:%s:lib(%lu):%s:func(%lu):%s:reason(%lu), supressed %d messages", e, ls ? ls : "(null)", l, fs ? fs : "(null)", f, rs ? rs : "(null)", r, count); else g_snprintf(buf, buflen, "error:%08lX:%s:lib(%lu):%s:func(%lu):%s:reason(%lu)", e, ls ? ls : "(null)", l, fs ? fs : "(null)", f, rs ? rs : "(null)", r); return buf; } /** * Callback used by OpenSSL to lock/unlock mutexes. * * @param[in] mode whether to lock or unlock the mutex * @param[in] n number of mutex * @param file unused * @param line unused **/ static void z_ssl_locking_callback(int mode, int n, const char *file G_GNUC_UNUSED, int line G_GNUC_UNUSED) { z_enter(); if (n >= mutexnum) { /*LOG This message indicates that the OpenSSL library is broken, since it tried to use more mutexes than it originally requested. Check your OpenSSL library version. */ z_log(NULL, CORE_ERROR, 4, "SSL requested an out of bounds mutex; max='%d', n='%d'", mutexnum, n); } if (mode & CRYPTO_LOCK) { z_trace(NULL, "Mutex %d locked", n); #if GLIB_MINOR_VERSION >=32 g_mutex_lock(&ssl_mutexes[n]); #else g_static_mutex_lock(&ssl_mutexes[n]); #endif } else { z_trace(NULL, "Mutex %d unlocked", n); #if GLIB_MINOR_VERSION >= 32 g_mutex_unlock(&ssl_mutexes[n]); #else g_static_mutex_unlock(&ssl_mutexes[n]); #endif } z_return(); } /** * Initialize mutexes and set mutex locking callback for OpenSSL. **/ static void z_ssl_init_mutexes(void) { z_enter(); mutexnum = CRYPTO_num_locks(); #if GLIB_MINOR_VERSION >=32 ssl_mutexes = g_new0(GMutex, mutexnum); #else ssl_mutexes = g_new0(GStaticMutex, mutexnum); #endif z_enter(); CRYPTO_set_locking_callback(z_ssl_locking_callback); z_return(); } /** * Free OpenSSL error queue. * * @param thread unused * @param user_data unused * * This function frees the OpenSSL error queue for the current thread. **/ static void z_ssl_remove_error_state(ZThread *thread G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { ERR_remove_state(0); } /** * Process ID callback function for OpenSSL. * * @returns pid * * @note See crypto_set_id_callback(3) for notes on what this is supposed to do. **/ static unsigned long z_ssl_get_id(void) { return (unsigned long) g_thread_self(); } /** * Initialize OpenSSL library. **/ void z_ssl_init() { z_enter(); if (ssl_initialized) z_return(); CRYPTO_set_id_callback(z_ssl_get_id); SSL_library_init(); SSL_load_error_strings(); SSLeay_add_all_algorithms(); #if ZORPLIB_ENABLE_SSL_ENGINE ENGINE_load_builtin_engines(); if (crypto_engine) { ENGINE *e; e = ENGINE_by_id(crypto_engine); if (!e) { e = ENGINE_by_id("dynamic"); if (!e || !ENGINE_ctrl_cmd_string(e, "SO_PATH", crypto_engine, 0) || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { ENGINE_free(e); e = NULL; /*LOG This message indicates that an error occurred during the crypto engine load. Check your SSL crypto card installation. */ z_log(NULL, CORE_ERROR, 1, "Error loading SSL engine module; crypto_engine='%s'", crypto_engine); } } if (e) { if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { /*LOG This message indicates that an error occurred during the crypto engine initialization. Check your SSL crypto card installation. */ z_log(NULL, CORE_ERROR, 1, "Error initializing SSL crypto engine; crypto_engine='%s'", crypto_engine); } ENGINE_free(e); } else { /*LOG This message indicates that the given SSL crypto engine is not found. Check your SSL crypto card installation, and the crypto engines name. */ z_log(NULL, CORE_ERROR, 1, "No such SSL crypto engine; crypto_engine='%s'", crypto_engine); } } #endif z_ssl_init_mutexes(); z_thread_register_stop_callback((GFunc) z_ssl_remove_error_state, NULL); ssl_initialized = 1; z_return(); } /** * Deinitialize OpenSSL library. **/ void z_ssl_destroy(void) { ssl_initialized = 0; } /** * Lookup name in X.509 certificate verification store. * * @param store certificate verification store * @param type type * @param name name * @param obj object * * @todo FIXME-DOC: Document this once proper OpenSSL documentation is discovered. **/ static int z_ssl_x509_store_lookup(X509_STORE *store, int type, X509_NAME *name, X509_OBJECT *obj) { X509_STORE_CTX store_ctx; int rc; z_enter(); X509_STORE_CTX_init(&store_ctx, store, NULL, NULL); rc = X509_STORE_get_by_subject(&store_ctx, type, name, obj); X509_STORE_CTX_cleanup(&store_ctx); z_return(rc); } int z_ssl_verify_crl(int ok, X509 *xs, X509_STORE_CTX *ctx, X509_STORE *crl_store, const gchar *session_id) { X509_OBJECT obj; X509_NAME *subject, *issuer; X509_CRL *crl; char subject_name[512], issuer_name[512]; int rc; z_enter(); subject = X509_get_subject_name(xs); X509_NAME_oneline(subject, subject_name, sizeof(subject_name)); issuer = X509_get_issuer_name(xs); X509_NAME_oneline(issuer, issuer_name, sizeof(issuer_name)); memset((char *)&obj, 0, sizeof(obj)); rc = z_ssl_x509_store_lookup(crl_store, X509_LU_CRL, subject, &obj); crl = obj.data.crl; if (rc > 0 && crl != NULL) { /* * Log information about CRL * (A little bit complicated because of ASN.1 and BIOs...) */ BIO *bio; char *cp; EVP_PKEY *pkey; int n, i; bio = BIO_new(BIO_s_mem()); BIO_printf(bio, "lastUpdate='"); ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl)); BIO_printf(bio, "', nextUpdate='"); ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl)); BIO_printf(bio, "'"); n = BIO_pending(bio); cp = alloca(n+1); n = BIO_read(bio, cp, n); cp[n] = 0; BIO_free(bio); /*LOG This message reports that the CA CRL verify starts for the given CA. */ z_log(session_id, CORE_DEBUG, 6, "Verifying CA CRL; issuer='%s', %s", subject_name, cp); pkey = X509_get_pubkey(xs); if (X509_CRL_verify(crl, pkey) <= 0) { /*LOG This message indicates an invalid Certificate Revocation List (CRL), because it is not signed by the CA it is said to belong to. */ z_log(session_id, CORE_ERROR, 1, "Invalid signature on CRL; issuer='%s'", subject_name); X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); X509_OBJECT_free_contents(&obj); EVP_PKEY_free(pkey); z_return(FALSE); } EVP_PKEY_free(pkey); i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); if (i == 0) { /*LOG This message indicates an invalid Certificate Revocation List (CRL), because it has an invalid nextUpdate field. */ z_log(session_id, CORE_ERROR, 1, "CRL has invalid nextUpdate field; issuer='%s'", subject_name); X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); X509_OBJECT_free_contents(&obj); z_return(FALSE); } if (i < 0) { /*LOG This message indicates an invalid Certificate Revocation List (CRL), because it is expired. */ z_log(session_id, CORE_ERROR, 1, "CRL is expired; issuer='%s'", subject_name); X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); X509_OBJECT_free_contents(&obj); z_return(FALSE); } X509_OBJECT_free_contents(&obj); } memset((char *)&obj, 0, sizeof(obj)); rc = z_ssl_x509_store_lookup(crl_store, X509_LU_CRL, issuer, &obj); crl = obj.data.crl; if (rc > 0 && crl != NULL) { X509_REVOKED *revoked; long serial; int i, n; n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); for (i = 0; i < n; i++) { revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(xs)) == 0) { serial = ASN1_INTEGER_get(revoked->serialNumber); /*LOG This message indicates that a certificate verification failed, because the issuing CA revoked it in its Certificate Revocation List. */ z_log(session_id, CORE_ERROR, 1, "Certificate revoked by CRL; issuer='%s', serial=0x%lX", issuer_name, serial); X509_OBJECT_free_contents(&obj); z_return(FALSE); } } X509_OBJECT_free_contents(&obj); } z_return(ok); } int z_ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { ZSSLSession *verify_data; SSL *ssl; X509 *xs; char subject_name[512], issuer_name[512]; int errnum; int errdepth; int forced_ok = FALSE; z_enter(); ssl = (SSL *) X509_STORE_CTX_get_app_data(ctx); verify_data = (ZSSLSession *) SSL_get_app_data(ssl); xs = X509_STORE_CTX_get_current_cert(ctx); errnum = X509_STORE_CTX_get_error(ctx); errdepth = X509_STORE_CTX_get_error_depth(ctx); X509_NAME_oneline(X509_get_subject_name(xs), subject_name, sizeof(subject_name)); X509_NAME_oneline(X509_get_issuer_name(xs), issuer_name, sizeof(issuer_name)); /*LOG This message indicates that the given certificate is being checked against validity. */ z_log(verify_data->session_id, CORE_DEBUG, 6, "Verifying certificate; depth='%d', subject='%s', issuer='%s'", errdepth, subject_name, issuer_name); if ((verify_data->verify_type == Z_SSL_VERIFY_REQUIRED_UNTRUSTED || verify_data->verify_type == Z_SSL_VERIFY_OPTIONAL) && (errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT || errnum == X509_V_ERR_CERT_UNTRUSTED || errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) { /*LOG This message indicates that certificate verification failed, but it is ignored since the administrator requested optional certificate verification. */ z_log(verify_data->session_id, CORE_ERROR, 4, "Untrusted certificate, ignoring because verification is not mandatory; subject='%s', issuer='%s'", subject_name, issuer_name); ok = TRUE; forced_ok = TRUE; } if (ok && verify_data->crl_store) { ok = z_ssl_verify_crl(ok, xs, ctx, verify_data->crl_store, verify_data->session_id); if (!ok) { errnum = X509_STORE_CTX_get_error(ctx); /*LOG This message indicates that a certificate verification failed, because the issuing CA revoked it in its Certificate Revocation List. */ z_log(verify_data->session_id, CORE_ERROR, 1, "Certificate is revoked; subject='%s', issuer='%s'", subject_name, issuer_name); } } if (ok && (verify_data->verify_depth != -1) && (errdepth > verify_data->verify_depth)) { /*LOG Certificate was verified successfully, but the length of the verification chain is over configured limits. */ z_log(verify_data->session_id, CORE_ERROR, 1, "Certificate chain is too long; subject='%s', issuer='%s' depth='%d' maxdepth='%d'", subject_name, issuer_name, errdepth, verify_data->verify_depth); errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG; ok = FALSE; } if (!ok) /*LOG This message indicates that certificate could not be verified, and the certificate is treated as invalid. */ z_log(verify_data->session_id, CORE_ERROR, 1, "Certificate verification error; subject='%s', issuer='%s', errcode='%d', error='%s'", subject_name, issuer_name, errnum, X509_verify_cert_error_string(errnum)); z_return(ok || forced_ok); } X509_STORE * z_ssl_crl_store_create(gchar *crl_path) { X509_STORE *store; X509_LOOKUP *lookup; z_enter(); if ((store = X509_STORE_new()) == NULL) z_return(NULL); if (crl_path != NULL) { if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) == NULL) { X509_STORE_free(store); z_return(NULL); } X509_LOOKUP_add_dir(lookup, crl_path, X509_FILETYPE_PEM); } z_return(store); } typedef struct _ZSSLCADirectory { time_t modtime; STACK_OF(X509_NAME) *contents; } ZSSLCADirectory; static int z_ssl_X509_name_cmp(const X509_NAME * const *a, const X509_NAME * const *b) { return(X509_NAME_cmp(*a, *b)); } static STACK_OF(X509_NAME) * z_ssl_dup_sk_x509_name(STACK_OF(X509_NAME) *old) { STACK_OF(X509_NAME) *sk; int i; z_enter(); sk = sk_X509_NAME_new_null(); for (i = 0; i < sk_X509_NAME_num(old); i++) { X509_NAME *xn; xn = sk_X509_NAME_value(old, i); sk_X509_NAME_push(sk, X509_NAME_dup(xn)); } z_return(sk); } gboolean z_ssl_set_trusted_ca_list(SSL_CTX *ctx, gchar *ca_path) { ZSSLCADirectory *ca_dir = NULL; static GHashTable *ca_dir_hash = NULL; G_LOCK_DEFINE_STATIC(lock); STACK_OF(X509_NAME) *ca_file = NULL; const gchar *direntname; struct stat ca_stat; GDir *dir; z_enter(); G_LOCK(lock); if (ca_dir_hash == NULL) { ca_dir_hash = g_hash_table_new(g_str_hash, g_str_equal); } else { gpointer orig_key; gpointer value; if (g_hash_table_lookup_extended(ca_dir_hash, ca_path, &orig_key, &value)) { ca_dir = (ZSSLCADirectory *) value; if (stat(ca_path, &ca_stat) >= 0 && ca_dir->modtime == ca_stat.st_mtime) { SSL_CTX_set_client_CA_list(ctx, z_ssl_dup_sk_x509_name(ca_dir->contents)); G_UNLOCK(lock); z_return(TRUE); } g_hash_table_remove(ca_dir_hash, orig_key); g_free(orig_key); sk_X509_NAME_pop_free(ca_dir->contents, X509_NAME_free); g_free(ca_dir); } } if (stat(ca_path, &ca_stat) < 0) { G_UNLOCK(lock); z_return(FALSE); } ca_dir = g_new0(ZSSLCADirectory, 1); ca_dir->modtime = ca_stat.st_mtime; ca_dir->contents = sk_X509_NAME_new(z_ssl_X509_name_cmp); dir = g_dir_open(ca_path,0,NULL); if (dir) { while ((direntname = g_dir_read_name(dir)) != NULL) { char file_name[256]; int i; g_snprintf(file_name, sizeof(file_name), "%s/%s", ca_path, direntname); ca_file = SSL_load_client_CA_file(file_name); if (!ca_file) { /*LOG This message indicates that an error occurred during loading client CA certificates from the given file. It is likely that the file is not readable or it is in a wrong format. */ z_log(NULL, CORE_ERROR, 4, "Error loading CA certificate bundle, skipping; filename='%s'", file_name); continue; } for (i = 0; ca_file != NULL && i < sk_X509_NAME_num(ca_file); i++) { if (sk_X509_NAME_find(ca_dir->contents, sk_X509_NAME_value(ca_file, i)) < 0) sk_X509_NAME_push(ca_dir->contents, sk_X509_NAME_value(ca_file, i)); else X509_NAME_free(sk_X509_NAME_value(ca_file, i)); } sk_X509_NAME_free(ca_file); } } g_hash_table_insert(ca_dir_hash, g_strdup(ca_path), ca_dir); SSL_CTX_set_client_CA_list(ctx, z_ssl_dup_sk_x509_name(ca_dir->contents)); g_dir_close(dir); G_UNLOCK(lock); z_return(TRUE); } /* FIXME: SSL context cache */ #ifndef G_OS_WIN32 static int z_ssl_password(char *buf G_GNUC_UNUSED, int size G_GNUC_UNUSED, int rwflag G_GNUC_UNUSED, void *userdata G_GNUC_UNUSED) { z_log(NULL, CORE_ERROR, 1, "Password protected key file detected;"); return -1; } static SSL_CTX * z_ssl_create_ctx(const char *session_id, int mode) { SSL_CTX *ctx; char buf[128]; z_enter(); if (mode == Z_SSL_MODE_CLIENT) ctx = SSL_CTX_new(SSLv23_client_method()); else ctx = SSL_CTX_new(SSLv23_server_method()); if (!ctx) { /*LOG This message indicates that an SSL_CTX couldn't be allocated, it usually means that Zorp has not enough memory. You might want to check your ulimit settings and/or the available physical/virtual RAM in your firewall host. */ z_log(session_id, CORE_ERROR, 3, "Error allocating new SSL_CTX; error='%s'", z_ssl_get_error_str(buf, sizeof(buf))); z_return(NULL); } SSL_CTX_set_options(ctx, SSL_OP_ALL); z_return(ctx); } static gboolean z_ssl_load_privkey_and_cert(const char *session_id, SSL_CTX *ctx, gchar *key_file, gchar *cert_file) { char buf[128]; z_enter(); if (key_file && key_file[0]) { SSL_CTX_set_default_passwd_cb(ctx, z_ssl_password); if (!SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM)) { /*LOG This message indicates that the given private key could not be loaded. Either the private key is not in PEM format, or the key data was encrypted. */ z_log(session_id, CORE_ERROR, 3, "Error loading private key; keyfile='%s', error='%s'", key_file, z_ssl_get_error_str(buf, sizeof(buf))); z_return(FALSE); } if (!SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM)) { /*LOG This message indicates that the given certificate file could not be loaded. It might not be in PEM format or otherwise corrupted. */ z_log(session_id, CORE_ERROR, 3, "Error loading certificate file; keyfile='%s', certfile='%s', error='%s'", key_file, cert_file, z_ssl_get_error_str(buf, sizeof(buf))); z_return(FALSE); } if (!SSL_CTX_check_private_key(ctx)) { /*LOG This message indicates that the private key and corresponding certificate do not match. */ z_log(session_id, CORE_ERROR, 3, "Certificate and private key mismatch; keyfile='%s', certfile='%s', error='%s'", key_file, cert_file, z_ssl_get_error_str(buf, sizeof(buf))); z_return(FALSE); } /*LOG This message reports that the given private key- and certificate files were successfully loaded. */ z_log(session_id, CORE_DEBUG, 6, "Certificate file successfully loaded; keyfile='%s', certfile='%s'", key_file, cert_file); } z_return(TRUE); } static gboolean z_ssl_set_privkey_and_cert(const char *session_id, SSL_CTX *ctx, GString *key_pem, GString *cert_pem) { char buf[128]; z_enter(); if (key_pem && key_pem->len) { EVP_PKEY *epk; RSA *rsa; BIO *bio; X509 *x509; bio = BIO_new_mem_buf(key_pem->str, key_pem->len); if (!bio) { z_log(session_id, CORE_ERROR, 3, "Cannot create BIO for private key;"); z_return(FALSE); } rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); BIO_free(bio); if (!rsa) { z_log(session_id, CORE_ERROR, 3, "Cannot parse rsa private key;"); z_return(FALSE); } epk = EVP_PKEY_new(); EVP_PKEY_assign_RSA(epk, rsa); SSL_CTX_set_default_passwd_cb(ctx, z_ssl_password); if (!SSL_CTX_use_PrivateKey(ctx, epk)) { /*LOG This message indicates that the given private key could not be loaded. Either the private key is not in PEM format, or the key data was encrypted. */ z_log(session_id, CORE_ERROR, 3, "Error loading private key; error='%s'", z_ssl_get_error_str(buf, sizeof(buf))); EVP_PKEY_free(epk); z_return(FALSE); } EVP_PKEY_free(epk); bio = BIO_new_mem_buf(cert_pem->str, cert_pem->len); if (!bio) { z_log(session_id, CORE_ERROR, 3, "Cannot create BIO for certificate;"); z_return(FALSE); } x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); BIO_free(bio); if (!SSL_CTX_use_certificate(ctx, x509)) { /*LOG This message indicates that the given certificate file could not be loaded. It might not be in PEM format or otherwise corrupted. */ z_log(session_id, CORE_ERROR, 3, "Error loading certificate; error='%s'", z_ssl_get_error_str(buf, sizeof(buf))); X509_free(x509); z_return(FALSE); } X509_free(x509); if (!SSL_CTX_check_private_key(ctx)) { /*LOG This message indicates that the private key and corresponding certificate do not match. */ z_log(session_id, CORE_ERROR, 3, "Certificate and private key mismatch; error='%s'", z_ssl_get_error_str(buf, sizeof(buf))); z_return(FALSE); } /*LOG This message reports that the given private key- and certificate files were successfully loaded. */ z_log(session_id, CORE_DEBUG, 6, "Certificate successfully loaded;"); } z_return(TRUE); } static gboolean z_ssl_load_ca_list(const char *session_id, SSL_CTX *ctx, int mode, gchar *ca_dir, gchar *crl_dir, X509_STORE **crl_store) { z_enter(); if (ca_dir && ca_dir[0]) { if (mode == Z_SSL_MODE_SERVER) { if (!z_ssl_set_trusted_ca_list(ctx, ca_dir)) { /*LOG This message indicates that loading the trustable CA certificates failed. The TLS peer is told which CAs we trust to ease the selection of certificates. This could mean that one or more of your CA certificates are invalid. */ z_log(session_id, CORE_ERROR, 3, "Error loading trusted CA list; cadir='%s'", ca_dir); z_return(FALSE); } } if (access(ca_dir, R_OK | X_OK) < 0) { z_log(session_id, CORE_ERROR, 3, "Insufficient permissions to CA directory; cadir='%s', error='%s'", ca_dir, g_strerror(errno)); z_return(FALSE); } if (!SSL_CTX_load_verify_locations(ctx, NULL, ca_dir)) { /*LOG This message indicates that setting the trusted CA directory for verification failed. */ z_log(session_id, CORE_ERROR, 3, "Cannot add trusted CA directory as verify location; cadir='%s'", ca_dir); z_return(FALSE); } if (crl_dir && crl_dir[0]) { if (access(crl_dir, R_OK | X_OK) < 0) { z_log(session_id, CORE_ERROR, 3, "Insufficient permissions to CRL directory; crldir='%s', error='%s'", crl_dir, g_strerror(errno)); z_return(FALSE); } *crl_store = z_ssl_crl_store_create(crl_dir); } else { /*LOG This message reports that CRLs are not in use for certificate verification. */ z_log(session_id, CORE_DEBUG, 6, "Certificate Revocation Lists not available;"); } } z_return(TRUE); } static ZSSLSession * z_ssl_session_new_from_context(const char *session_id, SSL_CTX *ctx, int verify_depth, int verify_type, X509_STORE *crl_store) { ZSSLSession *self = NULL; SSL *session; int verify_mode = 0; z_enter(); session = SSL_new(ctx); if (!session) { /*LOG This message indicates that creating the SSL session structure failed. It's usually caused by out-of-memory conditions. */ z_log(session_id, CORE_ERROR, 3, "Error creating SSL session from SSL_CTX;"); if (crl_store) X509_STORE_free(crl_store); z_return(NULL); } self = g_new0(ZSSLSession, 1); self->ref_cnt = 1; self->ssl = session; self->session_id = session_id; self->verify_type = verify_type; self->verify_depth = verify_depth; self->crl_store = crl_store; SSL_set_app_data(session, self); if (verify_type == Z_SSL_VERIFY_OPTIONAL || verify_type == Z_SSL_VERIFY_REQUIRED_UNTRUSTED) verify_mode = SSL_VERIFY_PEER; if (verify_type == Z_SSL_VERIFY_REQUIRED_TRUSTED) verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; if (verify_mode != 0) SSL_set_verify(session, verify_mode, z_ssl_verify_callback); z_return(self); } ZSSLSession * z_ssl_session_new_inline(const char *session_id, int mode, GString *key_pem, GString *cert_pem, gchar *ca_dir, gchar *crl_dir, int verify_depth, int verify_type) { ZSSLSession *self; SSL_CTX *ctx; X509_STORE *crl_store = NULL; z_enter(); ctx = z_ssl_create_ctx(session_id, mode); if (!ctx) z_return(NULL); if (!z_ssl_set_privkey_and_cert(session_id, ctx, key_pem, cert_pem) || !z_ssl_load_ca_list(session_id, ctx, mode, ca_dir, crl_dir, &crl_store)) { SSL_CTX_free(ctx); z_return(NULL); } self = z_ssl_session_new_from_context(session_id, ctx, verify_depth, verify_type, crl_store); SSL_CTX_free(ctx); z_return(self); } ZSSLSession * z_ssl_session_new(const char *session_id, int mode, gchar *key_file, gchar *cert_file, gchar *ca_dir, gchar *crl_dir, int verify_depth, int verify_type) { ZSSLSession *self; SSL_CTX *ctx; X509_STORE *crl_store = NULL; z_enter(); ctx = z_ssl_create_ctx(session_id, mode); if (!ctx) z_return(NULL); if (!z_ssl_load_privkey_and_cert(session_id, ctx, key_file, cert_file) || !z_ssl_load_ca_list(session_id, ctx, mode, ca_dir, crl_dir, &crl_store)) { SSL_CTX_free(ctx); z_return(NULL); } self = z_ssl_session_new_from_context(session_id, ctx, verify_depth, verify_type, crl_store); SSL_CTX_free(ctx); z_return(self); } #else ZSSLSession * z_ssl_session_new(const char *session_id, int mode, X509_STORE *store, int verify_depth, int verify_type) { ZSSLSession *self; SSL_CTX *ctx; SSL *session; int verify_mode = 0; char buf[128]; z_enter(); if (mode == Z_SSL_MODE_CLIENT) ctx = SSL_CTX_new(SSLv23_client_method()); else ctx = SSL_CTX_new(SSLv23_server_method()); if (!ctx) { /*LOG This message indicates that an SSL_CTX couldn't be allocated, it usually means that Zorp has not enough memory. You might want to check your ulimit settings and/or the available physical/virtual RAM in your firewall host. */ z_log(session_id, CORE_ERROR, 3, "Error allocating new SSL_CTX; error='%s'", z_ssl_get_error_str(buf, sizeof(buf))); z_return(NULL); } SSL_CTX_set_options(ctx, SSL_OP_ALL); if (store) SSL_CTX_set_cert_store(ctx, store); session = SSL_new(ctx); SSL_CTX_free(ctx); if (!session) { /*LOG This message indicates that creating the SSL session structure failed. It's usually caused by out-of-memory conditions. */ z_log(session_id, CORE_ERROR, 3, "Error creating SSL session from SSL_CTX;"); if (store) X509_STORE_free(store); z_return(NULL); } /* FIXME: CRL handling */ self = g_new0(ZSSLSession, 1); self->ref_cnt = 1; self->ssl = session; self->session_id = session_id; self->verify_type = verify_type; self->verify_depth = verify_depth; SSL_set_app_data(session, self); if (verify_type == Z_SSL_VERIFY_OPTIONAL || verify_type == Z_SSL_VERIFY_REQUIRED_UNTRUSTED) verify_mode = SSL_VERIFY_PEER; if (verify_type == Z_SSL_VERIFY_REQUIRED_TRUSTED) verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; if (verify_mode != 0) SSL_set_verify(session, verify_mode, z_ssl_verify_callback); z_return(self); } #endif ZSSLSession * z_ssl_session_new_ssl(SSL *ssl) { ZSSLSession *self = g_new0(ZSSLSession, 1); self->ref_cnt = 1; self->ssl = ssl; CRYPTO_add(&ssl->references, 1, CRYPTO_LOCK_SSL); return self; } static void z_ssl_session_free(ZSSLSession *self) { z_enter(); /* free verify_data */ SSL_free(self->ssl); if (self->crl_store) X509_STORE_free(self->crl_store); g_free(self); z_return(); } ZSSLSession * z_ssl_session_ref(ZSSLSession *self) { self->ref_cnt++; return self; } void z_ssl_session_unref(ZSSLSession *self) { if (self && --self->ref_cnt == 0) { z_ssl_session_free(self); } } /* SSL BIO functions */ typedef struct _ZStreamBio { BIO super; ZStream *stream; } ZStreamBio; int z_stream_bio_write(BIO *bio, const char *buf, int buflen) { ZStreamBio *self = (ZStreamBio *)bio; int rc = -1; GIOStatus ret; gsize write_size; z_enter(); if (buf != NULL) { ret = z_stream_write(self->stream, buf, buflen, &write_size, NULL); rc = (int)write_size; BIO_clear_retry_flags(bio); if (ret == G_IO_STATUS_AGAIN) { BIO_set_retry_write(bio); z_return(-1); } if (ret != G_IO_STATUS_NORMAL) z_return(-1); } z_return(rc); } int z_stream_bio_read(BIO *bio, char *buf, int buflen) { ZStreamBio *self = (ZStreamBio *)bio; int rc = -1; GIOStatus ret; gsize read_size; z_enter(); if (buf != NULL) { ret = z_stream_read(self->stream, buf, buflen, &read_size, NULL); rc = (int)read_size; BIO_clear_retry_flags(bio); if (ret == G_IO_STATUS_AGAIN) { BIO_set_retry_read(bio); z_return(-1); } if (ret == G_IO_STATUS_EOF) z_return(0); if (ret != G_IO_STATUS_NORMAL) z_return(-1); } z_return(rc); } int z_stream_bio_puts(BIO *bio, const char *str) { int n, ret; z_enter(); n = strlen(str); ret = z_stream_bio_write(bio, str, n); z_return(ret); } long z_stream_bio_ctrl(BIO *bio, int cmd, long num, void *ptr G_GNUC_UNUSED) { long ret = 1; z_enter(); switch (cmd) { case BIO_CTRL_GET_CLOSE: ret = bio->shutdown; break; case BIO_CTRL_SET_CLOSE: bio->shutdown = (int)num; break; case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret = 1; break; case BIO_CTRL_RESET: case BIO_C_FILE_SEEK: case BIO_C_FILE_TELL: case BIO_CTRL_INFO: case BIO_C_SET_FD: case BIO_C_GET_FD: case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: default: ret = 0; break; } z_return(ret); } int z_stream_bio_create(BIO *bio) { z_enter(); bio->init = 1; bio->num = 0; bio->ptr = NULL; bio->flags = 0; z_return(1); } int z_stream_bio_destroy(BIO *bio) { ZStreamBio *self = (ZStreamBio *)bio; z_enter(); if (self == NULL) z_return(0); if (self->super.shutdown) { z_stream_shutdown(self->stream, 2, NULL); bio->init = 0; bio->flags = 0; } z_return(1); } BIO_METHOD z_ssl_bio_method = { (21|0x0400|0x0100), "Zorp Stream BIO", z_stream_bio_write, z_stream_bio_read, z_stream_bio_puts, NULL, z_stream_bio_ctrl, z_stream_bio_create, z_stream_bio_destroy, NULL }; BIO * z_ssl_bio_new(ZStream *stream) { ZStreamBio *self = g_new0(ZStreamBio, 1); z_enter(); self->super.method = &z_ssl_bio_method; self->stream = stream; self->super.init = 1; z_return((BIO *)self); } libzorpll-3.9.4.1/src/stackdump.c000066400000000000000000000610661224546767600166610ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: stackdump.c,v 1.11 2004/05/22 14:04:17 bazsi Exp $ * * Author : bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #ifdef HAVE_UNISTD_H # include #endif #include #include #if HAVE_BACKTRACE # include #endif #ifndef G_OS_WIN32 #if defined(__i386__) && ZORPLIB_ENABLE_STACKDUMP #ifdef G_OS_WIN32 #define _WIN32_WINNT _WIN32_WINNT_WINXP #endif /** * Log parts of the current stack in hexadecimal form. * * @param[in] p signal context **/ void z_stackdump_log_stack(ZSignalContext *p) { unsigned long *esp __attribute__((__may_alias__)) = (unsigned long *) p->esp; int i; if (!esp) { /*LOG This message indicates that the contents of the pre-signal ESP register is bogus, stackdump will rely on the current stack frame. */ z_log(NULL, CORE_ERROR, 0, "ESP is NULL, stackdump is not available, falling back to current frame;"); esp = (unsigned long *) &esp; } for (i = 0; i < 64; i++) { /*NOLOG*/ z_log(NULL, CORE_ERROR, 0, "Stack 0x%08lx: %08lx %08lx %08lx %08lx", (unsigned long) esp, esp[0], esp[1], esp[2], esp[3]); esp += 4; } } /** * x86 specific stack unrolling function which logs all return addresses and * their associated frame pointers. * * @param[in] p signal context **/ void z_stackdump_log_backtrace(ZSignalContext *p) { /* NOTE: this is i386 specific */ unsigned long *ebp __attribute__((__may_alias__)) = (unsigned long *) p->ebp; /*NOLOG*/ z_log(NULL, CORE_ERROR, 0, "retaddr=0x%lx, ebp=0x%lx", p->eip, (unsigned long) ebp); while (ebp > (unsigned long *) &ebp && *ebp) { /*NOLOG*/ z_log(NULL, CORE_ERROR, 0, "retaddr=0x%lx, ebp=0x%lx", *(ebp+1), *ebp); ebp = (unsigned long *) *ebp; } } /** * Log information found directly in the signal context (register contents). * * @param[in] p signal context **/ void z_stackdump_log_context(ZSignalContext *p) { /*LOG This message indicates that the program caught a fatal signal. Please report this event to the Zorp QA team. */ z_log(NULL, CORE_ERROR, 0, "Fatal signal occurred, dumping stack; eax='%08lx', ebx='%08lx', ecx='%08lx', edx='%08lx', esi='%08lx', edi='%08lx', ebp='%08lx', esp='%08lx', eip='%08lx'", p->eax, p->ebx, p->ecx, p->edx, p->esi, p->edi, p->ebp, p->esp, p->eip); } #else #define z_stackdump_log_stack(p) #define z_stackdump_log_backtrace(p) #define z_stackdump_log_context(p) #endif /** * This function reads and logs the contents of the /proc//maps file * which includes memory mapping for mapped shared objects. **/ void z_stackdump_log_maps(void) { int fd; fd = open("/proc/self/maps", O_RDONLY); if (fd != -1) { gchar buf[32768]; int rc; gchar *p, *eol; gint avail, end = 0; while (1) { avail = sizeof(buf) - end; rc = read(fd, buf + end, avail); if (rc == -1) break; end += rc; if (rc == 0) break; p = buf; while (*p && p < (buf + end)) { eol = memchr(p, '\n', buf + end - p); if (eol) { *eol = 0; /*NOLOG*/ z_log(NULL, CORE_ERROR, 0, "%s", p); p = eol + 1; } else { end = end - (p - buf); memmove(buf, p, end); break; } } } if (end) /*NOLOG*/ z_log(NULL, CORE_ERROR, 0, "%.*s", end, buf); close(fd); } else { /*LOG This message indicates that system was unable to open the /proc/self/maps file to gather information on the previous error and the dump will lack this information. */ z_log(NULL, CORE_ERROR, 0, "Error opening /proc/self/maps;"); } } #if HAVE_BACKTRACE /** * This function uses the libc backtrace() and backtrace_symbols() functions * to display a backtrace with resolved names. As this does not always * succeed (as it uses malloc()) the alternative implementation without * symbols is also present. **/ void z_stackdump_log_symbols(void) { void *bt[256]; int count, i; count = backtrace(bt, 256); if (count) { gchar **symbols; /*LOG This message reports the number of dumped symbols. */ z_log(NULL, CORE_ERROR, 0, "Symbol dump; count='%d'", count); symbols = backtrace_symbols(bt, count); for (i = 0; i < count; i++) { /*NOLOG*/ z_log(NULL, CORE_ERROR, 0, "%p: %s", bt[i], symbols[i]); } } } #else #define z_stackdump_log_symbols() #endif /** * Log stackdump and other information for post-mortem analysis. * * @param[in] p signal context * * This function gathers as much information for post-mortem analysis as * possible. It is usually called from a fatal signal handler (like SIGSEGV). * The current signal context can be queried with the z_stackdump_get_context() macro. * This function is Linux & x86 specific. **/ void z_stackdump_log(ZSignalContext *p G_GNUC_UNUSED) { z_stackdump_log_context(p); z_stackdump_log_backtrace(p); z_stackdump_log_maps(); z_stackdump_log_stack(p); z_stackdump_log_symbols(); } #else /* G_OS_WIN32 */ #if ZORPLIB_ENABLE_STACKDUMP #include #include #include #include #include /* Visual Studio intelli sense needs this */ #if defined (_M_X64) #undef _M_IX86 #endif BOOL z_get_logical_address(VOID *addr, PTSTR module_name, DWORD len, DWORD *section, DWORD *offset); LPTOP_LEVEL_EXCEPTION_FILTER previous_filter; static TCHAR dump_file_name[MAX_PATH]; static BOOL write_dump_file = FALSE; /** * This function enables the exception handler code to * write the memory dump into a file. **/ void z_enable_write_dump_file(void) { write_dump_file = TRUE; } typedef BOOL (WINAPI *LPFNMiniDumpWriteDump)( HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam ); /** * This function attempts to write out the memory dump of an exception into a [modulename].dmp file. * * @param[in] exception_pointers exception pointers * * The dump will contain the whole memory of process where the excetpion come off. */ DWORD z_write_minidump(EXCEPTION_POINTERS* exception_pointers) { DWORD ret = ERROR_SUCCESS; HANDLE file = NULL; HANDLE process = NULL; MINIDUMP_EXCEPTION_INFORMATION exp_param; LPFNMiniDumpWriteDump lpfnMiniDumpWriteDump = NULL; HMODULE hMiniDump; exp_param.ThreadId = GetCurrentThreadId(); exp_param.ExceptionPointers = exception_pointers; exp_param.ClientPointers = TRUE; hMiniDump = LoadLibrary("dbghelp.dll"); if (hMiniDump) lpfnMiniDumpWriteDump = (LPFNMiniDumpWriteDump) GetProcAddress(hMiniDump, "MiniDumpWriteDump"); else { ret = GetLastError(); z_log(NULL, CORE_ERROR, 0, _T("Failed to load library dbghelp.dll: error='%08x'"), ret); goto clean_up; } if (!lpfnMiniDumpWriteDump) { ret = GetLastError(); z_log(NULL, CORE_ERROR, 0, _T("Failed to get process address of MiniDumpWriteDump: error='%08x'"), ret); goto clean_up; } // process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); process = GetCurrentProcess(); if (process==NULL) { ret = GetLastError(); z_log(NULL, CORE_ERROR, 0, _T("Failed to open process self: error='%08x'"), ret); goto clean_up; } file = CreateFile(dump_file_name, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file==NULL) { ret = GetLastError(); z_log(NULL, CORE_ERROR, 0, _T("Failed to create file for minidump: error='%08x'"), ret); goto clean_up; } if (!lpfnMiniDumpWriteDump(process, GetCurrentProcessId(), file, MiniDumpWithFullMemory, &exp_param, NULL, NULL)) { ret = GetLastError(); z_log(NULL, CORE_ERROR, 0, _T("Failed to call MiniDumpWrite dump: error='%08x'"), ret); goto clean_up; } z_log(NULL, CORE_ERROR, 0, _T("Minidump creation succeeded! filename='%s'"), dump_file_name); clean_up: if(file != NULL) CloseHandle(file); if(process != NULL) CloseHandle(process); return ret; } /** * This function uses the symbols from the pdb file to show the function names on the call stack. * * @param[in] context current processor context * * If there is no symbol in the file, it writes only the addresses into the log. **/ void z_imagehlp_stack_walk(CONTEXT *context) { STACKFRAME64 stack_frame; z_log(NULL, CORE_ERROR, 0, _T("Call stack:")); z_log(NULL, CORE_ERROR, 0, _T("Address Frame")); /* Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOAds flag */ memset(&stack_frame, 0, sizeof(stack_frame)); /* * Initialize the STACKFRAME structure for the first call. This is only * necessary for Intel CPUs, and isn't mentioned in the documentation. */ #ifdef _M_IX86 stack_frame.AddrPC.Offset = context->Eip; stack_frame.AddrPC.Mode = AddrModeFlat; stack_frame.AddrStack.Offset = context->Esp; stack_frame.AddrStack.Mode = AddrModeFlat; stack_frame.AddrFrame.Offset = context->Ebp; stack_frame.AddrFrame.Mode = AddrModeFlat; #elif defined(_M_X64) stack_frame.AddrPC.Offset = context->Rip; stack_frame.AddrPC.Mode = AddrModeFlat; stack_frame.AddrStack.Offset = context->Rsp; stack_frame.AddrStack.Mode = AddrModeFlat; stack_frame.AddrFrame.Offset = context->Rbp; stack_frame.AddrFrame.Mode = AddrModeFlat; #endif while (1) { if (!StackWalk64( #ifdef _M_IX86 IMAGE_FILE_MACHINE_I386, #elif defined(_M_X64) IMAGE_FILE_MACHINE_AMD64, #endif GetCurrentProcess(), GetCurrentThread(), &stack_frame, context, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0) ) { break; } if (0 == stack_frame.AddrFrame.Offset) /* Basic sanity check to make sure */ { break; /* the frame is OK. Bail if not. */ } z_log(NULL, CORE_ERROR, 0, _T("%08x %08x"), stack_frame.AddrPC.Offset, stack_frame.AddrFrame.Offset); /* * DEBUGHLP is wacky, and requires you to pass in a pointer to a * IMAGEHLP_SYMBOL64 structure. The problem is that this structure is * variable length. That is, you determine how big the structure is * at runtime. This means that you can't use sizeof(struct). * So...make a buffer that's big enough, and make a pointer * to the buffer. We also need to initialize not one, but TWO * members of the structure before it can be used. */ { DWORD64 symbol_displacement = 0; /* Displacement of the input address, relative to the start of the symbol */ BYTE symbol_buffer[sizeof(IMAGEHLP_SYMBOL) + 512]; PIMAGEHLP_SYMBOL64 symbol = (PIMAGEHLP_SYMBOL64)symbol_buffer; symbol->SizeOfStruct = sizeof(symbol_buffer); symbol->MaxNameLength = 512; if (SymGetSymFromAddr64(GetCurrentProcess(), stack_frame.AddrPC.Offset, &symbol_displacement, symbol)) { z_log(NULL, CORE_ERROR, 0, _T("%hs+%x"), symbol->Name, symbol_displacement); } else /* No symbol found. Print out the logical address instead. */ { TCHAR module_name[MAX_PATH] = _T(""); DWORD section = 0, offset = 0; if (z_get_logical_address((VOID*)stack_frame.AddrPC.Offset, module_name, sizeof(module_name), §ion, &offset)) { z_log(NULL, CORE_ERROR, 0, _T("%04x:%08x %s"), section, offset, module_name); } else { z_log(NULL, CORE_ERROR, 0, _T("")); } } }//block }//while(1) } /** * Walks the stack, and writes the results to the z_log. * * @param[in] context current processor context * * Only addresses are supported. **/ void z_intel_stack_walk (PCONTEXT context) { #ifdef _M_IX86 DWORD *frame_pointer, *prev_frame; DWORD eip = context->Eip; frame_pointer = (DWORD*)context->Ebp; #elif defined(_M_X64) DWORD64 *frame_pointer, *prev_frame; DWORD64 eip = context->Rip; frame_pointer = (DWORD64*)context->Rbp; #endif z_log(NULL, CORE_ERROR, 0, _T("Call stack:")); z_log(NULL, CORE_ERROR, 0, _T("Address Frame Logical addr Module")); do { TCHAR module_name[MAX_PATH] = _T(""); DWORD section = 0, offset = 0; if (!z_get_logical_address((VOID*) eip, module_name, sizeof (module_name), §ion, &offset)) { break; } z_log(NULL, CORE_ERROR, 0, _T("%08x %08x %04x:%08x %s"), eip, frame_pointer, section, offset, module_name); eip = frame_pointer[1]; prev_frame = frame_pointer; #ifdef _M_IX86 frame_pointer = (DWORD*) frame_pointer[0]; /* precede to next higher frame on stack */ if ((DWORD) frame_pointer & 3) /* Frame pointer must be aligned on a DWORD boundary. Bail if not so. (address that is aligned on a 4-BYTE (DWORD) boundary is evenly divisible by 4) 4=100b 3=011b */ { break; } if (frame_pointer <= prev_frame) { break; } /* Can two DWORDs be read from the supposed frame address? */ if (IsBadReadPtr (frame_pointer, sizeof (DWORD) * 2)) { break; } #elif defined(_M_X64) frame_pointer = (DWORD64*) pFrame[0]; /* precede to next higher frame on stack */ if ((DWORD64) frame_pointer & 7) /* Frame pointer must be aligned on a DWORD64 boundary. Bail if not so. (address that is aligned on a 8-BYTE (DWORD64) boundary is evenly divisible by 8) 8=1000b 7=0111b */ { break; } if (frame_pointer <= prev_frame) { break; } /* Can two DWORD64s be read from the supposed frame address? */ if (IsBadReadPtr (frame_pointer, sizeof (DWORD64) * 2)) { break; } #endif } while (1); } /** * This function translates the known exception codes into string format. * * @param[in] exception_code exception code * * If the exception is unknown, try to resolve the string from the ntdll.dll. **/ #define EXCEPTION( x ) case EXCEPTION_##x: return _T(#x); LPTSTR z_get_exception_string (DWORD exception_code) { static TCHAR message_buffer[512]; switch (exception_code) { EXCEPTION (ACCESS_VIOLATION) EXCEPTION (DATATYPE_MISALIGNMENT) EXCEPTION (BREAKPOINT) EXCEPTION (SINGLE_STEP) EXCEPTION (ARRAY_BOUNDS_EXCEEDED) EXCEPTION (FLT_DENORMAL_OPERAND) EXCEPTION (FLT_DIVIDE_BY_ZERO) EXCEPTION (FLT_INEXACT_RESULT) EXCEPTION (FLT_INVALID_OPERATION) EXCEPTION (FLT_OVERFLOW) EXCEPTION (FLT_STACK_CHECK) EXCEPTION (FLT_UNDERFLOW) EXCEPTION (INT_DIVIDE_BY_ZERO) EXCEPTION (INT_OVERFLOW) EXCEPTION (PRIV_INSTRUCTION) EXCEPTION (IN_PAGE_ERROR) EXCEPTION (ILLEGAL_INSTRUCTION) EXCEPTION (NONCONTINUABLE_EXCEPTION) EXCEPTION (STACK_OVERFLOW) EXCEPTION (INVALID_DISPOSITION) EXCEPTION (GUARD_PAGE) EXCEPTION (INVALID_HANDLE) } /* * If not one of the "known" exceptions, try to get the string * from NTDLL.DLL's message table. */ FormatMessage (FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle (_T("NTDLL.DLL")), exception_code, 0, message_buffer, sizeof (message_buffer), 0); return message_buffer; } /** * This function logs the information about the current process state (registers, callstack). * * @param[in] exception_info_ptr exception info **/ void z_generate_exception_report(PEXCEPTION_POINTERS exception_info_ptr) { PEXCEPTION_RECORD exception_record; TCHAR faulting_module_name[MAX_PATH]; DWORD section, offset; PCONTEXT context; DWORD64 symbol_displacement = 0; BYTE symbol_buffer[sizeof (IMAGEHLP_SYMBOL64) + 512]; PIMAGEHLP_SYMBOL64 symbol = (PIMAGEHLP_SYMBOL64) symbol_buffer; symbol->SizeOfStruct = sizeof (symbol_buffer); symbol->MaxNameLength = 512; exception_record = exception_info_ptr->ExceptionRecord; /* First print information about the type of exception */ z_log(NULL, CORE_ERROR, 0, _T("Exception code: %08x %s"), exception_record->ExceptionCode, z_get_exception_string (exception_record->ExceptionCode)); /* Now print information about where the fault occured */ if (!z_get_logical_address (exception_record->ExceptionAddress, faulting_module_name, sizeof (faulting_module_name), §ion, &offset)) { z_log(NULL, CORE_ERROR, 0, _T("Fault address: %08x %02x:%08x "), exception_record->ExceptionAddress, section, offset); } else { z_log(NULL, CORE_ERROR, 0, _T("Fault address: %08x %02x:%08x %s"), exception_record->ExceptionAddress, section, offset, faulting_module_name); } context = exception_info_ptr->ContextRecord; if (SymInitialize (GetCurrentProcess(), NULL, TRUE)) { z_imagehlp_stack_walk (context); } else { z_intel_stack_walk (context); } /* winnt.h 2954 _X86_ _CONTEXT // 32 bit Intel cpu and AMD eax * winnt.h 3437 _IA64_ _CONTEXT // 64 bit Intel Itanium cpu ??? * winnt.h 2271 _AMD64_ _CONTEXT // 64 bit Intel on AMD cpu rax * sizeof (DWORD) 4 * sizeof (DWORD64) 8 * * Show the registers */ z_log(NULL, CORE_ERROR, 0, _T("ProcessId: %08x"), GetCurrentProcessId()); #ifdef _M_IX86 z_log(NULL, CORE_ERROR, 0, _T("Registers:")); z_log(NULL, CORE_ERROR, 0, _T("eax:%08x ebx:%08x ecx:%08x edx:%08x esi:%08x edi:%08x"), context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi); if (SymGetSymFromAddr64 (GetCurrentProcess (), context->Eip, &symbol_displacement, symbol)) { z_log(NULL, CORE_ERROR, 0, _T("cs:eip:%04x:%08x %S"), context->SegCs, context->Eip, symbol->Name); } else { z_log(NULL, CORE_ERROR, 0, _T("cs:eip:%04x:%08x"), context->SegCs, context->Eip); } z_log(NULL, CORE_ERROR, 0, _T("ss:esp:%04x:%08x ebp:%08x"), context->SegSs, context->Esp, context->Ebp); z_log(NULL, CORE_ERROR, 0, _T("ds:%04x es:%04x fs:%04x gs:%04x"), context->SegDs, context->SegEs, context->SegFs, context->SegGs); z_log(NULL, CORE_ERROR, 0, _T("flags:%08x"), context->EFlags); #elif defined(_M_X64) /* NOTE: add mmx registers and debug registers if needed */ z_log(NULL, CORE_ERROR, 0, _T("Registers:")); z_log(NULL, CORE_ERROR, 0, _T("rax:%016x rbx:%016x rcx:%016x rdx:%016x rsi:%016x rdi:%016x"), context->Rax, context->Rbx, context->Rcx, context->Rdx, context->Rsi, context->Rdi); z_log(NULL, CORE_ERROR, 0, _T("r08:%016x r09:%016x r10:%016x r11:%016x r12:%016x r13:%016x r14:%016x r15:%016x"), context->R8, context->R9, context->R10, context->R11, context->R12, context->R13, context->R14, context->R15); if (SymGetSymFromAddr64 (GetCurrentProcess (), context->Rip, &symbol_displacement, symbol)) { z_log(NULL, CORE_ERROR, 0, _T("cs:rip:%04x:%016x %S"), context->SegCs, context->Rip, symbol->Name); } else { z_log(NULL, CORE_ERROR, 0, _T("cs:rip:%04x:%016x"), context->SegCs, context->Rip); } z_log(NULL, CORE_ERROR, 0, _T("ss:rsp:%04x:%016x rbp:%016x"), context->SegSs, context->Rsp, context->Rbp); z_log(NULL, CORE_ERROR, 0, _T("ds:%04x es:%04x fs:%04x gs:%04x"), context->SegDs, context->SegEs, context->SegFs, context->SegGs); z_log(NULL, CORE_ERROR, 0, _T("flags:%08x"), context->EFlags); #endif SymCleanup(GetCurrentProcess()); } /** * This function is the unhandled exception filter callback. * * @param[in] exception_info_ptr exception info * * Win32api will call it. **/ LONG WINAPI z_unhandled_exception_filter (PEXCEPTION_POINTERS exception_info_ptr) { if (write_dump_file) { DWORD ret = z_write_minidump(exception_info_ptr); if (ret != ERROR_SUCCESS) z_log(NULL, CORE_ERROR, 0, _T("Failed to write minidump file: %08x"), ret); } z_generate_exception_report(exception_info_ptr); if (previous_filter) return previous_filter(exception_info_ptr); else return EXCEPTION_CONTINUE_SEARCH; } /** * This funtion sets the windows unhandled exception filter to our z_unhandled_exception_filter. **/ #ifndef _SYSCRT int #else void #endif z_set_unhandled_exception_filter(void) { PTCHAR dot = NULL; previous_filter = SetUnhandledExceptionFilter(z_unhandled_exception_filter); GetModuleFileName(NULL, dump_file_name, MAX_PATH); /* Replace the extension with "dmp" */ dot = _tcsrchr(dump_file_name, _T('.')); if (dot) { dot++; /* Advance past the '.' */ if (_tcslen(dot) >= 3) { _tcscpy(dot, _T("dmp")); } } #ifndef _SYSCRT return 0; #else return; #endif } /* * .CRT$Xpq * Where p is the category or group ('I'=C init, 'C'=C++ init, 'P'=Pre-terminators and 'T'=Terminators), * and q is the segment within that group: 'A' is the first and 'Z' is the last (U' for "User" defsects.inc) * .CRT$XIU C Initializer Sections * .CRT$XCU C++ Constructor Section */ #if defined(_MSC_VER) # if defined(_M_X64) # pragma section(".CRT$XIU", read) __declspec(allocate(".CRT$XIU")) # else # pragma data_seg(".CRT$XIU") # endif #endif static #ifndef _SYSCRT int #else void #endif /* crt0data.c:_initp_misc_cfltcvt_tab will call this funtion pointer */ (*pz_set_unhandled_exception_filter)(void) = z_set_unhandled_exception_filter; #pragma data_seg() /** * This funtion collects information about a memory address form the PE headers. * * @param[in] addr original address * @param[out] module_name module name which contains the address * @param[in] len len of the module name * @param[out] section file section * @param[out] offset offset in the section * * @returns TRUE on success **/ BOOL z_get_logical_address (VOID *addr, PTSTR module_name, DWORD len, DWORD *section, DWORD *offset) { MEMORY_BASIC_INFORMATION memory_basic_information; DWORD allocation_base; PIMAGE_DOS_HEADER pe_dos_header; PIMAGE_NT_HEADERS pe_nt_header; PIMAGE_SECTION_HEADER pe_section_header; DWORD rva; unsigned i; if (!VirtualQuery (addr, &memory_basic_information, sizeof (memory_basic_information))) return FALSE; allocation_base = (DWORD) memory_basic_information.AllocationBase; if (!GetModuleFileName ((HMODULE) allocation_base, module_name, len)) return FALSE; /* Point to the DOS header in memory */ pe_dos_header = (PIMAGE_DOS_HEADER) allocation_base; /* From the DOS header, find the NT (PE) header */ pe_nt_header = (PIMAGE_NT_HEADERS) (allocation_base + pe_dos_header->e_lfanew); /* From the NT header, find the section header */ pe_section_header = IMAGE_FIRST_SECTION (pe_nt_header); /* RVA is offset from module load address */ rva = (DWORD) addr - allocation_base; /* * Iterate through the section table, looking for the one that encompasses * the linear address. */ for (i = 0; i < pe_nt_header->FileHeader.NumberOfSections; i++, pe_section_header++) { DWORD section_start = pe_section_header->VirtualAddress; DWORD section_end = section_start + max(pe_section_header->SizeOfRawData, pe_section_header->Misc.VirtualSize); // Is the address in this section??? if ((rva >= section_start) && (rva <= section_end)) { /* * Yes, address is in the section. Calculate section and offset, * and store in the "section" & "offset" params, which were * passed by reference. */ *section = i + 1; *offset = rva - section_start; return TRUE; } } return FALSE; } #endif /* ZORPLIB_ENABLE_STACKDUMP */ #endif /* ifndef G_OS_WIN32 */ libzorpll-3.9.4.1/src/stream.c000066400000000000000000001214141224546767600161530ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: stream.c,v 1.67 2004/06/03 08:00:58 sasa Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include /* source functions delegating prepare/check/dispatch/finalize to the stream * methods. */ /* GSource derived class used to implement ZStream callbacks */ /** * @file * *

Structure of streams

* * * Streams are cooperating, full-duplex pipes which can be "stacked" to each * other to create another, more complex stream. For example we can use * the following structure: * *
 *    ZStreamLine <-> ZStreamGzip <-> ZStreamSsl <-> ZStreamFd
 * 
* * In which case we can process an encrypted/compressed stream by lines. * Each stream can be the 'top' of the stack, but every individual stream * can only be in a single stack at a time. It is forbidden to address a * below the stream top directly. * * Each stream can be used in blocking and non-blocking fashion. The user is * free to register I/O callbacks to get notifications on the availability * of data. * *

Reference counts

* * * ZStreams are ZObjects, thus they are reference counted objects. However * in addition to the stream structure GSource objects are used to implement * the functionality. In reality references look something like below: * * *
 *  Application ---------+
 *                       |
 *                       ˇ
 *                     +----------+     +-------------+
 *                     |stream top| <-> |stream source|
 *                     +----------+     +-------------+
 *                       |  ^
 *                       ˇ  |
 *                     +----------+     +-------------+
 *                     |stream 1  | <-> |stream source|
 *                     +----------+     +-------------+
 *                       |  ^
 *                       ˇ  |
 *                     +----------+     +-------------+
 *                     |stream 2  | <-> |stream source|
 *                     +----------+     +-------------+
 *                       ...
 *                       |  ^
 *                       ˇ  |
 *                     +----------+     +-------------+
 *                     |stream bot| <-> |stream source|
 *                     +----------+     +-------------+
 * 
* * There are several circles in the reference counting model, thus we need * explicit reference breaking points. The circles are: * - streams reference their children and their parent * - streams reference their accompanying source and vica versa * * The internal structure of the stream stack is called 'structure' and has * a separate reference counter from the stream's main refcount. * * Destruction happens in three phases, the order of the first two is not * defined, it is up to the application which order it chooses to destruct * its streams: * - close it by calling z_stream_close(), * - detach the source by calling z_poll_remove_stream(), or * z_stream_detach(), or by returning FALSE from the dispatch callback * - unref the stream top * * The stream stack beneath the stream top will be freed right after the * reference counter of stream top's structure reaches zero, the stream top * itself will be freed when the application calls its final z_stream_unref(). **/ static void z_stream_struct_ref(ZStream *self); static void z_stream_struct_unref(ZStream *self); /** * GSource-derived event source for a stream. **/ struct _ZStreamSource { GSource super; ZStream *stream; }; G_LOCK_DEFINE_STATIC(detach_lock); /** * Check whether user callbacks can be called at all. * * @param[in] self this * @param[in] in_call FIXME: I don't know what this does. * * This function is used in all stream callbacks to check whether user * callbacks can be called at all. It currently checks whether the call is * recursive, or whether the source was already destroyed with * g_source_destroy(). The latter requires locking as g_source_destroy() * does not ensure that no further callbacks will be delivered. We are using * the global detach_lock for this purpose. * * We are also doing a z_stream_struct_ref() within the protection of the * lock. * * @note to be absolutely general we should check the return value for * g_source_get_can_recurse(), however the ZStream code creates this GSource * and currently it never uses recursive sources. If that assumption * changes, we need to properly check the recursion state. **/ static inline gboolean z_stream_source_grab_ref(ZStreamSource *self, gboolean in_call, ZStream **top_stream) { gboolean res = FALSE; ZStream *p; /* NOTE: no z_enter() on purpose, it would generate a _lot_ of logs */ G_LOCK(detach_lock); for (p = self->stream; p; p = p->parent) { ZStreamSource *source = (ZStreamSource *) p->source; if (!source || (source->super.flags & ((in_call ? 0 : G_HOOK_FLAG_IN_CALL) + G_HOOK_FLAG_ACTIVE)) != G_HOOK_FLAG_ACTIVE) { /* one of the streams has a pending destruction, bail out and don't call user callbacks */ G_UNLOCK(detach_lock); return FALSE; } /* NOTE: in_call only needs to be consulted for the stream that we were called with */ in_call = FALSE; *top_stream = p; } z_stream_struct_ref(*top_stream); res = TRUE; G_UNLOCK(detach_lock); return res; } static gboolean z_stream_source_prepare(GSource *s, gint *timeout) { ZStreamSource *self = (ZStreamSource *) s; gboolean ret = FALSE; ZStream *top_stream = NULL; z_enter(); if (!z_stream_source_grab_ref(self, FALSE, &top_stream)) z_return(FALSE); if (self->stream->want_read && self->stream->ungot_bufs) { *timeout = 0; ret = TRUE; } else { ret = z_stream_watch_prepare(self->stream, s, timeout); } z_stream_struct_unref(top_stream); z_return(ret); } static gboolean z_stream_source_check(GSource *s) { ZStreamSource *self = (ZStreamSource *) s; gboolean ret = FALSE; ZStream *top_stream = NULL; z_enter(); if (!z_stream_source_grab_ref(self, FALSE, &top_stream)) z_return(FALSE); if (self->stream->want_read && self->stream->ungot_bufs) ret = TRUE; else ret = z_stream_watch_check(self->stream, s); z_stream_struct_unref(top_stream); z_return(ret); } static gboolean z_stream_source_dispatch(GSource *s, GSourceFunc callback G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { ZStreamSource *self = (ZStreamSource *) s; gboolean ret = FALSE; ZStream *top_stream = NULL; z_enter(); if (!z_stream_source_grab_ref(self, TRUE, &top_stream)) { /* NOTE: we are returning TRUE as we come here only when the * destruction of this source has already been requested. */ z_return(TRUE); } if (self->stream->want_read && self->stream->ungot_bufs) ret = self->stream->read_cb(self->stream, G_IO_IN, self->stream->user_data_read); else ret = z_stream_watch_dispatch(self->stream, s); if (!ret) { /* NOTE: top_stream here is only a borrowed reference which might be * freed during z_stream_detach_source causing an abort or segfault. * Therefore we need to ref it to ensure a proper reference is passed * to the functions in the call chain. */ /* NOTE/2: I'm not sure that the NOTE above still applies, but ref/unref here won't hurt */ z_stream_ref(top_stream); z_stream_detach_source(top_stream); z_stream_unref(top_stream); } z_stream_struct_unref(top_stream); z_return(ret); } static void z_stream_source_finalize(GSource *s) { ZStreamSource *self = (ZStreamSource *) s; ZStream *stream; z_enter(); /* NOTE: we don't call _struct_ref here as we are only called when that * already dropped to zero */ z_stream_watch_finalize(self->stream, s); stream = self->stream; self->stream = NULL; z_stream_unref(stream); z_return(); } /** * ZStreamSource virtual methods. **/ static GSourceFuncs z_stream_source_funcs = { z_stream_source_prepare, z_stream_source_check, z_stream_source_dispatch, z_stream_source_finalize, NULL, NULL }; /** * Create a new ZStreamSource instance. * * @param[in] stream ZStream to associate with the ZStreamSource * * The new object will hold a reference to the ZStream and so the * reference count of the ZStream will be incremented. * * @return new object **/ GSource * z_stream_source_new(ZStream *stream) { ZStreamSource *self = (ZStreamSource *) g_source_new(&z_stream_source_funcs, sizeof(ZStreamSource)); z_enter(); z_stream_ref(stream); self->stream = stream; z_return(&self->super); } /* ZStreamContext */ /** * ZStreamContext destructor. * * @param[in] self ZStreamContext instance * * The GDestroyNotify callbacks will only be called if their user data pointers are also set. **/ void z_stream_context_destroy(ZStreamContext *self) { z_enter(); if (!self->restored) { if (self->user_data_read && self->user_data_read_notify) self->user_data_read_notify(self->user_data_read); if (self->user_data_write && self->user_data_write_notify) self->user_data_write_notify(self->user_data_write); if (self->user_data_pri && self->user_data_pri_notify) self->user_data_pri_notify(self->user_data_pri); g_free(self->stream_extra); self->stream_extra = NULL; self->restored = TRUE; } z_return(); } /** * Structure used for querying/changing ZStream I/O callbacks. **/ typedef struct _ZStreamSetCb { ZStreamCallback cb; gpointer cb_data; GDestroyNotify cb_notify; } ZStreamSetCb; /** * Increment the reference count of a ZStream instance. * * @param[in] self ZStream instance **/ static void z_stream_struct_ref(ZStream *self) { z_refcount_inc(&self->struct_ref); } /** * Decrement the reference count of a ZStream instance. * * @param[in] self ZStream instance * * Also breaks circular references to its child. **/ static void z_stream_struct_unref(ZStream *self) { if (z_refcount_dec(&self->struct_ref)) { ZStream *child; /* break circular reference to child */ child = self->child; if (child) { z_stream_ref(child); z_stream_set_child(self, NULL); z_stream_unref(child); } } } /** * Process stream control calls. * * @param[in] s ZStream instance * @param[in] function function selector * @param[in, out] value parameter to function * @param[in] vlen length of value * * @returns TRUE on success **/ gboolean z_stream_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen) { gboolean res = FALSE; z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_CTRL_GET_COND_READ: if (vlen == sizeof(gboolean)) { *(gboolean *)value = s->want_read; res = TRUE; } break; case ZST_CTRL_SET_COND_READ: if (vlen == sizeof(gboolean)) { s->want_read = *((gboolean *)value); res = TRUE; } break; case ZST_CTRL_GET_COND_WRITE: if (vlen == sizeof(gboolean)) { *(gboolean *)value = s->want_write; res = TRUE; } break; case ZST_CTRL_SET_COND_WRITE: if (vlen == sizeof(gboolean)) { s->want_write = *((gboolean *)value); res = TRUE; } break; case ZST_CTRL_GET_COND_PRI: if (vlen == sizeof(gboolean)) { *(gboolean *)value = s->want_pri; res = TRUE; } break; case ZST_CTRL_SET_COND_PRI: if (vlen == sizeof(gboolean)) { s->want_pri = *((gboolean *)value); res = TRUE; } break; case ZST_CTRL_GET_CALLBACK_READ: if (vlen == sizeof(ZStreamSetCb)) { ZStreamSetCb *cbv = (ZStreamSetCb *)value; cbv->cb = s->read_cb; cbv->cb_data = s->user_data_read; cbv->cb_notify = s->user_data_read_notify; res = TRUE; } break; case ZST_CTRL_SET_CALLBACK_READ: if (vlen == sizeof(ZStreamSetCb)) { ZStreamSetCb *cbv = (ZStreamSetCb *)value; if (s->user_data_read_notify) s->user_data_read_notify(s->user_data_read); s->read_cb = cbv->cb; s->user_data_read = cbv->cb_data; s->user_data_read_notify = cbv->cb_notify; res = TRUE; } break; case ZST_CTRL_GET_CALLBACK_WRITE: if (vlen == sizeof(ZStreamSetCb)) { ZStreamSetCb *cbv = (ZStreamSetCb *)value; cbv->cb = s->write_cb; cbv->cb_data = s->user_data_write; cbv->cb_notify = s->user_data_write_notify; res = TRUE; } break; case ZST_CTRL_SET_CALLBACK_WRITE: if (vlen == sizeof(ZStreamSetCb)) { ZStreamSetCb *cbv = (ZStreamSetCb *)value; if (s->user_data_write_notify) s->user_data_write_notify(s->user_data_write); s->write_cb = cbv->cb; s->user_data_write = cbv->cb_data; s->user_data_write_notify = cbv->cb_notify; res = TRUE; } break; case ZST_CTRL_GET_CALLBACK_PRI: if (vlen == sizeof(ZStreamSetCb)) { ZStreamSetCb *cbv = (ZStreamSetCb *)value; cbv->cb = s->pri_cb; cbv->cb_data = s->user_data_pri; cbv->cb_notify = s->user_data_pri_notify; res = TRUE; } break; case ZST_CTRL_SET_CALLBACK_PRI: if (vlen == sizeof(ZStreamSetCb)) { ZStreamSetCb *cbv = (ZStreamSetCb *)value; if (s->user_data_pri_notify) s->user_data_pri_notify(s->user_data_pri); s->pri_cb = cbv->cb; s->user_data_pri = cbv->cb_data; s->user_data_pri_notify = cbv->cb_notify; res = TRUE; } break; case ZST_CTRL_SET_TIMEOUT_BLOCK: if (vlen == sizeof(gint)) { s->timeout = *((gint *)value); res = TRUE; } break; default: if (s->child) { res = z_stream_ctrl(s->child, function, value, vlen); z_return(res); } break; } if (res && (function & ZST_CTRL_MSG_FORWARD) && s->child) res = z_stream_ctrl(s->child, function, value, vlen); z_return(res); } /** * Drop read, write and priority data callbacks. * * @param[in] self ZStream instance * * The GDestroyNotify callbacks will only be called if their user data pointers are also set. **/ void z_stream_drop_callbacks(ZStream *self) { if (self->user_data_read && self->user_data_read_notify) self->user_data_read_notify(self->user_data_read); self->user_data_read = NULL; self->read_cb = NULL; if (self->user_data_write && self->user_data_write_notify) self->user_data_write_notify(self->user_data_write); self->user_data_write = NULL; self->write_cb = NULL; if (self->user_data_pri && self->user_data_pri_notify) self->user_data_pri_notify(self->user_data_pri); self->user_data_pri = NULL; self->pri_cb = NULL; } /** * This function enables or disables an I/O callback by setting the * appropriate want_read/want_write flags. * * @param[in] s ZStream instance * @param[in] type callback type (G_IO_*) * @param[in] value enable or disable * * @returns TRUE on success **/ gboolean z_stream_set_cond(ZStream *s, guint type, gboolean value) { gboolean ret = FALSE; switch (type) { case G_IO_IN: ret = z_stream_ctrl(s, ZST_CTRL_SET_COND_READ, &value, sizeof(value)); break; case G_IO_OUT: ret = z_stream_ctrl(s, ZST_CTRL_SET_COND_WRITE, &value, sizeof(value)); break; case G_IO_PRI: ret = z_stream_ctrl(s, ZST_CTRL_SET_COND_PRI, &value, sizeof(value)); break; default: break; } return ret; } /** * This function returns the value of the appropriate want_read/want_write flags. * * @param[in] s ZStream instance * @param[out] v store actual value here; not modified if returns FALSE; NULL-tolerant * * @returns TRUE on success **/ gboolean z_stream_get_cond(ZStream *s, guint type, gboolean *v) { gboolean ret = FALSE; gboolean value; switch (type) { case G_IO_IN: ret = z_stream_ctrl(s, ZST_CTRL_GET_COND_READ, &value, sizeof(value)); break; case G_IO_OUT: ret = z_stream_ctrl(s, ZST_CTRL_GET_COND_WRITE, &value, sizeof(value)); break; case G_IO_PRI: ret = z_stream_ctrl(s, ZST_CTRL_GET_COND_PRI, &value, sizeof(value)); break; default: break; } if (ret && v) *v = value; return ret; } /** * This function attaches an I/O callback function to stream. * * @param[in] s ZStream instance * @param[in] type callback type (G_IO_*) * @param[in] callback I/O callback function * @param[in] user_data user data to pass to callback * @param[in] notify destroy notify function to free user_data * * @returns TRUE on success **/ gboolean z_stream_set_callback(ZStream *s, guint type, ZStreamCallback callback, gpointer user_data, GDestroyNotify notify) { gboolean ret = FALSE; ZStreamSetCb cb; cb.cb = callback; cb.cb_data = user_data; cb.cb_notify = notify; switch(type) { case G_IO_IN: ret = z_stream_ctrl(s, ZST_CTRL_SET_CALLBACK_READ, &cb, sizeof(cb)); break; case G_IO_OUT: ret = z_stream_ctrl(s, ZST_CTRL_SET_CALLBACK_WRITE, &cb, sizeof(cb)); break; case G_IO_PRI: ret = z_stream_ctrl(s, ZST_CTRL_SET_CALLBACK_PRI, &cb, sizeof(cb)); break; default: break; } return ret; } /** * This is the default extra_get_size method to query a stream how * much information it needs to store as its context when the * application calls z_stream_save_context(). * * @param[in] s ZStream instance * * @returns the size of the extra information to be stored **/ static gsize z_stream_extra_get_size_method(ZStream *s) { if (s->child) return z_stream_extra_get_size(s->child); return 0; } /** * This is the default extra_save method to save stream context when * the application calls z_stream_save_context(). * * @param[in] s ZStream instance * @param[in] extra extra pointer * * @returns offset where the next class can start its extra data **/ static gsize z_stream_extra_save_method(ZStream *s, gpointer extra) { if (s->child) return z_stream_extra_save(s->child, extra); return 0; } /** * This is the default extra_restore method to restore stream context * when the application calls z_stream_restore_context(). * * @param[in] s ZStream instance * @param[in] extra extra pointer * * @returns offset where the next class can start reading its extra data **/ static gsize z_stream_extra_restore_method(ZStream *s, gpointer extra) { if (s->child) return z_stream_extra_restore(s->child, extra); return 0; } /** * This method is called when a new stream is stacked beneath * self. * * @param[in] self ZStream instance * @param[in] new_child new stream child * * When a new stream is stacked beneath self, this method sets * the appropriate references and recalculates umbrella_flags * and timeout values. * Because of the z_stream_unref(parent) @self may * be freed in this this function. So we cannot reparent a * stream easily. The caller should have a reference to it * to do it. **/ static void z_stream_set_child_method(ZStream *self, ZStream *new_child) { ZStream *p; if (self->child) { ZStream *parent, *child; g_assert(self->child->parent == self); /* recalculate umbrella state */ self->child->umbrella_state = self->child->umbrella_flags; /* detach self->child->parent reference */ z_stream_drop_callbacks(self->child); /* NOTE: the set-NULL, unref order is important, as z_stream_free * asserts on self->child == NULL and these unrefs might trigger a * z_stream_free call */ parent = self->child->parent; child = self->child; self->child->parent = NULL; self->child = NULL; z_stream_struct_unref(child); z_stream_unref(child); z_stream_unref(parent); } if (new_child) { g_assert(new_child->parent == NULL); self->stack_depth = new_child->stack_depth + 1; z_stream_set_name(self, new_child->name); new_child->parent = z_stream_ref(self); self->child = z_stream_ref(new_child); z_stream_struct_ref(self->child); self->timeout = new_child->timeout; for (p = self; p && p->child; p = p->child) p->child->umbrella_state &= ~self->umbrella_flags; } } /** * Save the complete ZStream callback state. * * @param[in] self ZStream instance * @param[out] context save stream context here * * This function can be used to save the complete ZStream callback state. It * is usually needed when this stream is to be used in a completely * different context (e.g. ZTransfer vs. ZProxy). The function saves the * references to user_data associated with different callbacks, e.g. * GDestroyNotify callbacks are called when the context is freed without * restoring it. The function also NULLs all fields in ZStream to make it * sure the ZStream will not do the same. * * @returns always TRUE **/ gboolean z_stream_save_context(ZStream *self, ZStreamContext *context) { gsize extra_size; z_enter(); context->restored = FALSE; context->want_read = self->want_read; context->user_data_read = self->user_data_read; context->user_data_read_notify = self->user_data_read_notify; context->read_cb = self->read_cb; context->want_pri = self->want_pri; context->user_data_pri = self->user_data_pri; context->user_data_pri_notify = self->user_data_pri_notify; context->pri_cb = self->pri_cb; context->want_write = self->want_write; context->user_data_write = self->user_data_write; context->user_data_write_notify = self->user_data_write_notify; context->write_cb = self->write_cb; context->timeout = self->timeout; context->nonblocking = z_stream_get_nonblock(self); self->want_read = FALSE; self->user_data_read = NULL; self->user_data_read_notify = NULL; self->read_cb = NULL; self->want_pri = FALSE; self->user_data_pri = NULL; self->user_data_pri_notify = NULL; self->pri_cb = NULL; self->want_write = FALSE; self->user_data_write = NULL; self->user_data_write_notify = NULL; self->write_cb = NULL; extra_size = z_stream_extra_get_size(self); context->stream_extra = g_malloc0(extra_size); z_stream_extra_save(self, context->stream_extra); z_return(TRUE); } /** * This function restores the stream callback context previously saved by * z_stream_save_context. * * @param[in] self ZStream instance * @param[in] context stream context previously stored by z_stream_save_context * * @note: FIXME: What we should do if context->restored is TRUE? * @returns always TRUE **/ gboolean z_stream_restore_context(ZStream *self, ZStreamContext *context) { z_enter(); g_return_val_if_fail(!context->restored, FALSE); z_stream_drop_callbacks(self); self->want_read = context->want_read; self->user_data_read = context->user_data_read; self->user_data_read_notify = context->user_data_read_notify; self->read_cb = context->read_cb; self->want_pri = context->want_pri; self->user_data_pri = context->user_data_pri; self->user_data_pri_notify = context->user_data_pri_notify; self->pri_cb = context->pri_cb; self->want_write = context->want_write; self->user_data_write = context->user_data_write; self->user_data_write_notify = context->user_data_write_notify; self->write_cb = context->write_cb; self->timeout = context->timeout; z_stream_set_nonblock(self, context->nonblocking); if (context->stream_extra) { z_stream_extra_restore(self, context->stream_extra); g_free(context->stream_extra); context->stream_extra = NULL; } context->restored = TRUE; z_return(TRUE); } /** * This function searches the stream stack for a specific stream type. * * @param[in] self ZStream instance * @param[in] direction I/O direction (G_IO_*) * @param[in] class stream class that we are looking for * * @returns a ZStream of the requested type **/ ZStream * z_stream_search_stack(ZStream *self, gint direction, ZClass *class) { ZStream *p; z_enter(); for (p = self; p; p = p->child) { if (z_object_is_instance(&p->super, class)) z_return(p); if ((p->umbrella_flags & direction) == direction) break; /* this direction is shadowed by the current entry */ } z_return(NULL); } /** * Push a new stream to the top of a stream stack. * * @param[in] self current top of the stream stack (consumed reference) * @param[in] new_top stream to push (this reference is returned) * * Push a new stream to the top of a stream stack by setting child-parent * relationship and recalculating umbrella_state. The references are * manipulated to make it easy for calling code to push nested streams in a * code described in the example section below. Please note that the * reference semantics is not the same as the child argument to various * ZStream constructors, as those increment the reference count to the * passed argument. * * @returns the new top of the stream stack (borrowed reference). * * Example: * Stream construction using z_stream_push: * * stream = z_stream_fd_new(0, ""); * stream = z_stream_push(stream, z_stream_line_new(NULL, 4096, 0)); * stream = z_stream_push(stream, z_stream_ssl_new(...)); * * The end result is a single reference to the stream stack in the * variable 'stream' and single references to all nested streams in the * stream stack. Popping streams one by one can be done using: * * stream = z_stream_pop(stream); // pops ZStreamSsl from the top * stream = z_stream_pop(stream); // pops ZStreamLine from the top * stream = z_stream_pop(stream); // fails and returns NULL, not freeing anything **/ ZStream * z_stream_push(ZStream *self, ZStream *new_top) { z_stream_set_child(new_top, self); z_stream_unref(self); return new_top; } /** * Pop the topmost stream from the stack. * * @param[in] self current top of the stream stack (consumed reference) * * Pops the topmost stream from the stack, recalculating umbrella_state as * it goes. See the example at z_stream_push to see how references should * be treated. * * @returns the new top of the stack **/ ZStream * z_stream_pop(ZStream *self) { ZStream *new_top = z_stream_ref(self->child); if (new_top) { self->umbrella_state = self->umbrella_flags; z_stream_set_child(self, NULL); new_top->umbrella_state = new_top->umbrella_flags; z_stream_unref(self); } return new_top; } /** * This function is called when the stream is attached to a poll loop, it * creates the necessary GSource instance and calls z_stream_attach() on the * child streams recursively. * * @param[in] self ZStream instance * @param[in] context main context to attach to * * @note This can only be called from a single thread. **/ static void z_stream_attach_source_method(ZStream *self, GMainContext *context) { z_enter(); g_assert(self->source == NULL); z_stream_ref(self); /* NOTE: we need the structure referenced as long as the source is active */ z_stream_struct_ref(self); if (self->child) z_stream_attach_source(self->child, context); self->source = z_stream_source_new(self); g_source_set_priority(self->source, G_PRIORITY_DEFAULT - self->stack_depth); g_source_attach(self->source, context); z_stream_unref(self); z_return(); } /** * This function is called when the stream is detached from a poll loop. * * @param[in] self ZStream instance * * @note this can be called from a thread concurrent to the callbacks. **/ static void z_stream_detach_source_method(ZStream *self) { gboolean detached = FALSE; z_enter(); G_LOCK(detach_lock); if (self->source) { GSource *source = NULL; source = self->source; self->source = NULL; g_source_destroy(source); g_source_unref(source); detached = TRUE; } G_UNLOCK(detach_lock); if (self->child) z_stream_detach_source(self->child); if (detached) z_stream_struct_unref(self); z_return(); } /** * This function is called to read bytes from a stream. * * @param[in] self ZStream instance * @param[in] buf destination buffer * @param[in] count size of buf * @param[out] bytes_read number of bytes read * @param[out] err error value * * This function reads from the ZPktBuf inside the ZStream and returns * it in buf. (The ZPktBuf is in the GList ungot_bufs) * * @returns GLib I/O status **/ GIOStatus z_stream_read(ZStream *self, void *buf, gsize count, gsize *bytes_read, GError **err) { GIOStatus res; GError *local_error = NULL; z_enter(); g_return_val_if_fail((err == NULL) || (*err == NULL), G_IO_STATUS_ERROR); if (self->ungot_bufs) { GList *l; ZPktBuf *pack; l = self->ungot_bufs; pack = (ZPktBuf *) l->data; if (count >= pack->length) { /* consume the whole packet */ memcpy(buf, pack->data, pack->length); *bytes_read = pack->length; self->ungot_bufs = g_list_remove_link(self->ungot_bufs, self->ungot_bufs); g_list_free_1(l); z_pktbuf_unref(pack); } else { /* consume part of the packet */ memcpy(buf, pack->data, count); *bytes_read = count; memmove(pack->data, pack->data + count, pack->length - count); pack->data = g_realloc(pack->data, pack->length - count); pack->length = pack->length - count; } res = G_IO_STATUS_NORMAL; } else { res = Z_FUNCS(self, ZStream)->read(self, buf, count, bytes_read, &local_error); } if (res == G_IO_STATUS_ERROR) { /*LOG This message indicates that reading from the given stream failed of the given reason. */ z_log(self->name, CORE_ERROR, 1, "Stream read failed; stream='%s', reason='%s'", self->super.isa->name, local_error ? local_error->message : "unknown"); } else if (res == G_IO_STATUS_NORMAL) { self->bytes_recvd += *bytes_read; z_stream_data_dump(self, G_IO_IN, buf, *bytes_read); } if (local_error) g_propagate_error(err, local_error); z_leave(); return res; } /** * This function is called to write bytes to a stream. * * @param[in] self ZStream instance * @param[in] buf source buffer * @param[in] count size of buf * @param[out] bytes_written number of bytes written * @param[out] err error value * * @returns GLib I/O status **/ GIOStatus z_stream_write(ZStream *self, const void *buf, gsize count, gsize *bytes_written, GError **err) { GIOStatus res; GError *local_error = NULL; g_return_val_if_fail((err == NULL) || (*err == NULL), G_IO_STATUS_ERROR); res = Z_FUNCS(self, ZStream)->write(self, buf, count, bytes_written, &local_error); if (res == G_IO_STATUS_ERROR) { /*LOG This message indicates that some I/O error occurred in the write() system call. */ z_log(self->name, CORE_ERROR, 1, "Stream write failed; stream='%s', reason='%s'", self->super.isa->name, local_error ? local_error->message : "unknown"); } else if (res == G_IO_STATUS_NORMAL) { self->bytes_sent += *bytes_written; z_stream_data_dump(self, G_IO_OUT, buf, *bytes_written); } if (local_error) g_propagate_error(err, local_error); return res; } /** * This function is called to close the stream, it also initiates * destructing the stream stack structure by calling * z_stream_struct_unref(). * * @param[in] self ZStream instance * @param[out] error error value * * @note this can be called from a thread concurrent to the callbacks. * * @returns GIOStatus value **/ static GIOStatus z_stream_close_method(ZStream *self, GError **error) { GIOStatus res; g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); /*LOG This message indicates that the given stream is to be closed. */ z_log((gchar *) self->name, CORE_DEBUG, 6, "Closing stream; type='%s'", self->super.isa->name); if (self->child) res = z_stream_close(self->child, error); else res = G_IO_STATUS_NORMAL; z_stream_struct_unref(self); return res; } /** * This function reads exactly len bytes into buf. * * @param[in] self this instance * @param[in] buf buffer to read data into * @param[in] len size of data to read * @param[out] bytes_read size of data successfully read * @param[out] error error * * @returns G_IO_STATUS_NORMAL if successful and G_IO_STATUS_ERROR otherwise. * * @note this function may return less data than specified by its len parameter * when an EOF is encountered on the input stream. * * If G_IO_STATUS_ERROR is returned then the value in buf is undefined and * the number of characters read is also undefined. * * @returns GIOStatus value **/ GIOStatus z_stream_read_chunk(ZStream *self, void *buf, gsize len, gsize *bytes_read, GError **error) { GIOStatus status = G_IO_STATUS_NORMAL; gsize bytes; /* Only works on a blocking stream. */ g_return_val_if_fail(z_stream_get_nonblock(self) == FALSE, G_IO_STATUS_ERROR); g_return_val_if_fail((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); z_enter(); *bytes_read = 0; while (len > 0 && (status == G_IO_STATUS_NORMAL || status == G_IO_STATUS_AGAIN)) { status = z_stream_read(self, buf, len, &bytes, error); if (status == G_IO_STATUS_NORMAL) { /* FIXME: This line is really like this: * buf += bytes * just this cannot be used in windows. * The logic transform: * (gchar *)buf += bytes * is compile on windows, but not on linux. * But there are a webpage * http://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/Lvalues.html * which say that the expression above is almost equal to the * expression below. */ buf = (void *)(gchar *) ((gchar *)buf + bytes); len -= bytes; *bytes_read += bytes; } } g_assert(status != G_IO_STATUS_AGAIN); if (status == G_IO_STATUS_EOF && *bytes_read > 0) status = G_IO_STATUS_NORMAL; z_return(status); } /** * Attempt to write exactly len bytes to the stream by retrying the write * call multiple times. * * @param[in] self this instance * @param[in] buf buffer to read data into * @param[in] len size of data to read * @param[out] bytes_written size of the data successfully written * @param[out] error error * * This function writes attempts to write exactly len bytes to stream by * retrying the write call multiple times. As EOF is not possible for * writing a partial write is only possible if an error occurs while writing * the data. The bytes_written value is only present to be symmetric with * z_stream_read_chunk(). * * @returns GIOStatus value **/ GIOStatus z_stream_write_chunk(ZStream *self, const void *buf, gsize len, gsize *bytes_written, GError **error) { GIOStatus status = G_IO_STATUS_NORMAL; gsize bytes; z_enter(); *bytes_written = 0; while (status == G_IO_STATUS_NORMAL && len > 0) { status = z_stream_write(self, buf, len, &bytes, error); if (status == G_IO_STATUS_NORMAL) { buf = (void *)(const gchar *) ((const gchar *)buf + bytes); len -= bytes; *bytes_written += bytes; } } g_assert(status != G_IO_STATUS_AGAIN); z_return(status); } /** * The default unget_packet method for streams. * * @param[in] self ZStream instance * @param[in] pack packet to unget * @param[out] error error value * * This is the default unget_packet method for streams. It puts the * pack argument to its list of ungot packets. * * @return TRUE on success (it only fails if error is a NULL pointer or points to a NULL pointer) **/ static gboolean z_stream_unget_packet_method(ZStream *self, ZPktBuf *pack, GError **error) { ZStream *p; g_return_val_if_fail((error == NULL) || (*error == NULL), FALSE); z_enter(); for (p = self; p; p = p->child) { if ((p->umbrella_flags & G_IO_IN)) { p->ungot_bufs = g_list_prepend(p->ungot_bufs, pack); break; } } z_return(TRUE); } /** * This function is the generic unget method which copies bytes to a * packet buffer and calls z_stream_unget_packet(). * * @param[in] self ZStream instance * @param[in] buf data to unget * @param[in] count number of bytes to buf * @param[out] error error value * * @returns TRUE on success **/ gboolean z_stream_unget(ZStream *self, const void *buf, gsize count, GError **error) { ZPktBuf *pack; g_return_val_if_fail((error == NULL) || (*error == NULL), FALSE); pack = z_pktbuf_new(); z_pktbuf_copy(pack, buf, count); if (!z_stream_unget_packet(self, pack, error)) { z_pktbuf_unref(pack); return FALSE; } else { return TRUE; } } /** * Constructor for ZStream and derived classes. * * @param[in] class class of the new object, must be compatible with ZStream * @param[in] name name of the new object * @param[in] umbrella_flags umbrella flags of the new object * * @returns new object **/ ZStream * z_stream_new(ZClass *class, const gchar *name, gint umbrella_flags) { ZStream *self; z_enter(); self = Z_NEW_COMPAT(class, ZStream); z_stream_set_name(self, name); self->timeout = -2; self->time_open = time(NULL); self->umbrella_state = self->umbrella_flags = umbrella_flags; z_refcount_set(&self->struct_ref, 1); z_return(self); } /** * Destroy the stream structure but don't close the fd. * * @param[in] self ZStream instance * * This function can be called instead of z_stream_close() if only the * stream structure needs to be destroyed without actually closing the * fd under the stream. It is useful when the application needs to * retain the fd for later use. **/ void z_stream_destroy(ZStream *self) { z_stream_struct_unref(self); } /** * Destructor for ZStream and derived classes. * * @param[in] s self **/ void z_stream_free_method(ZObject *s) { ZStream *self = Z_CAST(s, ZStream); time_t time_close; z_enter(); g_assert(self->child == NULL); while (self->ungot_bufs) { GList *l; l = self->ungot_bufs; z_pktbuf_unref((ZPktBuf *) l->data); self->ungot_bufs = g_list_remove_link(self->ungot_bufs, self->ungot_bufs); g_list_free_1(l); } time_close = time(NULL); /*LOG This message contains accounting information on the given channel. It reports the number of seconds the fd was open and the number of bytes sent/received on this channel. */ z_log(self->name, CORE_ACCOUNTING, 4, "accounting info; type='%s', duration='%d', sent='%" G_GUINT64_FORMAT "', received='%" G_GUINT64_FORMAT "'", s->isa->name, (int) difftime(time_close, self->time_open), self->bytes_sent, self->bytes_recvd); #if ZORPLIB_ENABLE_DEBUG /* FIXME: Too many assert oocured g_assert(self->struct_ref.counter == 0); */ #endif z_stream_drop_callbacks(self); g_free((gpointer) self->name); z_object_free_method(s); z_return(); } void z_stream_set_keepalive(ZStream *self, gint keepalive) { gint fd = z_stream_get_fd(self); keepalive = !!keepalive; if (fd != -1) { z_fd_set_keepalive(fd, keepalive); z_stream_ctrl(self, ZST_CTRL_SET_KEEPALIVE, &keepalive, sizeof(keepalive)); } } /** * ZStream virtual methods. **/ ZStreamFuncs z_stream_funcs = { { Z_FUNCS_COUNT(ZStream), z_stream_free_method, }, NULL, /* read */ NULL, /* write */ NULL, /* read_pri */ NULL, /* write_pri */ NULL, /* shutdown */ z_stream_close_method,/* close */ z_stream_ctrl_method, /* ctrl */ z_stream_attach_source_method, /* attach_source */ z_stream_detach_source_method, /* detach_source */ NULL, /* watch_prepare */ NULL, /* watch_check */ NULL, /* watch_dispatch */ NULL, /* watch_finalize */ z_stream_extra_get_size_method, z_stream_extra_save_method, z_stream_extra_restore_method, z_stream_set_child_method, z_stream_unget_packet_method }; /** * ZStream class descriptor. **/ #ifdef G_OS_WIN32 LIBZORPLL_EXTERN #endif Z_CLASS_DEF(ZStream, ZObject, z_stream_funcs); libzorpll-3.9.4.1/src/streamblob.c000066400000000000000000000207701224546767600170150ustar00rootroot00000000000000/*************************************************************************** * * COPYRIGHTHERE * * $Id: streamblob.c,v 1.00 2004/11/29 13:58:32 fules Exp $ * * Author : fules * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include /** * A ZStream built around a ZBlob referred to by the instance. **/ typedef struct _ZStreamBlob { ZStream super; gint64 pos; ZBlob *blob; GIOCondition poll_cond; } ZStreamBlob; extern ZClass ZStreamBlob__class; static gboolean z_stream_blob_watch_prepare(ZStream *s, GSource *src G_GNUC_UNUSED, gint *timeout) { ZStreamBlob *self = Z_CAST(s, ZStreamBlob); gboolean res; z_enter(); if (timeout) *timeout = -1; res = FALSE; self->poll_cond = 0; if (self->super.want_read) { self->poll_cond |= G_IO_IN; res = TRUE; } if (self->super.want_write) { self->poll_cond |= G_IO_OUT; res = TRUE; } z_return(res); } static gboolean z_stream_blob_watch_check(ZStream *s, GSource *src) { gboolean res; /** @note Now (should be reconsidered!) it's the same as watch_prepare */ z_enter(); res = z_stream_blob_watch_prepare(s, src, NULL); z_return(res); } static gboolean z_stream_blob_watch_dispatch(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamBlob *self = Z_CAST(s, ZStreamBlob); gboolean rc = TRUE; z_enter(); if (self->super.want_read && (self->poll_cond & G_IO_IN) && rc) { if (self->super.read_cb) { rc = (*self->super.read_cb)(s, self->poll_cond, self->super.user_data_read); } else { /*LOG This message indicates an internal error, read event occurred, but no read callback is set. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(self->super.name, CORE_ERROR, 3, "Internal error, no read callback is set;"); } } if (self->super.want_write && (self->poll_cond & G_IO_OUT) && rc) { if (self->super.write_cb) { rc &= (*self->super.write_cb)(s, self->poll_cond, self->super.user_data_write); } else { /*LOG This message indicates an internal error, write event occurred, but no write callback is set. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(self->super.name, CORE_ERROR, 3, "Internal error, no write callback is set;"); } } z_return(rc); } /** * This method is called to read bytes from a ZStreamBlob. * * @param[in] stream ZStreamBlob instance * @param[in] buf destination buffer * @param[in] count size of buf * @param[out] bytes_read number of bytes read * @param[out] error error value * * This function reads from the ZBlob referenced by the * ZStreamBlob and returns it in buf. * * @returns GLib I/O status **/ static GIOStatus z_stream_blob_read_method(ZStream *stream, void *buf, gsize count, gsize *bytes_read, GError **error) { ZStreamBlob *self = Z_CAST(stream, ZStreamBlob); z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (count == 0) { *bytes_read = 0; } else { if (self->pos >= self->blob->size) { *bytes_read = 0; z_return(G_IO_STATUS_EOF); } *bytes_read = z_blob_get_copy(self->blob, self->pos, buf, count, self->super.timeout); if (*bytes_read == 0) { g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Channel read timed out"); z_return(G_IO_STATUS_ERROR); } self->pos += *bytes_read; } z_return(G_IO_STATUS_NORMAL); } /** * This method is called to write bytes to a ZStreamBlob. * * @param[in] stream ZStream instance * @param[in] buf source buffer * @param[in] count size of buf * @param[out] bytes_written number of bytes written * @param[out] error error value * * This function writes from buf to the ZBlob referenced by the * ZStreamBlob. * * @returns GLib I/O status **/ static GIOStatus z_stream_blob_write_method(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamBlob *self = Z_CAST(stream, ZStreamBlob); z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (count == 0) { *bytes_written = 0; } else { *bytes_written = z_blob_add_copy(self->blob, self->pos, buf, count, self->super.timeout); if (*bytes_written == 0) { g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Channel write timed out"); z_return(G_IO_STATUS_ERROR); } self->pos += *bytes_written; } z_return(G_IO_STATUS_NORMAL); } /** * Process stream control calls. * * @param[in] s ZStream instance * @param[in] function function selector * @param[in] value parameter to function * @param[in] vlen length of value * * @returns TRUE on success **/ static gboolean z_stream_blob_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen) { ZStreamBlob *self = Z_CAST(s, ZStreamBlob); z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_CTRL_SET_NONBLOCK: if (vlen == sizeof(gboolean)) { self->super.timeout = *((gboolean *)value) ? 0 : -1; z_return(TRUE); } /*LOG This message indicates that an internal error occurred, during setting NONBLOCK mode on a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for setting NONBLOCK mode; size='%d'", vlen); break; case ZST_CTRL_GET_NONBLOCK: if (vlen == sizeof(gboolean)) { *((gboolean *) value) = (self->super.timeout ==0); z_return(TRUE); } /*LOG This message indicates that an internal error occurred, during getting NONBLOCK mode status on a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for getting the NONBLOCK mode; size='%d'", vlen); break; default: if (z_stream_ctrl_method(s, function, value, vlen)) z_return(TRUE); /*LOG This message indicates that an internal error occurred, because an invalid control was called. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, unknown stream ctrl; ctrl='%d'", ZST_CTRL_MSG(function)); break; } z_return(FALSE); } /** * Allocate and initialize a ZStreamBlob instance with the given blob and name. * * @param[in] blob blob to create the stream around * @param[in] name name to identify the stream in the logs * * @returns The new stream instance */ ZStream * z_stream_blob_new(ZBlob *blob, gchar *name) { ZStreamBlob *self; z_enter(); self = Z_CAST(z_stream_new(Z_CLASS(ZStreamBlob), name, G_IO_IN|G_IO_OUT), ZStreamBlob); self->blob = z_blob_ref(blob); self->pos = 0; self->poll_cond = 0; z_return(&self->super); } /** destructor */ static void z_stream_blob_free_method(ZObject *s) { ZStreamBlob *self = Z_CAST(s, ZStreamBlob); z_enter(); z_blob_unref(self->blob); z_stream_free_method(s); z_return(); } /** * ZStreamBlob virtual methods. **/ static ZStreamFuncs z_stream_blob_funcs = { { Z_FUNCS_COUNT(ZStream), z_stream_blob_free_method /* ok */ }, z_stream_blob_read_method, /* ok */ z_stream_blob_write_method, /* ok */ NULL, NULL, NULL, NULL, /* ok */ z_stream_blob_ctrl_method, /* ok */ NULL, /* attach_source */ NULL, /* detach_source */ z_stream_blob_watch_prepare, z_stream_blob_watch_check, z_stream_blob_watch_dispatch, NULL, NULL, NULL, NULL, NULL, NULL }; /** * ZStreamBlob class descriptor. **/ Z_CLASS_DEF(ZStreamBlob, ZStream, z_stream_blob_funcs); libzorpll-3.9.4.1/src/streambuf.c000066400000000000000000000467731224546767600166660ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streambuf.c,v 1.36 2004/07/01 16:53:24 bazsi Exp $ * * Author : SaSa * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #ifdef _MSC_VER # include #else # include # include #endif #include #include #include #include #include #include #include #include #include /** * @file * * ZStreamBuf is a stream that makes it easier to use non-blocking streams * for writing. It basically supports a blocking like mode of operation, * e.g. write never returns G_IO_STATUS_AGAIN the data to be written is * stored in an internal buffer which is flushed to the child stream in an * independent process. * * Write errors are propagated to the user of the stream by storing the * possible error condition and returning it on the subsequent * z_stream_write() calls. * * Flow control is ensured using the poll interface, the stream always * accepts data with G_IO_STATUS_NORMAL but indicates writability only of * the buffer has free space available. This limitation is not hard, the * user of this class can freely bypass this limit by calling * z_stream_write() multiple times without checking for writability using * poll. Therefore the size of the buffer specified is only an advisory * limit, hence the name buf_threshold. * * If you are generating mass amounts of data in a single shot you should * check whether the internal buffer is being overflown by using the * z_stream_buf_space_avail() function. * * The stream supports write operations from threads independent of the * flush thread, e.g. it implements locking on its internal buffer. Please * note however that streams do not support this mode of operation in general. **/ #define MAX_BUF_LEN 262144 /** * Structure representing ZStreamBuf state. **/ typedef struct _ZStreamBuf { ZStream super; guint32 flags; gsize buf_threshold; gsize pending_pos; GError *flush_error; gsize current_size; GList *buffers; GStaticMutex buffer_lock; } ZStreamBuf; extern ZClass ZStreamBuf__class; static GIOStatus z_stream_write_packet_internal(ZStream *s, ZPktBuf *packet, GError **error); /** * Internal function to check if there's available buffer space. * * @param[in] self ZStreamBuf instance * * @returns TRUE if there's available buffer space. * * @note although current_size is protected by a lock it is not absolutely * required to lock it, as it does not cause problems to overcommit the * buffer, it only increases memory usage slightly. **/ static inline gboolean z_stream_buf_space_avail_internal(ZStreamBuf *self) { return self->current_size < self->buf_threshold; } /** * This function searches the stream stack for the topmost ZStreamBuf * instance and returns whether its buffer con * * @param[in] s ZStream stack top **/ gboolean z_stream_buf_space_avail(ZStream *s) { ZStreamBuf *self; /* NOTE: we return TRUE when a flush error occurred as in that case the * output buffer will never be emptied. By returning true, the caller will * attempt another write which will return with the error condition. */ self = Z_CAST(z_stream_search_stack(s, G_IO_OUT, Z_CLASS(ZStreamBuf)), ZStreamBuf); return self->flush_error || z_stream_buf_space_avail_internal(self); } /** * This function attempts to flush the internal ZStreamBuf buffer to the * child stream. * * @param[in] self ZStreamBuf instance * * It is automatically invoked when the child becomes writable * and provided Z_SBF_IMMED_FLUSH is specified after each write() operation. **/ static void z_stream_buf_flush_internal(ZStreamBuf *self) { ZPktBuf *packet; guint i = 10; gsize write_len; GIOStatus res = G_IO_STATUS_NORMAL; GError *local_error = NULL; z_enter(); g_static_mutex_lock(&self->buffer_lock); while (self->buffers && i && res == G_IO_STATUS_NORMAL) { packet = (ZPktBuf *) self->buffers->data; res = z_stream_write(self->super.child, packet->data + self->pending_pos, packet->length - self->pending_pos, &write_len, &local_error); if (res == G_IO_STATUS_NORMAL) { self->pending_pos += write_len; if (self->pending_pos >= packet->length) { self->current_size -= packet->length; z_pktbuf_unref(packet); self->pending_pos = 0; self->buffers = g_list_delete_link(self->buffers, self->buffers); } } else if (res != G_IO_STATUS_AGAIN) { self->flush_error = local_error; local_error = NULL; } i--; } g_static_mutex_unlock(&self->buffer_lock); z_return(); } /** * This function searches the stream stack for the topmost ZStreamBuf * instance and calls z_stream_buf_flush_internal() * * @param[in] s ZStream stack top **/ void z_stream_buf_flush(ZStream *s) { ZStreamBuf *self; self = Z_CAST(z_stream_search_stack(s, G_IO_OUT, Z_CLASS(ZStreamBuf)), ZStreamBuf); return z_stream_buf_flush_internal(self); } /** * This function is the z_stream_read() handler for ZStreamBuf, it basically * calls the child's read method. * * @param[in] s ZStream instance * @param[in] buf buffer to read data into * @param[in] count size of buf * @param[out] bytes_read the number of bytes returned in buf * @param[out] error error state **/ static GIOStatus z_stream_buf_read_method(ZStream *s, void *buf, gsize count, gsize *bytes_read, GError **error) { ZStreamBuf *self = Z_CAST(s, ZStreamBuf); GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); self->super.child->timeout = self->super.timeout; res = z_stream_read(self->super.child, buf, count, bytes_read, error); z_return(res); } /** * This function is the z_stream_write() handler for ZStreamBuf, it copies * the data from buf to the internal buffer. * * @param[in] s ZStream instance * @param[in] buf buffer to read data from * @param[in] count size of buf * @param[out] bytes_written the number of bytes successfully written * @param[out] error error state * * It never returns G_IO_STATUS_AGAIN and basically always succeeds unless some error * occurred in a previous flush operation in which case it returns that error. **/ static GIOStatus z_stream_buf_write_method(ZStream *s, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamBuf *self = Z_CAST(s, ZStreamBuf); gboolean ret; GError *local_error = NULL; ZPktBuf *packet; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); self->super.child->timeout = self->super.timeout; /* NOTE: we use internal functions to avoid logging the same data twice */ packet = z_pktbuf_new(); z_pktbuf_copy(packet, buf, count); ret = z_stream_write_packet_internal(s, packet, &local_error); if (ret == G_IO_STATUS_NORMAL) { *bytes_written = count; z_return(G_IO_STATUS_NORMAL); } if (local_error) g_propagate_error(error, local_error); z_return(ret); } /** * This function is the z_stream_shutdown handler for ZStreamBuf, it flushes * the output buffer while changing the child stream to nonblocking mode. * * @param[in] s ZStream instance * @param[in] i shutdown mode * @param[out] error error state * * This means that this operation might block up to the timeout specified in * s->timeout. **/ static GIOStatus z_stream_buf_shutdown_method(ZStream *s, int i, GError **error) { ZStreamBuf *self = (ZStreamBuf *) s; GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (i == SHUT_WR || i == SHUT_RDWR) { self->super.child->timeout = self->super.timeout; z_stream_set_nonblock(self->super.child, FALSE); z_stream_buf_flush_internal(self); } res = z_stream_shutdown(self->super.child, i, error); z_return(res); } /** * @param[in] s top of the stream stack * @param[in] packet packet to be written (consumed) * @param[out] error error state if G_IO_STATUS_ERROR is returned * * This function appends a block to the internal buffer, consuming the * packet passed in packet. The error indication is not immediate however, * as the flushing process is independent from this operation. If flushing * fails the next write_packetuf operation fails with the error state stored by * flush. * * @returns G_IO_STATUS_ERROR on failure, G_IO_STATUS_NORMAL on success **/ static GIOStatus z_stream_write_packet_internal(ZStream *s, ZPktBuf *packet, GError **error) { ZStreamBuf *self; z_enter(); self = Z_CAST(z_stream_search_stack(s, G_IO_OUT, Z_CLASS(ZStreamBuf)), ZStreamBuf); g_static_mutex_lock(&self->buffer_lock); if (self->current_size > MAX_BUF_LEN) z_log(s->name, CORE_ERROR, 0, "Internal error, ZStreamBuf internal buffer became too large, continuing anyway; current_size='%zd'", self->current_size); if (self->flush_error) { if (error) *error = g_error_copy(self->flush_error); g_static_mutex_unlock(&self->buffer_lock); z_return(G_IO_STATUS_ERROR); } self->buffers = g_list_append(self->buffers, packet); self->current_size += packet->length; g_static_mutex_unlock(&self->buffer_lock); if (self->flags & Z_SBF_IMMED_FLUSH) z_stream_buf_flush_internal(self); z_return(G_IO_STATUS_NORMAL); } /** * This function appends a block to the internal buffer, consuming the * packet passed in packet. * * @param[in] s top of the stream stack * @param[in] packet packet to be written (consumed) * @param[out] error error state if G_IO_STATUS_ERROR is returned * * The error indication is not immediate however, * as the flushing process is independent from this operation. If flushing * fails the next write_packetuf operation fails with the error state stored by * flush. * * @returns GIOStatus instance **/ GIOStatus z_stream_write_packet(ZStream *s, ZPktBuf *packet, GError **error) { ZStreamBuf *self; GIOStatus res; self = Z_CAST(z_stream_search_stack(s, G_IO_OUT, Z_CLASS(ZStreamBuf)), ZStreamBuf); z_pktbuf_ref(packet); res = z_stream_write_packet_internal(s, packet, error); if (res == G_IO_STATUS_NORMAL) z_stream_data_dump(&self->super, G_IO_OUT, packet->data, packet->length); z_pktbuf_unref(packet); return res; } /** * This function appends a block to the internal buffer, possibly copying or * consuming the buffer passed in buf. * * @param[in] s top of the stream stack * @param[in] buf buffer to write (possibly consumed) * @param[in] buflen size of buf * @param[in] copy_buf whether to copy buf or it is a pointer which is freed by ZStreamBuf * @param[out] error error state if G_IO_STATUS_ERROR is returned * * The error indication is not * immediate however as the flushing process is independent from this * operation. If flushing fails the next write_buf operation fails with the * error state stored by flush. **/ GIOStatus z_stream_write_buf(ZStream *s, void *buf, guint buflen, gboolean copy_buf, GError **error) { ZStreamBuf *self; GIOStatus res; ZPktBuf *packet; self = Z_CAST(z_stream_search_stack(s, G_IO_OUT, Z_CLASS(ZStreamBuf)), ZStreamBuf); /* copying is done outside the protection of the lock */ packet = z_pktbuf_new(); if (copy_buf) z_pktbuf_copy(packet, buf, buflen); else z_pktbuf_relocate(packet, buf, buflen, FALSE); z_pktbuf_ref(packet); res = z_stream_write_packet_internal(s, packet, error); if (res == G_IO_STATUS_NORMAL) z_stream_data_dump(&self->super, G_IO_OUT, packet->data, packet->length); z_pktbuf_unref(packet); return res; } /** * Process stream control calls. * * @param[in] s ZStream instance * @param[in] function stream control function to perform * @param[in, out] value value associated with function * @param[in] vlen size of the buffer pointed to by value * * @returns TRUE on success **/ static gboolean z_stream_buf_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen) { ZStreamBuf *self G_GNUC_UNUSED = Z_CAST(s, ZStreamBuf); gboolean ret; z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_CTRL_SET_CALLBACK_READ: case ZST_CTRL_SET_CALLBACK_WRITE: case ZST_CTRL_SET_CALLBACK_PRI: case ZST_CTRL_SET_COND_READ: case ZST_CTRL_SET_COND_WRITE: case ZST_CTRL_SET_COND_PRI: ret = z_stream_ctrl_method(s, function, value, vlen); break; default: ret = z_stream_ctrl_method(s, ZST_CTRL_MSG_FORWARD | function, value, vlen); break; } z_return(ret); } /* callbacks specified to the child stream */ /** * This function is called whenever our child stream indicates readability. * * @param s child ZStream instance (unused) * @param[in] poll_cond condition that triggered this callback * @param[in] user_data ZStream instance as a gpointer * * It basically calls our own callback as we rely on our child to trigger read/pri * callbacks. **/ static gboolean z_stream_buf_read_callback(ZStream *s G_GNUC_UNUSED, GIOCondition poll_cond, gpointer user_data) { ZStreamBuf *self = Z_CAST(user_data, ZStreamBuf); gboolean rc; z_enter(); rc = (*self->super.read_cb)(&self->super, poll_cond, self->super.user_data_read); z_return(rc); } /** * This function is called whenever our child stream indicates writability. * * @param s child ZStream instance (unused) * @param poll_cond condition that triggered this callback (unused) * @param[in] user_data ZStream instance as a gpointer * * It basically calls z_stream_buf_flush_internal() to write blocks in our buffer to * s->child. * * @returns always TRUE **/ static gboolean z_stream_buf_write_callback(ZStream *s G_GNUC_UNUSED, GIOCondition poll_cond G_GNUC_UNUSED, gpointer user_data) { ZStreamBuf *self = Z_CAST(user_data, ZStreamBuf); z_enter(); z_stream_buf_flush_internal(self); z_return(TRUE); } /** * This function is called whenever our child stream indicates that priority * data became available. * * @param s child ZStream instance (unused) * @param[in] poll_cond condition that triggered this callback * @param[in] user_data ZStream instance as a gpointer * * It basically calls our own callback as we rely on * our child to trigger read/pri callbacks. **/ static gboolean z_stream_buf_pri_callback(ZStream *s G_GNUC_UNUSED, GIOCondition poll_cond, gpointer user_data) { ZStreamBuf *self = Z_CAST(user_data, ZStreamBuf); gboolean rc; z_enter(); rc = (*self->super.pri_cb)(&self->super, poll_cond, self->super.user_data_pri); z_return(rc); } /* source helper functions */ /** * This function is called to prepare for a poll iteration. * * @param[in] s ZStream instance * @param src GSource associated with s (unused) * @param[out] timeout timeout value for this poll iteration * * It checks our internal state and prepares the watch conditions for s->child, it also * checks whether we are currently writable and indicates the immediate * availability of an event by returning TRUE. * * @returns TRUE if an event is immediately available **/ static gboolean z_stream_buf_watch_prepare(ZStream *s, GSource *src G_GNUC_UNUSED, gint *timeout) { ZStreamBuf *self = Z_CAST(s, ZStreamBuf); gboolean ret = FALSE; *timeout = -1; z_stream_set_cond(s->child, G_IO_IN, s->want_read); z_stream_set_cond(s->child, G_IO_PRI, s->want_pri); z_stream_set_cond(s->child, G_IO_OUT, !!self->current_size && self->flush_error == NULL); if (s->want_write && z_stream_buf_space_avail_internal(self)) ret = TRUE; return ret; } /** * This function is called after a poll iteration. * * @param[in] s ZStream instance * @param src GSource associated with s (unused) * * It checks whether space is available in our buffer and our user wants notification about * writability. If it is true an event is trigggered by returning TRUE. * * @returns TRUE if an event needs to be triggered, see above **/ static gboolean z_stream_buf_watch_check(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamBuf *self = Z_CAST(s, ZStreamBuf); gboolean ret = FALSE; if (s->want_write && z_stream_buf_space_avail_internal(self)) ret = TRUE; return ret; } /** * This function is called after a poll iteration if check returned TRUE. * * @param[in] s ZStream instance * @param src GSource associated with s (unused) * * It basically calls our write callback as we don't trigger any other event * ourselves, but rely on our child stream to trigger those for us. **/ static gboolean z_stream_buf_watch_dispatch(ZStream *s, GSource *src G_GNUC_UNUSED) { gboolean ret = TRUE; if (s->want_write && ret) ret = s->write_cb(s, G_IO_OUT, s->user_data_read); return ret; } /** * This function is called to change our child stream. * * @param[in] s ZStream instance * @param[in] new_child new child stream * * It basically sets up appropriate callbacks and switches new_child to nonblocking mode. **/ static void z_stream_buf_set_child(ZStream *s, ZStream *new_child) { z_stream_ref(s); Z_SUPER(s, ZStream)->set_child(s, new_child); if (new_child) { z_stream_set_callback(new_child, G_IO_IN, z_stream_buf_read_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(new_child, G_IO_OUT, z_stream_buf_write_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(new_child, G_IO_PRI, z_stream_buf_pri_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_nonblock(new_child, TRUE); } z_stream_unref(s); } /** * This function constructs a new ZStreamBuf instance. * * @param[in] child child stream * @param[in] buf_threshold buffer threshold * @param[in] flags one of Z_SBF_* flags * * @returns the new ZStreamBuf instance **/ ZStream * z_stream_buf_new(ZStream *child, gsize buf_threshold, guint32 flags) { ZStreamBuf *self; z_enter(); g_return_val_if_fail(buf_threshold <= MAX_BUF_LEN, NULL); self = Z_CAST(z_stream_new(Z_CLASS(ZStreamBuf), child ? child->name : "", G_IO_OUT), ZStreamBuf); self->buf_threshold = buf_threshold; self->flags = flags; z_stream_set_child(&self->super, child); z_return((ZStream *) self); } /** * Frees dynamically allocated variables associated with s. * * @param[in] s ZStream instance **/ static void z_stream_buf_free_method(ZObject *s) { ZStreamBuf *self = Z_CAST(s, ZStreamBuf); z_enter(); while (self->buffers) { ZPktBuf *packet = (ZPktBuf *) self->buffers->data; z_pktbuf_unref(packet); self->buffers = g_list_delete_link(self->buffers, self->buffers); } if (self->flush_error) g_error_free(self->flush_error); z_stream_free_method(s); z_return(); } /** * ZStreamBuf virtual methods. **/ ZStreamFuncs z_stream_buf_funcs = { { Z_FUNCS_COUNT(ZStream), z_stream_buf_free_method, }, z_stream_buf_read_method, z_stream_buf_write_method, NULL, NULL, z_stream_buf_shutdown_method, NULL, /* close */ z_stream_buf_ctrl_method, NULL, /* attach_source */ NULL, /* detach_source */ z_stream_buf_watch_prepare, z_stream_buf_watch_check, z_stream_buf_watch_dispatch, NULL, NULL, NULL, NULL, z_stream_buf_set_child, NULL }; /** * ZStreamBuf class descriptor. **/ Z_CLASS_DEF(ZStreamBuf, ZStream, z_stream_buf_funcs); libzorpll-3.9.4.1/src/streamfd.c000066400000000000000000000655371224546767600165020ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamfd.c,v 1.29 2004/05/21 13:58:32 abi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #ifdef G_OS_WIN32 # include # include #else # include # include # include #endif /** * ZStream-derived class that can be used to read/write an fd. * * On Windows, this can only be a WinSock fd. **/ typedef struct _ZStreamFD { ZStream super; GIOChannel *channel; gint fd; gint keepalive; gboolean shutdown; GPollFD pollfd; #ifdef G_OS_WIN32 int winsock_event; gboolean can_write; #endif } ZStreamFD; extern ZClass ZStreamFD__class; /** * ZStreamFD extra context data. **/ typedef struct _ZStreamFDExtra { gboolean nonblock; } ZStreamFDExtra; static gboolean z_stream_fd_watch_prepare(ZStream *s, GSource *src G_GNUC_UNUSED, gint *timeout) { ZStreamFD *mystream = (ZStreamFD *) s; GPollFD *mypollfd = &mystream->pollfd; #ifdef G_OS_WIN32 fd_set xf,wf; struct timeval to; int res; #endif z_enter(); *timeout = -1; if (mypollfd->revents) { *timeout = 0; z_return(TRUE); } #ifdef G_OS_WIN32 if (mystream->super.want_write) { FD_ZERO(&xf); FD_ZERO(&wf); FD_SET(mystream->fd,&wf); to.tv_sec = to.tv_usec = 0; res = select(0,&xf,&wf,&xf,&to); if (res == 1) { *timeout = 0; mystream->can_write = TRUE; z_trace(NULL, "WinSock: select said fd %d is writable at %s line %d", mystream->fd, __FILE__, __LINE__); } } else { mystream->can_write = FALSE; } mypollfd->events = FD_CLOSE; if (mystream->super.want_read) mypollfd->events |= FD_READ; if ((mystream->super.want_write) && !(mystream->can_write)) mypollfd->events |= FD_WRITE | FD_CONNECT; // MS KnowledgeBase article #Q199434 if (mystream->super.want_pri) mypollfd->events |= FD_OOB; z_trace(NULL, "WinSock: WSAEventSelect(%d,%d,%o) at %s line %d", mystream->fd, mypollfd->fd, mypollfd->events, __FILE__, __LINE__); if (WSAEventSelect(mystream->fd, (mypollfd->fd), mypollfd->events) == SOCKET_ERROR) //(HANDLE) { /*LOG This message indicates an internal error during WSAEventSelect. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 1, "Failed to set up WinSock event for z_stream_fd; error_code='%d'", z_errno_get()); z_return(FALSE); } mypollfd->events = G_IO_IN; #else mypollfd->events = 0; if (mystream->super.want_read) mypollfd->events |= G_IO_IN; if (mystream->super.want_write) mypollfd->events |= G_IO_OUT; if (mystream->super.want_pri) mypollfd->events |= G_IO_PRI; if (mypollfd->events != 0 && mystream->shutdown) { *timeout = 0; z_return(TRUE); } if (mypollfd->events == 0) mypollfd->events = G_IO_ERR; #endif z_return(FALSE); } static gboolean z_stream_fd_watch_check(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamFD *mystream = (ZStreamFD *) s; GPollFD *mypollfd = &mystream->pollfd; GIOCondition poll_condition; #ifdef G_OS_WIN32 WSANETWORKEVENTS evs; #endif z_enter(); if ((mypollfd->events & ~G_IO_ERR) != 0 && mystream->shutdown) z_return(TRUE); #ifdef G_OS_WIN32 WSAEnumNetworkEvents(mystream->fd, mypollfd->fd, &evs); //(HANDLE) mypollfd->revents = 0; if (mystream->can_write) mypollfd->revents |= G_IO_OUT; if (evs.lNetworkEvents & FD_WRITE) { if (evs.iErrorCode[FD_WRITE_BIT] != 0) mypollfd->revents |= G_IO_ERR; else mypollfd->revents |= G_IO_OUT; } if (evs.lNetworkEvents & FD_READ) { if (evs.iErrorCode[FD_READ_BIT] != 0) mypollfd->revents |= G_IO_ERR; else mypollfd->revents |= G_IO_IN; } if (evs.lNetworkEvents & FD_OOB) { if (evs.iErrorCode[FD_OOB_BIT] != 0) mypollfd->revents |= G_IO_ERR; else mypollfd->revents |= G_IO_PRI; } if (evs.lNetworkEvents & FD_CLOSE) mypollfd->revents |= G_IO_HUP; //v maybe G_IO_IN as well? z_trace(NULL, "WinSock: Event %o/%o on fd %d at %s line %d", evs.lNetworkEvents, mypollfd->revents, mypollfd->fd, __FILE__, __LINE__); #endif poll_condition = mypollfd->revents; z_return(poll_condition != 0); } static gboolean z_stream_fd_watch_dispatch(ZStream *s, GSource *src) { ZStreamFD *mystream = (ZStreamFD *) s; GPollFD *mypollfd = &mystream->pollfd; GIOCondition poll_cond = mypollfd->revents; gboolean rc = TRUE; z_enter(); #ifdef G_OS_WIN32 z_trace(NULL, "WinSock: Dispatching events %o for fd %d at %s line %d", mypollfd->revents, mypollfd->fd, __FILE__, __LINE__); #endif mypollfd->revents = 0; if (mystream->shutdown || (poll_cond & (G_IO_ERR | G_IO_HUP) && rc)) { if (mystream->super.want_read) rc = (*mystream->super.read_cb)(&mystream->super, poll_cond, mystream->super.user_data_read); else if (mystream->super.want_write) rc = (*mystream->super.write_cb)(&mystream->super, poll_cond, mystream->super.user_data_write); else if (mystream->super.want_pri) rc = (*mystream->super.pri_cb)(&mystream->super, poll_cond, mystream->super.user_data_pri); else if (!mystream->shutdown) { /* basically an EOF */ z_log(mystream->super.name, CORE_DEBUG, 6, "POLLERR or POLLHUP received, handling as EOF; poll_cond='%x'", poll_cond); mystream->shutdown = TRUE; g_source_remove_poll(src, mypollfd); } z_return(rc); } if (mystream->super.want_read && ((poll_cond & G_IO_IN) || mystream->shutdown) && rc) { if (mystream->super.read_cb) { rc = (*mystream->super.read_cb)(&mystream->super, poll_cond, mystream->super.user_data_read); } else { /*LOG This message indicates an internal error, read event occurred, but no read callback is set. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(mystream->super.name, CORE_ERROR, 3, "Internal error, no read callback is set;"); } } if (mystream->super.want_write && (poll_cond & G_IO_OUT) && rc) { if (mystream->super.write_cb) { rc &= (*mystream->super.write_cb)(&mystream->super, poll_cond, mystream->super.user_data_write); } else { /*LOG This message indicates an internal error, write event occurred, but no write callback is set. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(mystream->super.name, CORE_ERROR, 3, "Internal error, no write callback is set;"); } } if (mystream->super.want_pri && (poll_cond & G_IO_PRI) && rc) { if (mystream->super.pri_cb) { rc &= (*mystream->super.pri_cb)(&mystream->super, poll_cond, mystream->super.user_data_pri); } else { /*LOG This message indicates an internal error, pri-read event occurred, but no pri callback is set. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(mystream->super.name, CORE_ERROR, 3, "Internal error, no pri callback is set;"); } } z_return(rc); } /** * Wait for the fd encapsulated by self. * * @param[in] self ZStreamFD instance * @param[in] cond events to wait for * @param[in] timeout timeout * * On win32 select is used. On other platforms poll is used. **/ #ifndef G_OS_WIN32 static gboolean z_stream_wait_fd(ZStreamFD *self, guint cond, gint timeout) { struct pollfd pfd; gint res; GIOFlags flags; z_enter(); flags = g_io_channel_get_flags(self->channel); if ((flags & G_IO_FLAG_NONBLOCK) || timeout == -2) z_return(TRUE); errno = 0; pfd.fd = self->fd; pfd.events = cond; pfd.revents = 0; do { res = poll(&pfd, 1, timeout); if (res == 1) z_return(TRUE); } while (res == -1 && errno == EINTR); errno = ETIMEDOUT; z_return(FALSE); } #else static gboolean z_stream_wait_fd(ZStreamFD *self, guint cond, gint timeout) { fd_set rf,wf; struct timeval to,*tout; int res; GIOFlags flags; z_enter(); if (cond & G_IO_IN) { u_long bytes; ioctlsocket(self->fd, FIONREAD, &bytes); if (bytes > 0) z_return(TRUE); } FD_ZERO(&rf); if (cond & (G_IO_IN | G_IO_HUP)) FD_SET(self->fd,&rf); FD_ZERO(&wf); if (cond & G_IO_OUT) FD_SET(self->fd,&wf); flags = g_io_channel_get_flags(self->channel); if ((flags & G_IO_FLAG_NONBLOCK) || timeout == -2) z_return(TRUE); if (timeout > 0) { to.tv_sec = timeout/1000; to.tv_usec = (timeout % 1000) * 1000; tout = &to; } else tout = NULL; res = select(0, &rf, &wf, NULL, tout); if ((res == 0) || (res == SOCKET_ERROR)) { z_errno_set(ETIMEDOUT); z_return(FALSE); } z_return(TRUE); } #endif /** * Read from the fd encapsulated by a ZStreamFD instance. * * @param[in] stream ZStreamFD instance * @param[in] buf buffer to read to * @param[in] count number of bytes to ask for * @param[out] bytes_read number of bytes actually read will be put here * @param[out] error error value * * @returns GIOStatus value **/ static GIOStatus z_stream_fd_read_method(ZStream *stream, void *buf, gsize count, gsize *bytes_read, GError **error) { ZStreamFD *self = (ZStreamFD *) stream; GIOStatus res; GError *local_error = NULL; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (!z_stream_wait_fd(self, G_IO_IN | G_IO_HUP, self->super.timeout)) { g_set_error(&local_error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Channel read timed out"); res = G_IO_STATUS_ERROR; } else { res = g_io_channel_read_chars(self->channel, buf, count, bytes_read, &local_error); } if (!(self->super.umbrella_state & G_IO_IN)) { /* low-level logging if we're not the toplevel stream */ if (res == G_IO_STATUS_NORMAL) { /*LOG This message reports the number of bytes read from the given fd. */ z_log(self->super.name, CORE_DUMP, 8, "Reading channel; fd='%d', count='%zd'", self->fd, *bytes_read); z_log_data_dump(self->super.name, CORE_DUMP, 10, buf, *bytes_read); } else if (res == G_IO_STATUS_EOF) { /*LOG This message reports that EOF was read from the given fd. */ z_log(self->super.name, CORE_DUMP, 8, "Reading EOF on channel; fd='%d'", self->fd); } } if (local_error) g_propagate_error(error, local_error); z_return(res); } /** * Write to the fd encapsulated by a ZStreamFD instance. * * @param[in] stream ZStreamFD instance * @param[in] buf buffer to write the contents of * @param[in] count number of bytes to write * @param[out] bytes_written actual number of bytes written will be returned here * @param[out] error error value * * @returns GIOStatus value **/ static GIOStatus z_stream_fd_write_method(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamFD *self = (ZStreamFD *) stream; GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (self->shutdown) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Channel already shut down"); z_return(G_IO_STATUS_ERROR); } if (!z_stream_wait_fd(self, G_IO_OUT | G_IO_HUP, self->super.timeout)) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Channel write timed out"); z_return(G_IO_STATUS_ERROR); } res = g_io_channel_write_chars(self->channel, buf, count, bytes_written, error); if (!(self->super.umbrella_state & G_IO_OUT)) { /* low-level logging if we're not the toplevel stream */ if (res != G_IO_STATUS_AGAIN) { /*LOG This message reports the number of bytes read from the given fd. */ z_log(self->super.name, CORE_DUMP, 8, "Writing channel; fd='%d', count='%zd'", self->fd, *bytes_written); z_log_data_dump(self->super.name, CORE_DUMP, 10, buf, *bytes_written); } } z_return(res); } /** * Write priority data to the fd encapsulated by a ZStreamFD instance. * * @param[in] stream ZStreamFD instance * @param[in] buf buffer to write the contents of * @param[in] count number of bytes to write * @param[out] bytes_written actual number of bytes written will be returned here * @param[out] error error value * * @returns GIOStatus value **/ GIOStatus z_stream_fd_write_pri_method(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamFD *self = (ZStreamFD *) stream; int res, attempt = 1; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (self->shutdown) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Channel already shut down"); z_return(G_IO_STATUS_ERROR); } do { if (!z_stream_wait_fd(self, G_IO_OUT | G_IO_HUP, self->super.timeout)) { /*LOG This message indicates that send() timed out. */ z_log(self->super.name, CORE_ERROR, 1, "Send timed out; fd='%d'", self->fd); g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Channel send timed out"); z_return(G_IO_STATUS_ERROR); } res = send(self->fd, buf, count, MSG_OOB); if (res == -1) { if (!z_errno_is(EINTR) && !z_errno_is(EAGAIN)) { /*LOG This message indicates that some I/O error occurred in the send() system call. */ z_log(self->super.name, CORE_ERROR, 1, "Send failed; attempt='%d', error='%s'", attempt++, g_strerror(errno)); } } } while (res == -1 && z_errno_is(EINTR)); if (res >= 0) { *bytes_written = res; self->super.bytes_sent += res; z_return(G_IO_STATUS_NORMAL); } if (z_errno_is(EAGAIN)) z_return(G_IO_STATUS_AGAIN); g_clear_error(error); g_set_error (error, G_IO_CHANNEL_ERROR, g_io_channel_error_from_errno (z_errno_get()), "%s", strerror (z_errno_get())); z_return(G_IO_STATUS_ERROR); } /** * Close the socket associated with a ZStreamFD instance. * * @param[in] stream ZStreamFD instance * @param[in] i HOW argument to shutdown * @param[out] error error value * * shutdown(2) will be called on the fd. * * The action to perform is specified by i as follows: * - i == 0: Stop receiving data. * - i == 1: Stop trying to transmit data. * - i == 2: Stop both reception and transmission. * * @returns GIOStatus value **/ static GIOStatus z_stream_fd_shutdown_method(ZStream *stream, int i, GError **error) { ZStreamFD *self = (ZStreamFD *) stream; int res, attempt = 1; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); /*LOG This debug message indicates that shutdown is to be initiated on the given fd. */ z_log(self->super.name, CORE_DEBUG, 6, "Shutdown channel; fd='%d', mode='%d'", self->fd, i); do { res = shutdown(self->fd, i); if (res == -1) { if (!z_errno_is(EINTR)) { /*LOG This message indicates that the shutdown on the given fd was not successful. */ z_log(self->super.name, CORE_ERROR, 4, "Shutdown failed; attempt='%d', error='%s'", attempt++, g_strerror(errno)); } } } while (res == -1 && z_errno_is(EINTR)); if (res != 0) { g_set_error (error, G_IO_CHANNEL_ERROR, g_io_channel_error_from_errno (z_errno_get()), "%s", strerror (z_errno_get())); z_return(G_IO_STATUS_ERROR); } z_return(G_IO_STATUS_NORMAL); } /** * Close the fd associated with a ZStreamFD instance. * * @param[in] s ZStreamFD instance * @param[out] error error value * * @returns GIOStatus value **/ static GIOStatus z_stream_fd_close_method(ZStream *s, GError **error) { ZStreamFD *self = Z_CAST(s, ZStreamFD); GIOStatus res; z_enter(); res = Z_SUPER(self, ZStream)->close(s, error); if (res == G_IO_STATUS_NORMAL) res = g_io_channel_shutdown(self->channel, TRUE, error); z_return(res); } /** * Process stream control calls. * * @param[in] s ZStream instance * @param[in] function function selector * @param[in, out] value parameter to function * @param[in] vlen length of value * * @returns TRUE on success **/ static gboolean z_stream_fd_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen) { ZStreamFD *self = Z_CAST(s, ZStreamFD); z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_CTRL_SET_CLOSEONEXEC: if (vlen == sizeof(gboolean)) { gboolean cloexec = *((gboolean *)value); gint fd = self->fd; gint res; #ifndef G_OS_WIN32 if (cloexec) res = fcntl(fd, F_SETFD, FD_CLOEXEC); else res = fcntl(fd, F_SETFD, ~FD_CLOEXEC); #else res = 0; #endif if (res >= 0) z_return(TRUE); /*LOG This message indicates that an internal error occurred, during setting CLOSE_ON_EXEC mode on a stream. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, during setting CLOSE_ON_EXEC mode;"); } else { /*LOG This message indicates that an internal error occurred, during setting CLOSE_ON_EXEC mode on a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for setting CLOSE_ON_EXEC mode; size='%d'", vlen); } break; case ZST_CTRL_SET_NONBLOCK: if (vlen == sizeof(gboolean)) { gboolean nonblock = *((gboolean *)value); GIOStatus ret; GIOFlags flags; flags = g_io_channel_get_flags(self->channel); #ifndef G_OS_WIN32 if (nonblock) ret = g_io_channel_set_flags(self->channel, flags | G_IO_FLAG_NONBLOCK, NULL); else ret = g_io_channel_set_flags(self->channel, flags & ~G_IO_FLAG_NONBLOCK, NULL); #else z_fd_set_nonblock(self->fd, nonblock); ret = G_IO_STATUS_NORMAL; #endif if (ret == G_IO_STATUS_NORMAL) z_return(TRUE); /*LOG This message indicates that an internal error, during setting NONBLOCK mode on a stream. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, during setting NONBLOCK mode;"); } else /*LOG This message indicates that an internal error occurred, during setting NONBLOCK mode on a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for setting NONBLOCK mode; size='%d'", vlen); break; case ZST_CTRL_GET_NONBLOCK: if (vlen == sizeof(gboolean)) { GIOFlags flags; flags = g_io_channel_get_flags(self->channel); *((gboolean *) value) = !!(flags & G_IO_FLAG_NONBLOCK); z_return(TRUE); } /*LOG This message indicates that an internal error occurred, during getting NONBLOCK mode status on a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for getting the NONBLOCK mode; size='%d'", vlen); break; case ZST_CTRL_GET_FD: if (vlen == sizeof(gint)) { *((gint *)value) = self->fd; z_return(TRUE); } /*LOG This message indicates that an internal error occurred, during getting the FD of a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for getting the FD; size='%d'", vlen); break; case ZST_CTRL_GET_BROKEN: #ifndef G_OS_WIN32 if (vlen == sizeof(gboolean)) { gchar buf[1]; gint res; res = recv(self->fd, buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT); if ((res < 0 && (z_errno_is(EAGAIN) || z_errno_is(ENOTSOCK))) || res > 0) *((gboolean *)value) = FALSE; else *((gboolean *)value) = TRUE; z_return(TRUE); } /*LOG This message indicates that an internal error occurred, during getting the FD of a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for getting the broken state; size='%d'", vlen); #else z_log(NULL, CORE_ERROR, 4, "Internal error, this feature is not supported on Win32;"); z_return(FALSE); #endif break; case ZST_CTRL_GET_KEEPALIVE: if (vlen == sizeof(gint)) { *((gint *)value) = self->keepalive; z_leave(); return TRUE; } else /*LOG This message indicates that an internal error occurred, during getting the FD of a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for getting the KEEPALIVE option; size='%d'", vlen); break; case ZST_CTRL_SET_KEEPALIVE: if (vlen == sizeof(gint)) { self->keepalive = *((gint *)value); z_leave(); return TRUE; } else /*LOG This message indicates that an internal error occurred, during getting the FD of a stream, because the size of the parameter is wrong. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, bad parameter is given for setting the KEEPALIVE option; size='%d'", vlen); break; default: if (z_stream_ctrl_method(s, function, value, vlen)) z_return(TRUE); /*LOG This message indicates that an internal error occurred, because an invalid control was called. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 4, "Internal error, unknown stream ctrl; ctrl='%d'", ZST_CTRL_MSG(function)); break; } z_return(FALSE); } static void z_stream_fd_attach_source_method(ZStream *s, GMainContext *context) { ZStreamFD *self = (ZStreamFD *) s; z_enter(); Z_SUPER(self, ZStream)->attach_source(s, context); #ifdef G_OS_WIN32 self->pollfd.fd = self->winsock_event; z_trace(NULL, "WinSock: Event #%d created at %s line %d", self->pollfd.fd, __FILE__, __LINE__); #else self->pollfd.fd = self->fd; #endif g_source_add_poll(s->source, &self->pollfd); z_return(); } static gsize z_stream_fd_extra_get_size_method(ZStream *s) { return Z_SUPER(s, ZStream)->extra_get_size(s) + sizeof(ZStreamFDExtra); } static gsize z_stream_fd_extra_save_method(ZStream *s, gpointer extra) { ZStreamFDExtra *fd_extra; gsize ofs; ofs = Z_SUPER(s, ZStream)->extra_save(s, extra); fd_extra = (ZStreamFDExtra *) (((gchar *) extra) + ofs); fd_extra->nonblock = z_stream_get_nonblock(s); return ofs + sizeof(ZStreamFDExtra); } static gsize z_stream_fd_extra_restore_method(ZStream *s, gpointer extra) { ZStreamFDExtra *fd_extra; gsize ofs; ofs = Z_SUPER(s, ZStream)->extra_restore(s, extra); fd_extra = (ZStreamFDExtra *) (((gchar *) extra) + ofs); z_stream_set_nonblock(s, fd_extra->nonblock); return ofs + sizeof(ZStreamFDExtra); } /** * Allocate and initialize a ZStreamFD instance with the given fd and name. * * @param[in] fd fd to wrap this stream around * @param[in] name name to identify to stream in logs * * @returns ZStream instance **/ ZStream * z_stream_fd_new(gint fd, const gchar *name) { ZStreamFD *self; z_enter(); self = Z_CAST(z_stream_new(Z_CLASS(ZStreamFD), name, G_IO_IN|G_IO_OUT), ZStreamFD); self->fd = fd; #ifdef G_OS_WIN32 self->winsock_event = (int)WSACreateEvent(); self->channel = g_io_channel_win32_new_socket(fd); #else self->channel = g_io_channel_unix_new(fd); #endif self->keepalive = 0; self->shutdown = FALSE; g_io_channel_set_encoding(self->channel, NULL, NULL); g_io_channel_set_buffered(self->channel, FALSE); g_io_channel_set_close_on_unref(self->channel, FALSE); z_return(&self->super); } /** destructor */ static void z_stream_fd_free_method(ZObject *s) { ZStreamFD *self = Z_CAST(s, ZStreamFD); z_enter(); #ifdef G_OS_WIN32 z_trace(NULL, "WinSock: Event #%d destroyed at %s line %d", self->winsock_event, __FILE__, __LINE__); WSACloseEvent(self->winsock_event); #endif g_io_channel_unref(self->channel); z_stream_free_method(s); z_return(); } /** * ZStreamFD virtual methods. **/ static ZStreamFuncs z_stream_fd_funcs = { { Z_FUNCS_COUNT(ZStream), z_stream_fd_free_method }, z_stream_fd_read_method, z_stream_fd_write_method, NULL, z_stream_fd_write_pri_method, z_stream_fd_shutdown_method, z_stream_fd_close_method, z_stream_fd_ctrl_method, z_stream_fd_attach_source_method, NULL, /* detach_source */ z_stream_fd_watch_prepare, z_stream_fd_watch_check, z_stream_fd_watch_dispatch, NULL, /* watch_finalize */ z_stream_fd_extra_get_size_method, z_stream_fd_extra_save_method, z_stream_fd_extra_restore_method, NULL, NULL }; /** * ZStreamFD class descriptor. **/ Z_CLASS_DEF(ZStreamFD, ZStream, z_stream_fd_funcs); libzorpll-3.9.4.1/src/streamgzip.c000066400000000000000000000672131224546767600170530ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamgzip.c,v 1.5 2004/04/27 15:12:47 bazsi Exp $ * * Author : SaSa * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #ifdef G_OS_WIN32 # include #else # include # include #endif /** gzip stream state */ enum { Z_SGS_EOF_RECEIVED = 0x0001, Z_SGS_COMPRESS_FINISHED = 0x0002, Z_SGS_HEADER_READ = 0x0004, Z_SGS_HEADER_WRITTEN = 0x0008, Z_SGS_READ_ERROR = 0x0010, Z_SGS_WRITE_ERROR = 0x0020, }; extern ZClass ZStreamGzip__class; typedef struct _ZStreamGzip { ZStream super; guint flags; z_stream encode; z_stream decode; gsize buffer_length; /* FIXME: I think this is pointers below is NOT a void * */ void *buffer_encode_out; void *buffer_encode_out_p; void *buffer_decode_in; guint32 state; gint shutdown; GIOCondition child_cond; guint32 encode_crc, encode_in; time_t gzip_timestamp; gsize gzip_extra_len; gchar *gzip_extra; gchar *gzip_origname; gchar *gzip_comment; /* FIXME: header crc not supported yet */ } ZStreamGzip; /* NOTE: these values are defined but not exported by zlib */ #ifdef G_OS_WIN32 #define Z_GZ_OS_CODE 0x0b /**< win32 */ #else #define Z_GZ_OS_CODE 0x03 /**< unix */ #endif #define Z_GZH_ASCII_FLAG 0x01 /**< bit 0 set: file probably ascii text */ #define Z_GZH_HEAD_CRC 0x02 /**< bit 1 set: header CRC present */ #define Z_GZH_EXTRA_FIELD 0x04 /**< bit 2 set: extra field present */ #define Z_GZH_ORIG_NAME 0x08 /**< bit 3 set: original file name present */ #define Z_GZH_COMMENT 0x10 /**< bit 4 set: file comment present */ #define Z_GZH_RESERVED 0xE0 /**< bits 5..7: reserved */ #define MAX_GZIP_HEADER_STRING 4096 /** * This is an internal function to read a gzip header style, NUL * terminated string from a stream. * * @param[in] child stream to read data from (usually the gzip child stream * @param[out] dest return the gzip string here * * It is used to fetch the comment/origname fields in the gzip header. **/ static gboolean z_stream_gzip_read_gzip_string(ZStream *child, gchar **dest) { gchar buf[MAX_GZIP_HEADER_STRING]; gsize rdlen = 0, br; GIOStatus status; while (rdlen < sizeof(buf) - 1 && (status = z_stream_read(child, &buf[rdlen], 1, &br, NULL)) == G_IO_STATUS_NORMAL && buf[rdlen] != 0) { rdlen += br; } if (buf[rdlen] != 0) { /* string longer than MAX_GZIP_HEADER_STRING, truncate buf */ gchar ch; while ((status = z_stream_read(child, &ch, 1, &br, NULL)) == G_IO_STATUS_NORMAL && ch != 0) { } } if (status != G_IO_STATUS_NORMAL) return FALSE; buf[rdlen] = 0; *dest = strdup(buf); return TRUE; } /** * This function frees memory associated with the gzip header and sets * everything back to 'not-set' state. * * @param[in] self ZStreamGzip instance **/ static void z_stream_gzip_reset_gzip_header(ZStreamGzip *self) { if (self->gzip_origname) { g_free(self->gzip_origname); self->gzip_origname = NULL; } if (self->gzip_comment) { g_free(self->gzip_comment); self->gzip_comment = NULL; } if (self->gzip_extra) { g_free(self->gzip_extra); self->gzip_extra = NULL; } self->gzip_extra_len = 0; } /** * This internal function fetches a GZip header from the child stream * and stores the results in self. * * @param[in] self ZStreamGzip instance * @param[out] error error value * * @returns FALSE to indicate failure (in which case it also sets error) **/ static gboolean z_stream_gzip_read_gzip_header(ZStreamGzip *self, GError **error) { ZStream *child = self->super.child; guchar buf[16]; gsize br; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if ((self->flags & Z_SGZ_GZIP_HEADER) && (self->state & Z_SGS_HEADER_READ) == 0) { self->state |= Z_SGS_HEADER_READ; z_stream_gzip_reset_gzip_header(self); if (z_stream_read_chunk(child, buf, 4, &br, error) != G_IO_STATUS_NORMAL || br != 4) goto error; if (!GZIP_IS_GZIP_MAGIC(buf)) goto error; if (z_stream_read_chunk(child, buf + 4, 6, &br, error) != G_IO_STATUS_NORMAL || br != 6) goto error; self->gzip_timestamp = (time_t) (((guint)buf[7]) << 24) | (((guint)buf[6]) << 16) | (((guint)buf[5]) << 8) | buf[4]; if (buf[3] & Z_GZH_EXTRA_FIELD) { if (z_stream_read_chunk(child, buf, 2, &br, error) != G_IO_STATUS_NORMAL || br != 2) goto error; self->gzip_extra_len = buf[0] + (((guint)buf[1]) << 8); self->gzip_extra = g_new0(gchar, self->gzip_extra_len); if (z_stream_read_chunk(child, self->gzip_extra, self->gzip_extra_len, &br, error) != G_IO_STATUS_NORMAL || br != self->gzip_extra_len) goto error; } if (buf[3] & Z_GZH_ORIG_NAME) { if (!z_stream_gzip_read_gzip_string(child, &self->gzip_origname)) goto error; } if (buf[3] & Z_GZH_COMMENT) { if (!z_stream_gzip_read_gzip_string(child, &self->gzip_comment)) goto error; } if ((buf[3] & Z_GZH_HEAD_CRC) && (z_stream_read_chunk(child, buf, 2, &br, error) != G_IO_STATUS_NORMAL || br != 2)) goto error; } z_return(TRUE); error: z_return(FALSE); } /** * Write a gzip header into a stream. * * @param[in] self the stream * @param[out] error error value * * All args have default values, so if timestamp is zero, the current time is used, the string fields * are written as empty if NULL. * * @returns The status of the operation. **/ static gboolean z_stream_gzip_write_gzip_header(ZStreamGzip *self, GError **error) { /* FIXME: writing of header crc not supported yet */ ZStream *sc = self->super.child; gchar buf[16]; GError *local_error = NULL; gsize bw; g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if ((self->flags & Z_SGZ_GZIP_HEADER) && (self->state & Z_SGS_HEADER_WRITTEN) == 0) { self->state |= Z_SGS_HEADER_WRITTEN; g_snprintf(buf, sizeof(buf), "%c%c%c%c%c%c%c%c%c%c", GZIP_MAGIC_1, GZIP_MAGIC_2, Z_DEFLATED, (self->gzip_origname ? Z_GZH_ORIG_NAME : 0) | (self->gzip_comment ? Z_GZH_COMMENT : 0) | (self->gzip_extra ? Z_GZH_EXTRA_FIELD : 0), (gint) (self->gzip_timestamp & 0xff), (gint) ((self->gzip_timestamp >> 8) & 0xff), (gint) ((self->gzip_timestamp >> 16) & 0xff), (gint) ((self->gzip_timestamp >> 24) & 0xff), 0 /*xflags*/, Z_GZ_OS_CODE); if (z_stream_write_chunk(sc, buf, 10, &bw, &local_error) != G_IO_STATUS_NORMAL) goto error; if (self->gzip_extra) { buf[0] = self->gzip_extra_len & 0xff; buf[1] = (self->gzip_extra_len >> 8) & 0xff; if (z_stream_write_chunk(sc, buf, 2, &bw, &local_error) != G_IO_STATUS_NORMAL) goto error; if (z_stream_write_chunk(sc, self->gzip_extra, self->gzip_extra_len, &bw, &local_error) != G_IO_STATUS_NORMAL) goto error; } if (self->gzip_origname && z_stream_write_chunk(sc, self->gzip_origname, 1 + strlen(self->gzip_origname), &bw, &local_error) != G_IO_STATUS_NORMAL) goto error; if (self->gzip_comment && z_stream_write_chunk(sc, self->gzip_comment, 1 + strlen(self->gzip_comment), &bw, &local_error) != G_IO_STATUS_NORMAL) goto error; } z_return(TRUE); error: if (local_error) g_propagate_error(error, local_error); z_return(FALSE); } static gboolean z_stream_gzip_write_gzip_trailer(ZStreamGzip *self, GError **error) { gsize bw; g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if ((self->flags & Z_SGZ_GZIP_HEADER) && (self->state & Z_SGS_HEADER_WRITTEN) != 0) { gint j; guint32 x; guchar buf[8]; x = self->encode_crc; for (j = 0; j < 4; j++) { buf[j] = (x & 0xff); x >>= 8; } x = self->encode_in; for (j = 4; j < 8; j++) { buf[j] = (x & 0xff); x >>= 8; } x = 8; if (z_stream_write_chunk(self->super.child, buf, 8, &bw, error) != G_IO_STATUS_NORMAL) return FALSE; } return TRUE; } /* I/O callbacks for stacked stream */ static gboolean z_stream_gzip_read_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond G_GNUC_UNUSED, gpointer s) { ZStreamGzip *self = Z_CAST(s, ZStreamGzip); z_enter(); self->child_cond |= G_IO_IN; z_return(TRUE); } static gboolean z_stream_gzip_write_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond G_GNUC_UNUSED, gpointer s) { ZStreamGzip *self = Z_CAST(s, ZStreamGzip); GIOStatus res; z_enter(); /* * If some data in output buffer try to write it out. * If write is not success leave it, and doesn't set * it writeable. */ if (self->encode.avail_out < self->buffer_length) { gint length = (gchar *)self->encode.next_out - (gchar *)self->buffer_encode_out_p; gsize writted_length; res = z_stream_write(self->super.child, self->buffer_encode_out_p, length, &writted_length, NULL); if (res == G_IO_STATUS_AGAIN) z_return(TRUE); if (res != G_IO_STATUS_NORMAL) { self->state |= Z_SGS_WRITE_ERROR; z_return(TRUE); } /*FIXME: See the same expression in stream.c */ self->buffer_encode_out_p = (void *)(gchar *) ((gchar *)self->buffer_encode_out_p + writted_length); if ((gchar *)self->buffer_encode_out_p != (gchar *)self->encode.next_out) z_return(TRUE); } self->child_cond |= G_IO_OUT; z_return(TRUE); } /* virtual methods */ static GIOStatus z_stream_gzip_read_method(ZStream *stream, void *buf, gsize count, gsize *bytes_read, GError **error) { ZStreamGzip *self = Z_CAST(stream, ZStreamGzip); GIOStatus res; gint ret; GError *local_error = NULL; z_enter(); self->child_cond &= ~G_IO_IN; if (self->shutdown & G_IO_IN) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Read direction already shut down"); z_return(G_IO_STATUS_ERROR); } if (self->state & Z_SGS_COMPRESS_FINISHED) z_return(G_IO_STATUS_EOF); if (self->state & Z_SGS_READ_ERROR) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Previously stored error condition"); z_return(G_IO_STATUS_ERROR); } if (!z_stream_gzip_read_gzip_header(self, error)) z_return(G_IO_STATUS_ERROR); self->decode.next_out = buf; self->decode.avail_out = count; if (self->decode.avail_in == 0 && (self->state & Z_SGS_EOF_RECEIVED) == 0) { gsize length; self->decode.next_in = self->buffer_decode_in; res = z_stream_read(self->super.child, self->decode.next_in, self->buffer_length, &length, &local_error); self->decode.avail_in = length; if (res == G_IO_STATUS_AGAIN) { z_return(G_IO_STATUS_AGAIN); } else if (res == G_IO_STATUS_EOF) { self->state |= Z_SGS_EOF_RECEIVED; } else if (res != G_IO_STATUS_NORMAL) { self->state |= Z_SGS_READ_ERROR; if (local_error) g_propagate_error(error, local_error); z_return(G_IO_STATUS_ERROR); } } ret = inflate(&self->decode, Z_NO_FLUSH); if ((ret != Z_OK) && (ret != Z_STREAM_END)) { self->state |= Z_SGS_READ_ERROR; g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Error while inflating data (%s)", Z_STRING_SAFE(self->decode.msg)); z_return(G_IO_STATUS_ERROR); } if (ret == Z_STREAM_END) self->state |= Z_SGS_COMPRESS_FINISHED; /* FIXME: the crc32 trailer is not read */ *bytes_read = count - self->decode.avail_out; z_return(G_IO_STATUS_NORMAL); } static GIOStatus z_stream_gzip_write_method(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamGzip *self = Z_CAST(stream, ZStreamGzip); GIOStatus res = G_IO_STATUS_NORMAL; gint rc; gsize length; gsize writted_length; GError *local_error = NULL; z_enter(); self->child_cond &= ~G_IO_OUT; if (self->shutdown & G_IO_OUT) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Write direction already shut down"); z_return(G_IO_STATUS_ERROR); } if (self->state & Z_SGS_WRITE_ERROR) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Previously stored error condition"); z_return(G_IO_STATUS_ERROR); } if (!z_stream_gzip_write_gzip_header(self, error)) z_return(G_IO_STATUS_ERROR); if (self->encode.avail_out < self->buffer_length) { length = (gchar *)self->encode.next_out - (gchar *)self->buffer_encode_out_p; res = z_stream_write(self->super.child, self->buffer_encode_out_p, length, &writted_length, &local_error); if (res == G_IO_STATUS_AGAIN) z_return(G_IO_STATUS_AGAIN); if (res != G_IO_STATUS_NORMAL) { if (local_error) g_propagate_error(error, local_error); self->state |= Z_SGS_WRITE_ERROR; z_return(G_IO_STATUS_ERROR); } self->buffer_encode_out_p = (void *)(gchar *) ((gchar *)self->buffer_encode_out_p + writted_length); if ((gchar *)self->buffer_encode_out_p != (gchar *)self->encode.next_out) z_return(G_IO_STATUS_AGAIN); } self->encode.next_out = self->buffer_encode_out; self->encode.avail_out = self->buffer_length; self->encode.next_in = (void *) buf; self->encode.avail_in = count; self->buffer_encode_out_p = self->buffer_encode_out; while (res == G_IO_STATUS_NORMAL && self->encode.avail_in) { if (self->encode.avail_out) { rc = deflate(&self->encode, self->flags & Z_SGZ_SYNC_FLUSH ? Z_SYNC_FLUSH : Z_NO_FLUSH); if (rc != Z_OK) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Error while deflating data (%s)", self->encode.msg); self->state |= Z_SGS_READ_ERROR; z_return(G_IO_STATUS_ERROR); } } length = self->buffer_length - self->encode.avail_out; res = z_stream_write(self->super.child, self->buffer_encode_out, length, &writted_length, &local_error); if (res == G_IO_STATUS_NORMAL) { self->buffer_encode_out_p = (void *)(gchar *) ((gchar *)self->buffer_encode_out_p + writted_length); if ((gchar *)self->buffer_encode_out_p == (gchar *)self->encode.next_out) { self->encode.next_out = self->buffer_encode_out; self->encode.avail_out = self->buffer_length; self->buffer_encode_out_p = self->buffer_encode_out; } } else if (res != G_IO_STATUS_AGAIN) { self->state |= Z_SGS_WRITE_ERROR; if (local_error) g_propagate_error(error, local_error); z_return(G_IO_STATUS_ERROR); } } *bytes_written = count - self->encode.avail_in; if (*bytes_written == 0) z_return(G_IO_STATUS_AGAIN); if (self->flags & Z_SGZ_GZIP_HEADER) { self->encode_crc = crc32(self->encode_crc, buf, *bytes_written); self->encode_in += *bytes_written; } z_return(G_IO_STATUS_NORMAL); } static GIOStatus z_stream_gzip_shutdown_method(ZStream *stream, int method, GError **error) { ZStreamGzip *self = Z_CAST(stream, ZStreamGzip); GIOStatus res = G_IO_STATUS_ERROR, ret = G_IO_STATUS_NORMAL; GError *local_error = NULL; gint rc; /* FIXME: do not use res and ret at the same time */ z_enter(); if ((method == SHUT_RD || method == SHUT_RDWR) && (self->shutdown & G_IO_IN) == 0) { rc = inflateEnd(&self->decode); if (rc == Z_OK) res = G_IO_STATUS_NORMAL; self->shutdown |= G_IO_IN; } if ((method == SHUT_WR || method == SHUT_RDWR) && (self->shutdown & G_IO_OUT) == 0) { gboolean i; gsize length; i = z_stream_get_nonblock(self->super.child); z_stream_set_nonblock(self->super.child, FALSE); while ((gchar *)self->buffer_encode_out_p != (gchar *)self->encode.next_out && ret == G_IO_STATUS_NORMAL) { ret = z_stream_write(self->super.child, self->buffer_encode_out_p, (gchar *)self->encode.next_out - (gchar *)self->buffer_encode_out_p, &length, &local_error); if (ret == G_IO_STATUS_NORMAL) self->buffer_encode_out_p = (void *)(gchar *) ((gchar *)self->buffer_encode_out_p + length); } if (ret == G_IO_STATUS_NORMAL) { self->encode.avail_out = self->buffer_length; self->encode.next_out = self->buffer_encode_out; self->encode.avail_in = 0; self->encode.next_in = NULL; self->buffer_encode_out_p = self->buffer_encode_out; rc = deflate(&self->encode, Z_FINISH); if (rc == Z_STREAM_END) { if (self->encode.avail_out < self->buffer_length) { while ((gchar *)self->buffer_encode_out_p != (gchar *)self->encode.next_out && ret == G_IO_STATUS_NORMAL) { ret = z_stream_write(self->super.child, self->buffer_encode_out_p, (gchar *)self->encode.next_out - (gchar *)self->buffer_encode_out_p, &length, &local_error); if (ret == G_IO_STATUS_NORMAL) self->buffer_encode_out_p = (void *)(gchar *) ((gchar *)self->buffer_encode_out_p + length); } } if (self->flags & Z_SGZ_WRITE_EMPTY_HEADER) { if (!z_stream_gzip_write_gzip_header(self, &local_error)) res = G_IO_STATUS_ERROR; } if (res == G_IO_STATUS_NORMAL && !z_stream_gzip_write_gzip_trailer(self, &local_error)) res = G_IO_STATUS_ERROR; } } z_stream_set_nonblock(self->super.child, i); rc = deflateEnd(&self->encode); if (ret == G_IO_STATUS_NORMAL && rc == Z_OK) res = G_IO_STATUS_NORMAL; self->shutdown |= G_IO_OUT; } ret = z_stream_shutdown(self->super.child, method, error); if (ret != G_IO_STATUS_NORMAL) res = ret; if (local_error) g_propagate_error(error, local_error); z_return(res); } static GIOStatus z_stream_gzip_close_method(ZStream *s, GError **error) { GIOStatus st_shutdown, st_close; z_enter(); st_shutdown = z_stream_gzip_shutdown_method(s, SHUT_RDWR, NULL); st_close = Z_SUPER(s, ZStream)->close(s, error); if (st_shutdown != G_IO_STATUS_NORMAL) z_return(st_shutdown); z_return(st_close); } /** * Process stream control calls. * * @param[in] stream ZStream instance * @param[in] function function selector * @param[in, out] value parameter to function * @param[in] vlen length of value * * @returns TRUE on success **/ static gboolean z_stream_gzip_ctrl_method(ZStream *stream, guint function, gpointer value, guint vlen) { gboolean ret = FALSE; z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_CTRL_SET_CALLBACK_READ: case ZST_CTRL_SET_CALLBACK_WRITE: case ZST_CTRL_SET_CALLBACK_PRI: ret = z_stream_ctrl_method(stream, function, value, vlen); break; case ZST_CTRL_GET_BUFFERED_BYTES: if (vlen == sizeof(gsize)) { gsize *size = (gsize *) value; ZStreamGzip *self = Z_CAST(stream, ZStreamGzip); *size += self->decode.avail_in; ret = TRUE; if (stream->child) ret = z_stream_ctrl(stream->child, ZST_CTRL_MSG_FORWARD | function, value, vlen); } break; default: ret = z_stream_ctrl_method(stream, ZST_CTRL_MSG_FORWARD | function, value, vlen); break; } z_return(ret); } static gboolean z_stream_gzip_watch_prepare(ZStream *s, GSource *src G_GNUC_UNUSED, gint *timeout) { ZStreamGzip *self = Z_CAST(s, ZStreamGzip); gboolean ret = FALSE; gboolean child_readable, child_enable; z_enter(); *timeout = -1; if (s->want_read) { child_readable = !!(self->child_cond & G_IO_IN); if (self->decode.avail_in == 0 && !child_readable) { child_enable = TRUE; } else { child_enable = FALSE; ret = TRUE; } } else { child_enable = FALSE; } z_stream_set_cond(s->child, G_IO_IN, child_enable); if (s->want_write) { if (self->encode.avail_out == self->buffer_length) ret = TRUE; } if (self->encode.avail_out != self->buffer_length) z_stream_set_cond(s->child, G_IO_OUT, TRUE); else z_stream_set_cond(s->child, G_IO_OUT, FALSE); z_return(ret); } static gboolean z_stream_gzip_watch_check(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamGzip *self = Z_CAST(s, ZStreamGzip); gboolean ret = FALSE; gboolean child_readable, child_writeable; z_enter(); if (s->want_read) { child_readable = !!(self->child_cond & G_IO_IN); if (self->decode.avail_in || child_readable) ret = TRUE; } if (s->want_write) { child_writeable = !!(self->child_cond & G_IO_OUT); if (self->encode.avail_out == self->buffer_length || child_writeable) ret = TRUE; } z_return(ret); } static gboolean z_stream_gzip_watch_dispatch(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamGzip *self = Z_CAST(s, ZStreamGzip); gboolean rc = TRUE; gboolean child_readable, child_writeable; z_enter(); if (s->want_read && rc) { child_readable = !!(self->child_cond & G_IO_IN); if (self->decode.avail_in || child_readable) rc = self->super.read_cb(s, G_IO_IN, self->super.user_data_read); } if (s->want_write && rc) { child_writeable = !!(self->child_cond & G_IO_OUT); if (self->encode.avail_out == self->buffer_length || child_writeable) rc = self->super.write_cb(s, G_IO_OUT, self->super.user_data_write); } z_return(rc); } static void z_stream_gzip_set_child(ZStream *s, ZStream *new_child) { ZStreamGzip *self = Z_CAST(s, ZStreamGzip); z_stream_ref(s); Z_SUPER(s, ZStream)->set_child(s, new_child); if (new_child) { z_stream_set_callback(new_child, G_IO_IN, z_stream_gzip_read_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(new_child, G_IO_OUT, z_stream_gzip_write_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); g_assert((self->flags & Z_SGZ_GZIP_HEADER) == 0 || z_stream_get_nonblock(new_child) == FALSE); } z_stream_unref(s); } /** * Get header fields. * * @param[in] s stream top * @param[out] timestamp returned timestamp * @param[out] origname returned original name * @param[out] comment returned comment * @param[out] extra_len returned length of extra data * @param[out] extra returned extra data * * This function returns the gzip header values as stored in the * top-most gzip stream. The header fields are implicitly set by the * first read operation, or by an explicit call to * z_stream_gzip_fetch_header(). * * Any NULL pointers passed for any of the [out] variables results * nothing being returned for those values. **/ void z_stream_gzip_get_header_fields(ZStream *s, time_t *timestamp, gchar **origname, gchar **comment, gint *extra_len, gchar **extra) { ZStreamGzip *self; self = Z_CAST(z_stream_search_stack(s, G_IO_IN, Z_CLASS(ZStreamGzip)), ZStreamGzip); if (timestamp) *timestamp = self->gzip_timestamp; if (origname) *origname = self->gzip_origname; if (comment) *comment = self->gzip_comment; if (extra_len && extra) { *extra = self->gzip_extra; *extra_len = self->gzip_extra_len; } } /** * This function sets the gzip header fields to be written * automatically on the first write operation, or during shutdown. * * @param[in] s stream top * @param[in] timestamp timestamp * @param[in] origname original name * @param[in] comment comment * @param[in] extra_len length of extra data * @param[in] extra extra data **/ void z_stream_gzip_set_header_fields(ZStream *s, time_t timestamp, const gchar *origname, const gchar *comment, gint extra_len, const gchar *extra) { ZStreamGzip *self; z_enter(); self = Z_CAST(z_stream_search_stack(s, G_IO_OUT, Z_CLASS(ZStreamGzip)), ZStreamGzip); z_stream_gzip_reset_gzip_header(self); self->gzip_timestamp = timestamp ? timestamp : time(NULL); self->gzip_origname = g_strdup(origname); self->gzip_comment = g_strdup(comment); if (extra_len > 0) { self->gzip_extra_len = extra_len; memcpy(self->gzip_extra, extra, extra_len); } z_return(); } /** * This function explicitly requests the gzip header to be read if * Z_SGZ_GZIP_HEADER is set without actually attempting to decompress * data. * * @param[in] s stream top * @param[out] error error value * * It is useful when the contents of the gzip header are needed * before issuing the first read operation. **/ gboolean z_stream_gzip_fetch_header(ZStream *s, GError **error) { ZStreamGzip *self; self = Z_CAST(z_stream_search_stack(s, G_IO_IN, Z_CLASS(ZStreamGzip)), ZStreamGzip); return z_stream_gzip_read_gzip_header(self, error); } /** constructor */ /* * Flags: * - Automatic flush */ ZStream * z_stream_gzip_new(ZStream *child, gint flags, guint level, guint buffer_length) { ZStreamGzip *self; z_enter(); self = Z_CAST(z_stream_new(Z_CLASS(ZStreamGzip), child ? child->name : "", G_IO_IN | G_IO_OUT), ZStreamGzip); self->flags = flags; if (flags & Z_SGZ_GZIP_HEADER) { deflateInit2(&self->encode, level, Z_DEFLATED, -MAX_WBITS, level, Z_DEFAULT_STRATEGY); inflateInit2(&self->decode, -MAX_WBITS); /* windowBits is passed < 0 to suppress zlib header */ } else { deflateInit(&self->encode, level); inflateInit(&self->decode); } self->gzip_timestamp = 0; self->gzip_extra_len = 0; self->gzip_extra = self->gzip_origname = self->gzip_comment = NULL; self->buffer_length = buffer_length; self->buffer_encode_out = g_new(gchar, self->buffer_length); self->buffer_decode_in = g_new(gchar, self->buffer_length); self->encode.next_out = self->buffer_encode_out; self->encode.avail_out = self->buffer_length; self->buffer_encode_out_p = self->buffer_encode_out; z_stream_set_child(&self->super, child); z_return((ZStream *) self); } /** destructor */ static void z_stream_gzip_free_method(ZObject *s) { ZStreamGzip *self = Z_CAST(s, ZStreamGzip); z_enter(); g_free(self->buffer_encode_out); g_free(self->buffer_decode_in); z_stream_gzip_reset_gzip_header(self); z_stream_free_method(s); z_return(); } /** * ZStreamGzip virtual methods. **/ ZStreamFuncs z_stream_gzip_funcs = { { Z_FUNCS_COUNT(ZStream), z_stream_gzip_free_method, }, z_stream_gzip_read_method, z_stream_gzip_write_method, NULL, NULL, z_stream_gzip_shutdown_method, z_stream_gzip_close_method, z_stream_gzip_ctrl_method, NULL, /* attach_source */ NULL, /* detach_source */ z_stream_gzip_watch_prepare, z_stream_gzip_watch_check, z_stream_gzip_watch_dispatch, NULL, NULL, NULL, NULL, z_stream_gzip_set_child, NULL, }; Z_CLASS_DEF(ZStreamGzip, ZStream, z_stream_gzip_funcs); libzorpll-3.9.4.1/src/streamline.c000066400000000000000000000754731224546767600170400ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamline.c,v 1.87 2004/07/29 08:40:18 bazsi Exp $ * * Author : SaSa * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #include #include #include #ifdef G_OS_WIN32 # include #else # include # include #endif #define ZRL_SAVED_FLAGS_MASK 0x0000FFFF #define ZRL_IGNORE_TILL_EOL 0x00010000 #define ZRL_LINE_AVAIL_SET 0x00020000 #define ZRL_LINE_AVAIL 0x00040000 #define ZRL_ERROR 0x00080000 #define ZRL_EOF 0x00100000 extern ZClass ZStreamLine__class; /** * ZStream-derived class for line-based I/O. **/ typedef struct _ZStreamLine { ZStream super; guint flags; gchar *buffer; gsize bufsize, pos, end, oldpos; GIOCondition child_cond; } ZStreamLine; /** * ZStreamLine extra context data. **/ typedef struct _ZStreamLineExtra { guint flags; } ZStreamLineExtra; /** * Check if a line can be read from the buffer. * * @param[in] self ZStreamLine instance * * @returns whether a line can be read **/ static inline gboolean z_stream_line_have_line(ZStreamLine *self) { z_enter(); if (!(self->flags & ZRL_LINE_AVAIL_SET)) { gsize avail = self->end - self->pos; gchar *eol; eol = memchr(self->buffer + self->pos, self->flags & ZRL_EOL_NUL ? '\0' : '\n', avail); self->flags |= ZRL_LINE_AVAIL_SET; if (eol) self->flags |= ZRL_LINE_AVAIL; else self->flags &= ~ZRL_LINE_AVAIL; } z_return(!!(self->flags & ZRL_LINE_AVAIL)); } /** * Check if buffer is empty. * * @param[in] self ZStreamLine instance * * @returns whether buffer is empty **/ static inline gboolean z_stream_line_buf_empty(ZStreamLine *self) { return self->pos == self->end; } /** * Internal function used by z_stream_line_get_internal() * to read a line from the buffer. * * @param[in] self ZStreamLine instance * @param[out] line pointer to the line will be returned here * @param[out] length length of the line will be returned here * @param[out] error error value * * The string line points to won't be null-terminated. * * @returns GIOStatus value **/ static GIOStatus z_stream_line_get_from_buf(ZStreamLine *self, gchar **line, gsize *length, GError **error) { gsize avail = self->end - self->pos; gchar *eol = memchr(self->buffer + self->pos, self->flags & ZRL_EOL_NUL ? '\0' : '\n', avail); gchar *nul; gint eol_len = 0; z_enter(); /* if we encountered eof in the input stream, return all the buffer as a line */ if (self->flags & ZRL_EOF) eol = self->buffer + self->end - 1; if (eol) { *length = eol - (self->buffer + self->pos) + 1; *line = self->buffer + self->pos; self->oldpos = self->pos; self->pos += *length; if (!(self->flags & ZRL_EOL_NUL)) { nul = memchr(*line, '\0', *length); if (nul) { if (!(self->flags & ZRL_NUL_NONFATAL)) { /*LOG This message indicates that an invalid NUL character was found in the line, but the policy prohibits it. */ g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Invalid line, embedded NUL character found, buffer=[%.*s]", (gint) *length, *line); z_return(G_IO_STATUS_ERROR); } } } if (!(self->flags & ZRL_EOF)) { if ((self->flags & ZRL_EOL_NL) || (self->flags & ZRL_EOL_NUL)) { (*length)--; eol_len++; } else if (self->flags & ZRL_EOL_CRLF) { (*length)--; eol_len++; if (eol - self->buffer >= 1 && *(eol - 1) == '\r') { (*length)--; eol_len++; } else if (self->flags & ZRL_EOL_FATAL) { /*LOG This message indicates that the CRLF sequence was invalid, because no LF character was found before the CR character, but the policy requires it. */ g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Invalid line, bad CRLF sequence, buffer=[%.*s]", (gint) *length, *line); z_return(G_IO_STATUS_ERROR); } } if (self->flags & ZRL_RETURN_EOL) (*length) += eol_len; } z_return(G_IO_STATUS_NORMAL); } else if (self->pos) { *length = 0; memmove(self->buffer, self->buffer + self->pos, avail); self->end = avail; self->pos = 0; self->oldpos = 0; } z_return(G_IO_STATUS_AGAIN); } /** * Internal function used by z_stream_line_get() and z_stream_line_get_copy() * to get a line, reading to fill the buffer as necessary. * * @param[in] self ZStreamLine instance * @param[out] line pointer to the line will be returned here * @param[out] length length of the line will be returned here * @param[out] error error value * * Also handles some flags like ZRL_IGNORE_TILL_EOL. * * The string line points to won't be null-terminated. * * @returns GIOStatus value **/ static GIOStatus z_stream_line_get_internal(ZStreamLine *self, gchar **line, gsize *length, GError **error) { gsize avail, bytes_read; GError *local_error = NULL; GIOStatus rc; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (self->flags & ZRL_ERROR) { g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Previously stored error condition"); z_return(G_IO_STATUS_ERROR); } if (self->flags & ZRL_EOF) z_return(G_IO_STATUS_EOF); self->child_cond = 0; self->flags &= ~ZRL_LINE_AVAIL_SET; if (self->end != self->pos) { /* we have something, try to return it */ rc = z_stream_line_get_from_buf(self, line, length, &local_error); if (rc == G_IO_STATUS_NORMAL) { self->super.bytes_recvd += *length; z_return(rc); } if (rc == G_IO_STATUS_ERROR) { /* no need to log, we sent the exact error reason in get_from_buf() */ if (local_error) g_propagate_error(error, local_error); self->flags |= ZRL_ERROR; z_return(rc); } /* the available data is now at the beginning of our buffer */ } else { self->pos = self->end = self->oldpos = 0; } *length = 0; *line = NULL; while (1) { avail = self->bufsize - self->end; if (!avail) { /* * this means that there's no space in the buffer, and no eol could * be found */ if (self->flags & ZRL_IGNORE_TILL_EOL) { self->pos = self->end = self->oldpos = 0; avail = self->bufsize; } else if (self->flags & ZRL_TRUNCATE) { *line = self->buffer; *length = self->bufsize; self->super.bytes_recvd += *length; self->pos = self->end = self->oldpos = 0; self->flags |= ZRL_IGNORE_TILL_EOL; z_return(G_IO_STATUS_NORMAL); } else if (self->flags & ZRL_SPLIT) { /** * @todo FIXME: this hack violates the standard GIOStatus model, as * it returns G_IO_STATUS_AGAIN while consuming some of the * input data, callers detect this case by checking whether * line_len is not 0. **/ *line = self->buffer; *length = self->bufsize; self->super.bytes_recvd += *length; self->pos = self->end = self->oldpos = 0; z_return(G_IO_STATUS_AGAIN); } else { /*LOG This message is sent when the proxy reading too long input line. This may be caused by a cracking attempt. But if not try to increase max_line_length. */ g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Line too long, buffer=[%.*s], max_line_length=[%d]", (gint) self->bufsize, self->buffer, (gint) self->bufsize); *line = NULL; *length = 0; self->flags |= ZRL_ERROR; z_return(G_IO_STATUS_ERROR); } } self->super.child->timeout = self->super.timeout; rc = z_stream_read(self->super.child, self->buffer + self->end, avail, &bytes_read, &local_error); switch (rc) { case G_IO_STATUS_EOF: if ((self->flags & ZRL_EOF) || (self->pos == self->end)) z_return(G_IO_STATUS_EOF); self->flags |= ZRL_EOF; bytes_read = 0; /* intentional fallthrough */ case G_IO_STATUS_NORMAL: self->end += bytes_read; maybe_another_line: rc = z_stream_line_get_from_buf(self, line, length, &local_error); switch (rc) { case G_IO_STATUS_NORMAL: if (self->flags & ZRL_IGNORE_TILL_EOL) { self->flags &= ~ZRL_IGNORE_TILL_EOL; goto maybe_another_line; } else { self->super.bytes_recvd += *length; z_return(rc); } case G_IO_STATUS_AGAIN: if (self->flags & ZRL_SINGLE_READ) { *line = NULL; *length = 0; z_return(rc); } break; default: if (local_error) g_propagate_error(error, local_error); *line = NULL; *length = 0; z_return(rc); } break; case G_IO_STATUS_AGAIN: *line = NULL; *length = 0; z_return(G_IO_STATUS_AGAIN); default: if (local_error) g_propagate_error(error, local_error); self->flags |= ZRL_ERROR; z_return(G_IO_STATUS_ERROR); } } } /** * Read a line from a ZStream and give a pointer to it in the buffer. * * @param[in] stream ZStream instance * @param[out] line pointer to the line will be returned here * @param[out] length length of the line will be returned here * @param[out] error error value * * The first child of stream that is of class ZStreamLine will be sought * and the line will be requested from that instance. * * The string line points to won't be null-terminated. * * @returns GIOStatus value **/ GIOStatus z_stream_line_get(ZStream *stream, gchar **line, gsize *length, GError **error) { ZStreamLine *self; GIOStatus res; GError *local_error = NULL; self = Z_CAST(z_stream_search_stack(stream, G_IO_IN, Z_CLASS(ZStreamLine)), ZStreamLine); res = z_stream_line_get_internal(self, line, length, &local_error); if (local_error) { z_log(self->super.name, CORE_ERROR, 3, "Error while fetching line; error='%s'", local_error->message); g_propagate_error(error, local_error); } if (res == G_IO_STATUS_NORMAL) z_stream_data_dump(&self->super, G_IO_IN, *line, *length); return res; } /** * Read a line from a ZStream and copy it into the buffer given. * * @param[in] s ZStream instance * @param[in] line buffer where the line will be copied * @param[in, out] length in: the size of the buffer provided in line; out: the length of the line returned * @param[out] error error value * * The first child of stream that is of class ZStreamLine will be sought * and the line will be requested from that instance. * * The string line points to won't be null-terminated. * * @returns GIOStatus value **/ GIOStatus z_stream_line_get_copy(ZStream *s, gchar *line, gsize *length, GError **error) { gchar *b; gsize len; GIOStatus res; ZStreamLine *self; GError *local_error = NULL; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); self = Z_CAST(z_stream_search_stack(s, G_IO_IN, Z_CLASS(ZStreamLine)), ZStreamLine); if (*length == 0) z_return(G_IO_STATUS_AGAIN); res = z_stream_line_get_internal(self, &b, &len, &local_error); if (res == G_IO_STATUS_NORMAL || (res == G_IO_STATUS_AGAIN && len > 0)) { if (len > *length) { /** * @todo FIXME: this uses the non-standard trick to return the part of * the line which fits the result buffer, e.g. it returns * G_IO_STATUS_AGAIN with line_len set to a non-zero value while * consuming the returned amount from the buffer. this should be * cleaned up, but currently it is the less risky solution. **/ if (self->flags & ZRL_SPLIT) { if (self->end == 0) { self->pos = *length; self->end = len; } else { self->pos = self->oldpos + *length; } len = *length; res = G_IO_STATUS_AGAIN; } else { /*LOG This message indicates that the line buffer is too small to hold the whole line. It is likely caused by some max size limit or by some standard default. */ g_set_error(&local_error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Line buffer too small, buffer=[%.*s]", (gint) len, b); z_return(G_IO_STATUS_ERROR); } } *length = len; memcpy(line, b, len); z_stream_data_dump(s, G_IO_IN, line, len); } else { *length = 0; } if (local_error) { z_log(self->super.name, CORE_ERROR, 3, "Error while fetching line; error='%s'", local_error->message); g_propagate_error(error, local_error); } z_return(res); } /** * Unget a packet into a ZStreamLine -- write its buffer to the beginning of the buffer of * the ZStreamLine and consume (unref) the packet. * * @param[in] s ZStreamLine instance * @param[in] packet ZPktBuf instance, will be consumed * @param[out] error error value * * It won't unget the packet if there isn't enough space in the buffer. In that * case the packet won't be consumed. * * @returns TRUE on success **/ gboolean z_stream_line_unget_packet_method(ZStream *s, ZPktBuf *packet, GError **error) { ZStreamLine *self = Z_CAST(s, ZStreamLine); gsize avail_before, avail_after; GError *local_error = NULL; gboolean res = FALSE; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), FALSE); avail_before = self->pos; avail_after = self->bufsize - self->end; if (avail_before + avail_after > packet->length) { if (avail_before > packet->length) { memmove(&self->buffer[self->pos - packet->length], packet->data, packet->length); self->pos -= packet->length; } else { memmove(&self->buffer[packet->length], &self->buffer[self->pos], self->end - self->pos); memmove(self->buffer, packet->data, packet->length); self->end = self->end - self->pos + packet->length; self->pos = 0; } z_pktbuf_unref(packet); res = TRUE; } else { g_set_error(&local_error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Unget blob does not fit into ZStreamLine buffer"); } if (local_error) { z_log(self->super.name, CORE_ERROR, 3, "Internal error while ungetting data into ZStreamLine buffer; error='%s'", local_error->message); g_propagate_error(error, local_error); } z_return(res); } /* I/O callbacks for stacked stream */ static gboolean z_stream_line_read_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond G_GNUC_UNUSED, gpointer s) { ZStreamLine *self = (ZStreamLine *) s; z_enter(); self->child_cond |= G_IO_IN; z_return(TRUE); } static gboolean z_stream_line_pri_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond G_GNUC_UNUSED, gpointer s) { ZStreamLine *self = (ZStreamLine *) s; z_enter(); self->child_cond |= G_IO_PRI; z_return(TRUE); } static gboolean z_stream_line_write_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond G_GNUC_UNUSED, gpointer s) { ZStreamLine *self = (ZStreamLine *) s; gboolean rc; z_enter(); rc = (*self->super.write_cb)(s, poll_cond, self->super.user_data_write); z_return(rc); } /* virtual methods */ /** * Read from ZStreamLine (not line-based). * * @param[in] stream ZStreamLine instance * @param[in] buf buffer to return data in * @param[in] count number of bytes to read * @param[out] bytes_read number of bytes actually read will be returned here * @param[out] error error value * * Reads from own buffer if there's data to read or from child if there isn't. * * @returns GIOStatus value **/ static GIOStatus z_stream_line_read_method(ZStream *stream, void *buf, gsize count, gsize *bytes_read, GError **error) { ZStreamLine *self = (ZStreamLine *) stream; GIOStatus res; gsize avail = self->end - self->pos; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (avail) { *bytes_read = MIN(count, avail); memmove(buf, self->buffer + self->pos, *bytes_read); self->oldpos = self->pos; self->pos += *bytes_read; if (self->pos == self->end) self->pos = self->end = 0; self->flags &= ~ZRL_LINE_AVAIL_SET; res = G_IO_STATUS_NORMAL; z_stream_data_dump(&self->super, G_IO_IN, buf, *bytes_read); } else { /** @todo FIXME: What to do if the ZRL_IGNORE_TILL_EOL flag set */ self->child_cond = 0; self->super.child->timeout = self->super.timeout; res = z_stream_read(self->super.child, buf, count, bytes_read, error); } z_return(res); } /** * Write data to ZStreamLine. * * @param[in] stream ZStreamLine instance * @param[in] buf data to write * @param[in] count length of buffer * @param[out] bytes_written number of bytes written will be returned here * @param[out] error error value * * Writes to child, as nothing special needs to be done to write a line anyway. * * @returns GIOStatus value **/ static GIOStatus z_stream_line_write_method(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamLine *self = (ZStreamLine *) stream; GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); self->super.child->timeout = self->super.timeout; res = z_stream_write(self->super.child, buf, count, bytes_written, error); z_return(res); } /** * Write priority data to ZStreamLine. * * @param[in] stream ZStreamLine instance * @param[in] buf data to write * @param[in] count length of buffer * @param[out] bytes_written number of bytes written will be returned here * @param[out] error error value * * Writes to child, as nothing special needs to be done to write a line anyway. * * @returns GIOStatus value **/ static GIOStatus z_stream_line_write_pri_method(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamLine *self = (ZStreamLine *) stream; GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); self->super.child->timeout = self->super.timeout; res = z_stream_write_pri(self->super.child, buf, count, bytes_written, error); z_return(res); } /** * Shutdown the ZStream (ZStreamLine in this case). * * @param[in] stream ZStreamLine instance * @param[in] i HOW parameter to shutdown * @param[out] error error value * * The shutdown method will be called on the child. * * @see z_stream_shutdown * * The action to perform is specified by i as follows: * - i == 0: Stop receiving data. * - i == 1: Stop trying to transmit data. * - i == 2: Stop both reception and transmission. * * @returns GIOStatus value **/ static GIOStatus z_stream_line_shutdown_method(ZStream *stream, int i, GError **error) { ZStreamLine *self = (ZStreamLine *) stream; GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); res = z_stream_shutdown(self->super.child, i, error); z_return(res); } /** * Process stream control calls on ZStreamLine objects. * * @param[in] s ZStream instance * @param[in] function function selector * @param[in, out] value parameter to function * @param[in] vlen length of value * * @returns TRUE on success **/ static gboolean z_stream_line_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen) { ZStreamLine *self = Z_CAST(s, ZStreamLine); gboolean ret = FALSE; z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_LINE_SET_TRUNCATE: if (vlen == sizeof(gboolean)) { gboolean flag = *((gboolean *)value); if (flag) self->flags |= ZRL_TRUNCATE; else self->flags &= ~ZRL_TRUNCATE; z_return(TRUE); } break; case ZST_LINE_SET_NUL_NONFATAL: if (vlen == sizeof(gboolean)) { gboolean flag = *((gboolean *)value); if (flag) self->flags |= ZRL_NUL_NONFATAL; else self->flags &= ~ZRL_NUL_NONFATAL; z_return(TRUE); } break; case ZST_LINE_SET_SPLIT: if (vlen == sizeof(gboolean)) { gboolean flag = *((gboolean *)value); if (flag) self->flags |= ZRL_SPLIT; else self->flags &= ~ZRL_SPLIT; z_return(TRUE); } break; case ZST_LINE_SET_SINGLE_READ: if (vlen == sizeof(gboolean)) { gboolean flag = *((gboolean *)value); if (flag) self->flags |= ZRL_SINGLE_READ; else self->flags &= ~ZRL_SINGLE_READ; z_return(TRUE); } break; case ZST_LINE_SET_POLL_PARTIAL: if (vlen == sizeof(gboolean)) { gboolean flag = *((gboolean *)value); if (flag) self->flags |= ZRL_POLL_PARTIAL; else self->flags &= ~ZRL_POLL_PARTIAL; z_return(TRUE); } break; case ZST_LINE_SET_RETURN_EOL: if (vlen == sizeof(gboolean)) { gboolean flag = *((gboolean *)value); if (flag) self->flags |= ZRL_RETURN_EOL; else self->flags &= ~ZRL_RETURN_EOL; z_return(TRUE); } break; case ZST_LINE_GET_TRUNCATE: if (vlen == sizeof(gboolean)) { *(gboolean *)value = !!(self->flags & ZRL_TRUNCATE); z_return(TRUE); } break; case ZST_LINE_GET_SPLIT: if (vlen == sizeof(gboolean)) { *(gboolean *)value = !!(self->flags & ZRL_SPLIT); z_return(TRUE); } break; case ZST_LINE_GET_NUL_NONFATAL: if (vlen == sizeof(gboolean)) { *(gboolean *)value = !!(self->flags & ZRL_NUL_NONFATAL); z_return(TRUE); } break; case ZST_LINE_GET_SINGLE_READ: if (vlen == sizeof(gboolean)) { *(gboolean *)value = !!(self->flags & ZRL_SINGLE_READ); z_return(TRUE); } break; case ZST_LINE_GET_POLL_PARTIAL: if (vlen == sizeof(gboolean)) { *(gboolean *)value = !!(self->flags & ZRL_POLL_PARTIAL); z_return(TRUE); } break; case ZST_LINE_GET_RETURN_EOL: if (vlen == sizeof(gboolean)) { *(gboolean *)value = !!(self->flags & ZRL_RETURN_EOL); z_return(TRUE); } break; case ZST_CTRL_SET_CALLBACK_READ: case ZST_CTRL_SET_CALLBACK_WRITE: case ZST_CTRL_SET_CALLBACK_PRI: ret = z_stream_ctrl_method(s, function, value, vlen); break; case ZST_CTRL_GET_BUFFERED_BYTES: if (vlen == sizeof(gsize)) { gsize *size = (gsize *) value; *size += self->end - self->pos; ret = TRUE; if (s->child) ret = z_stream_ctrl(s->child, ZST_CTRL_MSG_FORWARD | function, value, vlen); } break; default: ret = z_stream_ctrl_method(s, ZST_CTRL_MSG_FORWARD | function, value, vlen); break; } z_return(ret); } static gboolean z_stream_line_watch_prepare(ZStream *s, GSource *src G_GNUC_UNUSED, gint *timeout) { ZStreamLine *self = Z_CAST(s, ZStreamLine); gboolean ret = FALSE; gboolean child_enable = FALSE, child_readable; z_enter(); *timeout = -1; if (s->want_read) { child_readable = !!(self->child_cond & G_IO_IN); if (self->flags & ZRL_POLL_PARTIAL) { if (z_stream_line_buf_empty(self) && !child_readable) { child_enable = TRUE; } else { child_enable = FALSE; ret = TRUE; } } else { if (!z_stream_line_have_line(self) && !child_readable) { child_enable = TRUE; } else { child_enable = FALSE; ret = TRUE; } } } else child_enable = FALSE; if (s->want_pri && (self->child_cond & G_IO_PRI)) ret = TRUE; z_stream_set_cond(s->child, G_IO_IN, child_enable); if (s->want_write) z_stream_set_cond(s->child, G_IO_OUT, TRUE); else z_stream_set_cond(s->child, G_IO_OUT, FALSE); z_return(ret); } static gboolean z_stream_line_watch_check(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamLine *self = (ZStreamLine *) s; gboolean ret = FALSE, child_readable; z_enter(); if (s->want_read) { child_readable = !!(self->child_cond & G_IO_IN); if (self->flags & ZRL_POLL_PARTIAL) { if (!z_stream_line_buf_empty(self) || child_readable) { ret = TRUE; } } else { if (z_stream_line_have_line(self) || child_readable) { ret = TRUE; } } } if (s->want_pri && (self->child_cond & G_IO_PRI)) ret = TRUE; z_return(ret); } static gboolean z_stream_line_watch_dispatch(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamLine *self = (ZStreamLine *) s; gboolean rc = TRUE; z_enter(); if (s->want_read && rc) rc = self->super.read_cb(s, G_IO_IN, self->super.user_data_read); else if (s->want_pri && rc) rc = self->super.pri_cb(s, G_IO_PRI, self->super.user_data_pri); z_return(rc); } /** * Get size of extra context data. * * @param[in] s ZStreamLine instance * * @returns size of extra context data **/ static gsize z_stream_line_extra_get_size_method(ZStream *s) { return Z_SUPER(s, ZStream)->extra_get_size(s) + sizeof(ZStreamLineExtra); } static gsize z_stream_line_extra_save_method(ZStream *s, gpointer extra) { ZStreamLine *self = Z_CAST(s, ZStreamLine); ZStreamLineExtra *line_extra; gsize ofs; ofs = Z_SUPER(s, ZStream)->extra_save(s, extra); line_extra = (ZStreamLineExtra *) (((gchar *) extra) + ofs); line_extra->flags = self->flags & ZRL_SAVED_FLAGS_MASK; return ofs + sizeof(ZStreamLineExtra); } static gsize z_stream_line_extra_restore_method(ZStream *s, gpointer extra) { ZStreamLine *self = Z_CAST(s, ZStreamLine); ZStreamLineExtra *line_extra; gsize ofs; ofs = Z_SUPER(s, ZStream)->extra_restore(s, extra); line_extra = (ZStreamLineExtra *) (((gchar *) extra) + ofs); self->flags = (self->flags & ~ZRL_SAVED_FLAGS_MASK) | (line_extra->flags & ZRL_SAVED_FLAGS_MASK); return ofs + sizeof(ZStreamLineExtra); } /** * Stack a new stream (will become child stream) beneath self. * * @param[in] s parent ZStream * @param[in] new_child will be set as child **/ static void z_stream_line_set_child(ZStream *s, ZStream *new_child) { z_stream_ref(s); Z_SUPER(s, ZStream)->set_child(s, new_child); if (new_child) { z_stream_set_callback(new_child, G_IO_IN, z_stream_line_read_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(new_child, G_IO_OUT, z_stream_line_write_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(new_child, G_IO_PRI, z_stream_line_pri_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); } z_stream_unref(s); } /** * Constructs a new ZStreamLine instance, reading from child, using a buffer * sized according to bufsize. * * @param[in] child * @param[in] bufsize * @param[in] flags * * @returns the new ZStreamLine instance **/ ZStream * z_stream_line_new(ZStream *child, gsize bufsize, guint flags) { ZStreamLine *self; z_enter(); self = Z_CAST(z_stream_new(Z_CLASS(ZStreamLine), child ? child->name : "", G_IO_IN), ZStreamLine); self->flags = flags; self->bufsize = bufsize; self->buffer = g_new(gchar, bufsize); z_stream_set_child(&self->super, child); z_return((ZStream *) self); } /** * Destructor of ZStreamLine. * * @param[in] s ZStreamLine instance **/ static void z_stream_line_free_method(ZObject *s) { ZStreamLine *self = Z_CAST(s, ZStreamLine); z_enter(); g_free(self->buffer); z_stream_free_method(s); z_return(); } /** * ZStreamLine virtual methods. **/ ZStreamFuncs z_stream_line_funcs = { { Z_FUNCS_COUNT(ZStream), z_stream_line_free_method, }, z_stream_line_read_method, z_stream_line_write_method, NULL, z_stream_line_write_pri_method, z_stream_line_shutdown_method, NULL, /* close */ z_stream_line_ctrl_method, NULL, /* attach_source */ NULL, /* detach_source */ z_stream_line_watch_prepare, z_stream_line_watch_check, z_stream_line_watch_dispatch, NULL, z_stream_line_extra_get_size_method, z_stream_line_extra_save_method, z_stream_line_extra_restore_method, z_stream_line_set_child, z_stream_line_unget_packet_method, }; /** * ZStreamLine class descriptor. **/ Z_CLASS_DEF(ZStreamLine, ZStream, z_stream_line_funcs); libzorpll-3.9.4.1/src/streamssl.c000066400000000000000000000374511224546767600167040ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamssl.c,v 1.45 2003/09/10 11:46:58 bazsi Exp $ * * Author : SaSa * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #ifdef _MSC_VER # include #else # include # include #endif #include #include #include #include #include #include #include #include #include #include #define ERR_buflen 4096 #define DO_AS_USUAL 0 #define CALL_READ_WHEN_WRITE 1 #define CALL_WRITE_WHEN_READ 2 /** * ZStream-derived class to handle connections over SSL. **/ typedef struct _ZStreamSsl { ZStream super; guint what_if_called; gboolean shutdown; ZSSLSession *ssl; gchar error[ERR_buflen]; /* List of handshake objects. Unfortunately OpenSSL callbacks cannot be * handed a destroy_notify callback so we generally cannot use * refcounting to manage the lifetime of handshake objects. * * Instead, we do store all handshake objects in this linked list in * the associated ZStreamSsl and make sure we delete these when we * can guarantee that the handshake is no longer needed * (referenced). * * Right now this means we delete handshake objects only when * closing the stream. */ GList *handshakes; } ZStreamSsl; /** * ZStreamSsl class descriptor. **/ extern ZClass ZStreamSsl__class; static gboolean z_stream_ssl_read_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond, gpointer s) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); gboolean rc; z_enter(); if (self->what_if_called == CALL_WRITE_WHEN_READ) rc = (*self->super.write_cb)(s, poll_cond, self->super.user_data_write); else rc = (*self->super.read_cb)(s, poll_cond, self->super.user_data_read); z_return(rc); } static gboolean z_stream_ssl_write_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond, gpointer s) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); gboolean rc; z_enter(); if (self->what_if_called == CALL_READ_WHEN_WRITE) rc = (*self->super.read_cb)(s, poll_cond, self->super.user_data_read); else rc = (*self->super.write_cb)(s, poll_cond, self->super.user_data_write); z_return(rc); } static gboolean z_stream_ssl_pri_callback(ZStream *stream G_GNUC_UNUSED, GIOCondition poll_cond, gpointer s) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); gboolean rc; z_enter(); rc = (*self->super.pri_cb)(s, poll_cond, self->super.user_data_pri); z_return(rc); } /* virtual functions */ static GIOStatus z_stream_ssl_read_method_impl(ZStreamSsl *self, void *buf, gsize count, gsize *bytes_read, GError **error) { gint result; gint ssl_err; z_enter(); result = SSL_read(self->ssl->ssl, buf, count); if (result < 0) { *bytes_read = 0; ssl_err = SSL_get_error(self->ssl->ssl, result); switch (ssl_err) { case SSL_ERROR_ZERO_RETURN: z_return(G_IO_STATUS_EOF); case SSL_ERROR_WANT_READ: z_return(G_IO_STATUS_AGAIN); case SSL_ERROR_WANT_WRITE: if (self->what_if_called == DO_AS_USUAL) { z_stream_set_cond(self->super.child, G_IO_OUT, TRUE); } self->what_if_called = CALL_READ_WHEN_WRITE; z_return(G_IO_STATUS_AGAIN); case SSL_ERROR_SYSCALL: if (z_errno_is(EAGAIN) || z_errno_is(EINTR)) z_return(G_IO_STATUS_AGAIN); if (z_errno_is(0)) z_return(G_IO_STATUS_EOF); /*LOG This message indicates that an OS level error occurred during the SSL read. */ g_set_error(error, G_IO_CHANNEL_ERROR, g_io_channel_error_from_errno(errno), "%s", g_strerror(errno)); z_return(G_IO_STATUS_ERROR); case SSL_ERROR_SSL: default: z_ssl_get_error_str(self->error, ERR_buflen); ERR_clear_error(); /*LOG This message indicates that an SSL error occurred during the SSL read. */ g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "SSL error occurred (%s)", self->error); z_return(G_IO_STATUS_ERROR); } } if (result == 0) { *bytes_read = result; ERR_clear_error(); z_return(G_IO_STATUS_EOF); } if (self->what_if_called != DO_AS_USUAL) { z_stream_set_cond(self->super.child, G_IO_OUT, FALSE); self->what_if_called = DO_AS_USUAL; } *bytes_read = result; ERR_clear_error(); z_return(G_IO_STATUS_NORMAL); } static GIOStatus z_stream_ssl_read_method(ZStream *s, void *buf, gsize count,gsize *bytes_read, GError **error) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); gint result; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (self->what_if_called == CALL_WRITE_WHEN_READ) { /*LOG This message indicates an internal error. Please report this event to the Balabit QA Team (devel@balabit.com). */ z_log(NULL, CORE_ERROR, 2, "Internal error; error='Read called, when only write might be called'"); } if (self->shutdown) z_return(G_IO_STATUS_EOF); self->super.child->timeout = self->super.timeout; if (self->ssl) result = z_stream_ssl_read_method_impl(self, buf, count, bytes_read, error); else result = z_stream_read(self->super.child, buf, count, bytes_read, error); z_return(result); } static GIOStatus z_stream_ssl_write_method_impl(ZStreamSsl *self, const void *buf, gsize count, gsize *bytes_written, GError **error) { gint result; gint ssl_err; z_enter(); result = SSL_write(self->ssl->ssl, buf, count); if (result < 0) { *bytes_written = 0; ssl_err = SSL_get_error(self->ssl->ssl, result); switch (ssl_err) { case SSL_ERROR_ZERO_RETURN: z_return(G_IO_STATUS_EOF); case SSL_ERROR_WANT_READ: if (self->what_if_called == DO_AS_USUAL) z_stream_set_cond(self->super.child, G_IO_IN, TRUE); self->what_if_called = CALL_WRITE_WHEN_READ; z_return(G_IO_STATUS_AGAIN); case SSL_ERROR_WANT_WRITE: z_return(G_IO_STATUS_AGAIN); case SSL_ERROR_SYSCALL: if (z_errno_is(EAGAIN) || z_errno_is(EINTR)) z_return(G_IO_STATUS_AGAIN); /*LOG This message indicates that an OS level error occurred during the SSL write. */ g_set_error(error, G_IO_CHANNEL_ERROR, g_io_channel_error_from_errno(errno), "%s", g_strerror(errno)); z_return(G_IO_STATUS_ERROR); case SSL_ERROR_SSL: default: z_ssl_get_error_str(self->error, ERR_buflen); ERR_clear_error(); /*LOG This message indicates that an internal SSL error occurred during the SSL write. */ g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "%s", self->error); z_return(G_IO_STATUS_ERROR); } } if (self->what_if_called != DO_AS_USUAL) { z_stream_set_cond(self->super.child, G_IO_IN, FALSE); self->what_if_called = DO_AS_USUAL; } *bytes_written = result; ERR_clear_error(); z_return(G_IO_STATUS_NORMAL); } static GIOStatus z_stream_ssl_write_method(ZStream *s, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); gint result; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (self->shutdown) { g_set_error(error, G_IO_CHANNEL_ERROR, g_io_channel_error_from_errno (ENOTCONN), "%s", g_strerror (ENOTCONN)); z_return(G_IO_STATUS_ERROR); } self->super.child->timeout = self->super.timeout; if (self->ssl) result = z_stream_ssl_write_method_impl(self, buf, count, bytes_written, error); else result = z_stream_write(self->super.child, buf, count, bytes_written, error); z_return(result); } /** * Close SSL connection. * * @param[in] s ZStreamSsl instance * @param i HOW parameter (unused) * @param[out] error error value * * @returns GLib I/O status value **/ static GIOStatus z_stream_ssl_shutdown_method(ZStream *s, int i, GError **error) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (!self->shutdown) { gboolean nonblock; gint original_timeout; /* NOTE: we set the stream to blocking mode for the SSL shutdown * sequence with 1 second hard-wired timeout, even if it is in * nonblocking mode. * * This may not be the optimal solution especially if we want to use * the ZStreamSsl in nonblocking mode, but our callers are not really * prepared to handle a G_IO_STATUS_AGAIN status code from * z_stream_shutdown. * * One possible solution is to start up a dedicated thread for * shutting down SSL connections. */ nonblock = z_stream_get_nonblock(s); original_timeout = s->timeout; z_stream_set_timeout(s->child, 1000); z_stream_set_nonblock(s, FALSE); if (self->ssl && SSL_shutdown(self->ssl->ssl) == 0) { /* if SSL_shutdown returns 0 it means that we still need to * process the shutdown alert by the peer, and to do that we need * to call SSL_shutdown again */ SSL_shutdown(self->ssl->ssl); } z_stream_set_nonblock(s, nonblock); z_stream_set_timeout(s, original_timeout); if (self->ssl) ERR_clear_error(); self->shutdown = TRUE; } res = z_stream_shutdown(self->super.child, i, error); z_return(res); } /** * Process stream control calls on ZStreamSsl object. * * @param[in] s ZStream instance * @param[in] function function selector * @param[in, out] value parameter to function * @param[in] vlen length of value * * @returns TRUE on success **/ static gboolean z_stream_ssl_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen) { ZStreamSsl *self G_GNUC_UNUSED = Z_CAST(s, ZStreamSsl); gboolean ret = FALSE; z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_CTRL_SET_CALLBACK_READ: case ZST_CTRL_SET_CALLBACK_WRITE: case ZST_CTRL_SET_CALLBACK_PRI: ret = z_stream_ctrl_method(s, function, value, vlen); break; case ZST_CTRL_SSL_SET_SESSION: if (vlen == sizeof(ZSSLSession *)) { ZSSLSession *ssl = (ZSSLSession *) value; BIO *bio; self->ssl = z_ssl_session_ref(ssl); if (self->super.child) { bio = z_ssl_bio_new(self->super.child); SSL_set_bio(self->ssl->ssl, bio, bio); } } break; case ZST_CTRL_SSL_ADD_HANDSHAKE: if (vlen == sizeof(ZStreamSslHandshakeData)) { ZStreamSslHandshakeData *data = (ZStreamSslHandshakeData *) value; ZStreamSslHandshakeData *our_data = g_new0(ZStreamSslHandshakeData, 1); our_data->handshake = data->handshake; our_data->destroy_function = data->destroy_function; self->handshakes = g_list_append(self->handshakes, our_data); } break; case ZST_CTRL_GET_BUFFERED_BYTES: /* we stop propagation here: this ctrl message queries the bytes buffered *above* the SSL layer. */ if (vlen == sizeof(gsize)) { ret = TRUE; } break; default: ret = z_stream_ctrl_method(s, ZST_CTRL_MSG_FORWARD | function, value, vlen); break; } z_return(ret); } static gboolean z_stream_ssl_watch_prepare(ZStream *s, GSource *src G_GNUC_UNUSED, gint *timeout) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); z_enter(); *timeout = -1; if (s->want_read) { if (self->shutdown) { *timeout = 0; z_return(TRUE); } if (self->ssl) { if (SSL_pending(self->ssl->ssl)) { *timeout = 0; z_return(TRUE); } } else { z_stream_set_cond(s->child, G_IO_IN, s->want_read); z_stream_set_cond(s->child, G_IO_PRI, s->want_pri); if (s->want_write) { z_stream_set_cond(s->child, G_IO_OUT, TRUE); z_return(TRUE); } else z_stream_set_cond(s->child, G_IO_OUT, FALSE); } } z_return(FALSE); } static gboolean z_stream_ssl_watch_check(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); z_enter(); if (s->want_read) { if (self->ssl) { if (SSL_pending(self->ssl->ssl)) z_return(TRUE); } } z_return(FALSE); } static gboolean z_stream_ssl_watch_dispatch(ZStream *s, GSource *src G_GNUC_UNUSED) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); gboolean rc = TRUE; z_enter(); if (s->want_read && rc) rc = self->super.read_cb(s, G_IO_IN, self->super.user_data_read); z_return(rc); } static void z_stream_ssl_set_child(ZStream *s, ZStream *new_child) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); BIO *bio; z_stream_ref(s); Z_SUPER(s, ZStream)->set_child(s, new_child); if (self->super.child) { if (self->ssl) { bio = z_ssl_bio_new(self->super.child); SSL_set_bio(self->ssl->ssl, bio, bio); } z_stream_set_callback(self->super.child, G_IO_IN, z_stream_ssl_read_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(self->super.child, G_IO_OUT, z_stream_ssl_write_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(self->super.child, G_IO_PRI, z_stream_ssl_pri_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); } z_stream_unref(s); } static GIOStatus z_stream_ssl_close_method(ZStream *s, GError **error) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); GList *p; /* free associated handshakes */ for (p = self->handshakes; p; p = p->next) { ZStreamSslHandshakeData *data = (ZStreamSslHandshakeData *) p->data; data->destroy_function(data->handshake); g_free(data); } g_list_free(self->handshakes); self->handshakes = NULL; return Z_SUPER(s, ZStream)->close(s, error); } ZStream * z_stream_ssl_new(ZStream *child, ZSSLSession *ssl) { ZStreamSsl *self; z_enter(); self = Z_CAST(z_stream_new(Z_CLASS(ZStreamSsl), "", G_IO_IN|G_IO_OUT), ZStreamSsl); if (ssl) self->ssl = z_ssl_session_ref(ssl); z_stream_set_child(&self->super, child); z_return((ZStream *) self); } /** destructor */ static void z_stream_ssl_free_method(ZObject *s) { ZStreamSsl *self = Z_CAST(s, ZStreamSsl); z_enter(); if (self->ssl) z_ssl_session_unref(self->ssl); ERR_clear_error(); z_stream_free_method(s); z_return(); } /** * ZStreamSsl virtual methods. **/ ZStreamFuncs z_stream_ssl_funcs = { { Z_FUNCS_COUNT(ZStream), z_stream_ssl_free_method, }, z_stream_ssl_read_method, z_stream_ssl_write_method, NULL, z_stream_ssl_write_method, z_stream_ssl_shutdown_method, z_stream_ssl_close_method, z_stream_ssl_ctrl_method, NULL, /* attach_source */ NULL, /* detach_source */ z_stream_ssl_watch_prepare, z_stream_ssl_watch_check, z_stream_ssl_watch_dispatch, NULL, NULL, NULL, NULL, z_stream_ssl_set_child, NULL }; /** * ZStreamSsl class descriptor **/ Z_CLASS_DEF(ZStreamSsl, ZStream, z_stream_ssl_funcs); libzorpll-3.9.4.1/src/streamtee.c000066400000000000000000000265031224546767600166540ustar00rootroot00000000000000#include #include /** * ZStream derived class that writes a copy of all data read from or written to * (depending on tee_direction) its child to another stream. **/ typedef struct _ZStreamTee { ZStream super; ZStream *fork; /**< stream that gets the duplicate data */ /** * G_IO_IN if read information should be duplicated, * G_IO_OUT if written information should be duplicated. **/ GIOCondition tee_direction; } ZStreamTee; extern ZClass ZStreamTee__class; /** * This function writes the data to the forked stream. * * @param[in] self this instance * @param[in] buf buffer to write * @param[in] count size of buf * @param[in] error error value * * @returns GIOStatus instance **/ static GIOStatus z_stream_tee_write_fork(ZStreamTee *self, const gchar *buf, gsize count, GError **error) { GIOStatus st = G_IO_STATUS_NORMAL; gsize bw, left; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); left = count; while (left) { st = z_stream_write(self->fork, buf + count - left, left, &bw, error); if (st != G_IO_STATUS_NORMAL) break; left -= bw; } z_return(st); } /** * The virtual read() method for ZStreamTee, it reads data from self->child * and writes the information read to the forked stream if the tee_direction * is G_IO_IN (e.g.\ the read information should be stored in self->fork) * * @param[in] s this instance * @param[in] buf buffer to read data into * @param[in] count size of buf * @param[out] bytes_read bytes read from the stream * @param[out] error error value * * @returns GIOStatus instance **/ static GIOStatus z_stream_tee_read_method(ZStream *s, void *buf, gsize count, gsize *bytes_read, GError **error) { ZStreamTee *self = Z_CAST(s, ZStreamTee); GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); self->super.child->timeout = self->super.timeout; res = z_stream_read(self->super.child, buf, count, bytes_read, error); if (res == G_IO_STATUS_NORMAL && self->tee_direction == G_IO_IN && *bytes_read) { res = z_stream_tee_write_fork(self, buf, *bytes_read, error); } z_return(res); } /** * The virtual write() method for ZStreamTee, it writes data to self->child * and writes the information written to the forked stream if the tee_direction * is G_IO_OUT (e.g.\ the written information should be stored in self->fork) * * @param[in] s this instance * @param[in] buf buffer to write * @param[in] count size of buf * @param[out] bytes_written bytes read from the stream * @param[out] error error value * * @returns GIOStatus instance **/ static GIOStatus z_stream_tee_write_method(ZStream *s, const void *buf, gsize count, gsize *bytes_written, GError **error) { ZStreamTee *self = Z_CAST(s, ZStreamTee); GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); self->super.child->timeout = self->super.timeout; res = z_stream_write(self->super.child, buf, count, bytes_written, error); if (res == G_IO_STATUS_NORMAL && self->tee_direction == G_IO_OUT && *bytes_written) res = z_stream_tee_write_fork(self, buf, *bytes_written, error); z_return(res); } /** * The virtual shutdown() method for ZStreamTee, it shuts down the child and * the forked stream if the appropriate shutdown mode is specified for the * tee. * * @param[in] s this instance * @param[in] shutdown_mode shutdown mode (one of SHUT_* macros) * @param[out] error error value * * @returns GIOStatus instance **/ static GIOStatus z_stream_tee_shutdown_method(ZStream *s, gint shutdown_mode, GError **error) { ZStreamTee *self = Z_CAST(s, ZStreamTee); GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if (shutdown_mode == SHUT_RDWR || (shutdown_mode == SHUT_WR && self->tee_direction == G_IO_OUT) || (shutdown_mode == SHUT_RD && self->tee_direction == G_IO_IN)) res = z_stream_shutdown(self->fork, SHUT_RDWR, error); else res = G_IO_STATUS_NORMAL; if (res == G_IO_STATUS_NORMAL) res = z_stream_shutdown(s->child, shutdown_mode, error); z_return(res); } /** * The virtual close() method for ZStreamTee, it closes the child and the * forked stream. * * @param[in] s this instance * @param[out] error error value * * @returns GIOStatus instance **/ static GIOStatus z_stream_tee_close_method(ZStream *s, GError **error) { ZStreamTee *self = Z_CAST(s, ZStreamTee); GIOStatus res; z_enter(); g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR); if ((res = z_stream_close(self->fork, error)) == G_IO_STATUS_NORMAL) res = Z_SUPER(s, ZStream)->close(s, error); z_return(res); } /** * Process stream control calls on ZStreamTee object. * * @param[in] s ZStream instance (supposed to be ZStreamTee, but it can be any ZStream in this case) * @param[in] function function selector * @param[in, out] value parameter to function * @param[in] vlen length of value * * @returns TRUE on success **/ static gboolean z_stream_tee_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen) { gboolean ret = FALSE; z_enter(); switch (ZST_CTRL_MSG(function)) { case ZST_CTRL_SET_CALLBACK_READ: case ZST_CTRL_SET_CALLBACK_WRITE: case ZST_CTRL_SET_CALLBACK_PRI: ret = z_stream_ctrl_method(s, function, value, vlen); break; default: ret = z_stream_ctrl_method(s, ZST_CTRL_MSG_FORWARD | function, value, vlen); break; } z_return(ret); } /** * This function is called to prepare for a poll iteration. * * @param[in] s ZStream instance * @param src GSource associated with s (unused) * @param[out] timeout timeout value for this poll iteration * * It checks our internal state and prepares the watch conditions for s->child. **/ static gboolean z_stream_tee_watch_prepare(ZStream *s, GSource *src G_GNUC_UNUSED, gint *timeout) { ZStreamTee *self = Z_CAST(s, ZStreamTee); z_enter(); *timeout = -1; z_stream_set_cond(s->child, G_IO_IN, self->super.want_read); z_stream_set_cond(s->child, G_IO_OUT, self->super.want_write); z_stream_set_cond(s->child, G_IO_PRI, self->super.want_pri); z_return(FALSE); } /** * This function is called to check the results of a poll iteration. * * @param s ZStream instance (unused) * @param src GSource associated with s (unused) * * In this case it basically does nothing and returns FALSE to indicate that * dispatch should not be called. * * @returns always FALSE **/ static gboolean z_stream_tee_watch_check(ZStream *s G_GNUC_UNUSED, GSource *src G_GNUC_UNUSED) { return FALSE; } /** * This function is call callbacks after check returned TRUE, which is never * in our case. * * @param s ZStream instance (unused) * @param src GSource associated with s (unused) * * It does nothing but returns TRUE. * * @returns always TRUE **/ static gboolean z_stream_tee_watch_dispatch(ZStream *s G_GNUC_UNUSED, GSource *src G_GNUC_UNUSED) { return TRUE; } /** * This function is called whenever our child stream indicates readability. * * @param s child ZStream instance (unused) * @param[in] cond condition that triggered this callback * @param[in] user_data ZStream instance as a gpointer * * It basically calls our own callback as we rely on our child to trigger read/write/pri * callbacks. **/ static gboolean z_stream_tee_read_callback(ZStream *s G_GNUC_UNUSED, GIOCondition cond, gpointer user_data) { ZStreamTee *self = Z_CAST(user_data, ZStreamTee); return self->super.read_cb(&self->super, cond, self->super.user_data_read); } /** * This function is called whenever our child stream indicates writability. * * @param s child ZStream instance (unused) * @param[in] cond condition that triggered this callback * @param[in] user_data ZStream instance as a gpointer * * It basically calls our own callback as we rely on our child to trigger read/write/pri * callbacks. **/ static gboolean z_stream_tee_write_callback(ZStream *s G_GNUC_UNUSED, GIOCondition cond, gpointer user_data) { ZStreamTee *self = Z_CAST(user_data, ZStreamTee); return self->super.write_cb(&self->super, cond, self->super.user_data_write); } /** * This function is called whenever our child stream indicates that priority * data is available. * * @param s child ZStream instance (unused) * @param[in] cond condition that triggered this callback * @param[in] user_data ZStream instance as a gpointer * * It basically calls our own callback as we rely on our * child to trigger read/write/pri callbacks. **/ static gboolean z_stream_tee_pri_callback(ZStream *s G_GNUC_UNUSED, GIOCondition cond, gpointer user_data) { ZStreamTee *self = Z_CAST(user_data, ZStreamTee); return self->super.pri_cb(&self->super, cond, self->super.user_data_pri); } /** * This function is called to change our child stream. * * @param[in] s ZStream instance * @param[in] new_child new child stream * * It basically sets up appropriate callbacks and switches new_child to nonblocking mode. **/ static void z_stream_tee_set_child(ZStream *s, ZStream *new_child) { z_stream_ref(s); Z_SUPER(s, ZStream)->set_child(s, new_child); if (new_child) { z_stream_set_callback(new_child, G_IO_IN, z_stream_tee_read_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(new_child, G_IO_OUT, z_stream_tee_write_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); z_stream_set_callback(new_child, G_IO_PRI, z_stream_tee_pri_callback, z_stream_ref(s), (GDestroyNotify) z_stream_unref); } z_stream_unref(s); } /** * This function constructs a new ZStreamTee instance which writes data * flown in one direction of a stream (read or write direction) and writes * this data in another stream (the fork). * * @param[in] child child stream * @param[in] fork fork child * @param[in] tee_direction which direction to save **/ ZStream * z_stream_tee_new(ZStream *child, ZStream *fork, GIOCondition tee_direction) { ZStreamTee *self; z_enter(); self = Z_CAST(z_stream_new(Z_CLASS(ZStreamTee), child ? child->name : "", 0), ZStreamTee); self->fork = fork; self->tee_direction = tee_direction; z_stream_set_child(&self->super, child); z_return((ZStream *) self); } /** * Destructor of a ZStreamTee. * * @param[in] s this instance **/ static void z_stream_tee_free_method(ZObject *s) { ZStreamTee *self = Z_CAST(s, ZStreamTee); z_stream_unref(self->fork); z_stream_free_method(s); } /** * ZStreamTee virtual methods. **/ static ZStreamFuncs z_stream_tee_funcs = { { Z_FUNCS_COUNT(ZStream), .free_fn = z_stream_tee_free_method }, .read = z_stream_tee_read_method, .write = z_stream_tee_write_method, .read_pri = NULL, .write_pri = NULL, .shutdown = z_stream_tee_shutdown_method, .close = z_stream_tee_close_method, .ctrl = z_stream_tee_ctrl_method, .attach_source = NULL, .detach_source = NULL, .watch_prepare = z_stream_tee_watch_prepare, .watch_check = z_stream_tee_watch_check, .watch_dispatch = z_stream_tee_watch_dispatch, .watch_finalize = NULL, .extra_get_size = NULL, .extra_save = NULL, .extra_restore = NULL, .set_child = z_stream_tee_set_child, .unget_packet = NULL }; /** * ZStreamTee class descriptor. **/ Z_CLASS_DEF(ZStreamTee, ZStream, z_stream_tee_funcs); libzorpll-3.9.4.1/src/thread.c000066400000000000000000000214371224546767600161330ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: thread.c,v 1.20 2004/02/11 13:26:36 sasa Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #include #if HAVE_SYS_RESOURCE_H #include #endif #include gint max_threads = 100; static gint num_threads = 0; static gint max_stack_size = 512 * 1024; static GPrivate *current_thread; /** * Linked list of callback functions with a user data pointer for each. **/ typedef struct _ZThreadCallback { struct _ZThreadCallback *next; GFunc cb; /**< callback function */ gpointer user_data; } ZThreadCallback; static ZThreadCallback *start_callbacks; static ZThreadCallback *stop_callbacks; /** * Frees a given Zorp thread state. * * @param[in] self Zorp thread state **/ static void z_thread_free(ZThread *self) { g_free(self); } /** * Returns the current Zorp specific thread state. **/ ZThread * z_thread_self(void) { return (ZThread *) g_private_get(current_thread); } /** * Use this function to register a start-callback. Start callbacks are called * when a given thread starts. * * @param[in] func callback to add to the set of start-callbacks * @param[in] user_data pointer to pass to this function **/ void z_thread_register_start_callback(GFunc func, gpointer user_data) { ZThreadCallback *cb = g_new0(ZThreadCallback, 1); cb->cb = func; cb->user_data = user_data; cb->next = start_callbacks; start_callbacks = cb; } /** * Use this function to register a stop-callback. Stop callbacks are called * when a given thread terminates. * * @param[in] func callback to add to the set of stop-callbacks * @param[in] user_data pointer to pass to this function **/ void z_thread_register_stop_callback(GFunc func, gpointer user_data) { ZThreadCallback *cb = g_new0(ZThreadCallback, 1); cb->cb = func; cb->user_data = user_data; cb->next = stop_callbacks; stop_callbacks = cb; } /** * This function iterates on a linked list of registered callbacks and calls * each function. * * @param[in] self thread state * @param[in] p linked list to iterate through **/ static void z_thread_iterate_callbacks(ZThread *self, ZThreadCallback *p) { for (; p; p = p->next) p->cb(self, p->user_data); } /** * This function is called upon thread startup and performs thread specific * initialization. It calls thread-start and thread-exit callbacks. * * @param[in] self thread specific variables * @param user_data pointer to pass to real thread function (unused) **/ static void z_thread_func_core(ZThread *self, gpointer user_data G_GNUC_UNUSED) { g_private_set(current_thread, self); self->thread = g_thread_self(); z_thread_iterate_callbacks(self, start_callbacks); /*LOG This message indicates that a thread is starting. */ z_log(self->name, CORE_DEBUG, 6, "thread starting;"); (*self->func)(self->arg); /*LOG This message indicates that a thread is ending. */ z_log(self->name, CORE_DEBUG, 6, "thread exiting;"); z_thread_iterate_callbacks(self, stop_callbacks); z_thread_free(self); } /* simple PThread based implementation */ static GAsyncQueue *queue; /** * This function wrapped around the real thread function logging two * events when the thread starts & stops * * @param[in] st thread state **/ static gpointer z_thread_func(gpointer st) { ZThread *self = (ZThread *) st; do { z_thread_func_core(self, NULL); self = NULL; g_async_queue_lock(queue); self = (ZThread *) g_async_queue_try_pop_unlocked(queue); if (!self) { num_threads--; g_async_queue_unref(queue); g_async_queue_unlock(queue); } else g_async_queue_unlock(queue); } while (self != NULL); return NULL; } /** * Allocate and initialize a Zorp thread identified by a name, and * using the given thread function. * * @param[in] name name to identify this thread with * @param[in] func thread function * @param[in] arg pointer to pass to thread function * * @returns TRUE to indicate success **/ gboolean z_thread_new(const gchar *name, GThreadFunc func, gpointer arg) { ZThread *self = g_new0(ZThread, 1); GError *error = NULL; static gint thread_id = 1; self->thread_id = thread_id++; self->func = func; self->arg = arg; strncpy(self->name, name, sizeof(self->name) - 1); g_async_queue_lock(queue); if (num_threads >= max_threads) { /*LOG This message reports that the maximal thread limit is reached. Try to increase the maximal thread limit. */ z_log(NULL, CORE_ERROR, 3, "Too many running threads, waiting for one to become free; num_threads='%d', max_threads='%d'", num_threads, max_threads); g_async_queue_push_unlocked(queue, self); g_async_queue_unlock(queue); } else { num_threads++; g_async_queue_ref(queue); g_async_queue_unlock(queue); if (!g_thread_create_full(z_thread_func, self, max_stack_size, FALSE, TRUE, G_THREAD_PRIORITY_NORMAL, &error)) { /*LOG This message indicates that creating a new thread failed. It is likely that the system is running low on some resources or some limit is reached. */ z_log(NULL, CORE_ERROR, 2, "Error starting new thread; error='%s'", error->message); g_async_queue_lock(queue); num_threads--; g_async_queue_unlock(queue); return FALSE; } } return TRUE; } /** * This function should be called before calling z_thread_init() to specify * the maximum number of threads. * * @param[in] max maximum number of threads **/ void z_thread_set_max_threads(gint max) { max_threads = max; } /** * This function should be called before calling z_thread_init() to specify * the maximum size of thread stacks. * * @param[in] stack_size maximum size for thread stacks **/ void z_thread_set_max_stack_size(gint stack_size) { max_stack_size = stack_size; } /** * This function should be called after specifying various threading * parameters using z_thread_*() functions and _before_ creating any threads * using z_thread_new(). **/ void z_thread_init(void) { #if HAVE_SETRLIMIT struct rlimit limit; /* NOTE: in addition to specifying the stack size where possible, we set * the stack limit, which sets per-thread stack limit for threadpools in * which case we are unable to set the stack limit any other way */ memset(&limit, 0, sizeof(limit)); limit.rlim_cur = max_stack_size; limit.rlim_max = max_stack_size; setrlimit(RLIMIT_STACK, &limit); #endif g_thread_init(NULL); queue = g_async_queue_new(); current_thread = g_private_new(NULL); } /** * Call this function when exiting your program to global thread related * data structures. **/ void z_thread_destroy(void) { g_async_queue_unref(queue); } /** * Set max_stack_size from command line argument. * * @param option_name unused * @param[in] value string value for stack size to set * @param data unused * @param[out] error * * @returns TRUE if parsing of the stack-size argument was successful **/ static gboolean z_thread_stack_size_arg(const gchar *option_name G_GNUC_UNUSED, const gchar *value, gpointer data G_GNUC_UNUSED, GError **error) { gchar *end; max_stack_size = strtol(value, &end, 10) * 1024; if (*end != '\0') { g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Error parsing stack-size argument"); return FALSE; } if (max_stack_size > 8192 * 1024) { fprintf(stderr, "Stack size limit exceeded, set default value 8MB;\n"); max_stack_size = 8192 * 1024; } return TRUE; } /** * Command line options for ZThread. **/ static GOptionEntry z_thread_option_entries[] = { { "threads", 't', 0, G_OPTION_ARG_INT, &max_threads, "Set the maximum number of threads", "" }, { "stack-size", 'S', 0, G_OPTION_ARG_CALLBACK, z_thread_stack_size_arg, "Set the stack size in kBytes", "" }, { NULL, 0, 0, 0, NULL, NULL, NULL }, }; /** * Add the command line options of ZThread to the option context. * * @param[in] ctx GOptionContext instance **/ void z_thread_add_option_group(GOptionContext *ctx) { GOptionGroup *group; group = g_option_group_new("thread", "Thread options", "Thread options", NULL, NULL); g_option_group_add_entries(group, z_thread_option_entries); g_option_context_add_group(ctx, group); } libzorpll-3.9.4.1/src/win32_reg.c000066400000000000000000000155501224546767600164620ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: registry.c,v 1.11 2004/08/18 11:46:46 bazsi Exp $ * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #ifdef G_OS_WIN32 #include #include #include #include /** * This function stores data in the value field of an registry key. * * @param[in] root The key that is opened or created by this function is a subkey of the key that is identified by this parameter. * @param[in] key Pointer to a null-terminated string that specifies the name of a subkey that this function opens or creates. * This is a subkey of the key that is identified by root. * @param[in] name Pointer to a string containing the name of the value to set. * @param[in] value The data to be stored with the specified value name. */ gboolean z_reg_key_write_dword(HKEY root, gchar *key, gchar *name, DWORD value) { HKEY hKey; if(RegCreateKeyEx(root, (LPCSTR)key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS) { return FALSE; } if(RegSetValueEx(hKey, (LPCSTR)name, 0, REG_DWORD, (LPBYTE)&value, sizeof(DWORD)) == ERROR_SUCCESS) { RegFlushKey(hKey); RegCloseKey(hKey); return TRUE; } RegCloseKey(hKey); return FALSE; } /** * This function stores data in the value field of an registry key. * * @param[in] root The key that is opened or created by this function is a subkey of the key that is identified by this parameter. * @param[in] key Pointer to a null-terminated string that specifies the name of a subkey that this function opens or creates. * This is a subkey of the key that is identified by root. * @param[in] name Pointer to a string containing the name of the value to set. * @param[in] value Pointer to a buffer that contains the data to be stored with the specified value name. */ gboolean z_reg_key_write_string(HKEY root, gchar *key, gchar *name, gchar *value) { HKEY hKey; if(RegCreateKeyEx(root, (LPCSTR)key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL) != ERROR_SUCCESS) return FALSE; if(RegSetValueEx(hKey, (LPCSTR)name, 0, REG_SZ, (LPBYTE)value, strlen(value)+1) == ERROR_SUCCESS) { RegFlushKey(hKey); RegCloseKey(hKey); return TRUE; } RegCloseKey(hKey); return FALSE; } /** * This function stores data in the value field of an registry key. * * @param[in] root The key that is removed by this function is a subkey of the key that is identified by this parameter. * @param[in] key Pointer to a null-terminated string that specifies the name of a subkey that this function removes. * This is a subkey of the key that is identified by root. * @param[in] name Pointer to a null-terminated string that names the value to remove. */ gboolean z_reg_key_delete(HKEY root, gchar *key, gchar *name) { HKEY hKey; if(RegOpenKeyEx(root,(LPCSTR)key, 0, KEY_SET_VALUE, &hKey) != ERROR_SUCCESS) return FALSE; if(RegDeleteValue(hKey, (LPCSTR)name) != ERROR_SUCCESS) { RegFlushKey(hKey); RegCloseKey(hKey); return TRUE; } RegCloseKey(hKey); return FALSE; } /** * This function retrieves the data for a specified value associated with a specified registry key. * * @param[in] root The key that is opened or created by this function is a subkey of the key that is identified by this parameter. * @param[in] key Pointer to a null-terminated string that specifies the name of a subkey that this function opens or creates. * This is a subkey of the key that is identified by root. * @param[in] name Pointer to a string containing the name of the value to set. * @param[in, out] value Pointer to a buffer that receives value data. */ gboolean z_reg_key_read_dword(HKEY root, gchar *key, gchar *name, DWORD *value) { HKEY hKey; DWORD t = sizeof(DWORD); DWORD type = REG_DWORD; if(RegOpenKeyEx(root,(LPCSTR)key, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) return FALSE; if(RegQueryValueEx(hKey, (LPCSTR)name, 0, &type, (LPBYTE)value, &t) == ERROR_SUCCESS) { RegCloseKey(hKey); return TRUE; } RegCloseKey(hKey); return FALSE; } /** * This function retrieves the data for a specified value associated with a specified registry key. * * @param[in] root The key that is opened or created by this function is a subkey of the key that is identified by this parameter. * @param[in] key Pointer to a null-terminated string that specifies the name of a subkey that this function opens or creates. * This is a subkey of the key that is identified by root. * @param[in] name Pointer to a string containing the name of the value to set. * @param[in, out] value Pointer to a buffer that receives value data. */ gboolean z_reg_key_read_string(HKEY root, gchar *key, gchar *name, gchar **value) { HKEY hKey; gchar temp[2000]; DWORD t = 2000; DWORD type = REG_SZ; if(RegOpenKeyEx(root,(LPCSTR)key, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) return FALSE; if(RegQueryValueEx(hKey, (LPCSTR)name, 0, &type, (LPBYTE)&temp, &t) == ERROR_SUCCESS) { *value = g_strdup(temp); RegCloseKey(hKey); return TRUE; } RegCloseKey(hKey); return FALSE; } gboolean z_sid_to_text( PSID ps, char *buf, int bufSize ) { PSID_IDENTIFIER_AUTHORITY psia; DWORD dwSubAuthorities; DWORD dwSidRev = SID_REVISION; DWORD i; int n, size; char *p; if ( ! IsValidSid( ps ) ) return FALSE; psia = GetSidIdentifierAuthority( ps ); dwSubAuthorities = *GetSidSubAuthorityCount( ps ); size = 15 + 12 + ( 12 * dwSubAuthorities ) + 1; if ( bufSize < size ) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); return FALSE; } size = wsprintf( buf, "S-%lu-", dwSidRev ); p = buf + size; if ( psia->Value[0] != 0 || psia->Value[1] != 0 ) { n = wsprintf( p, "0x%02hx%02hx%02hx%02hx%02hx%02hx", (USHORT) psia->Value[0], (USHORT) psia->Value[1], (USHORT) psia->Value[2], (USHORT) psia->Value[3], (USHORT) psia->Value[4], (USHORT) psia->Value[5] ); size += n; p += n; } else { n = wsprintf( p, "%lu", ( (ULONG) psia->Value[5] ) + ( (ULONG) psia->Value[4] << 8 ) + ( (ULONG) psia->Value[3] << 16 ) + ( (ULONG) psia->Value[2] << 24 ) ); size += n; p += n; } for ( i = 0; i < dwSubAuthorities; ++ i ) { n = wsprintf( p, "-%lu", *GetSidSubAuthority( ps, i ) ); size += n; p += n; } return TRUE; } #endif libzorpll-3.9.4.1/src/zcp.c000066400000000000000000000262751224546767600154650ustar00rootroot00000000000000/*************************************************************************** * * Copyright (c) 2000-2004 BalaBit IT Ltd. * All rights reserved. * * Author : Bazsi * Auditor : * Last audited version: * Notes: * ***************************************************************************/ #include #include #include #include #define ZAS_ERROR "zas.error" #define ZCP_STATE_IDLE 0 #define ZCP_STATE_WRITING 1 #define ZCP_STATE_READING_HEADER 10 #define ZCP_STATE_READING_VALUE 11 #define ZCP_STATE_READING_TRAILER 12 #define ZCP_MAX_HEADERS 256 #define ZCP_MAX_HEADER_LENGTH 4096 struct _ZCPContext { ZStream *stream; gint write_state; gint read_state; gboolean error; /* command currently being parsed */ guint pending_session_id; ZCPCommand *pending; /* headers being parsed */ GString *key; GString *value; gssize valuelen; /* write buffer */ GString *buffer; guint bufpos; }; /* ZCPCommand */ static inline gint z_cp_command_get_headers_count(ZCPCommand *self) { return z_header_set_get_count(&self->headers); } ZCPCommand * z_cp_command_new(const gchar *cmd) { ZCPCommand *self = g_new0(ZCPCommand, 1); z_enter(); z_header_set_init(&self->headers); if (cmd) self->command = g_string_new(cmd); z_return(self); } ZCPCommand * z_cp_command_new_accept(gchar *welcome, GSList *groups) { ZCPCommand *cmd; cmd = z_cp_command_new("ACCEPT"); if (welcome) z_cp_command_add_header(cmd, g_string_new("Result"), g_string_new(welcome), FALSE); while (groups) { z_cp_command_add_header(cmd, g_string_new("Group"), g_string_new(((GString *) groups->data)->str), TRUE); groups = g_slist_next(groups); } return cmd; } ZCPCommand * z_cp_command_new_reject(gchar *reason) { ZCPCommand *cmd; cmd = z_cp_command_new("REJECT"); if (reason) z_cp_command_add_header(cmd, g_string_new("Reason"), g_string_new(reason), FALSE); return cmd; } void z_cp_command_free(ZCPCommand *self) { z_enter(); if (self) { if (self->command) { g_string_free(self->command, TRUE); self->command = NULL; } z_header_set_destroy(&self->headers); g_free(self); } z_return(); } /* ZCPContext */ GIOStatus z_cp_context_read(ZCPContext *self, guint *session_id, ZCPCommand **cmd) { gchar *buf; gsize buflen = 4096; gchar *tmpbuf; gint len; GIOStatus ret = G_IO_STATUS_ERROR; gchar **split; z_enter(); if (self->error) z_return(G_IO_STATUS_ERROR); while (1) { switch (self->read_state) { case ZCP_STATE_IDLE: /* read command */ ret = z_stream_line_get(self->stream, &buf, &buflen, NULL); if (ret != G_IO_STATUS_NORMAL) { if (ret == G_IO_STATUS_ERROR) self->error = TRUE; z_return(ret); } /* eck... modifying the buffer in z_stream_line */ buf[buflen] = 0; split = g_strsplit(buf, " ", 2); if (split[0] == NULL || /* Session ID */ split[1] == NULL) /* Message type */ { z_log(NULL, ZAS_ERROR, 3, "Incomplete command header; header='%s'", buf); self->error = TRUE; z_return(G_IO_STATUS_ERROR); } else { self->pending = z_cp_command_new(split[1]); self->pending_session_id = atoi(split[0]); self->read_state = ZCP_STATE_READING_HEADER; } g_strfreev(split); break; case ZCP_STATE_READING_HEADER: ret = z_stream_line_get(self->stream, &buf, &buflen, NULL); if (ret != G_IO_STATUS_NORMAL) { if (ret == G_IO_STATUS_ERROR) self->error = TRUE; z_return(ret); } if (buflen > 2) { if (z_cp_command_get_headers_count(self->pending) >= ZCP_MAX_HEADERS) { /* too many headers */ self->error = TRUE; z_log(NULL, ZAS_ERROR, 3, "Too many headers; max='%d'", ZCP_MAX_HEADERS); z_return(G_IO_STATUS_ERROR); } if (buf[0] == '[') { if (buf[1] == ']') { len = -1; tmpbuf = buf + 1; } else { len = strtol(buf + 1, &tmpbuf, 10); if (len < 0) { len = 0; } else if (len > ZCP_MAX_HEADER_LENGTH) { self->error = TRUE; z_log(NULL, ZAS_ERROR, 3, "Header too long; len='%d'", len); z_return(G_IO_STATUS_ERROR); } } if (tmpbuf[0] == ']' && (tmpbuf - buf) < (gssize)buflen) { self->valuelen = len; self->key = g_string_new_len(tmpbuf + 1, buflen + buf - tmpbuf - 1); self->read_state = ZCP_STATE_READING_VALUE; self->value = g_string_sized_new(len); } else { self->error = TRUE; z_log(NULL, ZAS_ERROR, 3, "Invalid header length specification; line='%.*s'", (gint) buflen, buf); z_return(G_IO_STATUS_ERROR); } } else { self->error = TRUE; z_log(NULL, ZAS_ERROR, 3, "Invalid header length specification; line='%.*s'", (gint) buflen, buf); z_return(G_IO_STATUS_ERROR); } } else { if (buflen != 0) { /* line with a single character ? */ self->error = TRUE; z_log(NULL, ZAS_ERROR, 3, "Buffer too short to contain a valid header; line='%.*s'", (gint) buflen, buf); z_return(G_IO_STATUS_ERROR); } else { /* complete packet, closing empty line received */ *cmd = self->pending; *session_id = self->pending_session_id; self->pending = NULL; self->read_state = ZCP_STATE_IDLE; z_return(G_IO_STATUS_NORMAL); } } break; case ZCP_STATE_READING_VALUE: if (self->valuelen == -1) { /* unspecified length */ ret = z_stream_line_get(self->stream, &buf, &buflen, NULL); if (ret != G_IO_STATUS_NORMAL) { if (ret == G_IO_STATUS_ERROR) self->error = TRUE; z_return(ret); } self->value = g_string_new_len(buf, buflen); z_cp_command_add_header(self->pending, self->key, self->value, TRUE); self->key = self->value = NULL; self->read_state = ZCP_STATE_READING_HEADER; } else if (self->valuelen > 0) { gchar buf2[4096]; ret = z_stream_read(self->stream, buf2, MIN((gsize)self->valuelen, (gsize)sizeof(buf2)), &buflen, NULL); if (ret == G_IO_STATUS_NORMAL) { self->valuelen -= buflen; self->value = g_string_append_len(self->value, buf2, buflen); } else { if (ret == G_IO_STATUS_ERROR) self->error = TRUE; z_return(ret); } } if (self->valuelen == 0) { /* no remaining header data, add to header list */ z_cp_command_add_header(self->pending, self->key, self->value, TRUE); self->key = self->value = NULL; self->read_state = ZCP_STATE_READING_TRAILER; } break; case ZCP_STATE_READING_TRAILER: ret = z_stream_line_get(self->stream, &buf, &buflen, NULL); if (ret != G_IO_STATUS_NORMAL) { if (ret == G_IO_STATUS_ERROR) self->error = TRUE; z_return(ret); } if (buflen != 0) { self->error = TRUE; z_log(NULL, ZAS_ERROR, 3, "Trailer line must be empty; line='%.*s'", (gint) buflen, buf); z_return(G_IO_STATUS_ERROR); } self->read_state = ZCP_STATE_READING_HEADER; break; default: break; } } z_return(ret); } static gboolean z_cp_context_format_command(ZCPContext *self, guint session_id, ZCPCommand *cmd) { GList *hdrs, *p; z_enter(); g_string_truncate(self->buffer, 0); if (cmd == NULL) z_return(FALSE); g_string_append_printf(self->buffer, "%d %s\n", session_id, cmd->command->str); hdrs = z_header_set_get_all_headers(&cmd->headers); for (p = hdrs; p; p = p->next) { ZCPHeader *header; header = p->data; g_string_append_printf(self->buffer, "[%d]%s\n", (gint) header->value->len, header->key->str); g_string_append_len(self->buffer, header->value->str, header->value->len); g_string_append_c(self->buffer, '\n'); } g_list_free(hdrs); g_string_append_c(self->buffer, '\n'); z_return(TRUE); } GIOStatus z_cp_context_write(ZCPContext *self, guint session_id, ZCPCommand *cmd) { GIOStatus ret; gsize write_len; z_enter(); if ((self->error) || (self->write_state != ZCP_STATE_IDLE && self->write_state != ZCP_STATE_WRITING)) z_return(G_IO_STATUS_ERROR); if (self->write_state == ZCP_STATE_IDLE) { if (!z_cp_context_format_command(self, session_id, cmd)) z_return(G_IO_STATUS_ERROR); self->write_state = ZCP_STATE_WRITING; } ret = z_stream_write(self->stream, self->buffer->str + self->bufpos, self->buffer->len - self->bufpos, &write_len, NULL); switch (ret) { case G_IO_STATUS_NORMAL: self->bufpos += write_len; if (self->bufpos < self->buffer->len) { ret = G_IO_STATUS_AGAIN; } else { g_string_truncate(self->buffer, 0); self->bufpos = 0; self->write_state = ZCP_STATE_IDLE; } break; case G_IO_STATUS_ERROR: self->error = TRUE; default: break; } z_return(ret); } ZCPContext * z_cp_context_new(ZStream *stream) { ZCPContext *self = g_new0(ZCPContext, 1); z_stream_ref(stream); self->stream = stream; self->buffer = g_string_sized_new(128); return self; } void z_cp_context_destroy(ZCPContext *self, gboolean close_stream) { if (close_stream) { z_stream_close(self->stream, NULL); } z_stream_unref(self->stream); g_string_free(self->buffer, TRUE); g_free(self); } libzorpll-3.9.4.1/src/zobject.c000066400000000000000000000101611224546767600163140ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: zobject.c,v 1.14 2004/06/21 14:10:47 sasa Exp $ * ***************************************************************************/ #include #include /** * struct type to hold ZObject virtual methods. **/ typedef struct _ZClassFuncs { gint method_count; void (*methods[1])(void); } ZClassFuncs; /** * This function is the free method of the ZObject class. * * @param s ZObject instance * * This function currently does nothing as ZObject has no real data structure. **/ void z_object_free_method(ZObject *s G_GNUC_UNUSED) { /* empty */ } /** * Dummy ZClass class descriptor. **/ #ifdef G_OS_WIN32 LIBZORPLL_EXTERN #endif ZClass ZClass__class = { Z_CLASS_HEADER, NULL, "ZClass", sizeof(ZClass), NULL }; /** * ZObject virtual methods. **/ static ZObjectFuncs z_object_funcs = { Z_FUNCS_COUNT(ZObject), z_object_free_method }; /** * Descriptor of ZObject, the base (or root) class. **/ #ifdef G_OS_WIN32 LIBZORPLL_EXTERN #endif ZClass ZObject__class = { Z_CLASS_HEADER, NULL, "ZObject", sizeof(ZObject), &z_object_funcs }; /** * This function checks whether subclass is derived from class. * * @param[in] class parent class * @param[in] subclass child class **/ gboolean z_object_is_subclass(ZClass *class, ZClass *subclass) { ZClass *p; p = subclass; while (p && p != class) p = p->super_class; return !!p; } /** * This function checks whether self is compatible of class, e.g.\ whether * it is derived from class. * * @param[in] self ZObject instance * @param[in] class class descriptor **/ gboolean z_object_is_compatible(ZObject *self, ZClass *class) { if (!self) return FALSE; else return z_object_is_subclass(class, self->isa); } /** * This function returns whether self is an instance of class. * * @param[in] self ZObject instance * @param[in] class class descriptor **/ gboolean z_object_is_instance(ZObject *self, ZClass *class) { if (!self) return FALSE; else return self->isa == class; } /** * Resolve NULL methods to be used from parent classes. * * @param[in] class class descriptor * * This function is called once for each class instantiated. It resolves * NULL methods to be used from parent classes. **/ static void z_object_resolve_funcs(ZClass *class) { gint i; if (class->funcs_resolved) return; if (class->super_class) { z_object_resolve_funcs(class->super_class); for (i = 0; i < class->super_class->funcs->method_count; i++) { /* inherit from parent */ if (((ZClassFuncs *) class->funcs)->methods[i] == NULL) ((ZClassFuncs *) class->funcs)->methods[i] = ((ZClassFuncs *) class->super_class->funcs)->methods[i]; } } class->funcs_resolved = TRUE; } /** * Creates a new instance of class. * * @param[in] class class descriptor * * This function takes a class descriptor and creates an instance of class * by allocating an appropriate memory block, initializing the reference * counter and ZObject specific fields. * * @returns the new object **/ ZObject * z_object_new(ZClass *class) { ZObject *inst; if (class->super.isa == NULL) class->super.isa = &ZClass__class; if (!class->funcs_resolved) z_object_resolve_funcs(class); inst = g_malloc0(class->size); inst->isa = class; z_refcount_set(&inst->ref_cnt, 1); return inst; } /** * This function checks whether class is compatible with compat, and if it * is, it returns a new instance of class. * * @param[in] class class decriptor * @param[in] compat class descriptor **/ ZObject * z_object_new_compatible(ZClass *class, ZClass *compat) { if (z_object_is_subclass(compat, class)) { return z_object_new(class); } else { g_assert(0 && "Requested class is not compatible"); return NULL; } } libzorpll-3.9.4.1/src/zorp/000077500000000000000000000000001224546767600155035ustar00rootroot00000000000000libzorpll-3.9.4.1/src/zorp/.arch-inventory000066400000000000000000000000401224546767600204460ustar00rootroot00000000000000precious ^zorplibconfig\.h\.in$ libzorpll-3.9.4.1/src/zorp/.cvsignore000066400000000000000000000001131224546767600174760ustar00rootroot00000000000000Makefile.in Makefile zorplibconfig.h.in zorplibconfig.h stamp-h.in stamp-h libzorpll-3.9.4.1/src/zorp/Makefile.am000066400000000000000000000010701224546767600175350ustar00rootroot00000000000000EXTRA_DIST = zorplibconfig.h-win32 zorplibconfig.h-win32.in ZORP_H = \ cap.h streamssl.h log.h memtrace.h misc.h streamline.h sockaddr.h \ io.h ssl.h stream.h thread.h \ listen.h connect.h source.h zorplib.h poll.h zorplibconfig.h \ registry.h packetbuf.h socket.h streambuf.h socketsource.h \ random.h error.h streamfd.h stackdump.h zobject.h process.h \ streamgzip.h blob.h streamblob.h streamtee.h \ code_base64.h code_cipher.h code_gzip.h code.h \ headerset.h zcp.h zurlparse.h compat.h pkgincludedir=@includedir@/zorp pkginclude_HEADERS = $(ZORP_H) libzorpll-3.9.4.1/src/zorp/blob.h000066400000000000000000000147201224546767600165760ustar00rootroot00000000000000/*************************************************************************** * * COPYRIGHTHERE * * $Id: proxy.h,v 1.82 2004/06/11 12:57:39 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_BLOB_H_INCLUDED #define ZORP_BLOB_H_INCLUDED #include #include #include #ifdef __cplusplus extern "C" { #endif struct ZBlob; /** * Central management of blobs. **/ typedef struct ZBlobSystem { ZRefCount ref_cnt; /**< reference counter */ gchar *dir; /**< directory to store the blobs in */ guint64 disk_max, disk_used; /**< maximal and current disk usage */ gsize mem_max, mem_used; /**< maximal and current memory usage */ gsize lowat, hiwat, noswap_max; /**< control limits - see spec */ GMutex *mtx_blobsys; /**< gadgets used for signalling request like allocation, etc. */ GCond *cond_thread_started; GThread *thr_management; /**< management thread */ GError *thread_error; /**< error structure for creating thr_management */ GList *blobs; /**< blobs created in this blob system */ GAsyncQueue *req_queue; /**< queue of blobs who have pending requests */ GList *waiting_list; /**< list of blobs whose requests weren't approved immediately */ gboolean active; /**< false if the blobsys is 'under destruction' */ } ZBlobSystem; /** global default instance */ extern ZBlobSystem *z_blob_system_default; extern const gchar* z_blob_system_default_tmpdir; /**< directory to store the blobs in */ extern gint64 z_blob_system_default_max_disk_usage; /**< max disk usage = 1 GB */ extern gsize z_blob_system_default_max_mem_usage; /**< max mem usage = 256 MB */ extern gsize z_blob_system_default_lowat; /**< lowat = 96 MB */ extern gsize z_blob_system_default_hiwat; /**< hiwat = 128 MB */ extern gsize z_blob_system_default_noswap_max; /**< noswap_max = 16 kB */ /* constructor, ref, unref, destructor */ ZBlobSystem* z_blob_system_new(const char *dir, gint64 dmax, gsize mmax, gsize low, gsize hiw, gsize nosw); void z_blob_system_ref(ZBlobSystem *self); void z_blob_system_unref(ZBlobSystem *self); /* create and destroy the default instance */ void z_blob_system_default_init(void); void z_blob_system_default_destroy(void); /** * Usage statistics for a blob. **/ typedef struct ZBlobStatistic { gint req_rd, req_wr, req_map; /**< performed read, write and mapping requests */ gint swap_count; /**< swapout counter */ gint alloc_count; /**< alloc modification counter */ unsigned long long total_rd, total_wr; /**< total bytes read and written */ time_t created, last_accessed; /**< time of creation and last access */ } ZBlobStatistic; /* initialise a blob stat - counters set to zero, timestamps to 'now' */ void z_blob_statistic_init(ZBlobStatistic *self); /** Blob sends ZBlobRequestCode to the maintenance thread for approval or as notification. */ typedef enum ZBlobRequestCode { Z_BLOB_REQ_NONE, /**< none - default value, does nothing */ Z_BLOB_REQ_REGISTER, /**< new blob wants to register itself */ Z_BLOB_REQ_UNREGISTER, /**< blob wants to unregister itself */ Z_BLOB_REQ_ALLOC /**< blob asks for approval on modification of its allocation */ } ZBlobRequestCode; /** The blob itself. */ typedef struct ZBlob { ZRefCount ref_cnt; /**< reference counter */ gint64 size, alloc_size; /**< actual size of the blob and the allocated space */ gboolean is_in_file; /**< is the blob swapped out */ gchar *filename; /**< swapfile name */ gint fd; /**< swapfile descriptor */ gchar *data; /**< memory image pointer */ ZBlobSystem *system; /**< blob system it belongs to */ GMutex *mtx_lock; /**< lock for concurrent accesses */ ZBlobStatistic stat; /**< statistics */ GMutex *mtx_reply; /**< mutex and conditional for waiting for reply */ GCond *cond_reply; gboolean replied; gchar *mapped_ptr; /**< addr and length of the mapped area */ gsize mapped_length; /**< (when multiple mappings will be implemented, replace with ?GHash?) */ /* communication with the blobsystems threadproc */ gssize alloc_req; /**< communication with the blobsystems threadproc */ gboolean approved; /**< communication with the blobsystems threadproc */ gboolean storage_locked; /**< communication with the blobsystems threadproc */ } ZBlob; /* constructor, ref, unref, destructor */ ZBlob *z_blob_new(ZBlobSystem *sys, gsize initial_size); ZBlob *z_blob_ref(ZBlob *self); void z_blob_unref(ZBlob *self); /* swap out and get the filename - WARNING - the blob will be locked for reading (only) */ const gchar *z_blob_get_file(ZBlob *self, const gchar *user, const gchar *group, gint mode, gint timeout); void z_blob_release_file(ZBlob *self); /* truncate/expand a blob to a specified size */ gboolean z_blob_truncate(ZBlob *self, gint64 pos, gint timeout); /* write and read */ gsize z_blob_add_copy(ZBlob *self, gint64 pos, const gchar *data, gsize req_datalen, gint timeout); gsize z_blob_get_copy(ZBlob *self, gint64 pos, gchar *data, gsize req_datalen, gint timeout); GIOStatus z_blob_read_from_stream(ZBlob *self, gint64 pos, ZStream *stream, gint64 count, gint timeout, GError **error); GIOStatus z_blob_write_to_stream(ZBlob *self, gint64 pos, ZStream *stream, gint64 count, gint timeout, GError **error); /* lock and unlock part of the blob and return pointer to it - WARNING - the blob will be locked for reading (only) */ gchar *z_blob_get_ptr(ZBlob *self, gint64 pos, gsize *req_datalen, gint timeout); void z_blob_free_ptr(ZBlob *self, gchar *data); void z_blob_storage_lock(ZBlob *self, gboolean st); /* locking functions - needed by ZStreamBlob */ gboolean z_blob_lock(ZBlob *self, gint timeout); void z_blob_unlock(ZBlob *self); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/cap.h000066400000000000000000000021411224546767600164150ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: cap.h,v 1.6 2003/09/10 11:46:58 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_CAP_H_INCLUDED #define ZORP_CAP_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #if ZORPLIB_ENABLE_CAPS #if HAVE_SYS_CAPABILITY_H #include #endif extern const gchar *zorp_caps; gboolean cap_modify(int capability, int onoff); cap_t cap_save(void); gboolean cap_restore(cap_t r); #define cap_enable(cap) cap_modify(cap, TRUE) #define cap_disable(cap) cap_modify(cap, FALSE) #else typedef int cap_t; #define CAP_NET_ADMIN 0 #define CAP_NET_BIND_SERVICE 0 #define cap_save() 0 #define cap_restore(r) #define cap_enable(cap) #define cap_disable(cap) #endif #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/code.h000066400000000000000000000040461224546767600165720ustar00rootroot00000000000000#ifndef ZORP_PROXY_CODE_H #define ZORP_PROXY_CODE_H // #include #include /** default buffer size */ #define ZCODE_BUFSIZE_DEFAULT 256 #ifdef __cplusplus extern "C" { #endif typedef struct _ZCode ZCode; /** * The ZCode class facilitates transforming (encoding or decoding) binary data. **/ struct _ZCode { guchar *buf; gsize buf_len, buf_used; gint error_counter; gboolean (*transform)(ZCode *self, const void *from, gsize fromlen); gboolean (*finish)(ZCode *self); void (*free_fn)(ZCode *self); }; gboolean z_code_grow(ZCode *self, gint reqlen); gsize z_code_get_result_length(ZCode *self); gsize z_code_get_result(ZCode *self, void *to, gsize tolen); const void *z_code_peek_result(ZCode *self); void z_code_unget_result(ZCode *self, const void *from, gsize fromlen); void z_code_flush_result(ZCode *self, gsize flush_length); ZCode *z_code_new(gint bufsize); void z_code_init(ZCode *self, gint bufsize); void z_code_free(ZCode *self); /** * Get the error counter of the ZCode instance. * * @param[in] self ZCode instance * * @returns error counter **/ static inline gint z_code_get_errors(ZCode *self) { return self->error_counter; } /** * Reset the error counter. * * @param[in] self ZCode instance **/ static inline void z_code_clear_errors(ZCode *self) { self->error_counter = 0; } /** * Transforms data to the internal buffer. * * @param[in] self this * @param[in] from source buffer * @param[in] fromlen number of bytes to transform * * Can be used any number of * times, the internal buffer grows automatically. * * @returns The number of bytes written */ static inline gboolean z_code_transform(ZCode *self, const void *from, gsize fromlen) { return self->transform(self, from, fromlen); } /** * Finalizes the output in the internal buffer. * * @param[in] self this * * Should be called once at the end of the encoding process. */ static inline gboolean z_code_finish(ZCode *self) { if (self->finish) return self->finish(self); return TRUE; } #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/code_base64.h000066400000000000000000000004551224546767600177360ustar00rootroot00000000000000#ifndef ZORP_PROXY_CODE_BASE64_H #define ZORP_PROXY_CODE_BASE64_H #include #ifdef __cplusplus extern "C" { #endif ZCode *z_code_base64_encode_new(gint bufsize, gint linelen); ZCode *z_code_base64_decode_new(gint bufsize, gboolean error_tolerant); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/code_cipher.h000066400000000000000000000003751224546767600201250ustar00rootroot00000000000000#ifndef ZORP_CODE_CIPHER_H_INCLUDED #define ZORP_CODE_CIPHER_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif ZCode *z_code_cipher_new(EVP_CIPHER_CTX *cipher_ctx); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/code_gzip.h000066400000000000000000000004231224546767600176160ustar00rootroot00000000000000#ifndef ZORP_PROXY_CODE_GZIP_H #define ZORP_PROXY_CODE_GZIP_H #include #ifdef __cplusplus extern "C" { #endif ZCode *z_code_gzip_encode_new(gint bufsize, gint compress_level); ZCode *z_code_gzip_decode_new(gint bufsize); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/compat.h000066400000000000000000000007701224546767600171430ustar00rootroot00000000000000/*************************************************************************** * * COPYRIGHTHERE * * Author: Laszlo Attila Toth * ***************************************************************************/ #ifndef ZORP_COMPAT_H_INCLUDED #define ZORP_COMPAT_H_INCLUDED #if GLIB_CHECK_VERSION(2, 30, 0) #define G_LOCK_MUTEX_POINTER(name) (&(G_LOCK_NAME(name))) #else #define G_LOCK_MUTEX_POINTER(name) g_static_mutex_get_mutex(&(G_LOCK_NAME(name))) #endif #endif /* ZORP_COMPAT_H_INCLUDED */ libzorpll-3.9.4.1/src/zorp/connect.h000066400000000000000000000100331224546767600173020ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: connect.h,v 1.15 2004/10/05 14:06:37 chaoron Exp $ * ***************************************************************************/ #ifndef ZORP_CONNECT_H_INCLUDED #define ZORP_CONNECT_H_INCLUDED #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** z_io_connect public interface */ typedef void (*ZConnectFunc)(ZStream *fdstream, GError *error, gpointer user_data); /** * Connect to the given socket address using the given local address, * and call a given callback function if the connection is established. **/ typedef struct _ZConnector { ZObject super; ZSockAddr *local; gint fd; /* private */ ZSockAddr *remote; /* we use a reference to our GSource, as using source_id would cause a race */ GSource *watch; gint timeout; ZConnectFunc callback; gpointer user_data; GDestroyNotify destroy_data; gint refcnt; GStaticRecMutex lock; GMainContext *context; gboolean blocking; gint socket_type; guint32 sock_flags; gchar *session_id; } ZConnector; /** * ZConnector virtual method table type. **/ typedef struct _ZConnectorFuncs { ZObjectFuncs super; } ZConnectorFuncs; LIBZORPLL_EXTERN ZClass ZConnector__class; LIBZORPLL_EXTERN ZClass ZStreamConnector__class; ZConnector * z_connector_new(ZClass *_class, const gchar *session_id, gint socket_type, ZSockAddr *local, ZSockAddr *remote, guint32 sock_flags, ZConnectFunc callback, gpointer user_data, GDestroyNotify destroy_data); gboolean z_connector_start_block(ZConnector *self, ZSockAddr **local, ZStream **stream); gboolean z_connector_start(ZConnector *self, ZSockAddr **local); gboolean z_connector_start_in_context(ZConnector *self, GMainContext *context, ZSockAddr **local); void z_connector_set_timeout(ZConnector *self, gint timeout); void z_connector_set_tos(ZConnector *self, gint tos); void z_connector_set_mark(ZConnector *self, int mark); void z_connector_cancel(ZConnector *self); /** * Increment reference count and return a reference to a ZConnector. * * @param[in] self ZConnector instance * * @returns self **/ static inline ZConnector * z_connector_ref(ZConnector *self) { return Z_CAST(z_object_ref(&self->super), ZConnector); } /** * Decrement reference count of a ZConnector. * * @param[in] self ZConnector instance. **/ static inline void z_connector_unref(ZConnector *self) { z_object_unref(&self->super); } /** * Get session id. * * @param[in] self ZConnector instance * * @returns session id **/ static inline const gchar * z_connector_get_session_id(ZConnector *self) { return self->session_id; } /** * Create a new ZStreamConnector instance. * * @param[in] session_id session id used for logging * @param[in] local local address to bind to. * @param[in] remote remote address to connect to. * @param[in] sock_flags socket flags * @param[in] callback function to call when the connection is established. * @param[in] user_data opaque pointer to pass to callback. * @param[in] destroy_data destroy callback for user_data * * @returns The allocated instance. **/ static inline ZConnector * z_stream_connector_new(const gchar *session_id, ZSockAddr *local, ZSockAddr *remote, guint32 sock_flags, ZConnectFunc callback, gpointer user_data, GDestroyNotify destroy_data) { return z_connector_new(Z_CLASS(ZStreamConnector), session_id, SOCK_STREAM, local, remote, sock_flags, callback, user_data, destroy_data); } #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/error.h000066400000000000000000000014031224546767600170030ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: error.h,v 1.4 2004/05/21 13:58:32 abi Exp $ * ***************************************************************************/ #ifndef _ZORP_ERROR_H_INCLUDED #define _ZORP_ERROR_H_INCLUDED #include #ifdef G_OS_WIN32 # include #endif #include #ifdef __cplusplus extern "C" { #endif gboolean z_errno_is(int e); int z_errno_get(void); void z_errno_set(int e); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/headerset.h000066400000000000000000000020031224546767600176130ustar00rootroot00000000000000/*************************************************************************** * * COPYRIGHTHERE * ***************************************************************************/ #ifndef ZORP_HEADERSET_H #define ZORP_HEADERSET_H #include #ifdef __cplusplus extern "C" { #endif typedef struct _ZHeader { GString *key; GString *value; } ZHeader; typedef struct _ZHeaderSet { gint headers_count; GHashTable *headers; } ZHeaderSet; GList *z_header_set_get_all_headers(ZHeaderSet *self); ZHeader *z_header_set_iterate(ZHeaderSet *self, const gchar *key, gpointer *opaque); gboolean z_header_set_add(ZHeaderSet *self, GString *key, GString *value, gboolean multiple); void z_header_set_init(ZHeaderSet *self); void z_header_set_destroy(ZHeaderSet *self); static inline ZHeader * z_header_set_find(ZHeaderSet *self, gchar *key) { return z_header_set_iterate(self, key, NULL); } static inline gint z_header_set_get_count(ZHeaderSet *self) { return self->headers_count; } #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/io.h000066400000000000000000000022151224546767600162630ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: io.h,v 1.8 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_IO_H_INCLUDED #define ZORP_IO_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif extern GSourceFuncs z_io_watch_funcs; gboolean z_fd_set_nonblock(int fd, gboolean enable); gboolean z_fd_set_keepalive(int fd, gboolean enable); gboolean z_fd_set_oobinline(int fd, gboolean enable); void z_fd_set_our_mark(int fd, int mark); #if ZORPLIB_ENABLE_TOS void z_fd_get_peer_tos(gint fd, guint8 *tos); void z_fd_get_our_tos(gint fd, guint8 *tos); void z_fd_set_our_tos(gint fd, guint8 tos); #else #define z_fd_get_peer_tos(fd, tos) #define z_fd_get_our_tos(fd, tos) #define z_fd_set_our_tos(fd, tos) #endif #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/listen.h000066400000000000000000000060211224546767600171510ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: listen.h,v 1.11 2004/10/05 14:06:37 chaoron Exp $ * ***************************************************************************/ #ifndef ZORP_LISTEN_H_INCLUDED #define ZORP_LISTEN_H_INCLUDED #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif typedef gboolean (*ZAcceptFunc)(ZStream *fdstream, ZSockAddr *client, ZSockAddr *dest, gpointer user_data); /** * Listen on the given socket address, and call a given callback for * each incoming connection. **/ typedef struct _ZListener { ZObject super; /** user request bind address */ ZSockAddr *bind_addr; /** address we bound to */ ZSockAddr *local; gint fd; /* these are private */ GSource *watch; ZAcceptFunc callback; gpointer user_data; guint32 sock_flags; GStaticRecMutex lock; GMainContext *context; gchar *session_id; } ZListener; /** * ZListener virtual method table type. **/ typedef struct _ZListenerFuncs { ZObjectFuncs super; gint (*open_listener)(ZListener *self); GIOStatus (*accept_connection)(ZListener *self, ZStream **fdstream, ZSockAddr **client, ZSockAddr **dest); } ZListenerFuncs; extern ZClass ZListener__class; ZListener * z_listener_new(ZClass *class_, const gchar *session_id, ZSockAddr *local, guint32 sock_flags, ZAcceptFunc callback, gpointer user_data); /** * Increment reference count and return a reference. * * @param[in] self ZListener instance * * @returns self **/ static inline ZListener * z_listener_ref(ZListener *self) { return Z_CAST(z_object_ref(&self->super), ZListener); } /** * Decrement reference count. * * @param[in] self ZListener instance **/ static inline void z_listener_unref(ZListener *self) { z_object_unref(&self->super); } gboolean z_listener_start(ZListener *self) G_GNUC_WARN_UNUSED_RESULT; gboolean z_listener_start_in_context(ZListener *self, GMainContext *context) G_GNUC_WARN_UNUSED_RESULT; void z_listener_cancel(ZListener *self); void z_listener_suspend(ZListener *self); void z_listener_resume(ZListener *self); /** * Get session id. * * @param[in] self ZListener instance * * @returns session id **/ static inline const gchar * z_listener_get_session_id(ZListener *self) { return self->session_id; } gboolean z_listener_open(ZListener *s) G_GNUC_WARN_UNUSED_RESULT; ZListener * z_stream_listener_new(const gchar *session_id, ZSockAddr *local, guint32 sock_flags, gint backlog, ZAcceptFunc callback, gpointer user_data); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/log.h000066400000000000000000000163051224546767600164420ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: log.h,v 1.31 2004/05/18 15:33:40 abi Exp $ * ***************************************************************************/ #ifndef ZORP_LOG_H_INCLUDED #define ZORP_LOG_H_INCLUDED #include #include #ifdef HAVE_SYSLOG_H #include #endif #ifdef __cplusplus extern "C" { #endif #ifndef ENABLE_TRACE #if ZORPLIB_ENABLE_TRACE #define ENABLE_TRACE 1 #endif /* ZORPLIB_ENABLE_TRACE */ #endif /* ENABLE_TRACE */ LIBZORPLL_EXTERN gchar fake_session_id[256]; typedef gint (*ZLogMapTagFunc)(const gchar *tag, gsize len); #define ZORP_SYSLOG_FACILITY LOG_LOCAL6 #define ZLF_SYSLOG 0x0001 #define ZLF_TAGS 0x0002 #define ZLF_THREAD 0x0004 #define ZLF_STDERR 0x0008 #define ZLF_WINDEBUG 0x0010 #define ZLF_ESCAPE 0x0020 #ifndef G_OS_WIN32 #define z_debug(level, format, args...) z_llog("core.debug", level, format, ##args) #define z_warning(level, format, args...) z_llog("core.warning", level, format, ##args) #define z_message(level, format, args...) z_llog("core.message", level, format, ##args) #else #define z_debug(level, format, args) z_llog("core.debug", level, format, ##args) #define z_warning(level, format, args) z_llog("core.warning", level, format, ##args) #define z_message(level, format, args) z_llog("core.message", level, format, ##args) #endif gboolean z_log_init(const gchar *syslog_name, guint flags); void z_log_enable_syslog(const gchar *syslog_name); void z_log_enable_stderr_redirect(gboolean threaded); void z_log_enable_tag_map_cache(ZLogMapTagFunc map_tags, gint max_tag); void z_logv(const gchar *class_, int level, const gchar *format, va_list ap); #ifndef G_OS_WIN32 void z_llog(const gchar *class_, int level, const gchar *format, ...) __attribute__ ((format(printf, 3, 4))); #else void z_llog(const gchar *class_, int level, const gchar *format, ...); #endif gboolean z_log_enabled_len(const gchar *class_, gsize class_len, int level); /** * Checks if a message with a given class/level combination would actually be written to the log -- with null-terminated tag string. * * @param[in] class_ message tag * @param[in] level log message level * * @see z_log_enabled_len in log.c * * @returns TRUE if the log would be written, FALSE otherwise **/ #ifndef G_OS_WIN32 #define z_log_enabled(class_, level) \ ({ \ gboolean __res; \ if (__builtin_constant_p(class_)) \ __res = z_log_enabled_len(class_, __builtin_strlen(class_), level); \ else \ __res = z_log_enabled_len(class_, strlen(class_), level); \ __res; \ }) #else #define z_log_enabled(class_, level) \ z_log_enabled_len(class_, strlen(class_), level) #endif gboolean z_log_change_verbose_level(gint direction, gint value, gint *new_value); gboolean z_log_change_logspec(const gchar *log_spec, const gchar **new_value); void z_log_clear_caches(void); void z_log_destroy(void); const gchar *z_log_session_id(const gchar *session_id); /** * This function generates hexdumps of the specified buffer to the system * log using z_log(). * * @param[in] session_id session id to be used for the log messages * @param[in] class_ log message class * @param[in] level log message verbosity level * @param[in] buf buffer * @param[in] len buffer length * * This inline function checks if the dump would be logged before generating it. * * @see z_format_data_dump() **/ static inline void z_log_data_dump(const gchar *session_id, const gchar *class_, gint level, const void *buf, guint len) { if (z_log_enabled(class_, level)) z_format_data_dump(session_id, class_, level, buf, len); } /** * This function generates textual dumps of the specified buffer to the system * log using z_log(). * * @param[in] session_id session id to be used for the log messages * @param[in] class_ log message class * @param[in] level log message verbosity level * @param[in] buf buffer * @param[in] len buffer length * * This inline function checks if the dump would be logged before generating it. * * @see z_format_text_dump() **/ static inline void z_log_text_dump(const gchar *session_id, const gchar *class_, gint level, const char *buf, guint len) { if (z_log_enabled(class_, level)) z_format_text_dump(session_id, class_, level, buf, len); } const gchar * z_log_trace_indent(gint dir); /** * Platform-dependent z_log() macro. * * @see the non-Win32 implementation as z_llog() in log.c. * Whether the message would really be written is checked * and the string form of session id is prepended to the format string * and argument list before calling z_llog(). * @see the Win32 implementation as z_log() in log.c. **/ #ifdef G_OS_WIN32 void z_log(const gchar* session_id, const gchar* class_, int level, gchar* format, ...); #else #define z_log(session_id, class_, level, format, args...) \ do \ { \ if (z_log_enabled(class_, level)) \ /*NOLOG*/ \ z_llog(class_, level, "(%s): " format, z_log_session_id(session_id) , ##args); \ } \ while (0) #endif #if ENABLE_TRACE #ifndef G_OS_WIN32 #define z_trace(session_id, args...) z_log(session_id , CORE_TRACE, 7, ##args) #else #define z_trace #endif #define z_session_enter(s) z_log(s, CORE_TRACE, 7, "%sEnter %s (%s:%d)", z_log_trace_indent(1), __FUNCTION__, __FILE__, __LINE__) #define z_session_leave(s) z_log(s, CORE_TRACE, 7, "%sLeave %s (%s:%d)", z_log_trace_indent(-1), __FUNCTION__, __FILE__, __LINE__) #define z_session_cp(s) z_log(s, CORE_TRACE, 7, "%sCheckpoint %s (%s:%d)", z_log_trace_indent(0), __FUNCTION__, __FILE__, __LINE__) #define z_enter() z_session_enter(NULL) #define z_leave() z_session_leave(NULL) #define z_cp() z_session_cp(NULL) #else #ifndef G_OS_WIN32 #define z_trace(session_id, args...) #else #define z_trace #endif #define z_enter() #define z_leave() #define z_cp() #define z_session_enter(s) #define z_session_leave(s) #define z_session_cp(s) #endif #ifdef G_OS_WIN32 /* disable C4003: not enough actual parameters for macro 'z_return' */ #pragma warning(disable: 4003) #endif #define z_return(retval) do { z_leave(); return retval; } while (0) void z_log_set_defaults(gint verbose_level, gboolean use_syslog, gboolean n_log_tags, const gchar *n_log_spec); void z_log_set_use_syslog(gboolean use_syslog); gint z_log_get_verbose_level(void); gboolean z_log_get_use_syslog(void); const gchar * z_log_get_log_spec(void); gboolean z_log_get_log_tags(void); gint z_log_get_tag_loglevel(const gchar *tag, gsize tag_len); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/memtrace.h000066400000000000000000000020021224546767600174430ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: memtrace.h,v 1.12 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_MEMTRACE_H_INCLUDED #define ZORP_MEMTRACE_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif void z_mem_trace_init(const gchar *memtrace_file_name); void z_mem_trace_stats(void); void z_mem_trace_dump(void); #if ZORPLIB_ENABLE_MEM_TRACE #include void *z_malloc(size_t size, gpointer backtrace[]); void z_free(void *ptr, gpointer backtrace[]); void *z_realloc(void *ptr, size_t size, gpointer backtrace[]); void *z_calloc(size_t nmemb, size_t size, gpointer backtrace[]); #endif #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/misc.h000066400000000000000000000132361224546767600166140ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: misc.h,v 1.20 2004/06/21 14:10:47 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_MISC_H_INCLUDED #define ZORP_MISC_H_INCLUDED #include #include #include #ifdef G_OS_WIN32 #define _WINSOCKAPI_ #include #include #endif #ifdef __cplusplus extern "C" { #endif #define MAX_REF 512*1024 #define Z_STRING_SAFE(x) (x ? x : "(null)") #define ON_OFF_STR(x) (x ? "on" : "off") #define YES_NO_STR(x) (x ? "yes" : "no") #ifndef G_GNUC_WARN_UNUSED_RESULT # if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) # define G_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) # else # define G_GNUC_WARN_UNUSED_RESULT # endif #endif #define IGNORE_UNUSED_RESULT(x) if ((x)) { } /** * Stores a character set in the form of a bitfield. * * ZCharSet is a simple representation of a character set. It can be parsed * from a string representation where regexp like expressions can be used. * Checking whether a given character is in the character set is quite fast * as each character is represented as a bit in a bitstring. **/ typedef struct _ZCharSet { guint32 enable_mask[256 / 32]; } ZCharSet; void z_charset_init(ZCharSet *self); gboolean z_charset_parse(ZCharSet *self, gchar *spec); gboolean z_charset_is_string_valid(ZCharSet *self, gchar *str, gint len); /** * Puts chr into the ZCharSet. * * @param[in] self ZCharSet instance * @param[in] chr the character to put into the set * * Sets the bit corresponding to the character chr in self. **/ static inline void z_charset_enable(ZCharSet *self, char chr) { guint ndx = ((guchar) chr) >> 5; /* top 3 bits are the index of the byte */ guint bit = 1 << (((guchar) chr) & 0x1F); /* bit mask from the value of the lower 5 bits */ self->enable_mask[ndx] |= bit; } /** * Checks if chr is in the ZCharSet. * * @param[in] self ZCharSet instance * @param[in] chr character to look up in self * * @returns TRUE if it's in the charset, FALSE if not **/ static inline gboolean z_charset_is_enabled(ZCharSet *self, char chr) { guint ndx = ((guchar) chr) >> 5; /* top 3 bits are the index of the byte */ guint bit = 1 << (((guchar) chr) & 0x1F); /* bit mask from the value of the lower 5 bits */ return !!(self->enable_mask[ndx] & bit); } void z_format_data_dump(const gchar *session_id, const gchar *class_, gint level, const void *buf, guint len); void z_format_text_dump(const gchar *session_id, const gchar *class_, gint level, const void *buf, guint len); GString *g_string_assign_len(GString *s, const gchar *val, gint len); gint g_time_val_compare(const GTimeVal *t1, const GTimeVal *t2); glong g_time_val_diff(const GTimeVal *t1, const GTimeVal *t2); void g_time_val_subtract(GTimeVal *result, const GTimeVal *t1, const GTimeVal *t2); gchar *z_str_escape(const gchar *s, gint len); gchar *z_str_compress(const gchar *s, gint len); gboolean z_port_enabled(gchar *port_range, guint port); void z_crypt(const char *key, const char *salt, char *result, size_t result_len); guint z_casestr_hash(gconstpointer key); /** * Increase the reference count pointed to by ref. * * @param[in, out] ref * * Does some sanity checking. **/ static inline void z_incref(guint *ref) { g_assert(*ref < MAX_REF && *ref > 0); (*ref)++; } /** * Decrease the reference count pointed to by ref. * * @param[in, out] ref * * Does some sanity checking. * * @returns the new value of the reference count. **/ static inline guint z_decref(guint *ref) { g_assert(*ref < MAX_REF && *ref > 0); (*ref)--; return *ref; } /** * Reference counter. **/ typedef struct _ZRefCount { gint counter; } ZRefCount; #define Z_REFCOUNT_INIT { 1 } /** * Atomically increase a reference count. * * @param[in] ref ZRefCount instance * * This function atomically increases a reference count while checking its * value for sanity. If the value is insane, the program is aborted. **/ static inline void z_refcount_inc(ZRefCount *ref) { g_assert(ref->counter < MAX_REF && ref->counter > 0); g_atomic_int_inc(&ref->counter); } /** * Atomically decrease a reference count and check if it is zero already. * * @param[in] ref ZRefCount instance * * @returns TRUE if the reference count reached zero, e.g. the object * must be freed. **/ static inline gboolean z_refcount_dec(ZRefCount *ref) { g_assert(ref->counter < MAX_REF && ref->counter > 0); return g_atomic_int_dec_and_test(&ref->counter); } /** * Set the reference counter to the value specified. * * @param[in] ref ZRefCount instance * @param[in] value set reference count to this value * * @note This function is not * atomic wrt _inc and _dec, and thus it should only be used during * initialization. **/ static inline void z_refcount_set(ZRefCount *ref, gint value) { ref->counter = value; } static inline void g_ustrfreev(guchar **str) { g_strfreev((gchar **)str); } static inline void g_sstrfreev(gint8 **str) { g_strfreev((gchar **)str); } const gchar *z_libzorpll_version_info(void); typedef enum { Z_OG_PROCESS = 0x1, Z_OG_THREAD = 0x2, Z_OG_LOG = 0x4, } ZOptionGroupFlags; void z_libzorpll_add_option_groups(GOptionContext *ctx, guint disable_groups); #ifndef HAVE_LOCALTIME_R struct tm *localtime_r(const time_t *timep, struct tm *result); #endif #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/packetbuf.h000066400000000000000000000236451224546767600176320ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * ***************************************************************************/ #ifndef ZORP_PACKETBUF_H_INCLUDED #define ZORP_PACKETBUF_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif /** glib is missing this endianness define */ #define G_HOST_ENDIAN G_BYTE_ORDER /** glib is missing this endianness define */ #define G_NETWORK_ENDIAN G_BIG_ENDIAN typedef enum _ZPktBufFlags { Z_PB_NONE = 0x0000, Z_PB_BORROWED = 0x0001, } ZPktBufFlags; /** * Buffer intended to hold a single packet. **/ typedef struct _ZPktBuf { ZRefCount ref_cnt; gsize allocated, length, pos; ZPktBufFlags flags; guchar *data; } ZPktBuf; /* Get attributes */ static inline void *z_pktbuf_data(ZPktBuf *self) { return self->data; } static inline void *z_pktbuf_current(ZPktBuf *self) { return self->data + self->pos; } static inline void *z_pktbuf_end(ZPktBuf *self) { return self->data + self->length; } static inline gsize z_pktbuf_size(const ZPktBuf *self) { return self->allocated; } static inline gsize z_pktbuf_free_size(const ZPktBuf *self) { return self->allocated - self->length; } static inline gsize z_pktbuf_length(const ZPktBuf *self) { return self->length; } static inline gsize z_pktbuf_pos(const ZPktBuf *self) { return self->pos; } static inline ZPktBufFlags z_pktbuf_flags(const ZPktBuf *self) { return self->flags; } /* Work with the buffer itself, regardless of position */ void z_pktbuf_resize(ZPktBuf *self, gsize size); gboolean z_pktbuf_copy(ZPktBuf *self, const void *data, gsize length); void z_pktbuf_relocate(ZPktBuf *self, void *data, gsize length, gboolean is_borrowed); gboolean z_pktbuf_append(ZPktBuf *self, const void *data, gsize length); gboolean z_pktbuf_insert(ZPktBuf *self, gsize pos, const void *data, gsize length); gboolean z_pktbuf_data_equal(ZPktBuf *lhs, ZPktBuf *rhs); /* Instance control */ ZPktBuf *z_pktbuf_new(void); ZPktBuf *z_pktbuf_ref(ZPktBuf *self); void z_pktbuf_unref(ZPktBuf *self); ZPktBuf *z_pktbuf_part(ZPktBuf *self, gsize pos, gsize len); void z_pktbuf_dump(const gchar *session_id, const gchar *class_, int level, ZPktBuf *self, const gchar *title); /* Fancy constructors */ ZPktBuf *z_pktbuf_new_from_gstring(const GString * const str); static inline void z_pktbuf_data_dump(const gchar *session_id, const gchar *class_, int level, ZPktBuf *self) { z_pktbuf_dump(session_id, class_, level, self, NULL); } /* Position-related operations */ static inline gsize z_pktbuf_available(ZPktBuf *self) { return (self->length - self->pos); } gboolean z_pktbuf_set_available(ZPktBuf *self, gsize size); gboolean z_pktbuf_seek(ZPktBuf *self, GSeekType whence, gssize pos); gboolean z_pktbuf_get_boolean(ZPktBuf *self, gboolean *res); gboolean z_pktbuf_put_boolean(ZPktBuf *self, gboolean res); gboolean z_pktbuf_get_boolean16(ZPktBuf *self, gboolean *res); gboolean z_pktbuf_get_u8(ZPktBuf *self, guint8 *res); gboolean z_pktbuf_get_u16(ZPktBuf *self, gint e, guint16 *res); gboolean z_pktbuf_get_u32(ZPktBuf *self, gint e, guint32 *res); gboolean z_pktbuf_get_u64(ZPktBuf *self, gint e, guint64 *res); gboolean z_pktbuf_put_u8(ZPktBuf *self, guint8 d); gboolean z_pktbuf_put_u16(ZPktBuf *self, gint e, guint16 d); gboolean z_pktbuf_put_u32(ZPktBuf *self, gint e, guint32 d); gboolean z_pktbuf_put_u64(ZPktBuf *self, gint e, guint64 d); gboolean z_pktbuf_get_u8s(ZPktBuf *self, gsize n, guint8 *res); gboolean z_pktbuf_get_u16s(ZPktBuf *self, gint e, gsize n, guint16 *res); gboolean z_pktbuf_get_u32s(ZPktBuf *self, gint e, gsize n, guint32 *res); gboolean z_pktbuf_get_u64s(ZPktBuf *self, gint e, gsize n, guint64 *res); gboolean z_pktbuf_put_u8s(ZPktBuf *self, gsize n, const guint8 *d); gboolean z_pktbuf_put_u16s(ZPktBuf *self, gint e, gsize n, const guint16 *d); gboolean z_pktbuf_put_u32s(ZPktBuf *self, gint e, gsize n, const guint32 *d); gboolean z_pktbuf_put_u64s(ZPktBuf *self, gint e, gsize n, const guint64 *d); static inline gboolean z_pktbuf_get_u16_le(ZPktBuf *self, guint16 *res) { return z_pktbuf_get_u16(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_get_u64_le(ZPktBuf *self, guint64 *res) { return z_pktbuf_get_u64(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_get_u32_le(ZPktBuf *self, guint32 *res) { return z_pktbuf_get_u32(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_put_u16_le(ZPktBuf *self, guint16 res) { return z_pktbuf_put_u16(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_put_u32_le(ZPktBuf *self, guint32 res) { return z_pktbuf_put_u32(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_put_u64_le(ZPktBuf *self, guint64 res) { return z_pktbuf_put_u64(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_get_u16_be(ZPktBuf *self, guint16 *res) { return z_pktbuf_get_u16(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_get_u32_be(ZPktBuf *self, guint32 *res) { return z_pktbuf_get_u32(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_get_u64_be(ZPktBuf *self, guint64 *res) { return z_pktbuf_get_u64(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_put_u16_be(ZPktBuf *self, guint16 res) { return z_pktbuf_put_u16(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_put_u32_be(ZPktBuf *self, guint32 res) { return z_pktbuf_put_u32(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_put_u64_be(ZPktBuf *self, guint64 res) { return z_pktbuf_put_u64(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_get_s8(ZPktBuf *self, gint8 *res) { return z_pktbuf_get_u8(self, (guint8*)res); } static inline gboolean z_pktbuf_get_c8(ZPktBuf *self, gchar *res) { return z_pktbuf_get_u8(self, (guint8*)res); } static inline gboolean z_pktbuf_get_s16(ZPktBuf *self, gint e, gint16 *res) { return z_pktbuf_get_u16(self, e, (guint16*)res); } static inline gboolean z_pktbuf_get_s32(ZPktBuf *self, gint e, gint32 *res) { return z_pktbuf_get_u32(self, e, (guint32*)res); } static inline gboolean z_pktbuf_get_s64(ZPktBuf *self, gint e, gint64 *res) { return z_pktbuf_get_u64(self, e, (guint64*)res); } static inline gboolean z_pktbuf_put_s8(ZPktBuf *self, gint8 d) { return z_pktbuf_put_u8(self, (guint8)d); } static inline gboolean z_pktbuf_put_c8(ZPktBuf *self, gchar d) { return z_pktbuf_put_u8(self, (guint8)d); } static inline gboolean z_pktbuf_put_s16(ZPktBuf *self, gint e, gint16 d) { return z_pktbuf_put_u16(self, e, (guint16)d); } static inline gboolean z_pktbuf_put_s32(ZPktBuf *self, gint e, gint32 d) { return z_pktbuf_put_u32(self, e, (guint32)d); } static inline gboolean z_pktbuf_put_s64(ZPktBuf *self, gint e, gint64 d) { return z_pktbuf_put_u64(self, e, (guint64)d); } static inline gboolean z_pktbuf_get_s16_le(ZPktBuf *self, gint16 *res) { return z_pktbuf_get_s16(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_get_s64_le(ZPktBuf *self, gint64 *res) { return z_pktbuf_get_s64(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_get_s32_le(ZPktBuf *self, gint32 *res) { return z_pktbuf_get_s32(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_put_s16_le(ZPktBuf *self, gint16 res) { return z_pktbuf_put_s16(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_put_s32_le(ZPktBuf *self, gint32 res) { return z_pktbuf_put_s32(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_put_s64_le(ZPktBuf *self, gint64 res) { return z_pktbuf_put_s64(self, G_LITTLE_ENDIAN, res); } static inline gboolean z_pktbuf_get_s16_be(ZPktBuf *self, gint16 *res) { return z_pktbuf_get_s16(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_get_s32_be(ZPktBuf *self, gint32 *res) { return z_pktbuf_get_s32(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_get_s64_be(ZPktBuf *self, gint64 *res) { return z_pktbuf_get_s64(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_put_s16_be(ZPktBuf *self, gint16 res) { return z_pktbuf_put_s16(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_put_s32_be(ZPktBuf *self, gint32 res) { return z_pktbuf_put_s32(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_put_s64_be(ZPktBuf *self, gint64 res) { return z_pktbuf_put_s64(self, G_BIG_ENDIAN, res); } static inline gboolean z_pktbuf_get_s8s(ZPktBuf *self, gsize n, gint8 *res) { return z_pktbuf_get_u8s(self, n, (guint8*)res); } static inline gboolean z_pktbuf_get_c8s(ZPktBuf *self, gsize n, gchar *res) { return z_pktbuf_get_u8s(self, n, (guint8*)res); } static inline gboolean z_pktbuf_get_s16s(ZPktBuf *self, gint e, gsize n, gint16 *res) { return z_pktbuf_get_u16s(self, e, n, (guint16*)res); } static inline gboolean z_pktbuf_get_s32s(ZPktBuf *self, gint e, gsize n, gint32 *res) { return z_pktbuf_get_u32s(self, e, n, (guint32*)res); } static inline gboolean z_pktbuf_get_s64s(ZPktBuf *self, gint e, gsize n, gint64 *res) { return z_pktbuf_get_u64s(self, e, n, (guint64*)res); } static inline gboolean z_pktbuf_put_s8s(ZPktBuf *self, gsize n, const gint8 *d) { return z_pktbuf_put_u8s(self, n, (const guint8*)d); } static inline gboolean z_pktbuf_put_c8s(ZPktBuf *self, gsize n, const gchar *d) { return z_pktbuf_put_u8s(self, n, (const guint8*)d); } static inline gboolean z_pktbuf_put_s16s(ZPktBuf *self, gint e, gsize n, const gint16 *d) { return z_pktbuf_put_u16s(self, e, n, (const guint16*)d); } static inline gboolean z_pktbuf_put_s32s(ZPktBuf *self, gint e, gsize n, const gint32 *d) { return z_pktbuf_put_u32s(self, e, n, (const guint32*)d); } static inline gboolean z_pktbuf_put_s64s(ZPktBuf *self, gint e, gsize n, const gint64 *d) { return z_pktbuf_put_u64s(self, e, n, (const guint64*)d); } gboolean z_pktbuf_put_string(ZPktBuf *self, const gchar *str); ZPktBuf* z_pktbuf_split(ZPktBuf *self, gsize at); ZPktBuf* z_pktbuf_append_pktbuf(ZPktBuf *self, ZPktBuf *other); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/poll.h000066400000000000000000000022261224546767600166240ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: poll.h,v 1.7 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_POLL_H_INCLUDED #define ZORP_POLL_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif /** * ZPoll interface encapsulates a poll() loop. **/ typedef struct _ZPoll ZPoll; ZPoll *z_poll_new(void); void z_poll_ref(ZPoll *); void z_poll_unref(ZPoll *); void z_poll_wakeup(ZPoll *s); void z_poll_add_stream(ZPoll *s, struct _ZStream *channel); void z_poll_remove_stream(ZPoll *s, ZStream *stream); #define z_poll_iter(s) z_poll_iter_timeout(s, -1) guint z_poll_iter_timeout(ZPoll *s, gint timeout); gboolean z_poll_is_running(ZPoll *s); void z_poll_quit(ZPoll *s); GMainContext *z_poll_get_context(ZPoll *s); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/process.h000066400000000000000000000034461224546767600173410ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: process.h,v 1.4 2004/01/09 10:44:31 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_PROCESS_H_INCLUDED #define ZORP_PROCESS_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #ifndef G_OS_WIN32 #include typedef enum { Z_PM_FOREGROUND, Z_PM_BACKGROUND, Z_PM_SAFE_BACKGROUND, } ZProcessMode; void z_process_message(const gchar *fmt, ...); gboolean z_resolve_user(const gchar *user, uid_t *gid); gboolean z_resolve_group(const gchar *group, gid_t *gid); void z_process_set_mode(ZProcessMode mode); void z_process_set_name(const gchar *name); void z_process_set_user(const gchar *user); void z_process_set_group(const gchar *group); void z_process_set_chroot(const gchar *chroot); void z_process_set_pidfile(const gchar *pidfile); void z_process_set_pidfile_dir(const gchar *pidfile_dir); void z_process_set_working_dir(const gchar *cwd); void z_process_set_caps(const gchar *caps); void z_process_set_argv_space(gint argc, gchar **argv); void z_process_set_use_fdlimit(gboolean use); void z_process_set_check(gint check_period, gboolean (*check_fn)(void)); void z_process_set_check_enable(gboolean new_state); gboolean z_process_get_check_enable(void); void z_process_start(void); void z_process_startup_failed(guint ret_num, gboolean may_exit); void z_process_startup_ok(void); void z_process_finish(void); void z_process_finish_prepare(void); #endif #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/random.h000066400000000000000000000020711224546767600171340ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: zorplib.h,v 1.10 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORPLIB_RANDOM_H_INCLUDED #define ZORPLIB_RANDOM_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif /** * Strength of random number generation algorithm. **/ typedef enum { Z_RANDOM_STRONG=0, Z_RANDOM_BASIC, Z_RANDOM_WEAK, Z_RANDOM_NUM_STRENGTHS } ZRandomStrength; gboolean z_random_sequence_get(ZRandomStrength strength, guchar *target, gsize target_len); gboolean z_random_sequence_get_bounded(ZRandomStrength strength, guchar *target, gsize target_len, guchar min, guchar max); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/registry.h000066400000000000000000000026541224546767600175330ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: registry.h,v 1.10 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_REGISTRY_H_INCLUDED #define ZORP_REGISTRY_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #define MAX_PROXY_NAME 32 #define ZR_NONE 0 #define ZR_PROXY 1 #define ZR_PYPROXY 2 /* deprecated #define ZR_DPROXY 3 */ #define ZR_CONNTRACK 4 #define ZR_OTHER 5 #define ZR_MODULE 6 #define MAX_REGISTRY_TYPE 16 /** * Specifies the type of the function passed to z_registry_foreach(). * It is called for each entry, with the name, type and the value stored, * and the user_data passed to z_registry_foreach. **/ typedef void (*ZRFunc)(const gchar *name, gint type, gpointer value, gpointer user_data); void z_registry_init(void); void z_registry_destroy(void); void z_registry_add(const gchar *name, gint type, gpointer value); gpointer z_registry_get(const gchar *name, gint *type); guint z_registry_has_key(const gchar *name); void z_registry_foreach(gint type, ZRFunc func, gpointer user_data); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/sockaddr.h000066400000000000000000000146531224546767600174570ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: sockaddr.h,v 1.19 2004/02/17 16:08:04 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_SOCKADDR_H_INCLUDED #define ZORP_SOCKADDR_H_INCLUDED #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #ifdef G_OS_WIN32 # include # include #else # include # include # include # include #endif #ifdef __cplusplus extern "C" { #endif #define MAX_SOCKADDR_STRING 128 /* sockaddr public interface */ #define ZSA_LOCAL 0x0001 /**< within host */ typedef struct _ZSockAddrFuncs ZSockAddrFuncs; /** * A class that encapsulates an (IPv4, IPv6 or Unix domain socket) address. * * Internally a struct sockaddr (from libc) is used. **/ typedef struct _ZSockAddr { ZRefCount refcnt; guint32 flags; ZSockAddrFuncs *sa_funcs; int salen; struct sockaddr sa; } ZSockAddr; /** * ZSockAddr virtual method table type. **/ struct _ZSockAddrFuncs { GIOStatus (*sa_bind_prepare) (int sock, ZSockAddr *self, guint32 sock_flags); GIOStatus (*sa_bind) (int sock, ZSockAddr *self, guint32 sock_flags); ZSockAddr *(*sa_clone) (ZSockAddr *self, gboolean wildcard_clone); gchar *(*sa_format) (ZSockAddr *self, /* format to text form */ gchar *text, gulong n); void (*freefn) (ZSockAddr *self); gboolean (*sa_equal) (ZSockAddr *self, ZSockAddr *other); }; /* * Map an address family to the related protocol family, currently it is * a no-op as values for address and protocol families currently match, * at least on Linux. * * @param[in] af address family (one of AF_* constants) */ static inline gint z_map_pf(gint af) { return af; } /* generic ZSockAddr */ gchar *z_sockaddr_format(ZSockAddr *self, gchar *text, gulong n); gboolean z_sockaddr_equal(ZSockAddr *self, ZSockAddr *b); ZSockAddr *z_sockaddr_ref(ZSockAddr *self); void z_sockaddr_unref(ZSockAddr *self); ZSockAddr *z_sockaddr_new(struct sockaddr *sa, gsize salen); static inline const struct sockaddr * z_sockaddr_get_sa(ZSockAddr *self) { return &self->sa; } /* AF_INET sockaddr */ gboolean z_sockaddr_inet_check(ZSockAddr *s); static inline const struct sockaddr_in * z_sockaddr_inet_get_sa(ZSockAddr *s) { g_assert(z_sockaddr_inet_check(s)); return (struct sockaddr_in *) z_sockaddr_get_sa(s); } gboolean z_sockaddr_inet6_check(ZSockAddr *s); static inline const struct sockaddr_in6 * z_sockaddr_inet6_get_sa(ZSockAddr *s) { g_assert(z_sockaddr_inet6_check(s)); return (struct sockaddr_in6 *) z_sockaddr_get_sa(s); } /** * This ZSockAddrInet specific function returns the address part of the * address. * * @param[in] s ZSockAddrInet instance **/ static inline struct in_addr z_sockaddr_inet_get_address(ZSockAddr *s) { g_assert(z_sockaddr_inet_check(s)); return z_sockaddr_inet_get_sa(s)->sin_addr; } /** * This ZSockAddrInet6 specific function returns the address part of the * address. * * @param[in] s ZSockAddrInet6 instance **/ static inline struct in6_addr z_sockaddr_inet6_get_address(ZSockAddr *s) { g_assert(z_sockaddr_inet6_check(s)); return z_sockaddr_inet6_get_sa(s)->sin6_addr; } /** * This ZSockAddrInet specific function sets the address part of the * address. * * @param[in] s ZSockAddrInet instance * @param[in] addr new address * **/ static inline void z_sockaddr_inet_set_address(ZSockAddr *s, struct in_addr addr) { g_assert(z_sockaddr_inet_check(s)); ((struct sockaddr_in *) &s->sa)->sin_addr = addr; } /** * This ZSockAddrInet specific function returns the port part of the * address. * * @param[in] s ZSockAddrInet instance * * @returns the port in host byte order **/ static inline guint16 z_sockaddr_inet_get_port(ZSockAddr *s) { g_assert(z_sockaddr_inet_check(s)); return ntohs(z_sockaddr_inet_get_sa(s)->sin_port); } /** * This ZSockAddrInet specific function sets the port part of the * address. * * @param[in] s ZSockAddrInet instance * @param[in] port new port in host byte order **/ static inline void z_sockaddr_inet_set_port(ZSockAddr *s, guint16 port) { g_assert(z_sockaddr_inet_check(s)); ((struct sockaddr_in *) &s->sa)->sin_port = htons(port); } /** * This ZSockAddrInet6 specific function returns the port part of the * address. * * @param[in] s ZSockAddrInet6 instance * * @returns the port in host byte order **/ static inline guint16 z_sockaddr_inet6_get_port(ZSockAddr *s) { g_assert(z_sockaddr_inet6_check(s)); return ntohs(z_sockaddr_inet6_get_sa(s)->sin6_port); } /** * This ZSockAddrInet6 specific function sets the port part of the * address. * * @param[in] s ZSockAddrInet6 instance * @param[in] port new port in host byte order **/ static inline void z_sockaddr_inet6_set_port(ZSockAddr *s, guint16 port) { g_assert(z_sockaddr_inet6_check(s)); ((struct sockaddr_in6 *) &s->sa)->sin6_port = htons(port); } ZSockAddr *z_sockaddr_inet_new(const gchar *ip, guint16 port); ZSockAddr *z_sockaddr_inet_new2(struct sockaddr_in *sinaddr); ZSockAddr *z_sockaddr_inet_new_hostname(const gchar *hostname, guint16 port); ZSockAddr *z_sockaddr_inet_range_new(const gchar *ip, guint16 min_port, guint16 max_port); ZSockAddr *z_sockaddr_inet_range_new_inaddr(struct in_addr addr, guint16 min_port, guint16 max_port); /* AF_INET6 */ ZSockAddr *z_sockaddr_inet6_new(gchar *ip, guint16 port); ZSockAddr *z_sockaddr_inet6_new2(struct sockaddr_in6 *sin6); #ifndef G_OS_WIN32 gboolean z_sockaddr_unix_check(ZSockAddr *s); static inline const gchar * z_sockaddr_unix_get_path(ZSockAddr *s) { z_sockaddr_unix_check(s); return ((struct sockaddr_un *) &s->sa)->sun_path; } ZSockAddr *z_sockaddr_unix_new(const gchar *name); ZSockAddr *z_sockaddr_unix_new2(struct sockaddr_un *s_un, int sunlen); #endif static inline ZSockAddr * z_sockaddr_clone(ZSockAddr *addr, gboolean wildcard_clone) { return addr->sa_funcs->sa_clone(addr, wildcard_clone); } gchar *z_inet_ntoa(gchar *buf, size_t bufsize, struct in_addr a); gboolean z_inet_aton(const gchar *buf, struct in_addr *a); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/socket.h000066400000000000000000000101261224546767600171440ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: socket.h,v 1.9 2003/11/26 12:01:22 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_SOCKET_H_INCLUDED #define ZORP_SOCKET_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif /** bind to the next unused port in the same group */ #define ZSF_LOOSE_BIND 0x0001 #define ZSF_ACCEPT_ONE 0x0002 #define ZSF_MARK_TPROXY 0x0004 #define ZSF_TRANSPARENT 0x0008 /** bind to a port in the same group chosen at (truly) random */ #define ZSF_RANDOM_BIND 0x0010 static inline const gchar * z_socket_type_to_str(gint socket_type) { return socket_type == SOCK_STREAM ? "stream" : socket_type == SOCK_DGRAM ? "dgram" : "unknown"; } /** * Type for table of socket-related functions. **/ typedef struct _ZSocketFuncs { gint (*bind)(int fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags); gint (*accept)(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags); gint (*connect)(int fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags); gint (*listen)(int fd, gint backlog, guint32 sock_flags); gint (*getsockname)(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags); gint (*getpeername)(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags); gint (*getdestname)(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags); } ZSocketFuncs; gint z_do_ll_bind(int fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags); gint z_do_ll_accept(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags); gint z_do_ll_connect(int fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags); gint z_do_ll_listen(int fd, gint backlog, guint32 sock_flags); gint z_do_ll_getsockname(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags); gint z_do_ll_getpeername(int fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags); extern ZSocketFuncs *socket_funcs; static inline gint z_ll_bind(gint fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags) { return socket_funcs->bind(fd, sa, salen, sock_flags); } static inline gint z_ll_accept(gint fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags) { return socket_funcs->accept(fd, sa, salen, sock_flags); } static inline gint z_ll_connect(gint fd, struct sockaddr *sa, socklen_t salen, guint32 sock_flags) { return socket_funcs->connect(fd, sa, salen, sock_flags); } static inline gint z_ll_listen(gint fd, gint backlog, guint32 sock_flags) { return socket_funcs->listen(fd, backlog, sock_flags); } static inline gint z_ll_getsockname(gint fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags) { return socket_funcs->getsockname(fd, sa, salen, sock_flags); } static inline gint z_ll_getpeername(gint fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags) { return socket_funcs->getpeername(fd, sa, salen, sock_flags); } static inline gint z_ll_getdestname(gint fd, struct sockaddr *sa, socklen_t *salen, guint32 sock_flags) { return socket_funcs->getdestname(fd, sa, salen, sock_flags); } GIOStatus z_bind(gint fd, ZSockAddr *addr, guint32 sock_flags); GIOStatus z_bind2(gint fd, ZSockAddr *addr, guint32 sock_flags); GIOStatus z_accept(gint fd, gint *newfd, ZSockAddr **addr, guint32 sock_flags); GIOStatus z_connect(gint fd, ZSockAddr *remote, guint32 sock_flags); GIOStatus z_disconnect(int fd, guint32 sock_flags); GIOStatus z_listen(gint fd, gint backlog, guint32 sock_flags); GIOStatus z_getsockname(gint fd, ZSockAddr **local_addr, guint32 sock_flags); GIOStatus z_getpeername(gint fd, ZSockAddr **peer_addr, guint32 sock_flags); GIOStatus z_getdestname(gint fd, ZSockAddr **dest_addr, guint32 sock_flags); gboolean z_socket_init(void); void z_socket_done(void); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/socketsource.h000066400000000000000000000034471224546767600203750ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: socketsource.h,v 1.5 2003/05/20 13:47:50 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_SOCKET_SOURCE_H_INCLUDED #define ZORP_SOCKET_SOURCE_H_INCLUDED #include #include #include #ifdef G_OS_WIN32 # include # define Z_SOCKEVENT_READ FD_READ # define Z_SOCKEVENT_WRITE FD_WRITE # define Z_SOCKEVENT_PRI FD_PRI # define Z_SOCKEVENT_ACCEPT FD_ACCEPT # define Z_SOCKEVENT_CONNECT FD_CONNECT # define Z_SOCKEVENT_HUP FD_CLOSE #else # define Z_SOCKEVENT_READ G_IO_IN # define Z_SOCKEVENT_WRITE G_IO_OUT # define Z_SOCKEVENT_PRI G_IO_PRI # define Z_SOCKEVENT_ACCEPT G_IO_IN # define Z_SOCKEVENT_CONNECT G_IO_OUT # define Z_SOCKEVENT_HUP G_IO_HUP #endif #ifdef __cplusplus extern "C" { #endif /** * Event source class for sockets. **/ typedef struct _ZSocketSource { GSource super; GIOCondition cond; GPollFD poll; gint timeout_time; gboolean suspended; gboolean timed_out; #ifdef G_OS_WIN32 SOCKET fd; gboolean acceptevent; #endif } ZSocketSource; static inline gboolean z_socket_source_is_suspended(GSource *s) { return ((ZSocketSource *) s)->suspended; } typedef gboolean (*ZSocketSourceFunc)(gboolean timed_out, gpointer data); GSource *z_socket_source_new(gint fd, GIOCondition cond, gint timeout); void z_socket_source_suspend(GSource *); void z_socket_source_resume(GSource *); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/source.h000066400000000000000000000021031224546767600171500ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: source.h,v 1.23 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_SOURCE_H_INCLUDED #define ZORP_SOURCE_H_INCLUDED #include #include #include #ifdef __cplusplus extern "C" { #endif GSource *z_threshold_source_new(guint idle_threshold, guint busy_threshold); void z_threshold_source_set_threshold(GSource *source, guint idle_threshold, guint busy_threshold); void z_timeout_source_set_timeout(GSource *s, gulong new_timeout); void z_timeout_source_set_time(GSource *source, GTimeVal *nexttime); GSource *z_timeout_source_new(gulong initial_timeout); void z_timeout_source_disable(GSource *source); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/ssl.h000066400000000000000000000045641224546767600164660ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: ssl.h,v 1.10 2004/01/20 16:58:54 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_SSL_H_INCLUDED #define ZORP_SSL_H_INCLUDED #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * Class to encapsulate the data for an SSL session. **/ typedef struct _ZSSLSession { guint ref_cnt; SSL *ssl; const gchar *session_id; gint verify_type; gint verify_depth; X509_STORE *crl_store; } ZSSLSession; #define Z_SSL_MODE_CLIENT 0 #define Z_SSL_MODE_SERVER 1 #define Z_SSL_VERIFY_NONE 0 #define Z_SSL_VERIFY_OPTIONAL 1 #define Z_SSL_VERIFY_REQUIRED_UNTRUSTED 2 #define Z_SSL_VERIFY_REQUIRED_TRUSTED 3 void z_ssl_init(void); void z_ssl_destroy(void); #ifndef G_OS_WIN32 #if ZORPLIB_ENABLE_SSL_ENGINE extern gchar *crypto_engine; #endif ZSSLSession * z_ssl_session_new(const char *session_id, int mode, gchar *key_file, gchar *cert_file, gchar *ca_dir, gchar *crl_dir, int verify_depth, int verify_type); ZSSLSession * z_ssl_session_new_inline(const char *session_id, int mode, GString *key_pem, GString *cert_pem, gchar *ca_dir, gchar *crl_dir, int verify_depth, int verify_type); #else // G_OS_WIN32 ZSSLSession * z_ssl_session_new(const char *session_id, int mode, X509_STORE *store, int verify_depth, int verify_type); #endif // G_OS_WIN32 ZSSLSession *z_ssl_session_new_ssl(SSL *ssl); ZSSLSession *z_ssl_session_ref(ZSSLSession *self); void z_ssl_session_unref(ZSSLSession *self); gchar *z_ssl_get_error_str(gchar *buf, int buflen); BIO *z_ssl_bio_new(ZStream *stream); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/stackdump.h000066400000000000000000000022671224546767600176560ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: zorplib.h,v 1.10 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_STACKDUMP_H_INCLUDED #define ZORP_STACKDUMP_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #if ZORPLIB_ENABLE_STACKDUMP typedef struct sigcontext ZSignalContext; #else typedef void ZSignalContext; #endif /** * Return the current signal context used for stack dumping. * The variable passed as parameter must be declared in a signal handler. **/ #define z_stackdump_get_context(p) \ (ZSignalContext *) (((char *) &p) + 16) void z_stackdump_log(ZSignalContext *context); #ifdef G_OS_WIN32 void z_enable_write_dump_file(); #ifndef _SYSCRT int z_set_unhandled_exception_filter(void); #else void z_set_unhandled_exception_filter(void); #endif #endif #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/stream.h000066400000000000000000000422301224546767600171500ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: stream.h,v 1.44 2004/02/09 11:25:49 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_STREAM_H_INCLUDED #define ZORP_STREAM_H_INCLUDED #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #ifdef G_OS_WIN32 #define SHUT_RDWR SD_BOTH #define SHUT_WR SD_SEND #define SHUT_RD SD_RECEIVE #endif #define Z_STREAM_MAX_NAME 128 /* Stream types */ /** * Stream control messages are the same as ioctl() is for UNIX fds, they * define a generic interface for various stream implementation specific * operations. * * 0. byte message * 1. byte stream type * 3. byte undefined * 4. byte stream flags **/ #define ZST_CTRL_MSG(x) ((x)&0xFFFF) #define ZST_CTRL_MSG_FLAGS(x) ((x) & 0xFF000000) /* stream flags */ enum { ZST_CTRL_MSG_FORWARD = 0x80000000, }; /* message */ enum { ZST_CTRL_GET_FD = 0x01, ZST_CTRL_SET_COND_READ = 0x02, ZST_CTRL_SET_COND_WRITE = 0x03, ZST_CTRL_SET_COND_PRI = 0x04, ZST_CTRL_SET_CALLBACK_READ = 0x06, ZST_CTRL_SET_CALLBACK_WRITE = 0x07, ZST_CTRL_SET_CALLBACK_PRI = 0x08, ZST_CTRL_SET_TIMEOUT_BLOCK = 0x0A, ZST_CTRL_GET_COND_READ = 0x0C, ZST_CTRL_GET_COND_WRITE = 0x0D, ZST_CTRL_GET_COND_PRI = 0x0E, ZST_CTRL_GET_CALLBACK_READ = 0x10, ZST_CTRL_GET_CALLBACK_WRITE = 0x11, ZST_CTRL_GET_CALLBACK_PRI = 0x12, ZST_CTRL_SET_NONBLOCK = 0x14, ZST_CTRL_GET_NONBLOCK = 0x15, ZST_CTRL_GET_BROKEN = 0x16, ZST_CTRL_SET_CLOSEONEXEC = 0x17, ZST_CTRL_GET_KEEPALIVE = 0x18, ZST_CTRL_SET_KEEPALIVE = 0x19, ZST_CTRL_GET_BUFFERED_BYTES = 0x20, }; /* stream type */ enum { ZST_CTRL_LINE_OFS = ('L' << 8), ZST_CTRL_SSL_OFS = ('S' << 8), }; typedef struct _ZStream ZStream; typedef struct _ZStreamContext ZStreamContext; typedef struct _ZStreamSource ZStreamSource; typedef gboolean (*ZStreamCallback)(struct _ZStream *stream, GIOCondition cond, gpointer user_data); GSource *z_stream_source_new(ZStream *stream); /** * Stream context describing I/O callbacks to make it easy to change how a * stream is being handled by different parts of Zorp (ie.\ proxy and associated * transfer code) **/ struct _ZStreamContext { gboolean restored; gboolean want_read; /**< do we want read callbacks? */ gpointer user_data_read; /**< opaque pointer, can be used by read callback */ GDestroyNotify user_data_read_notify; ZStreamCallback read_cb; /**< pointer to read callback */ gboolean want_pri; /**< do we want urgent data callbacks? */ gpointer user_data_pri; /**< opaque pointer, can be used by pri callback */ GDestroyNotify user_data_pri_notify; ZStreamCallback pri_cb; /**< pointer to urgent data callback */ gboolean want_write; /**< do we want write callbacks */ gpointer user_data_write; /**< opaque pointer, can be used by write callback */ GDestroyNotify user_data_write_notify; ZStreamCallback write_cb; /**< pointer to write callback */ gint timeout; gboolean nonblocking; gpointer stream_extra; }; void z_stream_context_destroy(ZStreamContext *self); /** * ZStream virtual method table type. **/ typedef struct _ZStreamFuncs { ZObjectFuncs super; GIOStatus (*read)(ZStream *stream, void *buf, gsize count, gsize *bytes_read, GError **err); GIOStatus (*write)(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **err); GIOStatus (*read_pri)(ZStream *stream, void *buf, gsize count, gsize *bytes_read, GError **err); GIOStatus (*write_pri)(ZStream *stream, const void *buf, gsize count, gsize *bytes_written, GError **err); GIOStatus (*shutdown)(ZStream *stream, int i, GError **err); GIOStatus (*close) (ZStream *stream, GError **err); gboolean (*ctrl) (ZStream *stream, guint function, gpointer value, guint vlen); void (*attach_source)(ZStream *stream, GMainContext *context); void (*detach_source)(ZStream *stream); gboolean (*watch_prepare)(ZStream *s, GSource *src, gint *timeout); gboolean (*watch_check)(ZStream *s, GSource *src); gboolean (*watch_dispatch)(ZStream *s, GSource *src); void (*watch_finalize)(ZStream *s, GSource *source); gsize (*extra_get_size)(ZStream *s); gsize (*extra_save)(ZStream *s, gpointer context); gsize (*extra_restore)(ZStream *s, gpointer context); void (*set_child)(ZStream *s, ZStream *new_child); gboolean (*unget_packet)(ZStream *s, ZPktBuf *packet, GError **error); } ZStreamFuncs; LIBZORPLL_EXTERN ZClass ZStream__class; /** * ZStream encapsulates a generic I/O stream. It contains some attributes * and callbacks which are used by ZPoll. Description of some of the notions * used in ZStream. * * Umbrella: * Being an umbrella for read or write direction means that all streams * below are completely hidden from the user of the stream. For example: * *
 *    (top)      ZStreamBuf <-> ZStreamLine <-> ZStreamSsl <-> ZStreamLine <-> ZStreamFd
 *    (umbrella)    (w)              (r)           (rw)             (r)           (rw)
 * 
* * In the example above the umbrella in write direction is the on-top * ZStreamBuf while the umbrella in read direction is ZStreamLine. If an * operation that applies to ZStreamLine instance is invoked on the top of * the stream then the operation will succeed. * * On the other hand neither read nor write operations will succeed on * ZStreamSsl as it is already hidden from the top in both read and write * directions. * * Umbrellas are also used to determine whether the core routines will log * the I/O dump and to implement z_stream_unget as it always stores ungot * data at the read-side top. * **/ struct _ZStream { ZObject super; const gchar *name; /* const */ /** current umbrella state in the current stack */ gint umbrella_state; /** umbrella flags requested by the stream */ gint umbrella_flags; GList *ungot_bufs; gint timeout; /* stream structure pointers */ ZRefCount struct_ref; /**< stream structure pointers */ ZStream *parent; /**< stream structure pointers */ ZStream *child; /**< stream structure pointers */ gint stack_depth; /**< stream structure pointers */ GSource *source; /**< stream structure pointers */ time_t time_open; guint64 bytes_recvd, bytes_sent; /**< bytes received/sent counters for accounting info logging */ gpointer user_data_read; /**< opaque pointer, can be used by read callback */ GDestroyNotify user_data_read_notify; ZStreamCallback read_cb; /**< pointer to read callback */ gboolean want_read; /**< do we want read callbacks? */ gboolean want_pri; /**< do we want urgent data callbacks? */ gpointer user_data_pri; /**< opaque pointer, can be used by pri callback */ GDestroyNotify user_data_pri_notify; ZStreamCallback pri_cb; /**< pointer to urgent data callback */ gpointer user_data_write; /**< opaque pointer, can be used by write callback */ GDestroyNotify user_data_write_notify; ZStreamCallback write_cb; /**< pointer to write callback */ gboolean want_write; /**< do we want write callbacks */ }; ZStream *z_stream_new(ZClass *class_, const gchar *name, gint umbrella_flags); gboolean z_stream_save_context(ZStream *self, ZStreamContext *context); gboolean z_stream_restore_context(ZStream *self, ZStreamContext *context); GIOStatus z_stream_read(ZStream *self, void *buf, gsize count, gsize *bytes_read, GError **err); GIOStatus z_stream_write(ZStream *self, const void *buf, gsize count, gsize *bytes_written, GError **err); gboolean z_stream_set_cond(ZStream *s, guint type, gboolean value); gboolean z_stream_get_cond(ZStream *s, guint type, gboolean *value); gboolean z_stream_set_callback(ZStream *s, guint type, ZStreamCallback callback, gpointer user_data, GDestroyNotify notify); ZStream *z_stream_push(ZStream *self, ZStream *new_top); ZStream *z_stream_pop(ZStream *self); gboolean z_stream_unget(ZStream *self, const void *buf, gsize count, GError **error); void z_stream_destroy(ZStream *self); /* virtual methods for static references like calling the superclass's function in derived classes */ gboolean z_stream_ctrl_method(ZStream *s, guint function, gpointer value, guint vlen); void z_stream_free_method(ZObject *s); /** * Reference a ZStream instance. * * @param[in] self ZStream instance * * Increments the reference count of self and returns a reference to it. * * @returns self **/ static inline ZStream * z_stream_ref(ZStream *self) { return (ZStream *) z_object_ref(&self->super); } /** * Unreference a ZStream instance. * * @param[in] self ZStream instance * * Decrements the reference count of self. **/ static inline void z_stream_unref(ZStream *self) { z_object_unref(&self->super); } /** * Set the name of a stream (and its child, if any) * * @param[in] self ZStream instance * @param[in] new_name new name to set, it will be g_strdup-ed **/ static inline void z_stream_set_name(ZStream *self, const gchar *new_name) { g_return_if_fail(new_name); if (self->name) g_free((gpointer) self->name); if (new_name) self->name = g_strdup(new_name); if (self->child) z_stream_set_name(self->child, new_name); } static inline void z_stream_data_dump(ZStream *self, gint direction, const void *data, gsize data_len) { if (self->umbrella_state & direction) { /*LOG This message reports the number of bytes read from the given fd. */ if (direction == G_IO_IN) z_log(self->name, CORE_DUMP, 7, "Reading stream; stream='%s', count='%zd'", self->super.isa->name, data_len); else z_log(self->name, CORE_DUMP, 7, "Writing stream; stream='%s', count='%zd'", self->super.isa->name, data_len); z_log_data_dump(self->name, CORE_DUMP, 9, data, data_len); } } /* virtual functions */ /** * Call ctrl virtual method. * * @see Default definition: z_stream_ctrl_method() **/ static inline gboolean z_stream_ctrl(ZStream *self, guint function, gpointer value, guint vlen) { return Z_FUNCS(self, ZStream)->ctrl(self, function, value, vlen); } /** * Call read_pri virtual method. * * Method is NULL by default. **/ static inline GIOStatus z_stream_read_pri(ZStream *self, void *buf, gsize count, gsize *bytes_read, GError **err) { return Z_FUNCS(self, ZStream)->read_pri(self, buf, count, bytes_read, err); } /** * Call write_pri virtual method. * * Method is NULL by default. **/ static inline GIOStatus z_stream_write_pri(ZStream *self, const void *buf, gsize count, gsize *bytes_written, GError **err) { return Z_FUNCS(self, ZStream)->write_pri(self, buf, count, bytes_written, err); } /** * Call shutdown(2) for the ZStream if applicable. * * @param[in] stream ZStreamFD instance * @param[in] how HOW argument to shutdown * @param[out] err error value * * The shutdown method will be called on the stream if it has one. * That method will call shutdown(2) on the fd. * * The action to perform is specified by i as follows: * - i == 0: Stop receiving data. * - i == 1: Stop trying to transmit data. * - i == 2: Stop both reception and transmission. * * @returns GIOStatus value **/ static inline GIOStatus z_stream_shutdown(ZStream *self, int how, GError **err) { if (Z_FUNCS(self, ZStream)->shutdown) return Z_FUNCS(self, ZStream)->shutdown(self, how, err); return G_IO_STATUS_NORMAL; } /** * Call close virtual method. * * @see Default definition: z_stream_close_method() **/ static inline GIOStatus z_stream_close(ZStream *self, GError **err) { return Z_FUNCS(self, ZStream)->close(self, err); } /** * Call attach_source virtual method. * * @see Default definition: z_stream_attach_source_method() **/ static inline void z_stream_attach_source(ZStream *self, GMainContext *context) { Z_FUNCS(self, ZStream)->attach_source(self, context); } /** * Call detach_source virtual method. * * @see Default definition: z_stream_detach_source_method() **/ static inline void z_stream_detach_source(ZStream *self) { Z_FUNCS(self, ZStream)->detach_source(self); } /** * Call watch_prepare virtual method. * * Method is NULL by default. **/ static inline gboolean z_stream_watch_prepare(ZStream *self, GSource *s, gint *timeout) { return Z_FUNCS(self, ZStream)->watch_prepare(self, s, timeout); } /** * Call watch_check virtual method. * * Method is NULL by default. **/ static inline gboolean z_stream_watch_check(ZStream *self, GSource *s) { return Z_FUNCS(self, ZStream)->watch_check(self, s); } /** * Call watch_dispatch virtual method. * * Method is NULL by default. **/ static inline gboolean z_stream_watch_dispatch(ZStream *self, GSource *s) { return Z_FUNCS(self, ZStream)->watch_dispatch(self, s); } /** * Call watch_finalize virtual method. * * Method is NULL by default. **/ static inline void z_stream_watch_finalize(ZStream *self, GSource *s) { if (Z_FUNCS(self, ZStream)->watch_finalize) Z_FUNCS(self, ZStream)->watch_finalize(self, s); } /** * Call extra_get_size virtual method. * * @see Default definition: z_stream_extra_get_size_method() **/ static inline gsize z_stream_extra_get_size(ZStream *s) { return Z_FUNCS(s, ZStream)->extra_get_size(s); } /** * Call extra_save virtual method. * * @see Default definition: z_stream_extra_save_method() **/ static inline gsize z_stream_extra_save(ZStream *s, gpointer context) { return Z_FUNCS(s, ZStream)->extra_save(s, context); } /** * Call extra_restore virtual method. * * @see Default definition: z_stream_extra_restore_method() **/ static inline gsize z_stream_extra_restore(ZStream *s, gpointer context) { return Z_FUNCS(s, ZStream)->extra_restore(s, context); } /** * Call set_child virtual method. * * @see Default definition: z_stream_set_child_method() **/ static inline void z_stream_set_child(ZStream *s, ZStream *new_child) { Z_FUNCS(s, ZStream)->set_child(s, new_child); } /** * Call unget_packet virtual method. * * @see Default definition: z_stream_unget_packet_method() **/ static inline gboolean z_stream_unget_packet(ZStream *s, ZPktBuf *pack, GError **error) { return Z_FUNCS(s, ZStream)->unget_packet(s, pack, error); } /* helper functions */ /** * Get the fd associated with the stream, if any. * * @param[in] s ZStream instance * * @returns -1 if there's no fd or the actual fd if there is. **/ static inline int z_stream_get_fd(ZStream *s) { gint ret = -1; if (!z_stream_ctrl(s, ZST_CTRL_GET_FD, &ret, sizeof(ret))) ret = -1; return ret; } /** * Check if the connection associated with the stream (if any) is broken. * * @param[in] s ZStream instance * * @returns broken state if it could be determined; FALSE otherwise. **/ static inline gboolean z_stream_broken(ZStream *s) { gboolean ret = -1; if (!z_stream_ctrl(s, ZST_CTRL_GET_BROKEN, &ret, sizeof(ret))) ret = FALSE; return ret; } /** * Set timeout of stream. * * @param[in] s ZStream instance * @param[in] timeout new timeout value * * Emits a SET_TIMEOUT_BLOCK control message that propagates down through the * stream stack. * * @returns TRUE if setting the timeout succeeded **/ static inline gboolean z_stream_set_timeout(ZStream *s, gint timeout) { gboolean ret = TRUE; if (!z_stream_ctrl(s, ZST_CTRL_MSG_FORWARD | ZST_CTRL_SET_TIMEOUT_BLOCK, &timeout, sizeof(timeout))) ret = FALSE; return ret; } /** * Set nonblock of stream. * * @param[in] self ZStream instance * @param[in] nonblock new value * * @todo FIXME-DOC: write a better description. also, write a description for the ones below. **/ static inline gboolean z_stream_set_nonblock(ZStream *self, gboolean nonblock) { return z_stream_ctrl(self, ZST_CTRL_SET_NONBLOCK, &nonblock, sizeof(nonblock)); } static inline gboolean z_stream_get_nonblock(ZStream *self) { gboolean nonblock; z_stream_ctrl(self, ZST_CTRL_GET_NONBLOCK, &nonblock, sizeof(nonblock)); return nonblock; } static inline gboolean z_stream_set_closeonexec(ZStream *self, gboolean cloexec) { return z_stream_ctrl(self, ZST_CTRL_SET_CLOSEONEXEC, &cloexec, sizeof(cloexec)); } static inline gint z_stream_get_keepalive(ZStream *self) { gint keepalive; z_stream_ctrl(self, ZST_CTRL_GET_KEEPALIVE, &keepalive, sizeof(keepalive)); return keepalive; } void z_stream_set_keepalive(ZStream *self, gint keepalive); static inline gsize z_stream_get_buffered_bytes(ZStream *self) { gsize bytes = 0; if (z_stream_ctrl(self, ZST_CTRL_GET_BUFFERED_BYTES, &bytes, sizeof(bytes))) return bytes; else return G_MAXSIZE; } ZStream * z_stream_search_stack(ZStream *top, gint direction, ZClass *class_); GIOStatus z_stream_read_chunk(ZStream *self, void *buf, gsize count, gsize *bytes_read, GError **err); GIOStatus z_stream_write_chunk(ZStream *self, const void *buf, gsize count, gsize *bytes_written, GError **err); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/streamblob.h000066400000000000000000000007331224546767600200110ustar00rootroot00000000000000/*************************************************************************** * * COPYRIGHTHERE * * $Id: streamfd.h,v 1.8 2003/05/14 16:40:23 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_STREAMBLOB_H #define ZORP_STREAMBLOB_H 1 #include #include #ifdef __cplusplus extern "C" { #endif ZStream *z_stream_blob_new(ZBlob *blob, gchar *name); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/streambuf.h000066400000000000000000000026601224546767600176500ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streambuf.h,v 1.7 2003/06/04 09:34:06 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_STREAMBUF_H_INCLUDED #define ZORP_STREAMBUF_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif enum { /** * Whether flush is attempted immediately after a write operation. Should * only be used when the flush process and write calls are in the same * thread, as the child stream might not support multiple threads entering * their write method at the same time. Otherwise it is worth using as it * might improve write latency a lot (=no need to wait for a poll() loop * to check for writability) **/ Z_SBF_IMMED_FLUSH=0x0001 }; gboolean z_stream_buf_space_avail(ZStream *s); GIOStatus z_stream_write_buf(ZStream *stream, void *buf, guint buflen, gboolean copy_data, GError **error); GIOStatus z_stream_write_packet(ZStream *s, ZPktBuf *packet, GError **error); ZStream *z_stream_buf_new(ZStream *stream, gsize bufsize_threshold, guint32 flags); void z_stream_buf_flush(ZStream *stream); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/streamfd.h000066400000000000000000000013111224546767600174550ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamfd.h,v 1.8 2003/05/14 16:40:23 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_STREAMFD_H_INCLUDED #define ZORP_STREAMFD_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif ZStream *z_stream_fd_new(gint fd, const gchar *name); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/streamgzip.h000066400000000000000000000032501224546767600200410ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamgzip.h,v 1.2 2003/11/14 15:49:09 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_STREAMGZIP_H_INCLUDED #define ZORP_STREAMGZIP_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif /* gzip flags */ enum { Z_SGZ_SYNC_FLUSH = 0x0001, /**< flush output for every write */ Z_SGZ_GZIP_HEADER = 0x0002, /**< read/write a gzip file header, requires a blocking child */ Z_SGZ_WRITE_EMPTY_HEADER = 0x0004, /**< write the gzip header even if nothing was written */ }; #define GZIP_MAGIC_LEN 4 #define GZIP_MAGIC_1 0x1F #define GZIP_MAGIC_2 0x8B #define GZIP_IS_GZIP_MAGIC(magic_buf) (((magic_buf)[0] == GZIP_MAGIC_1) && ((magic_buf)[1] == GZIP_MAGIC_2) && ((magic_buf)[2] == Z_DEFLATED) && !((magic_buf)[3] & 0xe0)) gboolean z_stream_gzip_fetch_header(ZStream *s, GError **error); void z_stream_gzip_get_header_fields(ZStream *s, time_t *timestamp, gchar **origname, gchar **comment, gint *extra_len, gchar **extra); void z_stream_gzip_set_header_fields(ZStream *s, time_t timestamp, const gchar *origname, const gchar *comment, gint extra_len, const gchar *extra); ZStream *z_stream_gzip_new(ZStream *child, gint flags, guint level, guint buffer_length); #ifdef __cplusplus } #endif #endif /* ZORP_STREAMGZIP_H_INCLUDED */ libzorpll-3.9.4.1/src/zorp/streamline.h000066400000000000000000000065001224546767600200200ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamline.h,v 1.16 2004/07/01 16:53:24 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_READLINE_H_INCLUDED #define ZORP_READLINE_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif #define ZRL_EOL_NL 0x00000001 /**< end-of-line is indicated by nl */ #define ZRL_EOL_CRLF 0x00000002 /**< end-of-line is indicated by crlf pair */ #define ZRL_EOL_NUL 0x00000004 #define ZRL_EOL_FATAL 0x00000008 /**< erroneous eol mark is fatal */ #define ZRL_NUL_NONFATAL 0x00000010 /**< embedded NUL character is not fatal */ #define ZRL_TRUNCATE 0x00000020 /**< truncate if line longer than buffer */ #define ZRL_SPLIT 0x00000040 /**< split line if longer than buffer */ #define ZRL_SINGLE_READ 0x00000080 /**< don't issue several read()s when fetching a line */ #define ZRL_POLL_PARTIAL 0x00000100 /**< poll for any data, not just for complete lines */ #define ZRL_RETURN_EOL 0x00000200 /**< return end-of-line as part of the data */ #define ZRL_PARTIAL_READ ZRL_POLL_PARTIAL #define ZST_LINE_GET_TRUNCATE (0x01) | ZST_CTRL_LINE_OFS #define ZST_LINE_GET_SPLIT (0x02) | ZST_CTRL_LINE_OFS #define ZST_LINE_GET_SINGLE_READ (0x03) | ZST_CTRL_LINE_OFS #define ZST_LINE_GET_POLL_PARTIAL (0x04) | ZST_CTRL_LINE_OFS #define ZST_LINE_GET_NUL_NONFATAL (0x05) | ZST_CTRL_LINE_OFS #define ZST_LINE_GET_RETURN_EOL (0x06) | ZST_CTRL_LINE_OFS #define ZST_LINE_GET_PARTIAL_READ ZST_LINE_GET_POLL_PARTIAL #define ZST_LINE_SET_TRUNCATE (0x11) | ZST_CTRL_LINE_OFS #define ZST_LINE_SET_SPLIT (0x12) | ZST_CTRL_LINE_OFS #define ZST_LINE_SET_SINGLE_READ (0x13) | ZST_CTRL_LINE_OFS #define ZST_LINE_SET_POLL_PARTIAL (0x14) | ZST_CTRL_LINE_OFS #define ZST_LINE_SET_NUL_NONFATAL (0x15) | ZST_CTRL_LINE_OFS #define ZST_LINE_SET_RETURN_EOL (0x16) | ZST_CTRL_LINE_OFS #define ZST_LINE_SET_PARTIAL_READ ZST_LINE_SET_POLL_PARTIAL LIBZORPLL_EXTERN ZClass ZStreamLine__class; GIOStatus z_stream_line_get(ZStream *s, gchar **line, gsize *length, GError **error); GIOStatus z_stream_line_get_copy(ZStream *s, gchar *line, gsize *length, GError **error); void z_stream_line_unget_line(ZStream *stream); gboolean z_stream_line_unget(ZStream *stream, const gchar *unget_line, gsize unget_len); ZStream *z_stream_line_new(ZStream *from, gsize bufsize, guint flags); static inline void z_stream_line_set_poll_partial(ZStream *stream, gboolean enable) { z_stream_ctrl(stream, ZST_LINE_SET_PARTIAL_READ, &enable, sizeof(enable)); } static inline void z_stream_line_set_split(ZStream *stream, gboolean enable) { z_stream_ctrl(stream, ZST_LINE_SET_SPLIT, &enable, sizeof(enable)); } static inline void z_stream_line_set_truncate(ZStream *stream, gboolean enable) { z_stream_ctrl(stream, ZST_LINE_SET_TRUNCATE, &enable, sizeof(enable)); } static inline void z_stream_line_set_nul_nonfatal(ZStream *stream, gboolean enable) { z_stream_ctrl(stream, ZST_LINE_SET_NUL_NONFATAL, &enable, sizeof(enable)); } #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/streamssl.h000066400000000000000000000025501224546767600176730ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: streamssl.h,v 1.4 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_STREAMSSL_H_INCLUDED #define ZORP_STREAMSSL_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #define ZST_CTRL_SSL_SET_SESSION (0x01) | ZST_CTRL_SSL_OFS #define ZST_CTRL_SSL_ADD_HANDSHAKE (0x02) | ZST_CTRL_SSL_OFS ZStream * z_stream_ssl_new(ZStream *stream, ZSSLSession *ssl); static inline void z_stream_ssl_set_session(ZStream *self, ZSSLSession *ssl) { z_stream_ctrl(self, ZST_CTRL_SSL_SET_SESSION, ssl, sizeof(&ssl)); } typedef struct { gpointer handshake; GDestroyNotify destroy_function; } ZStreamSslHandshakeData; static inline void z_stream_ssl_add_handshake(ZStream *self, gpointer handshake, GDestroyNotify destroy) { ZStreamSslHandshakeData data; data.handshake = handshake; data.destroy_function = destroy; z_stream_ctrl(self, ZST_CTRL_SSL_ADD_HANDSHAKE, &data, sizeof(data)); } #ifdef __cplusplus } #endif #endif /* ZORP_GIOSSL_H_INCLUDED */ libzorpll-3.9.4.1/src/zorp/streamtee.h000066400000000000000000000003561224546767600176510ustar00rootroot00000000000000#ifndef ZCV_STREAMTEE_H #define ZCV_STREAMTEE_H #include #ifdef __cplusplus extern "C" { #endif ZStream *z_stream_tee_new(ZStream *child, ZStream *fork, GIOCondition tee_direction); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/thread.h000066400000000000000000000025151224546767600171260ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: thread.h,v 1.8 2003/07/02 14:21:06 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_THREAD_H_INCLUDED #define ZORP_THREAD_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif #define MAX_THREAD_NAME 128 /** * ZThread encapsulates a simple thread, and adds some meta information * like thread name, thread id etc. **/ typedef struct _ZThread { GThread *thread; gint thread_id; gchar name[MAX_THREAD_NAME]; GThreadFunc func; gpointer arg; } ZThread; void z_thread_register_start_callback(GFunc func, gpointer user_data); void z_thread_register_stop_callback(GFunc func, gpointer user_data); gboolean z_thread_new(const gchar *name, GThreadFunc func, gpointer arg); void z_thread_enable_threadpools(gint idle); void z_thread_set_max_threads(gint max); void z_thread_set_max_stack_size(gint stack_size); void z_thread_init(void); void z_thread_destroy(void); ZThread *z_thread_self(void); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/win32_reg.h000066400000000000000000000022051224546767600174520ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: registry.h,v 1.10 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORP_WIN32_REGISTRY_H_INCLUDED #define ZORP_WIN32_REGISTRY_H_INCLUDED #ifdef G_OS_WIN32 #include #include #include #ifdef __cplusplus extern "C" { #endif gboolean z_reg_key_write_dword(HKEY root, gchar *key, gchar *name, DWORD value); gboolean z_reg_key_write_string(HKEY root, gchar *key, gchar *name, gchar *value); gboolean z_reg_key_read_dword(HKEY root, gchar *key, gchar *name, DWORD *value); gboolean z_reg_key_read_string(HKEY root, gchar *key, gchar *name, gchar **value); gboolean z_reg_key_delete(HKEY root, gchar *key, gchar *name); gboolean z_sid_to_text( PSID ps, char *buf, int bufSize ); #ifdef __cplusplus } #endif #endif #endif libzorpll-3.9.4.1/src/zorp/zcp.h000066400000000000000000000034031224546767600164500ustar00rootroot00000000000000/*************************************************************************** * * COPYRIGHTHERE * ***************************************************************************/ #ifndef ZORP_ZCP_H #define ZORP_ZCP_H #include #include #define ZCP_LINE_LENGTH 4096 #ifdef __cplusplus extern "C" { #endif typedef ZHeader ZCPHeader; typedef struct _ZCPCommand { GString *command; ZHeaderSet headers; } ZCPCommand; typedef struct _ZCPContext ZCPContext; static inline GList * z_cp_command_get_all_headers(ZCPCommand *self) { return z_header_set_get_all_headers(&self->headers); } static inline ZCPHeader * z_cp_command_iterate_headers(ZCPCommand *self, const gchar *key, gpointer *opaque) { return z_header_set_iterate(&self->headers, key, opaque); } static inline ZCPHeader * z_cp_command_find_header(ZCPCommand *self, const gchar *key) { return z_cp_command_iterate_headers(self, key, NULL); } static inline gboolean z_cp_command_add_header(ZCPCommand *self, GString *key, GString *value, gboolean multiple) { return z_header_set_add(&self->headers, key, value, multiple); } ZCPCommand *z_cp_command_new(const gchar *cmd); ZCPCommand *z_cp_command_new_accept(gchar *welcome, GSList *groups); ZCPCommand *z_cp_command_new_reject(gchar *reason); void z_cp_command_free(ZCPCommand *self); GIOStatus z_cp_context_read(ZCPContext *self, guint *session_id, ZCPCommand **cmd); GIOStatus z_cp_context_write(ZCPContext *self, guint session_id, ZCPCommand *cmd); ZCPContext *z_cp_context_new(ZStream *stream); void z_cp_context_destroy(ZCPContext *self, gboolean close_stream); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/zobject.h000066400000000000000000000106761224546767600173260ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: zobject.h,v 1.6 2003/10/17 17:38:28 bazsi Exp $ * ***************************************************************************/ #ifndef ZORP_ZOBJECT_H_INCLUDED #define ZORP_ZOBJECT_H_INCLUDED /* this might need to be moved to libzorpll */ #include #include #ifdef __cplusplus extern "C" { #endif typedef struct _ZClass ZClass; typedef struct _ZObject ZObject; /** * struct type to hold ZObject virtual methods. **/ typedef struct _ZObjectFuncs { gint method_count; void (*free_fn)(ZObject *self); } ZObjectFuncs; /** * Base class. * * Not all classes in zorp-lib use it. **/ struct _ZObject { ZRefCount ref_cnt; ZClass *isa; }; /** * The metaclass of the object system. **/ struct _ZClass { ZObject super; gboolean funcs_resolved; /**< indicates whether method inheritance was already performed */ struct _ZClass *super_class; const gchar *name; gsize size; ZObjectFuncs *funcs; }; LIBZORPLL_EXTERN ZClass ZClass__class; LIBZORPLL_EXTERN ZClass ZObject__class; typedef ZClass ZInterface; #define Z_OBJECT_HEADER { Z_REFCOUNT_INIT, NULL } #define Z_CLASS_HEADER Z_OBJECT_HEADER, 0 #define Z_CLASS(class_) (&class_##__class) #define Z_CLASS_DEF(klass_, super_class, class_methods) \ ZClass klass_##__class = \ { \ Z_CLASS_HEADER, \ Z_CLASS(super_class), \ #klass_, \ sizeof(klass_), \ (ZObjectFuncs*) &class_methods, \ } #define Z_CAST(inst, class_) ((class_ *) z_object_check_compatible((ZObject *) inst, Z_CLASS(class_))) #define Z_FUNCS(inst, class_) ((class_##Funcs *) (z_object_check_compatible((ZObject *) inst, Z_CLASS(class_))->isa->funcs)) #define Z_FUNCS_CALL(inst, class_, func_name, ...) Z_FUNCS(inst, class_)->func_name(inst, ## __VA_ARGS__) #define Z_SUPER(inst, class_) ((class_##Funcs *) (z_object_check_compatible((ZObject *) inst, Z_CLASS(class_))->isa->super_class->funcs)) #define Z_FUNCS_COUNT(class_) ((sizeof(class_##Funcs)-sizeof(gint))/sizeof(void (*)(void))) #define Z_NEW(class_) (class_ *) z_object_new(Z_CLASS(class_)) #define Z_NEW_COMPAT(class_, compat) (compat *) z_object_new_compatible(class_, Z_CLASS(compat)) ZObject *z_object_new(ZClass *class_); ZObject *z_object_new_compatible(ZClass *class_, ZClass *compat); gboolean z_object_is_compatible(ZObject *self, ZClass *class_); gboolean z_object_is_subclass(ZClass *class_, ZClass *subclass); gboolean z_object_is_instance(ZObject *self, ZClass *class_); #if ZORPLIB_ENABLE_DEBUG /** * Check if self is compatible with class, e.g.\ whether it's derived from class. * * @param[in] self object * @param[in] class_ class * * Debug version. Asserts that the above assumption is true. * * @returns self **/ static inline ZObject * z_object_check_compatible(ZObject *self, ZClass *class_) { g_assert(!self || z_object_is_compatible(self, class_)); return self; } #else /** * Check if self is compatible with class, e.g.\ whether it's derived from class. * * @param[in] self object * @param class_ class (unused) * * Non-debug version, doesn't really do anything but return self. * * @returns self **/ static inline ZObject * z_object_check_compatible(ZObject *self, ZClass *class_ G_GNUC_UNUSED) { return self; } #endif /* function declaration for virtual functions */ void z_object_free_method(ZObject *s); /** * Increment the reference count of self and return a reference. * * @param[in,out] self ZObject instance * * @returns self **/ static inline ZObject * z_object_ref(ZObject *self) { if (self) z_refcount_inc(&self->ref_cnt); return self; } /** * Decrement the reference count of self and free it if the reference count * goes down to zero. * * @param[in] self ZObject instance **/ static inline void z_object_unref(ZObject *self) { if (self && z_refcount_dec(&self->ref_cnt)) { Z_FUNCS(self, ZObject)->free_fn(self); g_free(self); } } #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/zorplib.h000066400000000000000000000024411224546767600173360ustar00rootroot00000000000000/*************************************************************************** * * This file is covered by a dual licence. You can choose whether you * want to use it according to the terms of the GNU GPL version 2, or * under the terms of Zorp Professional Firewall System EULA located * on the Zorp installation CD. * * $Id: zorplib.h,v 1.10 2003/04/08 13:32:29 sasa Exp $ * ***************************************************************************/ #ifndef ZORPLIB_H_INCLUDED #define ZORPLIB_H_INCLUDED #if 0 # ifdef COMPILING_LIBZORPLL # define LIBZORPLL_EXTERN __declspec(dllexport) # else # define LIBZORPLL_EXTERN __declspec(dllimport) # endif #else # define LIBZORPLL_EXTERN extern #endif #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define CORE_DEBUG "core.debug" #define CORE_ERROR "core.error" #define CORE_LICENSE "core.license" #define CORE_TRACE "core.trace" #define CORE_ACCOUNTING "core.accounting" #define CORE_INFO "core.info" #define CORE_STDERR "core.stderr" #define CORE_AUTH "core.auth" #define CORE_DUMP "core.dump" #define CORE_CAPS "core.caps" #define CORE_SESSION "core.session" #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zorp/zorplibconfig.h-win32.in000066400000000000000000000007011224546767600220660ustar00rootroot00000000000000/* src/zorp/zorplibconfig.h-win32 */ #define ZORPLIB_ENABLE_CAPS 0 #define ZORPLIB_ENABLE_MEM_TRACE 0 #define ZORPLIB_ENABLE_DEBUG 0 #define ZORPLIB_ENABLE_TRACE 0 #define ZORPLIB_ENABLE_STACKDUMP 1 #define ZORPLIB_ENABLE_THREADPOOL 0 /* Zorp low level library package name */ #define ZORPLIBLL_PACKAGE "libzorpll" /* Zorp low level library version */ #define ZORPLIBLL_VERSION "@VERSION@" #define ZORPLIBLL_REVISION "@SOURCE_REVISION@" libzorpll-3.9.4.1/src/zorp/zorplibconfig.h.in000066400000000000000000000152031224546767600211310ustar00rootroot00000000000000/* src/zorp/zorplibconfig.h.in. Generated from configure.in by autoheader. */ /* 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 have `alloca', as a function or macro. */ #undef HAVE_ALLOCA /* Define to 1 if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H /* Define to 1 if you have the `backtrace' function. */ #undef HAVE_BACKTRACE /* have buggy syslog() in libc */ #undef HAVE_BUGGY_SYSLOG_IN_LIBC /* Define to 1 if you have the `crypt' function. */ #undef HAVE_CRYPT /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define to 1 if you have the `inet_addr' function. */ #undef HAVE_INET_ADDR /* Define to 1 if you have the `inet_aton' function. */ #undef HAVE_INET_ATON /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* have IP_RECVTOS */ #undef HAVE_IP_RECVTOS /* Define to 1 if you have the `cap' library (-lcap). */ #undef HAVE_LIBCAP /* Define to 1 if you have the `crypt' library (-lcrypt). */ #undef HAVE_LIBCRYPT /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the `z' library (-lz). */ #undef HAVE_LIBZ /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Have transparent md5 support in crypt() */ #undef HAVE_MD5_CRYPT /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* have IP_PKTOPTIONS */ #undef HAVE_PKTOPTIONS /* Define to 1 if you have the `prctl' function. */ #undef HAVE_PRCTL /* have PR_SET_KEEPCAPS */ #undef HAVE_PR_SET_KEEPCAPS /* Define to 1 if you have the header file. */ #undef HAVE_PWD_H /* Define to 1 if you have the `setrlimit' function. */ #undef HAVE_SETRLIMIT /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* have SOL_IP */ #undef HAVE_SOL_IP /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the `strtoul' function. */ #undef HAVE_STRTOUL /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_CAPABILITY_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PRCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* 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. */ #undef STDC_HEADERS /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Zorp low level library package name */ #undef ZORPLIBLL_PACKAGE /* Zorp low level library, source revision */ #undef ZORPLIBLL_REVISION /* Zorp low level library version */ #undef ZORPLIBLL_VERSION /* Binary branch */ #undef ZORPLIB_BINARY_BRANCH /* Binary compatibility version */ #undef ZORPLIB_COMPAT_BRANCH /* enable caps */ #undef ZORPLIB_ENABLE_CAPS /* enable debug */ #undef ZORPLIB_ENABLE_DEBUG /* enable memtrace */ #undef ZORPLIB_ENABLE_MEM_TRACE /* enable residual protection */ #undef ZORPLIB_ENABLE_RESIDUAL_PROTECTION /* enable ssl engine */ #undef ZORPLIB_ENABLE_SSL_ENGINE /* enable stack dump */ #undef ZORPLIB_ENABLE_STACKDUMP /* enable ToS manipulation */ #undef ZORPLIB_ENABLE_TOS /* enable trace */ #undef ZORPLIB_ENABLE_TRACE /* libexecdir */ #undef ZORPLIB_LIBEXECDIR /* default PID file directory */ #undef ZORPLIB_PIDFILE_DIR /* default temporary directory */ #undef ZORPLIB_TEMP_DIR /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if doesn't define. */ #undef uid_t libzorpll-3.9.4.1/src/zorp/zurlparse.h000066400000000000000000000012061224546767600177020ustar00rootroot00000000000000#ifndef ZORP_ZURLPARSE_H_INCLUDED #define ZORP_ZURLPARSE_H_INCLUDED #include #define ZURL_ERROR z_url_error_quark() #ifdef __cplusplus extern "C" { #endif GQuark z_url_error_quark(void); enum ZURLError { ZURL_ERROR_FAILED, }; typedef struct _ZURL { /* all gstrings below might contain NUL characters as they store the URL-decoded form */ GString *scheme; GString *user; GString *passwd; GString *host; guint port; GString *file; } ZURL; gboolean z_url_parse(ZURL *self, const gchar *url_str, GError **error); void z_url_init(ZURL *self); void z_url_free(ZURL *self); #ifdef __cplusplus } #endif #endif libzorpll-3.9.4.1/src/zurlparse.c000066400000000000000000000202341224546767600167050ustar00rootroot00000000000000#include #include #include /** * z_url_xdigit_value: * @c: possible hexadecimal character * * Return the hexadecimal value of @c or return -1 if not a hexadecimal character. **/ static inline gint z_url_xdigit_value(char c) { c = tolower(c); if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; return -1; } /** * z_url_decode_hex_byte: * @dst: store decoded value here * @src: read hexadecimal numbers from here * @reason: error reason text if the operation fails * * Convert a hexadecimal encoded byte to the equivalent value. **/ static inline gboolean z_url_decode_hex_byte(guchar *dst, const gchar *src, GError **error) { g_return_val_if_fail(error == NULL || *error == NULL, FALSE); if (isxdigit(*src) && isxdigit(*(src+1))) { *dst = (z_url_xdigit_value(*src) << 4) + z_url_xdigit_value(*(src+1)); } else { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Invalid hexadecimal encoding"); return FALSE; } return TRUE; } /** * g_string_assign_url_decode: * @part: store the decoded string here * @permit_invalid_hex_escape: whether to treat invalid url encoding sequences as errors * @src: source string to decode * @len: length of string pointed to by @src * @reason: terror reason text if the operation fails * * Decodes an URL part such as username, password or host name. Assumes * single byte destination encoding, e.g. US-ASCII with the 128-255 range * defined. **/ static gboolean g_string_assign_url_decode(GString *part, const gchar *src, gint len, GError **error) { gchar *dst; gint left = len; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* url decoding shrinks the string, using len is a good bet */ g_string_set_size(part, len); dst = part->str; while (left) { guchar c = (guchar) *src; if (*src == '%') { if (left < 2 || !z_url_decode_hex_byte(&c, src+1, error)) { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Hexadecimal encoding too short"); return FALSE; } else { src += 2; left -= 2; } } *dst = c; dst++; src++; left--; } *dst = 0; part->len = dst - part->str; /* some space might still be allocated at the end of the string * but we don't care to avoid reallocing and possible data copy */ return TRUE; } /** * z_url_parse: * @url: store URL parts to this structure * @permit_unicode_url: permit IIS style unicode character encoding * @permit_invalid_hex_escape: permit invalid hexadecimal escaping, treat % in these cases literally * @url_str: URL to parse * @reason: parse error * * Parse the URL specified in @url_str and store the resulting parts in * @url. Scheme, username, password, hostname and filename are stored in * decoded form (UTF8 in permit_unicode_url case), query and fragment are * stored in URL encoded, but canonicalized form. * * Returns: TRUE for success, FALSE otherwise setting @reason to the explanation **/ gboolean z_url_parse(ZURL *url, const gchar *url_str, GError **error) { const gchar *p, *part[4], *sep[4], *file_start; gchar *end; int i; g_return_val_if_fail(error == NULL || *error == NULL, FALSE); g_string_truncate(url->scheme, 0); g_string_truncate(url->user, 0); g_string_truncate(url->passwd, 0); g_string_truncate(url->host, 0); g_string_truncate(url->file, 0); url->port = 0; p = url_str; while (*p && *p != ':') p++; if (!*p) { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "URL has no scheme, colon missing"); return FALSE; } if (*(p + 1) != '/' || *(p + 2) != '/') { /* protocol not terminated by '//' */ g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Scheme not followed by '//'"); return FALSE; } g_string_assign_len(url->scheme, url_str, p - url_str); p += 3; for (i = 0; i < 4; i++) { part[i] = p; while (*p && *p != ':' && *p != '/' && *p != '@' && *p != '?' && *p != '#') p++; sep[i] = p; if (!*p || *p == '/') break; p++; } switch (i) { case 0: /* hostname only */ if (!g_string_assign_url_decode(url->host, part[0], sep[0] - part[0], error)) return FALSE; break; case 1: /* username && host || hostname && port number */ if (*sep[0] == ':') { if (!g_string_assign_url_decode(url->host, part[0], sep[0] - part[0], error)) return FALSE; /* port number */ url->port = strtoul(part[1], &end, 10); if (end != sep[1]) { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Error parsing port number"); return FALSE; } } else if (*sep[0] == '@') { /* username */ if (!g_string_assign_url_decode(url->user, part[0], sep[0] - part[0], error) || !g_string_assign_url_decode(url->host, part[1], sep[1] - part[1], error)) return FALSE; } else { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Unrecognized URL construct"); return FALSE; } break; case 2: /* username && host && port || username && password && host */ if (*sep[0] == '@' && *sep[1] == ':') { /* username, host, port */ if (!g_string_assign_url_decode(url->user, part[0], sep[0] - part[0], error) || !g_string_assign_url_decode(url->host, part[1], sep[1] - part[1], error)) return FALSE; url->port = strtoul(part[2], &end, 10); if (end != sep[2]) { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Error parsing port number"); return FALSE; } } else if (*sep[0] == ':' && *sep[1] == '@') { /* username, password, host */ if (!g_string_assign_url_decode(url->user, part[0], sep[0] - part[0], error) || !g_string_assign_url_decode(url->passwd, part[1], sep[1] - part[1], error) || !g_string_assign_url_decode(url->host, part[2], sep[2] - part[2], error)) return FALSE; } else { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Unrecognized URL construct"); return FALSE; } break; case 3: /* username && password && hostname && port */ if (*sep[0] == ':' && *sep[1] == '@' && *sep[2] == ':') { if (!g_string_assign_url_decode(url->user, part[0], sep[0] - part[0], error) || !g_string_assign_url_decode(url->passwd, part[1], sep[1] - part[1], error) || !g_string_assign_url_decode(url->host, part[2], sep[2] - part[2], error)) return FALSE; url->port = strtoul(part[3], &end, 10); if (end != sep[3]) { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Error parsing port number"); return FALSE; } } else { g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Unrecognized URL construct"); return FALSE; } break; default: g_assert_not_reached(); } file_start = p; if (*file_start != '/') { if (*file_start == '\0') { g_string_assign(url->file, "/"); return TRUE; } g_set_error(error, ZURL_ERROR, ZURL_ERROR_FAILED, "Invalid path component in URL"); return FALSE; } g_string_assign(url->file, file_start); return TRUE; } void z_url_init(ZURL *self) { self->scheme = g_string_sized_new(0); self->user = g_string_sized_new(0); self->passwd = g_string_sized_new(0); self->host = g_string_sized_new(0); self->port = 0; self->file = g_string_sized_new(0); } void z_url_free(ZURL *self) { g_string_free(self->scheme, TRUE); g_string_free(self->user, TRUE); g_string_free(self->passwd, TRUE); g_string_free(self->host, TRUE); g_string_free(self->file, TRUE); } GQuark z_url_error_quark(void) { return g_quark_from_static_string("gurl-error-quark"); } libzorpll-3.9.4.1/tests/000077500000000000000000000000001224546767600150645ustar00rootroot00000000000000libzorpll-3.9.4.1/tests/Makefile.am000066400000000000000000000031471224546767600171250ustar00rootroot00000000000000AM_CPPFLAGS=-I$(top_srcdir)/src -I../src check_PROGRAMS = zcrypt test_readline test_registry test_conns test_ssl test_streams test_random test_valid_chars test_sockaddr test_blob test_base64 test_codegzip test_codecipher portrandom test_pktbuf zcrypt_SOURCES = zcrypt.c zcrypt_LDADD = ../src/libzorpll.la test_readline_SOURCES = test_readline.c test_readline_LDADD = ../src/libzorpll.la test_registry_SOURCES = test_registry.c test_registry_LDADD = ../src/libzorpll.la test_conns_SOURCES = test_conns.c test_conns_LDADD = ../src/libzorpll.la test_ssl_SOURCES = test_ssl.c test_ssl_LDADD = ../src/libzorpll.la test_random_SOURCES = test_random.c test_random_LDADD = ../src/libzorpll.la test_streams_SOURCES = test_streams.c test_streams_LDADD = ../src/libzorpll.la test_valid_chars_SOURCES = test_valid_chars.c test_valid_chars_LDADD = ../src/libzorpll.la test_sockaddr_SOURCES = test_sockaddr.c test_sockaddr_LDADD = ../src/libzorpll.la test_blob_SOURCES = test_blob.c test_blob_LDADD = ../src/libzorpll.la test_base64_SOURCES = test_base64.c test_base64_LDADD = ../src/libzorpll.la test_codegzip_SOURCES = test_codegzip.c test_codegzip_LDADD = ../src/libzorpll.la test_codecipher_SOURCES = test_codecipher.c test_codecipher_LDADD = ../src/libzorpll.la portrandom_SOURCES = portrandom.c randtest.c randtest.h portrandom_LDADD = ../src/libzorpll.la -lm test_pktbuf_SOURCES = test_pktbuf.c test_pktbuf_LDADD = ../src/libzorpll.la TESTS = test_registry test_readline zcrypt test_conns test_ssl test_random test_streams test_valid_chars test_sockaddr test_blob test_base64 test_codegzip test_codecipher portrandom test_pktbuf libzorpll-3.9.4.1/tests/portrandom.c000066400000000000000000000071261224546767600174230ustar00rootroot00000000000000/** * Test source port randomization implementation in socket.c. **/ /* third-party headers */ #include /* * randtest.h and randtest.c come from http://www.fourmilab.ch/random/ * * According to the website, they're public domain. */ /* zorp headers */ #include /* glib headers */ #include /* unix headers */ #include #include #include /* standard c headers */ #include #include /* test-specific constants */ /** number of iterations to run */ #define ITERATIONS 100000 /** a port that should be in the port range */ #define DEFAULT_PORT 6666 /** lowest port in range; should match the one in socket.c. */ #define PORT_MIN 1024 /** highest port in range; should match the one in socket.c. */ #define PORT_MAX 65535 /** print each port number as we go */ #define PRINT_PORTS 0 /** minimum entropy per byte of port required */ #define MIN_ENTROPY 7.9 /** disable this to see what happened if we used only ZSF_LOOSE_BIND. */ #define REALLY_RANDOM 1 /** if enabled, failing to bind will stop the test; otherwise we only really test the random numbers */ #define FAIL_ON_BIND 1 /** * Bind once and return the port we got. * * @returns port bound to **/ int try_bind_once(void) { int socket_fd; struct sockaddr_in socket_address; char *ip_address = "127.0.0.1"; #if REALLY_RANDOM guint32 sock_flags = ZSF_LOOSE_BIND | ZSF_RANDOM_BIND; #else guint32 sock_flags = ZSF_LOOSE_BIND; #endif gint rc = -1; /* result code, 0 is success and -1 failure */ /* create socket */ socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd == -1) { perror("Failed: trying to create socket in portrandom.c:try_bind_once()"); exit(1); } /* set address */ socket_address.sin_family = AF_INET; inet_aton(ip_address, &socket_address.sin_addr); socket_address.sin_port = htons(DEFAULT_PORT); /* call the function to test */ rc = z_do_ll_bind(socket_fd, (struct sockaddr *)&socket_address, sizeof(socket_address), sock_flags); if (rc == -1) { printf("port=%d\n", ntohs(socket_address.sin_port)); perror("Failed: z_do_ll_bind call in portrandom.c:try_bind_once()"); #if FAIL_ON_BIND exit(1); #endif } close(socket_fd); return ntohs(socket_address.sin_port); } /** * Run the entire unit test. **/ int main(void) { int i; int port; guint16 real_port; /* port at its actual size (for randomtest) */ double ent, chisq, mean, montepi, scc; /* randomtest results */ printf("Testing source port randomness; iterations=%d, minimal entropy=%f\n", ITERATIONS, MIN_ENTROPY); rt_init(FALSE); /* initialize randomtest, not binary */ /* run test iterations */ for (i = 0; i < ITERATIONS; i++) { port = try_bind_once(); #if PRINT_PORTS printf("Port bound to: %d\n", port); #endif if (port < PORT_MIN) { printf("Failed: port number below minimum.\n"); exit(1); } if (port > PORT_MAX) { printf("Failed: port number above maximum.\n"); exit(1); } real_port = (guint16)port; rt_add(&real_port, sizeof(real_port)); } /* check randomness */ rt_end(&ent, &chisq, &mean, &montepi, &scc); printf("Randomness: entropy=%f, chi-square=%f, mean=%f, monte-carlo-pi=%f, serial correlation=%f\n", ent, chisq, mean, montepi, scc); /* make decision */ if (ent >= MIN_ENTROPY) { printf("Passed: entropy is high enough.\n"); exit(0); } else { printf("Failed: entropy is not high enough.\n"); exit(1); } } libzorpll-3.9.4.1/tests/randtest.c000066400000000000000000000111361224546767600170560ustar00rootroot00000000000000/* Apply various randomness tests to a stream of bytes by John Walker -- September 1996 http://www.fourmilab.ch/ */ #include #define FALSE 0 #define TRUE 1 #define log2of10 3.32192809488736234787 static int binary = FALSE; /* Treat input as a bitstream */ static long ccount[256], /* Bins to count occurrences of values */ totalc = 0; /* Total bytes counted */ static double prob[256]; /* Probabilities per bin for entropy */ /* RT_LOG2 -- Calculate log to the base 2 */ static double rt_log2(double x) { return log2of10 * log10(x); } #define MONTEN 6 /* Bytes used as Monte Carlo co-ordinates. This should be no more bits than the mantissa of your "double" floating point type. */ static int mp, sccfirst; static unsigned int monte[MONTEN]; static long inmont, mcount; static double c_exp, incirc, montex, montey, montepi, scc, sccun, sccu0, scclast, scct1, scct2, scct3, ent, chisq, datasum; /* RT_INIT -- Initialise random test counters. */ void rt_init(int binmode) { int i; binary = binmode; /* Set binary / byte mode */ /* Initialise for calculations */ ent = 0.0; /* Clear entropy accumulator */ chisq = 0.0; /* Clear Chi-Square */ datasum = 0.0; /* Clear sum of bytes for arithmetic mean */ mp = 0; /* Reset Monte Carlo accumulator pointer */ mcount = 0; /* Clear Monte Carlo tries */ inmont = 0; /* Clear Monte Carlo inside count */ incirc = 65535.0 * 65535.0;/* In-circle distance for Monte Carlo */ sccfirst = TRUE; /* Mark first time for serial correlation */ scct1 = scct2 = scct3 = 0.0; /* Clear serial correlation terms */ incirc = pow(pow(256.0, (double) (MONTEN / 2)) - 1, 2.0); for (i = 0; i < 256; i++) { ccount[i] = 0; } totalc = 0; } /* RT_ADD -- Add one or more bytes to accumulation. */ void rt_add(void *buf, int bufl) { unsigned char *bp = buf; int oc, c, bean; while (bean = 0, (bufl-- > 0)) { oc = *bp++; do { if (binary) { c = !!(oc & 0x80); } else { c = oc; } ccount[c]++; /* Update counter for this bin */ totalc++; /* Update inside / outside circle counts for Monte Carlo computation of PI */ if (bean == 0) { monte[mp++] = oc; /* Save character for Monte Carlo */ if (mp >= MONTEN) { /* Calculate every MONTEN character */ int mj; mp = 0; mcount++; montex = montey = 0; for (mj = 0; mj < MONTEN / 2; mj++) { montex = (montex * 256.0) + monte[mj]; montey = (montey * 256.0) + monte[(MONTEN / 2) + mj]; } if ((montex * montex + montey * montey) <= incirc) { inmont++; } } } /* Update calculation of serial correlation coefficient */ sccun = c; if (sccfirst) { sccfirst = FALSE; scclast = 0; sccu0 = sccun; } else { scct1 = scct1 + scclast * sccun; } scct2 = scct2 + sccun; scct3 = scct3 + (sccun * sccun); scclast = sccun; oc <<= 1; } while (binary && (++bean < 8)); } } /* RT_END -- Complete calculation and return results. */ void rt_end(double *r_ent, double *r_chisq, double *r_mean, double *r_montepicalc, double *r_scc) { int i; /* Complete calculation of serial correlation coefficient */ scct1 = scct1 + scclast * sccu0; scct2 = scct2 * scct2; scc = totalc * scct3 - scct2; if (scc == 0.0) { scc = -100000; } else { scc = (totalc * scct1 - scct2) / scc; } /* Scan bins and calculate probability for each bin and Chi-Square distribution. The probability will be reused in the entropy calculation below. While we're at it, we sum of all the data which will be used to compute the mean. */ c_exp = totalc / (binary ? 2.0 : 256.0); /* Expected count per bin */ for (i = 0; i < (binary ? 2 : 256); i++) { double a = ccount[i] - c_exp;; prob[i] = ((double) ccount[i]) / totalc; chisq += (a * a) / c_exp; datasum += ((double) i) * ccount[i]; } /* Calculate entropy */ for (i = 0; i < (binary ? 2 : 256); i++) { if (prob[i] > 0.0) { ent += prob[i] * rt_log2(1 / prob[i]); } } /* Calculate Monte Carlo value for PI from percentage of hits within the circle */ montepi = 4.0 * (((double) inmont) / mcount); /* Return results through arguments */ *r_ent = ent; *r_chisq = chisq; *r_mean = datasum / totalc; *r_montepicalc = montepi; *r_scc = scc; } libzorpll-3.9.4.1/tests/randtest.h000066400000000000000000000003621224546767600170620ustar00rootroot00000000000000 /* Random test function prototypes */ extern void rt_init(int binmode); extern void rt_add(void *buf, int bufl); extern void rt_end(double *r_ent, double *r_chisq, double *r_mean, double *r_montepicalc, double *r_scc); libzorpll-3.9.4.1/tests/test_base64.c000066400000000000000000000200441224546767600173530ustar00rootroot00000000000000#include #include #include #include #include #include int error(const char *msg) { fprintf(stderr, "%s\n", msg); return 1; } void hexdump(const char* buf, int len) { int i, j; for (i = 0; i < len; i += 0x10) { printf("%06x: ", i); for (j = i; j < (i + 0x10); j++) if (j < len) printf("%02x ", (int)(unsigned char)buf[j]); else printf(" "); for (j = i; (j < (i + 0x10)) && (j < len); j++) printf("%c", isprint(buf[j]) ? buf[j] : '.'); printf("\n"); } } int get_and_dump(ZCode *c, int len, const char *shouldbe, int shouldbelen) { char *dst; int i, err; i = z_code_get_result_length(c); printf("Result length is '%d' bytes, obtaining '%d' bytes\n", i, len); dst = (char*)malloc(len); len = z_code_get_result(c, dst, len); printf("Got '%d' bytes, dump follows:\n", len); hexdump(dst, len); if (shouldbelen >= 0) { if (len != shouldbelen) return error("Result length mismatch"); } if (shouldbe) { if (memcmp(dst, shouldbe, len)) return error("Result mismatch"); } printf("Result matches\n"); err = z_code_get_errors(c); i = z_code_get_result_length(c); printf("Errors = '%d', remaining result length is '%d' bytes\n", err, i); free(dst); return i; } int check_for_error(ZCode *c, const char *src, int srclen, int shall_be_error) { int i; int has_error; char dummy[1024]; printf("Testing '%s' for errors: ", src); z_code_clear_errors(c); i = z_code_transform(c, src, srclen); i &= z_code_finish(c); has_error = !i; while (z_code_get_result(c, dummy, 1024) == 1024) ; z_code_clear_errors(c); if (!shall_be_error != !has_error) { printf("Unexpected behaviour; has_error='%d', shall_be_error='%d'\n", has_error, shall_be_error); return 1; } printf("OK; has_error='%d'\n", has_error); return 0; } int main(void) { int i, len; char *src; unsigned char q; unsigned char *usrc; ZCode *enc, *dec, *dec_noerr; enc = z_code_base64_encode_new(0, 0); if (!enc) return error("Can't instantiate encoder"); dec = z_code_base64_decode_new(0, FALSE); if (!dec) return error("Can't instantiate decoder"); dec_noerr = z_code_base64_decode_new(0, TRUE); if (!dec_noerr) return error("Can't instantiate decoder"); /***********************************************************************/ /* vanilla case, just the basic operation */ src = "ingyombingyom"; printf("\nTesting the encoder, transforming '%s'\n", src); len = strlen(src); i = z_code_transform(enc, src, len); printf("Encoded '%d' bytes, closing encoder\n", i); z_code_finish(enc); get_and_dump(enc, 1024, "aW5neW9tYmluZ3lvbQ==\r\n", 22); src = "aW5neW9tYmluZ3lvbQ=="; printf("\nTesting the decoder, transforming '%s'\n", src); len = strlen(src); i = z_code_transform(dec, src, len); printf("Decoded '%d' bytes, closing decoder\n", i); z_code_finish(dec); get_and_dump(dec, 1024, "ingyombingyom", 13); /***********************************************************************/ /* partial read */ src = "ingyombingyom"; printf("\nTesting partial read (encoder side), transforming '%s'\n", src); len = strlen(src); i = z_code_transform(enc, src, len); printf("Encoded '%d' bytes, closing encoder\n", i); z_code_finish(enc); get_and_dump(enc, 4, "aW5n", 4); get_and_dump(enc, 4, "eW9t", 4); get_and_dump(enc, 4, "Ymlu", 4); get_and_dump(enc, 4, "Z3lv", 4); get_and_dump(enc, 4, "bQ==", 4); get_and_dump(enc, 4, "\r\n", 2); src = "aW5neW9tYmluZ3lvbQ=="; printf("\nTesting partial read (decoder side), transforming '%s'\n", src); len = strlen(src); i = z_code_transform(dec, src, len); printf("Decoded '%d' bytes, closing decoder\n", i); z_code_finish(dec); get_and_dump(dec, 4, "ingy", 4); get_and_dump(dec, 4, "ombi", 4); get_and_dump(dec, 4, "ngyo", 4); get_and_dump(dec, 4, "m", 1); /***********************************************************************/ /* unget */ src = "ihajcsuhaj"; printf("\nTesting the unget feature, transforming '%s'\n", src); len = strlen(src); z_code_unget_result(enc, src, len); printf("Pushed back '%d' bytes\n", len); get_and_dump(enc, 1024, "ihajcsuhaj", 10); /***********************************************************************/ /* excess whitespaces */ src = "aW5neW9tYm\r\n \tlu\t\rZ3\n lvbQ=="; printf("\nTesting the decoder with excess whitespaces, transforming '%s'\n", src); len = strlen(src); i = z_code_transform(dec, src, len); printf("Decoded '%d' bytes, closing decoder\n", i); z_code_finish(dec); get_and_dump(dec, 1024, "ingyombingyom", 13); /***********************************************************************/ /* invalid input */ src = "aW5neW9tYm\xffluZ3lvbQ=="; printf("\nTesting the decoder with invalid input, transforming '%s'\n", src); len = strlen(src); i = z_code_transform(dec, src, len); printf("Decoded '%d' bytes, closing decoder\n", i); z_code_finish(dec); get_and_dump(dec, 1024, NULL, -1); if (z_code_get_errors(dec) == 0) return error("Errors weren't recognised"); else printf("Errors recognised\n"); z_code_clear_errors(dec); /***********************************************************************/ /* invalid input - error tolerant */ usrc = (unsigned char *) "aW5neW9tYm\xffluZ3lvbQ=="; printf("\nTesting the decoder with invalid input, transforming '%s'\n", usrc); len = strlen((char *) usrc); i = z_code_transform(dec_noerr, usrc, len); printf("Decoded '%d' bytes, closing decoder\n", i); z_code_finish(dec_noerr); get_and_dump(dec_noerr, 1024, "ingyombingyom", 13); if (z_code_get_errors(dec_noerr) != 0) return error("Errors weren't ignored"); else printf("Errors ignored\n"); z_code_clear_errors(dec_noerr); /***********************************************************************/ /* huge block */ #define BLOCKSIZE (1024*1024*2) printf("\nTesting with a pattern block, encoding %d kbytes\n", BLOCKSIZE/1024); for (i = 0; i < BLOCKSIZE; i++) { if (!(i & 0x3ff)) { printf("%8d\r", i); fflush(stdout); } q = (i & 0xff); if (!z_code_transform(enc, &q, 1)) return error("\nerror in encoding"); } if (!z_code_finish(enc)) return error("\nerror in finishing"); len = z_code_get_result_length(enc); usrc = (unsigned char*)malloc(len); i = z_code_get_result(enc, usrc, len); if (i != len) return error("Error getting the result"); printf("Decoding the result (%d, %d)\n", i, len); if (!z_code_transform(dec, usrc, len)) return error("Error decoding the result"); len = z_code_get_result_length(dec); if (len != BLOCKSIZE) return error("Result length doesn't match"); i = z_code_get_result(dec, usrc, len); if (i != len) return error("Can't decode the result"); printf("Checking the pattern in the result\n"); for (i = 0; i < len; i++) { if (!(i & 0x3ff)) { printf("%8d\r", i); fflush(stdout); } if (usrc[i] != (i & 0xff)) return error("Decoded pattern doesn't match"); } printf("Done. \n"); /***********************************************************************/ /* checks for error patterns */ printf("\nTesting with a error patterns\n"); if (check_for_error(dec, "AAAA", 4, FALSE)) return 1; if (check_for_error(dec, "AAA=", 4, FALSE)) return 1; if (check_for_error(dec, "AA==", 4, FALSE)) return 1; if (check_for_error(dec, "AA=A", 4, TRUE )) return 1; if (check_for_error(dec, "A===", 4, TRUE )) return 1; if (check_for_error(dec, "A=AA", 4, TRUE )) return 1; if (check_for_error(dec, "====", 4, TRUE )) return 1; if (check_for_error(dec, "=AAA", 4, TRUE )) return 1; if (check_for_error(dec, "AAA", 3, TRUE )) return 1; if (check_for_error(dec, "A!AA", 4, TRUE )) return 1; printf("\nDropping en/decoder\n"); z_code_free(enc); z_code_free(dec); printf("All tests succeeded\n"); return 0; } libzorpll-3.9.4.1/tests/test_blob.c000066400000000000000000000225721224546767600172150ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #define TEST_DELAY 100 /*********************************************************************** * Concurrent access test * ***********************************************************************/ void send_log(void *p G_GNUC_UNUSED, const gchar *s G_GNUC_UNUSED, gint n G_GNUC_UNUSED, const char *fmt, ...) { va_list vl; va_start(vl, fmt); vprintf(fmt, vl); printf("\n"); fflush(stdout); va_end(vl); } #define b2str(a) a ? "TRUE" : "FALSE" void test_and_log(gboolean condition, gboolean expected, gchar *log_format, ...) { va_list vl; gchar orig_log[4096]; va_start(vl, log_format); g_vsnprintf(orig_log, sizeof(orig_log), log_format, vl); va_end(vl); printf("%s, expected='%s', condition='%s'\n", orig_log, b2str(expected), b2str(condition)); if (condition != expected) { exit(1); } } /*********************************************************************** * Growing allocation sizes test * ***********************************************************************/ /** * test_growing_sizes: * @blobsys: this * * Growing allocation sizes test main function */ void test_growing_sizes(ZBlobSystem *blobsys) { ZBlob *blob; int i; char p; /* create a blob */ blob = z_blob_new(blobsys, 100); /* z_blob_new(NULL, ...) to use the default blobsys */ send_log(NULL, CORE_DEBUG, 4, "-- created blob; blob='%p'", blob); p = '\xd0'; /* why not */ for (i=1; i<0x10000; i++) { if (!(i & 0x3ff)) send_log(NULL, CORE_DEBUG, 4, "-- writing; blob='%p', pos='%d'", blob, i); z_blob_add_copy(blob, i, &p, 1, -1); usleep(TEST_DELAY); } } /*********************************************************************** * Blob fetching-in test * ***********************************************************************/ /** * test_fetch_in: * @blobsys: this * * Fetch-in test main function */ void test_fetch_in(ZBlobSystem *blobsys) { ZBlob *blob[3]; send_log(NULL, CORE_DEBUG, 4, "-- creating blob[0]; size='2000'"); blob[0] = z_blob_new(blobsys, 2000); /* will be allocated in mem */ send_log(NULL, CORE_DEBUG, 4, "-- creating blob[1]; size='2000'"); blob[1] = z_blob_new(blobsys, 2000); /* ditto */ send_log(NULL, CORE_DEBUG, 4, "-- creating blob[2]; size='2000'"); blob[2] = z_blob_new(blobsys, 2000); /* out of limit -> goes to disk */ send_log(NULL, CORE_DEBUG, 4, "-- destroying blob[0]"); z_blob_unref(blob[0]); /* b0 dies, still above lowat, nothing happens */ send_log(NULL, CORE_DEBUG, 4, "-- destroying blob[1]"); z_blob_unref(blob[1]); /* b1 dies, b2 must be fetched in */ send_log(NULL, CORE_DEBUG, 4, "-- sleeping 2 seconds to leave time for fetch in... (shall be fetched in)"); sleep(2); test_and_log(blob[2]->is_in_file, FALSE, "-- blob[2]->is_in_file: %s", blob[2]->is_in_file ? "TRUE" : "FALSE"); send_log(NULL, CORE_DEBUG, 4, "-- exiting and destroying blob[2]"); z_blob_unref(blob[2]); } /*********************************************************************** * Deferred allocation test * ***********************************************************************/ gpointer mk_blob_deferred1(ZBlobSystem *blobsys) { ZBlob *blob; send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred1, creating blob; size='4000'"); blob = z_blob_new(blobsys, 4000); /* can't be allocated until another blob is destroyed */ send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred1, blob created, sleeping 10 sec;"); sleep(10); send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred1, destroying blob;"); z_blob_unref(blob); send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred1, exiting;"); return NULL; } gpointer mk_blob_deferred2(ZBlobSystem *blobsys) { ZBlob *blob; send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred2, creating blob; size='4000'"); blob = z_blob_new(blobsys, 4000); /* can't be allocated until another blob is destroyed */ send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred2, blob created, sleeping 10 sec;"); sleep(10); send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred2, destroying blob;"); z_blob_unref(blob); send_log(NULL, CORE_DEBUG, 4, "---- mk_blob_deferred2, exiting;"); return NULL; } /** * test_deferred_alloc: * @blobsys: this * * Deferred allocation test main function */ void test_deferred_alloc(ZBlobSystem *blobsys) { ZBlob *blob[2]; GThread *thr[2]; send_log(NULL, CORE_DEBUG, 4, "-- creating blob[0]; size='4500'"); blob[0] = z_blob_new(blobsys, 4500); /* will be allocated in mem - 500 bytes remaining*/ send_log(NULL, CORE_DEBUG, 4, "-- creating blob[1]; size='9500'"); blob[1] = z_blob_new(blobsys, 9500); /* will be allocated on disk - 500 bytes remaining */ send_log(NULL, CORE_DEBUG, 4, "-- creating threads for another 2 allocations"); thr[0] = g_thread_create((GThreadFunc)mk_blob_deferred1, (gpointer)blobsys, TRUE, NULL); thr[1] = g_thread_create((GThreadFunc)mk_blob_deferred2, (gpointer)blobsys, TRUE, NULL); send_log(NULL, CORE_DEBUG, 4, "-- thread created, sleeping 3 sec"); sleep(3); send_log(NULL, CORE_DEBUG, 4, "-- destroying blob[0]"); /* the deferred alloc shall succeed now */ z_blob_unref(blob[0]); send_log(NULL, CORE_DEBUG, 4, "-- sleeping 3 sec"); sleep(3); send_log(NULL, CORE_DEBUG, 4, "-- destroying blob[1]"); /* the deferred alloc shall succeed now */ z_blob_unref(blob[1]); send_log(NULL, CORE_DEBUG, 4, "-- waiting for the threads"); g_thread_join(thr[0]); g_thread_join(thr[1]); send_log(NULL, CORE_DEBUG, 4, "-- threads finished, exiting"); } /** * test_fetch_in_lock: * @blobsys: this * * Fetch-in locking test main function */ void test_fetch_in_lock(ZBlobSystem *blobsys) { ZBlob *blob[3]; send_log(NULL, CORE_DEBUG, 4, "-- creating blob[0]; size='2000'"); blob[0] = z_blob_new(blobsys, 2000); /* will be allocated in mem */ send_log(NULL, CORE_DEBUG, 4, "-- creating blob[1]; size='2000'"); blob[1] = z_blob_new(blobsys, 2000); /* ditto */ send_log(NULL, CORE_DEBUG, 4, "-- creating blob[2]; size='2000'"); blob[2] = z_blob_new(blobsys, 2000); /* out of limit -> goes to disk */ z_blob_get_file(blob[2], NULL, NULL, 664, 0); z_blob_storage_lock(blob[2], TRUE); /* locking b2 - fetch-in disabled */ z_blob_release_file(blob[2]); send_log(NULL, CORE_DEBUG, 4, "-- destroying blob[0]"); z_blob_unref(blob[0]); /* b0 dies, still above lowat, nothing happens */ send_log(NULL, CORE_DEBUG, 4, "-- destroying blob[1]"); z_blob_unref(blob[1]); /* b1 dies, but b2 can't be fetched in */ send_log(NULL, CORE_DEBUG, 4, "-- sleeping 2 seconds to leave time for fetch in... (shall remain in file)"); sleep(2); test_and_log(blob[2]->is_in_file, TRUE, "-- blob[2]->is_in_file: %s", blob[2]->is_in_file ? "yes" : "no"); send_log(NULL, CORE_DEBUG, 4, "-- exiting and destroying blob[2]"); z_blob_unref(blob[2]); } /** * test_swap_out_and_then_released: * @blobsys: this * * This function test the scenario when the blob swapped out and then * scanned, and after that released. * The size of the blob should not change after this scenario. */ void test_swap_out_and_then_released(ZBlobSystem *blobsys) { ZBlob *blob; char p; int i; blob = z_blob_new(blobsys, 0); /* will be allocated in mem - 500 bytes remaining*/ p = '\xd0'; /* why not */ for (i = 0; i < 5500; i++) { z_blob_add_copy(blob, i, &p, 1, -1); } test_and_log(blob->size==5500, TRUE, "-- blob->size (before): %ld", blob->size); test_and_log(blob->is_in_file, TRUE, "-- blob[2]->is_in_file: %s", blob->is_in_file ? "yes" : "no"); z_blob_lock(blob, -1); z_blob_release_file(blob); test_and_log(blob->size==5500, TRUE, "-- blob->size (after): %ld", blob->size); } /*********************************************************************** * 'Framework' * ***********************************************************************/ int main(void) { ZBlobSystem *blobsys; ZBlob *blob; /*gchar *blobptr;*/ /*gsize blobptr_size;*/ /*const gchar *blobfile;*/ z_thread_init(); /*verbose_level=9;*/ send_log(NULL, CORE_DEBUG, 4, "============= STARTING TEST ================"); /* Initialise default blob system */ z_blob_system_default_init(); /* Initialise custom blob system */ blobsys = z_blob_system_new("/tmp", 10000, 5000, 1000, 2000, 500); /*test_growing_sizes(blobsys);*/ test_fetch_in(blobsys); test_fetch_in_lock(blobsys); test_deferred_alloc(blobsys); test_swap_out_and_then_released(blobsys); /* Deinitialie custom blob system */ z_blob_system_unref(blobsys); /* Create blob in the default blob system */ blob = z_blob_new(NULL, 500); if (blob == NULL) { send_log(NULL, CORE_DEBUG, 3, "Cannot alocate blob in the default blob system;"); } else { /*blobptr_size = 10;*/ /*blobptr = z_blob_get_ptr(blob, 0, &blobptr_size, -1);*/ /*blobfile =*/ z_blob_get_file(blob, NULL, NULL, 0644, -1); /* Leave it allocated and locked, let's see what happens when the blobsys is destroyed */ } /* Deinitialise default blob system */ z_blob_system_default_destroy(); z_thread_destroy(); send_log(NULL, CORE_DEBUG, 4, "============= TEST FINISHED ================"); return 0; } libzorpll-3.9.4.1/tests/test_codecipher.c000066400000000000000000000046051224546767600204010ustar00rootroot00000000000000#include #include int main(void) { gchar buf[4097], buf2[4097]; unsigned char key[128], iv[128]; gchar *encrypted = NULL; gsize length = 0; ZCode *cipher; gint i, j; const EVP_CIPHER *algo; EVP_CIPHER_CTX cipher_ctx; memset(buf, 'A', sizeof(buf)); memset(buf2, 'B', sizeof(buf2)); algo = EVP_aes_128_cbc(); memset(key, '\x55', sizeof(key)); memset(iv, '\xaa', sizeof(iv)); g_assert((gint) sizeof(key) > algo->key_len); g_assert((gint) sizeof(iv) > algo->iv_len); EVP_CipherInit(&cipher_ctx, algo, key, iv, TRUE); cipher = z_code_cipher_new(&cipher_ctx); for (i = 0; i < 4096; i++) { if (!z_code_transform(cipher, buf, sizeof(buf)) || !z_code_transform(cipher, buf2, sizeof(buf2))) { fprintf(stderr, "Encryption failed\n"); return 1; } } if (!z_code_finish(cipher)) { fprintf(stderr, "Encryption failed\n"); return 1; } length = z_code_get_result_length(cipher); encrypted = g_malloc(length); memcpy(encrypted, z_code_peek_result(cipher), length); z_code_free(cipher); EVP_CipherInit(&cipher_ctx, algo, key, iv, FALSE); cipher = z_code_cipher_new(&cipher_ctx); if (!z_code_transform(cipher, encrypted, length) || !z_code_finish(cipher)) { fprintf(stderr, "Decryption failed\n"); return 1; } if (z_code_get_result_length(cipher) != 4096 * 2 * sizeof(buf)) { fprintf(stderr, "Decryption resulted different length, than encrypted length='%"G_GSIZE_FORMAT"', result='%"G_GSIZE_FORMAT"' ???\n", 4096 * 2 * sizeof(buf), z_code_get_result_length(cipher)); return 1; } for (i = 0; i < 4096; i++) { for (j = 0; j < 2; j++) { guchar check; memset(buf, 'C', sizeof(buf)); length = z_code_get_result(cipher, buf, sizeof(buf)); if (length != sizeof(buf)) { fprintf(stderr, "Expected some more data\n"); return 1; } if (j == 0) check = 'A'; else check = 'B'; for (i = 0; i < (gint) sizeof(buf); i++) { if (buf[i] != check) { fprintf(stderr, "Invalid data returned from decryption\n"); return 1; } } } } return 0; } libzorpll-3.9.4.1/tests/test_codegzip.c000066400000000000000000000040121224546767600200700ustar00rootroot00000000000000#include #include #include #include int main(void) { gchar buf[4096], buf2[4096]; gchar *compressed = NULL; gsize length = 0; ZCode *gz; guint i, j; memset(buf, 'A', sizeof(buf)); memset(buf2, 'B', sizeof(buf2)); gz = z_code_gzip_encode_new(1024, 1); length = 0; for (i = 0; i < 4096; i++) { if (!z_code_transform(gz, buf, sizeof(buf)) || !z_code_transform(gz, buf2, sizeof(buf2)) || !z_code_finish(gz)) { fprintf(stderr, "Compression failed\n"); return 1; } compressed = realloc(compressed, length + z_code_get_result_length(gz)); memcpy(compressed + length, z_code_peek_result(gz), z_code_get_result_length(gz)); length += z_code_get_result_length(gz); z_code_flush_result(gz, 0); } gz = z_code_gzip_decode_new(4096); if (!z_code_transform(gz, compressed, length) || !z_code_finish(gz)) { fprintf(stderr, "Decompression failed\n"); return 1; } if (z_code_get_result_length(gz) != 4096 * 2 * sizeof(buf)) { fprintf(stderr, "Decompression resulted different length, than compressed length='%"G_GSIZE_FORMAT"', result='%"G_GSIZE_FORMAT"' ???\n", length, z_code_get_result_length(gz)); return 1; } for (i = 0; i < 4096; i++) { for (j = 0; j < 2; j++) { guchar check; memset(buf, 'C', sizeof(buf)); length = z_code_get_result(gz, buf, sizeof(buf)); if (length != sizeof(buf)) { fprintf(stderr, "Expected some more data\n"); return 1; } if (j == 0) check = 'A'; else check = 'B'; for (i = 0; i < sizeof(buf); i++) { if (buf[i] != check) { fprintf(stderr, "Invalid data returned from decompression\n"); return 1; } } } } return 0; } libzorpll-3.9.4.1/tests/test_conns.c000066400000000000000000000022711224546767600174110ustar00rootroot00000000000000#include #include #include #include GMainLoop *loop; gint counter = 0; static void test_done(void) { counter++; if (counter == 2) g_main_quit(loop); } static gboolean test_accepted(ZStream *stream G_GNUC_UNUSED, ZSockAddr *client, ZSockAddr *dest, gpointer user_data G_GNUC_UNUSED) { printf("Connection accepted\n"); z_sockaddr_unref(client); z_sockaddr_unref(dest); test_done(); return TRUE; } static void test_connected(ZStream *fdstream G_GNUC_UNUSED, GError *error G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { printf("Connected\n"); test_done(); } int main(void) { ZSockAddr *a; ZListener *l; ZConnector *c; ZSockAddr *dest; loop = g_main_loop_new(NULL, TRUE); a = z_sockaddr_unix_new("sock"); l = z_stream_listener_new("sessionid", a, 0, 255, test_accepted, NULL); g_return_val_if_fail(z_listener_start(l), 254); c = z_stream_connector_new("sessionid", NULL, a, 0, test_connected, NULL, NULL); z_connector_start(c, &dest); while (g_main_loop_is_running(loop)) { g_main_context_iteration(NULL, TRUE); } z_listener_unref(l); z_connector_unref(c); return 0; } libzorpll-3.9.4.1/tests/test_pktbuf.c000066400000000000000000000030651224546767600175660ustar00rootroot00000000000000#include #include #include static void test_pktbuf_split(void) { const char data[] = "first.last"; const gsize at = 5; ZPktBuf *buf, *newbuf; buf = z_pktbuf_new(); z_pktbuf_copy(buf, data, sizeof(data)); newbuf = z_pktbuf_split(buf, at); g_assert_cmpint(z_pktbuf_length(buf), ==, 5); /* "first", without terminating 0 */ g_assert(memcmp(buf->data, "first", z_pktbuf_length(buf)) == 0); g_assert_cmpint(z_pktbuf_length(newbuf), ==, 6); /* ".last", with terminating 0 */ g_assert(memcmp(newbuf->data, ".last", z_pktbuf_length(newbuf)) == 0); z_pktbuf_unref(buf); z_pktbuf_unref(newbuf); } static void test_pktbuf_append_pktbuf(void) { ZPktBuf *buf, *other; buf = z_pktbuf_new(); other = z_pktbuf_new(); z_pktbuf_put_string(other, "qwerty"); z_pktbuf_append_pktbuf(buf, other); g_assert(z_pktbuf_length(buf) == 6); g_assert(memcmp(buf->data, "qwerty", z_pktbuf_length(buf)) == 0); other = z_pktbuf_new(); z_pktbuf_append_pktbuf(buf, other); g_assert(z_pktbuf_length(buf) == 6); g_assert(memcmp(buf->data, "qwerty", z_pktbuf_length(buf)) == 0); other = z_pktbuf_new(); z_pktbuf_put_string(other, "qwerty"); z_pktbuf_append_pktbuf(buf, other); g_assert(z_pktbuf_length(buf) == 12); g_assert(memcmp(buf->data, "qwertyqwerty", z_pktbuf_length(buf)) == 0); } int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func("/pktbuf/split", test_pktbuf_split); g_test_add_func("/pktbuf/append_pktbuf", test_pktbuf_append_pktbuf); g_test_run(); return 0; } libzorpll-3.9.4.1/tests/test_random.c000066400000000000000000000010301224546767600175410ustar00rootroot00000000000000#include #include #define ROUNDS 1000 int main(void) { guchar buf[64]; guint i, j; for (i = 0; i < ROUNDS; i++) { z_random_sequence_get_bounded(Z_RANDOM_STRONG, buf, sizeof(buf), 'A', 'Z'); for (j = 0; j < sizeof(buf); j++) { if (buf[j] < 'A' || buf[j] > 'Z') { fprintf(stderr, "Invalid character in bounded random data: %02x [%c]\n", (guint) buf[j], buf[j]); return 1; } } } return 0; } libzorpll-3.9.4.1/tests/test_readline.c000066400000000000000000000061371224546767600200610ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include const gchar *expected_outputs[] = { "1", "2", "3", "01234567", "012345678", //truncates "9abc" "abc", "abcdef", "012345678", //truncates 90123456789012345678" "abcdef", "012345678", "abcdef" }; int main(void) { ZStream *input; int pair[2], status = 0; pid_t pid; gchar *line; gsize length; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { perror("socketpair()"); return 254; } pid = fork(); if (pid < 0) { perror("fork()"); return 254; } else if (pid != 0) { close(pair[1]); g_return_val_if_fail(write(pair[0], "1\n2\n3\n", 6) == 6, 253); g_return_val_if_fail(write(pair[0], "0123", 4) == 4, 253); g_return_val_if_fail(write(pair[0], "4567\n", 5) == 5, 253); g_return_val_if_fail(write(pair[0], "0123456789", 10) == 10, 253); g_return_val_if_fail(write(pair[0], "abc\nAabc\nabcdef\n", 16) == 16, 253); /* Because of truncate A will be eliminated */ g_return_val_if_fail(write(pair[0], "0123456789", 10) == 10, 253); g_return_val_if_fail(write(pair[0], "0123456789", 10) == 10, 253); g_return_val_if_fail(write(pair[0], "012345678\nAabcdef\n", 18) == 18, 253); /* Because of truncate A will be eliminated */ g_return_val_if_fail(write(pair[0], "012345678\nAabcdef", 17) == 17, 253); close(pair[0]); waitpid(pid, &status, 0); } else { gint rc; guint i; printf("%d\n", getpid()); sleep(1); close(pair[0]); input = z_stream_fd_new(pair[1], "sockpair input"); input = z_stream_line_new(input, 10, ZRL_EOL_NL | ZRL_TRUNCATE); i = 0; if (!z_stream_unget(input, "A", 1, NULL)) { printf("Error on unget\n"); _exit(1); } rc = z_stream_line_get(input, &line, &length, NULL); while (rc == G_IO_STATUS_NORMAL) { if (i >= (sizeof(expected_outputs) / sizeof(gchar *)) || line[0] != 'A' || strlen(expected_outputs[i]) != length - 1 || memcmp(expected_outputs[i], line + 1, length - 1) != 0) { printf("Error checking line: [%.*s] (length: %"G_GSIZE_FORMAT"), should be: %s\n", (int) length - 1, line + 1, length - 1, expected_outputs[i]); _exit(1); } else { printf("line ok: %.*s\n", (int) length, line); } if (!z_stream_unget(input, "A", 1, NULL)) { printf("Error on unget\n"); _exit(1); } rc = z_stream_line_get(input, &line, &length, NULL); i++; } if (i < (sizeof(expected_outputs) / sizeof(gchar *))) { printf("Missing output %u of %"G_GSIZE_FORMAT"\n", i, (sizeof(expected_outputs) / sizeof(gchar *))); _exit(1); } close(pair[1]); _exit(0); } return status >> 8; } libzorpll-3.9.4.1/tests/test_registry.c000066400000000000000000000012531224546767600201400ustar00rootroot00000000000000#include #include int main(void) { int i; char buf[128]; z_registry_init(); for (i = 0; i < 10; i++) { snprintf(buf, sizeof(buf), "key%d", i); z_registry_add(buf, ZR_PROXY, GINT_TO_POINTER(i)); } for (i = 0; i < 10; i++) { gint res; gint type = 0; snprintf(buf, sizeof(buf), "key%d", i); res = GPOINTER_TO_UINT(z_registry_get(buf, &type)); if (res != i) { printf("problem.\n"); return 1; } if (type != ZR_PROXY) { printf("problem 2.\n"); return 1; } } z_registry_destroy(); return 0; } libzorpll-3.9.4.1/tests/test_sockaddr.c000066400000000000000000000023111224546767600200560ustar00rootroot00000000000000#include #include #include #define test_assert(res) \ if (!(res)) \ { \ fprintf(stderr, "Test assertion failed at %d\n", __LINE__); \ exit(1); \ } int main(void) { ZSockAddr *a, *b; struct sockaddr_in s_sin; struct sockaddr_un s_sun; /* AF_INET */ a = z_sockaddr_inet_new("1.2.3.4", 5555); memset(&s_sin, 0xaa, sizeof(s_sin)); s_sin.sin_family = AF_INET; z_inet_aton("1.2.3.4", &s_sin.sin_addr); s_sin.sin_port = htons(5555); b = z_sockaddr_new((struct sockaddr *) &s_sin, sizeof(s_sin)); test_assert(z_sockaddr_equal(a, b) == TRUE); z_sockaddr_unref(a); z_sockaddr_unref(b); /* AF_UNIX */ a = z_sockaddr_unix_new("abcdef"); memset(&s_sun, 0xaa, sizeof(s_sun)); s_sun.sun_family = AF_UNIX; strncpy(s_sun.sun_path, "abcdef", sizeof(s_sun.sun_path)); b = z_sockaddr_new((struct sockaddr *) &s_sun, sizeof(s_sun)); test_assert(z_sockaddr_equal(a, b) == TRUE); z_sockaddr_unref(a); z_sockaddr_unref(b); return 0; } libzorpll-3.9.4.1/tests/test_ssl.c000066400000000000000000000041411224546767600170700ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include gchar testcert[512]; gchar testkey[512]; gint test_server(gint fd) { ZStream *stream; ZSSLSession *ssl_session; gsize bw, br; gchar buf[512]; ssl_session = z_ssl_session_new("server/ssl", Z_SSL_MODE_SERVER, testkey, testcert, NULL, NULL, 9, Z_SSL_VERIFY_NONE); g_return_val_if_fail(ssl_session, 1); stream = z_stream_fd_new(fd, "server"); stream = z_stream_push(stream, z_stream_ssl_new(NULL, ssl_session)); SSL_accept(ssl_session->ssl); z_stream_write(stream, "helloka", 7, &bw, NULL); z_stream_read(stream, buf, sizeof(buf), &br, NULL); printf("%.*s", (int)br, buf); if (memcmp(buf, "haliho", br) == 0) return 0; return 1; } gint test_client(gint fd) { ZStream *stream; ZSSLSession *ssl_session; gchar buf[512]; gsize bw, br; ssl_session = z_ssl_session_new("client/ssl", Z_SSL_MODE_CLIENT, NULL, NULL, NULL, NULL, 9, Z_SSL_VERIFY_NONE); g_return_val_if_fail(ssl_session, 1); stream = z_stream_fd_new(fd, "client"); stream = z_stream_push(stream, z_stream_ssl_new(NULL, ssl_session)); SSL_connect(ssl_session->ssl); z_stream_write(stream, "haliho", 6, &bw, NULL); z_stream_read(stream, buf, sizeof(buf), &br, NULL); printf("%.*s", (int)br, buf); if (memcmp(buf, "helloka", br) == 0) return 0; return 1; } int main(void) { gint fds[2], rc, status; gchar *srcdir = getenv("srcdir"); z_ssl_init(); g_snprintf(testcert, sizeof(testcert), "%s/testx509.crt", srcdir); g_snprintf(testkey, sizeof(testkey), "%s/testx509.key", srcdir); if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); return 1; } if (fork() != 0) { close(fds[1]); return test_server(fds[0]); } else { close(fds[0]); rc = test_client(fds[1]); wait(&status); if (status) rc = 1; } return rc; } libzorpll-3.9.4.1/tests/test_streams.c000066400000000000000000000155011224546767600177470ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include int test_stream_unget(void) { ZStream *stream; gchar *buf = "12345678901234567890"; gchar testbuf[20]; gint fds[2], i; gsize br; gint res = 0; if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); return 1; } if (write(fds[1], "hoppala", 7) < 0) { perror("write"); res = 1; } close(fds[1]); stream = z_stream_fd_new(fds[0], "stdin"); z_stream_unget(stream, buf, strlen(buf), NULL); for (i = 0; i < (int)sizeof(testbuf); i++) { if (z_stream_read(stream, &testbuf[i], 1, &br, NULL) != G_IO_STATUS_NORMAL) { perror("z_stream_read"); res = 1; } else if (testbuf[i] != buf[i]) { fprintf(stderr, "Invalid data read\n"); res = 1; } } if (z_stream_read(stream, testbuf, sizeof(testbuf), &br, NULL) != G_IO_STATUS_NORMAL) { perror("z_stream_read2"); } if (memcmp(testbuf, "hoppala", 7) != 0) { fprintf(stderr, "Invalid data read\n"); res = 1; } z_stream_close(stream, NULL); z_stream_unref(stream); return res; } int test_streambuf(void) { ZStream *stream; gint fds[2]; ZPoll *poll; gsize bw; gint res = 1, i; if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); return 1; } poll = z_poll_new(); stream = z_stream_buf_new(z_stream_fd_new(fds[0], "fdstream"), 4096, 0); z_poll_add_stream(poll, stream); /* generate lots of messages */ for (i = 0; i < 1000; i++) { if (z_stream_write(stream, "ABCDEF", 6, &bw, NULL) != G_IO_STATUS_NORMAL) { fprintf(stderr, "z_stream_buf_write returned non-normal status\n"); goto exit; } } i = 0; while (z_poll_iter_timeout(poll, 100) && i < 1000) { i++; } z_stream_shutdown(stream, SHUT_RDWR, NULL); for (i = 0; i < 1000; i++) { gchar buf[16]; if (read(fds[1], buf, 6) < 0) { perror("read"); goto exit; } if (memcmp(buf, "ABCDEF", 6) != 0) { fprintf(stderr, "comparison mismatch; buf=[%.*s]\n", 6, buf); goto exit; } } res = 0; exit: z_stream_close(stream, NULL); z_stream_unref(stream); close(fds[1]); return res; } int test_streamline(void) { ZStream *stream; gint fds[2]; gint res = 1; gchar *line; gsize length; if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); return 1; } stream = z_stream_line_new(z_stream_fd_new(fds[0], "fdstream"), 4096, ZRL_RETURN_EOL); g_return_val_if_fail(write(fds[1], "abcdef\r\n", 8) == 8, 1); if (z_stream_line_get(stream, &line, &length, NULL) != G_IO_STATUS_NORMAL) { fprintf(stderr, "z_stream_line_get returned non-normal status\n"); goto exit; } if (strncmp(line, "abcdef\r\n", 8) != 0) { fprintf(stderr, "comparison mismatch, line='%*.s'", (int)length, line); goto exit; } res = 0; exit: z_stream_close(stream, NULL); z_stream_unref(stream); close(fds[1]); return res; } int test_streamgzip_with_headers(void) { ZStream *stream, *fdstream; gint fds[2]; gint res = 1; gchar contents[32]; gsize length; gchar compressed_file[] = "\x1f\x8b\x08\x1c\x0c\x4f\xc9\x43\x00\x03" "\x05\x00" "extra" /* extra field, 2 byte length field in little-endian */ "abcdef\x00" /* original filename, NUL terminated */ "comment\x00" /* comment, NUL terminated */ "\x4b\x4c\x4a\x4e\x49\x4d\x03\x00\xef\x39\x8e\x4b\x06\x00\x00" "\x00"; time_t ts; gchar *origname; gchar *comment; gchar *extra; gint extra_len; if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); return 1; } fdstream = z_stream_fd_new(fds[0], "fdstream"); g_return_val_if_fail(write(fds[1], compressed_file, sizeof(compressed_file)) == sizeof(compressed_file), 1); stream = z_stream_gzip_new(fdstream, Z_SGZ_GZIP_HEADER, 6, 32768); if (!z_stream_gzip_fetch_header(stream, NULL)) { fprintf(stderr, "z_stream_gzip_fetch_header returned error\n"); goto exit; } z_stream_gzip_get_header_fields(stream, &ts, &origname, &comment, &extra_len, &extra); if (extra_len != 5 || strncmp(extra, "extra", strlen("extra")) != 0) { fprintf(stderr, "extra mismatch %.*s\n", extra_len, extra); goto exit; } if (strcmp(origname, "abcdef") != 0) { fprintf(stderr, "Original filename mismatch %s\n", origname); goto exit; } if (strcmp(comment, "comment") != 0) { fprintf(stderr, "Comment mismatch\n"); goto exit; } if (z_stream_read(stream, contents, sizeof(contents), &length, NULL) != G_IO_STATUS_NORMAL) { fprintf(stderr, "z_stream_read returned non-normal status\n"); goto exit; } if (length != 6 || strncmp(contents, "abcdef", 6) != 0) { fprintf(stderr, "comparison mismatch, content='%.*s'", (int)length, contents); goto exit; } res = 0; exit: z_stream_close(stream, NULL); z_stream_unref(stream); close(fds[1]); return res; } int test_streamgzip_no_headers(void) { ZStream *stream, *fdstream; gint fds[2]; gint res = 1; gchar contents[32]; gsize length; gchar compressed_file[] = "x\x9cKLJNIM\x03\x00\x08\x1e\x02V"; if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); return 1; } fdstream = z_stream_fd_new(fds[0], "fdstream"); g_return_val_if_fail(write(fds[1], compressed_file, sizeof(compressed_file)) == sizeof(compressed_file), 1); stream = z_stream_gzip_new(fdstream, 0, 6, 32768); if (!z_stream_gzip_fetch_header(stream, NULL)) { fprintf(stderr, "z_stream_gzip_fetch_header returned error\n"); goto exit; } if (z_stream_read(stream, contents, sizeof(contents), &length, NULL) != G_IO_STATUS_NORMAL) { fprintf(stderr, "z_stream_read returned non-normal status\n"); goto exit; } if (length != 6 || strncmp(contents, "abcdef", 6) != 0) { fprintf(stderr, "comparison mismatch, content='%.*s'", (int)length, contents); goto exit; } res = 0; exit: z_stream_close(stream, NULL); z_stream_unref(stream); close(fds[1]); return res; } int main(void) { gint res; res = test_stream_unget(); if (res == 0) res = test_streambuf(); if (res == 0) res = test_streamline(); if (res == 0) res = test_streamgzip_with_headers(); if (res == 0) res = test_streamgzip_no_headers(); return res; } libzorpll-3.9.4.1/tests/test_valid_chars.c000066400000000000000000000024541224546767600205530ustar00rootroot00000000000000#include #include typedef struct _Tests { gchar *valid_chars; gchar *teststring; gboolean expected_result; } Tests; static struct _Tests testcases[] = { {"a-z", "appletree", TRUE}, {"a-z", "AppleTree", FALSE}, {"a-zA-Z0-9._@\\\\", "appletree", TRUE}, {"a-zA-Z0-9._@\\\\", "AppleTree", TRUE}, {"a-zA-Z0-9._@\\\\", "Apple\\Tree", TRUE}, {NULL, NULL, FALSE}}; gboolean z_charset_test(gchar *valid, gchar *test, gboolean *result) { ZCharSet charset; z_charset_init(&charset); if (!z_charset_parse(&charset, valid)) { printf("problem in parsing valid chars: %s.\n", valid); return FALSE; } *result = z_charset_is_string_valid(&charset, test, -1); return TRUE; } int main(void) { guint i; int ret = 0; printf("Test valid chars\n"); for (i = 0; testcases[i].valid_chars != NULL; i++) { gboolean result; if (z_charset_test(testcases[i].valid_chars, testcases[i].teststring, &result)) { if (result != testcases[i].expected_result) { printf("Failed\n"); ret = 1; } else { printf("PASS\n"); } } else { printf("Failed\n"); ret = 1; } } return ret; } libzorpll-3.9.4.1/tests/testx509.crt000066400000000000000000000014721224546767600172070ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICNTCCAZ4CAQIwDQYJKoZIhvcNAQEEBQAwYjELMAkGA1UEBhMCSFUxETAPBgNV BAcTCEJ1ZGFwZXN0MRgwFgYDVQQKEw9CYWxhQml0IElUIEx0ZC4xJjAkBgNVBAMT HVRydXN0ZWQgSW50ZXJuZXQgQ2VydGlmaWNhdGVzMB4XDTA0MDkxNjEyMjcyM1oX DTA0MDkxODEyMjcyM1owZDELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0 MRcwFQYDVQQKEw5CYWxhQml0IElUIEx0ZDERMA8GA1UECxMIaW50cmFuZXQxFjAU BgNVBAMTDXd3d2h1LmJhbGFiaXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB AK62iH4tQ6wsaUPHpFuJTpD4v4OaNH0EUpfch8qpbUB9SiZE7qFYMzOKQ5jfRVs3 0NS+dXghwSraxAfoZkXxWMXlyJANPqXMXzpGCcwbf0/pwL81//yYe8YkC27Le+2z T4AyFVZy7RCj4G4Cwsx0Vnmife47gGevSrdiGEgLLQ+7AgMBAAEwDQYJKoZIhvcN AQEEBQADgYEALBYONWgvOLg0WGtbKg4C/E2wJQcd9flBnc+zfHoGeIdqnT45gxah oko00oEfSmtefnixE8onysKUFX6F/sFbn4xSj0LDq4FjSmPvOWEJrGaOBRmNtvjs 33zFKFUaB/iN6SUrUB/zEqkSxAB5FIyRXPaHwvxDH6Xl+7T2E5dYi1I= -----END CERTIFICATE----- libzorpll-3.9.4.1/tests/testx509.key000066400000000000000000000015731224546767600172110ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQCutoh+LUOsLGlDx6RbiU6Q+L+DmjR9BFKX3IfKqW1AfUomRO6h WDMzikOY30VbN9DUvnV4IcEq2sQH6GZF8VjF5ciQDT6lzF86RgnMG39P6cC/Nf/8 mHvGJAtuy3vts0+AMhVWcu0Qo+BuAsLMdFZ5on3uO4Bnr0q3YhhICy0PuwIDAQAB AoGAM2wEBmcaKN21ab6j0FE8b4zXCUvksPsJuCqvSOXPAxEdNuBI//Hut/e055Sn XC60ZzlbZ60/pnZXBiDPoTxkrPXzpwsFv+AcTHiGmH8lAd1tvW/jcjhGP0T3vVkN veV0QYTugJlyEsvXnYobd1fSxqMFg2B2JXnpkAFMtNfz6IkCQQDTpXum9guba/Nu sQgBqSXqzhB7TEGxgSOqkefv3c1smdPwGNaT1g5YjvGvquHtDmssouqvDKo9+2S1 M2r7R/SNAkEA01Ogx6KWKI9pcXHjpsbLj6fiZsJoQywQoLFbbAbvKvuaOAg87do7 71AIsOKfsrfx7bzhredFn7iLALWWYYUXZwJBAKSA3GKCnbT5LCYeTaXUzlb6Qc9E D0+jm5BJhihnkvLVgej9tVMFLvNgb7RlsuMpsN3p51WWF4DDtJwu0flsDUUCQQCY FDfBUx0SpVoxfM9ihu+ZOy0v3DniFUUGD3yGOltFqHksV6lZVlMJfqQyf3SDzeJ5 vxL97lBpiAnogcVt+rSDAkEAr8v9mNQblwxC/BaJf/OT52Pn4CmjX+pjnli+HMiN 5WIVpXe1+wo5+i+++Z3Lff6WzUrZx4w0/zGo2YzHzFm9sw== -----END RSA PRIVATE KEY----- libzorpll-3.9.4.1/tests/zcrypt.c000066400000000000000000000011761224546767600165700ustar00rootroot00000000000000#include #include #include void testcase(char *pw, char *salt, char *expected) { char result[128]; z_crypt(pw, salt, result, sizeof(result)); if (strcmp(result, expected) != 0) exit(1); } int main(void) { testcase("titkos", "$1$abcdef$", "$1$abcdef$tViuCKijOibTb1mxJ.nuL1"); testcase("titkos", "$1$abc$", "$1$abc$.CtgYDt9Kysbluq2wuHVL0"); testcase("titkos", "$1$abc$", "$1$abc$.CtgYDt9Kysbluq2wuHVL0"); testcase("titkos", "$1$01234567$", "$1$01234567$8.GchdyyhO1de8.vYREOZ1"); testcase("titkos", "$1$0123456789$", "$1$01234567$8.GchdyyhO1de8.vYREOZ1"); return 0; } libzorpll-3.9.4.1/zorplibll.pc.in000066400000000000000000000004571224546767600166720ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: Zorpll Description: Low level Zorp Library Requires: glib-2.0 gthread-2.0 gobject-2.0 Version: @ZORPLIBLL_VERSION@ Libs: -L${libdir} -lzorpll @OPENSSL_LIBS@ Cflags: -D_GNU_SOURCE -I${includedir} @OPENSSL_CPPFLAGS@