dovecot-2.3.21.1/ 0000755 0000000 0000000 00000000000 14656633642 010367 5 0000000 0000000 dovecot-2.3.21.1/dovecot-version.h 0000644 0000000 0000000 00000000347 14656633633 013612 0000000 0000000 #ifndef DOVECOT_VERSION_H
#define DOVECOT_VERSION_H
#define DOVECOT_REVISION "d492236fa0"
#define DOVECOT_VERSION_FULL VERSION" ("DOVECOT_REVISION")"
#define DOVECOT_BUILD_INFO DOVECOT_VERSION_FULL
#endif /* DOVECOT_VERSION_H */
dovecot-2.3.21.1/COPYING 0000644 0000000 0000000 00000007576 14656633576 011367 0000000 0000000 See AUTHORS file for list of copyright holders.
Everything in src/lib/, src/auth/, and src/lib-sql/ is under MIT license
(see COPYING.MIT) unless otherwise mentioned at the beginning of the file.
Everything else is LGPLv2.1 (see COPYING.LGPL) unless otherwise mentioned
at the beginning of the file.
Current exceptions are:
src/lib/md5.c : Public Domain
src/lib/sha1.c and sha2.c:
Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
Copyright (C) 2005, 2007 Olivier Gay
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
src/lib/UnicodeData.txt:
Copyright (C) 1991-2007 Unicode, Inc. All rights reserved. Distributed
under the Terms of Use in http://www.unicode.org/copyright.html.
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Unicode data files and any associated documentation (the "Data
Files") or Unicode software and any associated documentation (the
"Software") to deal in the Data Files or Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, and/or sell copies of the Data Files or Software, and
to permit persons to whom the Data Files or Software are furnished to do
so, provided that (a) the above copyright notice(s) and this permission
notice appear with all copies of the Data Files or Software, (b) both the
above copyright notice(s) and this permission notice appear in associated
documentation, and (c) there is clear notice in each modified Data File or
in the Software as well as in the documentation associated with the Data
File(s) or Software that the data or software has been modified.
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR
CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder shall
not be used in advertising or otherwise to promote the sale, use or other
dealings in these Data Files or Software without prior written
authorization of the copyright holder.
dovecot-2.3.21.1/README 0000644 0000000 0000000 00000011570 14656633635 011175 0000000 0000000 Installation
See INSTALL.md file.
Configuration
See doc/documentation.txt or http://wiki2.dovecot.org/
RFCs conformed
email
- RFC822 - Standard for ARPA Internet Text Messages
- RFC2822 - Internet Message Format (updated RFC822)
- RFC2045 - Multipurpose Internet Mail Extensions (MIME) (part 1)
- RFC2046 - Multipurpose Internet Mail Extensions (MIME) (part 2)
- RFC2047 - Multipurpose Internet Mail Extensions (MIME) (part 3)
- RFC2048 - Multipurpose Internet Mail Extensions (MIME) (part 4)
- RFC2049 - Multipurpose Internet Mail Extensions (MIME) (part 5)
Auth
- RFC2245 - Anonymous SASL Mechanism.
- RFC2595 - Using TLS with IMAP, POP3 and ACAP
- RFC2831 - Using Digest Authentication as a SASL Mechanism
(DIGEST-MD5)
- RFC5802 - Salted Challenge Response Authentication Mechanism (SCRAM)
- SASL and GSS-API Mechanisms
- RFC7628 - A Set of Simple Authentication and Security Layer (SASL)
Mechanisms for OAuth
- Google XOAUTH2 protocol
POP3
- RFC1939 - Post Office Protocol - Version 3
- RFC2449 - POP3 Extension Mechanism
- RFC2595 - Using TLS with IMAP, POP3 and ACAP
- RFC3206 - The SYS and AUTH POP Response Codes
- RFC5034 - The Post Office Protocol (POP3) - Simple Authentication
and Security Layer (SASL) Authentication Mechanism
IMAP base
- RFC3501 - IMAP4rev1
- RFC2180 - IMAP4 Multi-Accessed Mailbox Practice
- RFC2595 - Using TLS with IMAP, POP3 and ACAP
- RFC2683 - IMAP4 Implementation Recommendations
IMAP extensions
- RFC2087 - IMAP4 QUOTA extension
- RFC2088 - IMAP4 non-synchronizing literals (LITERAL+)
- RFC2177 - IMAP4 IDLE command
- RFC2221 - IMAP4 Login Referrals
- RFC2342 - IMAP4 Namespace
- RFC2971 - IMAP4 ID extension
- RFC3348 - IMAP4 Child Mailbox Extension
- RFC3502 - IMAP4 MULTIAPPEND Extension
- RFC3516 - IMAP4 Binary Content Extension
- RFC3691 - IMAP4 UNSELECT command
- RFC4314 - IMAP4 Access Control List (ACL) Extension
- RFC4315 - IMAP UIDPLUS extension
- RFC4467 - IMAP URLAUTH Extension
- RFC4469 - IMAP CATENATE Extension
- RFC4551 - IMAP Extension for Conditional STORE Operation or Quick
Flag Changes Resynchronization
- RFC4731 - IMAP4 Extension to SEARCH Command for Controlling What
Kind of Information Is Returned
- RFC4959 - IMAP Extension for Simple Authentication and Security
Layer (SASL) Initial Client Response
- RFC4978 - The IMAP COMPRESS Extension
- RFC5032 - WITHIN Search Extension to the IMAP Protocol
- RFC5161 - The IMAP ENABLE Extension
- RFC5162 - IMAP4 Extensions for Quick Mailbox Resynchronization
- RFC5182 - IMAP Extension for Referencing the Last SEARCH Result
- RFC5255 - IMAP Internationalization (I18NLEVEL=1 only)
- RFC5256 - IMAP SORT and THREAD Extensions
- RFC5258 - IMAP4 - LIST Command Extensions
- RFC5267 - Contexts for IMAP4 (ESORT and CONTEXT=SEARCH only)
- RFC5464 - The IMAP METADATA Extension
- RFC5465 - The IMAP NOTIFY Extension
- RFC5524 - Extended URLFETCH for Binary and Converted Parts
- RFC5530 - IMAP Response Codes
- RFC5819 - IMAP4 Extension for Returning STATUS Information in
Extended LIST
- RFC5957 - Display-Based Address Sorting for the IMAP4 SORT Extension
- RFC6154 - IMAP LIST Extension for Special-Use Mailboxes (SPECIAL-USE
only)
- RFC6203 - IMAP4 Extension for Fuzzy Search
- RFC6785 - Support for IMAP Events in Sieve (via Pigeonhole plugin)
- RFC6851 - Internet Message Access Protocol (IMAP) - MOVE Extension
- RFC7162 - IMAP Extensions: Quick Flag Changes Resynchronization
(CONDSTORE) and Quick Mailbox Resynchronization (QRESYNC) (updated
RFC4551 and RFC5162)
- RFC7888 - IMAP4 Non-synchronizing Literals (updated RFC2088)
- RFC8457 - IMAP "$Important" Keyword and "\Important" Special-Use
Attribute
- RFC8970 - IMAP4 Extension: Message Preview Generation
SMTP/LMTP base
- RFC821 - Simple Mail Transfer Protocol
- RFC2821 - Simple Mail Transfer Protocol (updated RFC821)
- RFC5321 - Simple Mail Transfer Protocol (updated RFC2821)
- RFC2033 - Local Mail Transfer Protocol
- RFC6409 - Message Submission for Mail
SMTP/LMTP extensions
- RFC1870 - SMTP Service Extension for Message Size Declaration
- RFC2034 - SMTP Service Extension for Returning Enhanced Error Codes
- RFC2920 - SMTP Service Extension for Command Pipelining
- RFC3030 - SMTP Service Extensions for Transmission of Large and
Binary MIME Messages
- RFC3207 - SMTP Service Extension for Secure SMTP over Transport
Layer Security
- RFC4468 - Message Submission BURL Extension
- RFC4954 - SMTP Service Extension for Authentication
- RFC6152 - SMTP Service Extension for 8-bit MIME Transport
Contact info
Timo Sirainen tss@iki.fi, http://www.dovecot.org/
Please use the Dovecot mailing list dovecot@dovecot.org for questions
about Dovecot. You can post to the list without subscribing, the mail
then waits in a moderator queue for a while. See
http://dovecot.org/mailinglists.html
dovecot-2.3.21.1/install-sh 0000755 0000000 0000000 00000035776 14656633607 012336 0000000 0000000 #!/bin/sh
# install - install a program, script, or datafile
scriptversion=2020-11-14.01; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
# Create dirs (including intermediate dirs) using mode 755.
# This is like GNU 'install' as of coreutils 8.32 (2020).
mkdir_umask=22
backupsuffix=
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-p pass -p to $cpprog.
-s $stripprog installed files.
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
By default, rm is invoked with -f; when overridden with RMPROG,
it's up to you to specify -f if you want it.
If -S is not specified, no backups are attempted.
Email bug reports to bug-automake@gnu.org.
Automake home page: https://www.gnu.org/software/automake/
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-p) cpprog="$cpprog -p";;
-s) stripcmd=$stripprog;;
-S) backupsuffix="$2"
shift;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
# Don't chown directories that already exist.
if test $dstdir_status = 0; then
chowncmd=""
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dstbase=`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
# The $RANDOM variable is not portable (e.g., dash). Use it
# here however when possible just to lower collision chance.
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap '
ret=$?
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
exit $ret
' 0
# Because "mkdir -p" follows existing symlinks and we likely work
# directly in world-writeable /tmp, make sure that the '$tmpdir'
# directory is successfully created first before we actually test
# 'mkdir -p'.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
trap '' 0;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_
rmtmp=${dstdirslash}_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask &&
{ test -z "$stripcmd" || {
# Create $dsttmp read-write so that cp doesn't create it read-only,
# which would cause strip to fail.
if test -z "$doit"; then
: >"$dsttmp" # No need to fork-exec 'touch'.
else
$doit touch "$dsttmp"
fi
}
} &&
$doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# If $backupsuffix is set, and the file being installed
# already exists, attempt a backup. Don't worry if it fails,
# e.g., if mv doesn't support -f.
if test -n "$backupsuffix" && test -f "$dst"; then
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
fi
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
dovecot-2.3.21.1/src/ 0000755 0000000 0000000 00000000000 14656633641 011155 5 0000000 0000000 dovecot-2.3.21.1/src/old-stats/ 0000755 0000000 0000000 00000000000 14656633641 013067 5 0000000 0000000 dovecot-2.3.21.1/src/old-stats/mail-command.h 0000644 0000000 0000000 00000000727 14656633576 015533 0000000 0000000 #ifndef MAIL_COMMAND_H
#define MAIL_COMMAND_H
struct mail_command;
extern struct mail_command *stable_mail_commands_head;
extern struct mail_command *stable_mail_commands_tail;
int mail_command_update_parse(const char *const *args, const char **error_r);
void mail_command_ref(struct mail_command *cmd);
void mail_command_unref(struct mail_command **cmd);
void mail_commands_free_memory(void);
void mail_commands_init(void);
void mail_commands_deinit(void);
#endif
dovecot-2.3.21.1/src/old-stats/client-export.c 0000644 0000000 0000000 00000043665 14656633576 015775 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "net.h"
#include "ostream.h"
#include "str.h"
#include "strescape.h"
#include "wildcard-match.h"
#include "mail-stats.h"
#include "mail-command.h"
#include "mail-session.h"
#include "mail-user.h"
#include "mail-domain.h"
#include "mail-ip.h"
#include "client.h"
#include "client-export.h"
enum mail_export_level {
MAIL_EXPORT_LEVEL_COMMAND,
MAIL_EXPORT_LEVEL_SESSION,
MAIL_EXPORT_LEVEL_USER,
MAIL_EXPORT_LEVEL_DOMAIN,
MAIL_EXPORT_LEVEL_IP,
MAIL_EXPORT_LEVEL_GLOBAL
};
static const char *mail_export_level_names[] = {
"command", "session", "user", "domain", "ip", "global"
};
struct mail_export_filter {
const char *user, *domain, *session;
struct ip_addr ip;
unsigned int ip_bits;
time_t since;
bool connected;
};
struct client_export_cmd {
enum mail_export_level level;
struct mail_export_filter filter;
string_t *str;
int (*export_iter)(struct client *client);
bool header_sent;
};
static int
mail_export_level_parse(const char *str, enum mail_export_level *level_r)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(mail_export_level_names); i++) {
if (strcmp(mail_export_level_names[i], str) == 0) {
*level_r = (enum mail_export_level)i;
return 0;
}
}
return -1;
}
static int
mail_export_parse_filter(const char *const *args, pool_t pool,
struct mail_export_filter *filter_r,
const char **error_r)
{
unsigned long l;
/* filters:
user= | domain= | session=
ip=[/]
since=
connected
*/
i_zero(filter_r);
for (; *args != NULL; args++) {
if (str_begins(*args, "user="))
filter_r->user = p_strdup(pool, *args + 5);
else if (str_begins(*args, "domain="))
filter_r->domain = p_strdup(pool, *args + 7);
else if (str_begins(*args, "session="))
filter_r->session = p_strdup(pool, *args + 8);
else if (str_begins(*args, "ip=")) {
if (net_parse_range(*args + 3, &filter_r->ip,
&filter_r->ip_bits) < 0) {
*error_r = "Invalid ip filter";
return -1;
}
} else if (str_begins(*args, "since=")) {
if (str_to_ulong(*args + 6, &l) < 0) {
*error_r = "Invalid since filter";
return -1;
}
filter_r->since = (time_t)l;
} else if (strcmp(*args, "connected") == 0) {
filter_r->connected = TRUE;
}
}
return 0;
}
static void
client_export_stats_headers(struct client *client)
{
unsigned int i, count = stats_field_count();
string_t *str = t_str_new(128);
i_assert(count > 0);
str_append(str, stats_field_name(0));
for (i = 1; i < count; i++) {
str_append_c(str, '\t');
str_append(str, stats_field_name(i));
}
str_append_c(str, '\n');
o_stream_nsend(client->output, str_data(str), str_len(str));
}
static void
client_export_stats(string_t *str, const struct stats *stats)
{
unsigned int i, count = stats_field_count();
i_assert(count > 0);
stats_field_value(str, stats, 0);
for (i = 1; i < count; i++) {
str_append_c(str, '\t');
stats_field_value(str, stats, i);
}
}
static bool
mail_export_filter_match_session(const struct mail_export_filter *filter,
const struct mail_session *session)
{
if (filter->connected && session->disconnected)
return FALSE;
if (filter->since > session->last_update.tv_sec)
return FALSE;
if (filter->session != NULL &&
strcmp(session->id, filter->session) != 0)
return FALSE;
if (filter->user != NULL &&
!wildcard_match(session->user->name, filter->user))
return FALSE;
if (filter->domain != NULL &&
!wildcard_match(session->user->domain->name, filter->domain))
return FALSE;
if (filter->ip_bits > 0 &&
!net_is_in_network(&session->ip->ip, &filter->ip, filter->ip_bits))
return FALSE;
return TRUE;
}
static bool
mail_export_filter_match_user_common(const struct mail_export_filter *filter,
const struct mail_user *user)
{
struct mail_session *s;
bool connected = FALSE, ip_ok = FALSE;
if (filter->user != NULL &&
!wildcard_match(user->name, filter->user))
return FALSE;
if (filter->connected || filter->ip_bits > 0) {
for (s = user->sessions; s != NULL; s = s->user_next) {
if (!s->disconnected)
connected = TRUE;
if (filter->ip_bits > 0 &&
net_is_in_network(&s->ip->ip, &filter->ip,
filter->ip_bits))
ip_ok = TRUE;
}
if (filter->connected && !connected)
return FALSE;
if (filter->ip_bits > 0 && !ip_ok)
return FALSE;
}
return TRUE;
}
static bool
mail_export_filter_match_user(const struct mail_export_filter *filter,
const struct mail_user *user)
{
if (filter->since > user->last_update.tv_sec)
return FALSE;
if (filter->domain != NULL &&
!wildcard_match(user->domain->name, filter->domain))
return FALSE;
return mail_export_filter_match_user_common(filter, user);
}
static bool
mail_export_filter_match_domain(const struct mail_export_filter *filter,
const struct mail_domain *domain)
{
struct mail_user *user;
if (filter->since > domain->last_update.tv_sec)
return FALSE;
if (filter->domain != NULL &&
!wildcard_match(domain->name, filter->domain))
return FALSE;
if (filter->user != NULL || filter->connected || filter->ip_bits > 0) {
for (user = domain->users; user != NULL; user = user->domain_next) {
if (mail_export_filter_match_user_common(filter, user))
break;
}
if (user == NULL)
return FALSE;
}
return TRUE;
}
static bool
mail_export_filter_match_ip(const struct mail_export_filter *filter,
const struct mail_ip *ip)
{
struct mail_session *s;
bool connected = FALSE, user_ok = FALSE, domain_ok = FALSE;
if (filter->connected || filter->ip_bits > 0) {
for (s = ip->sessions; s != NULL; s = s->ip_next) {
if (!s->disconnected)
connected = TRUE;
if (filter->user != NULL &&
wildcard_match(s->user->name, filter->user))
user_ok = TRUE;
if (filter->domain != NULL &&
wildcard_match(s->user->domain->name, filter->domain))
domain_ok = TRUE;
}
if (filter->connected && !connected)
return FALSE;
if (filter->user != NULL && !user_ok)
return FALSE;
if (filter->domain != NULL && !domain_ok)
return FALSE;
}
if (filter->since > ip->last_update.tv_sec)
return FALSE;
if (filter->ip_bits > 0 &&
!net_is_in_network(&ip->ip, &filter->ip, filter->ip_bits))
return FALSE;
return TRUE;
}
static void client_export_timeval(string_t *str, const struct timeval *tv)
{
str_printfa(str, "\t%ld.%06u", (long)tv->tv_sec,
(unsigned int)tv->tv_usec);
}
static int client_export_iter_command(struct client *client)
{
struct client_export_cmd *cmd = client->cmd_export;
struct mail_command *command = client->mail_cmd_iter;
i_assert(cmd->level == MAIL_EXPORT_LEVEL_COMMAND);
mail_command_unref(&client->mail_cmd_iter);
if (!cmd->header_sent) {
o_stream_nsend_str(client->output,
"cmd\targs\tsession\tuser\tlast_update\t");
client_export_stats_headers(client);
cmd->header_sent = TRUE;
}
for (; command != NULL; command = command->stable_next) {
if (client_is_busy(client))
break;
if (!mail_export_filter_match_session(&cmd->filter,
command->session))
continue;
str_truncate(cmd->str, 0);
str_append_tabescaped(cmd->str, command->name);
str_append_c(cmd->str, '\t');
str_append_tabescaped(cmd->str, command->args);
str_append_c(cmd->str, '\t');
str_append(cmd->str, command->session->id);
str_append_c(cmd->str, '\t');
str_append_tabescaped(cmd->str,
command->session->user->name);
client_export_timeval(cmd->str, &command->last_update);
str_append_c(cmd->str, '\t');
client_export_stats(cmd->str, command->stats);
str_append_c(cmd->str, '\n');
o_stream_nsend(client->output, str_data(cmd->str),
str_len(cmd->str));
}
if (command != NULL) {
client->mail_cmd_iter = command;
mail_command_ref(command);
return 0;
}
return 1;
}
static int client_export_iter_session(struct client *client)
{
struct client_export_cmd *cmd = client->cmd_export;
struct mail_session *session = client->mail_session_iter;
i_assert(cmd->level == MAIL_EXPORT_LEVEL_SESSION);
mail_session_unref(&client->mail_session_iter);
if (!cmd->header_sent) {
o_stream_nsend_str(client->output,
"session\tuser\tip\tservice\tpid\tconnected"
"\tlast_update\tnum_cmds\t");
client_export_stats_headers(client);
cmd->header_sent = TRUE;
}
for (; session != NULL; session = session->stable_next) {
if (client_is_busy(client))
break;
if (!mail_export_filter_match_session(&cmd->filter, session))
continue;
str_truncate(cmd->str, 0);
str_append(cmd->str, session->id);
str_append_c(cmd->str, '\t');
str_append_tabescaped(cmd->str, session->user->name);
str_append_c(cmd->str, '\t');
if (session->ip != NULL) T_BEGIN {
str_append(cmd->str, net_ip2addr(&session->ip->ip));
} T_END;
str_append_c(cmd->str, '\t');
str_append_tabescaped(cmd->str, session->service);
str_printfa(cmd->str, "\t%ld", (long)session->pid);
str_printfa(cmd->str, "\t%d", !session->disconnected);
client_export_timeval(cmd->str, &session->last_update);
str_printfa(cmd->str, "\t%u\t", session->num_cmds);
client_export_stats(cmd->str, session->stats);
str_append_c(cmd->str, '\n');
o_stream_nsend(client->output, str_data(cmd->str),
str_len(cmd->str));
}
if (session != NULL) {
client->mail_session_iter = session;
mail_session_ref(session);
return 0;
}
return 1;
}
static int client_export_iter_user(struct client *client)
{
struct client_export_cmd *cmd = client->cmd_export;
struct mail_user *user = client->mail_user_iter;
i_assert(cmd->level == MAIL_EXPORT_LEVEL_USER);
mail_user_unref(&client->mail_user_iter);
if (!cmd->header_sent) {
o_stream_nsend_str(client->output,
"user\treset_timestamp\tlast_update"
"\tnum_logins\tnum_cmds\t");
client_export_stats_headers(client);
cmd->header_sent = TRUE;
}
for (; user != NULL; user = user->stable_next) {
if (client_is_busy(client))
break;
if (!mail_export_filter_match_user(&cmd->filter, user))
continue;
str_truncate(cmd->str, 0);
str_append_tabescaped(cmd->str, user->name);
str_printfa(cmd->str, "\t%ld", (long)user->reset_timestamp);
client_export_timeval(cmd->str, &user->last_update);
str_printfa(cmd->str, "\t%u\t%u\t",
user->num_logins, user->num_cmds);
client_export_stats(cmd->str, user->stats);
str_append_c(cmd->str, '\n');
o_stream_nsend(client->output, str_data(cmd->str),
str_len(cmd->str));
}
if (user != NULL) {
client->mail_user_iter = user;
mail_user_ref(user);
return 0;
}
return 1;
}
static int client_export_iter_domain(struct client *client)
{
struct client_export_cmd *cmd = client->cmd_export;
struct mail_domain *domain = client->mail_domain_iter;
i_assert(cmd->level == MAIL_EXPORT_LEVEL_DOMAIN);
mail_domain_unref(&client->mail_domain_iter);
if (!cmd->header_sent) {
o_stream_nsend_str(client->output,
"domain\treset_timestamp\tlast_update"
"\tnum_logins\tnum_cmds\tnum_connected_sessions\t");
client_export_stats_headers(client);
cmd->header_sent = TRUE;
}
for (; domain != NULL; domain = domain->stable_next) {
if (client_is_busy(client))
break;
if (!mail_export_filter_match_domain(&cmd->filter, domain))
continue;
str_truncate(cmd->str, 0);
str_append_tabescaped(cmd->str, domain->name);
str_printfa(cmd->str, "\t%ld", (long)domain->reset_timestamp);
client_export_timeval(cmd->str, &domain->last_update);
str_printfa(cmd->str, "\t%u\t%u\t%u\t",
domain->num_logins, domain->num_cmds,
domain->num_connected_sessions);
client_export_stats(cmd->str, domain->stats);
str_append_c(cmd->str, '\n');
o_stream_nsend(client->output, str_data(cmd->str),
str_len(cmd->str));
}
if (domain != NULL) {
client->mail_domain_iter = domain;
mail_domain_ref(domain);
return 0;
}
return 1;
}
static int client_export_iter_ip(struct client *client)
{
struct client_export_cmd *cmd = client->cmd_export;
struct mail_ip *ip = client->mail_ip_iter;
i_assert(cmd->level == MAIL_EXPORT_LEVEL_IP);
mail_ip_unref(&client->mail_ip_iter);
if (!cmd->header_sent) {
o_stream_nsend_str(client->output,
"ip\treset_timestamp\tlast_update"
"\tnum_logins\tnum_cmds\tnum_connected_sessions\t");
client_export_stats_headers(client);
cmd->header_sent = TRUE;
}
for (; ip != NULL; ip = ip->stable_next) {
if (client_is_busy(client))
break;
if (!mail_export_filter_match_ip(&cmd->filter, ip))
continue;
str_truncate(cmd->str, 0);
T_BEGIN {
str_append(cmd->str, net_ip2addr(&ip->ip));
} T_END;
str_printfa(cmd->str, "\t%ld", (long)ip->reset_timestamp);
client_export_timeval(cmd->str, &ip->last_update);
str_printfa(cmd->str, "\t%u\t%u\t%u\t",
ip->num_logins, ip->num_cmds, ip->num_connected_sessions);
client_export_stats(cmd->str, ip->stats);
str_append_c(cmd->str, '\n');
o_stream_nsend(client->output, str_data(cmd->str),
str_len(cmd->str));
}
if (ip != NULL) {
client->mail_ip_iter = ip;
mail_ip_ref(ip);
return 0;
}
return 1;
}
static int client_export_iter_global(struct client *client)
{
struct client_export_cmd *cmd = client->cmd_export;
struct mail_global *g = &mail_global_stats;
i_assert(cmd->level == MAIL_EXPORT_LEVEL_GLOBAL);
if (!cmd->header_sent) {
o_stream_nsend_str(client->output,
"reset_timestamp\tlast_update"
"\tnum_logins\tnum_cmds\tnum_connected_sessions\t");
client_export_stats_headers(client);
cmd->header_sent = TRUE;
}
str_truncate(cmd->str, 0);
str_printfa(cmd->str, "%ld", (long)g->reset_timestamp);
client_export_timeval(cmd->str, &g->last_update);
str_printfa(cmd->str, "\t%u\t%u\t%u\t",
g->num_logins, g->num_cmds, g->num_connected_sessions);
client_export_stats(cmd->str, g->stats);
str_append_c(cmd->str, '\n');
o_stream_nsend(client->output, str_data(cmd->str),
str_len(cmd->str));
return 1;
}
static int client_export_more(struct client *client)
{
if (client->cmd_export->export_iter(client) == 0)
return 0;
o_stream_nsend_str(client->output, "\n");
return 1;
}
static bool client_export_iter_init(struct client *client)
{
struct client_export_cmd *cmd = client->cmd_export;
if (cmd->filter.user != NULL && strchr(cmd->filter.user, '*') == NULL &&
(cmd->level == MAIL_EXPORT_LEVEL_USER ||
cmd->level == MAIL_EXPORT_LEVEL_SESSION)) {
/* exact user */
struct mail_user *user = mail_user_lookup(cmd->filter.user);
if (user == NULL)
return FALSE;
if (cmd->level == MAIL_EXPORT_LEVEL_SESSION) {
client->mail_session_iter = user->sessions;
if (client->mail_session_iter == NULL)
return FALSE;
mail_session_ref(client->mail_session_iter);
cmd->export_iter = client_export_iter_session;
} else {
client->mail_user_iter = user;
mail_user_ref(user);
cmd->export_iter = client_export_iter_user;
}
return TRUE;
}
if (cmd->filter.ip_bits == IPADDR_BITS(&cmd->filter.ip) &&
(cmd->level == MAIL_EXPORT_LEVEL_IP ||
cmd->level == MAIL_EXPORT_LEVEL_SESSION)) {
/* exact IP address */
struct mail_ip *ip = mail_ip_lookup(&cmd->filter.ip);
if (ip == NULL)
return FALSE;
if (cmd->level == MAIL_EXPORT_LEVEL_SESSION) {
client->mail_session_iter = ip->sessions;
if (client->mail_session_iter == NULL)
return FALSE;
mail_session_ref(client->mail_session_iter);
cmd->export_iter = client_export_iter_session;
} else {
client->mail_ip_iter = ip;
mail_ip_ref(ip);
cmd->export_iter = client_export_iter_ip;
}
return TRUE;
}
if (cmd->filter.domain != NULL &&
strchr(cmd->filter.domain, '*') == NULL &&
(cmd->level == MAIL_EXPORT_LEVEL_DOMAIN ||
cmd->level == MAIL_EXPORT_LEVEL_USER)) {
/* exact domain */
struct mail_domain *domain =
mail_domain_lookup(cmd->filter.domain);
if (domain == NULL)
return FALSE;
if (cmd->level == MAIL_EXPORT_LEVEL_USER) {
client->mail_user_iter = domain->users;
mail_user_ref(client->mail_user_iter);
cmd->export_iter = client_export_iter_user;
} else {
client->mail_domain_iter = domain;
mail_domain_ref(domain);
cmd->export_iter = client_export_iter_domain;
}
return TRUE;
}
switch (cmd->level) {
case MAIL_EXPORT_LEVEL_COMMAND:
client->mail_cmd_iter = stable_mail_commands_head;
if (client->mail_cmd_iter == NULL)
return FALSE;
mail_command_ref(client->mail_cmd_iter);
cmd->export_iter = client_export_iter_command;
break;
case MAIL_EXPORT_LEVEL_SESSION:
client->mail_session_iter = stable_mail_sessions;
if (client->mail_session_iter == NULL)
return FALSE;
mail_session_ref(client->mail_session_iter);
cmd->export_iter = client_export_iter_session;
break;
case MAIL_EXPORT_LEVEL_USER:
client->mail_user_iter = stable_mail_users;
if (client->mail_user_iter == NULL)
return FALSE;
mail_user_ref(client->mail_user_iter);
cmd->export_iter = client_export_iter_user;
break;
case MAIL_EXPORT_LEVEL_DOMAIN:
client->mail_domain_iter = stable_mail_domains;
if (client->mail_domain_iter == NULL)
return FALSE;
mail_domain_ref(client->mail_domain_iter);
cmd->export_iter = client_export_iter_domain;
break;
case MAIL_EXPORT_LEVEL_IP:
client->mail_ip_iter = stable_mail_ips;
if (client->mail_ip_iter == NULL)
return FALSE;
mail_ip_ref(client->mail_ip_iter);
cmd->export_iter = client_export_iter_ip;
break;
case MAIL_EXPORT_LEVEL_GLOBAL:
cmd->export_iter = client_export_iter_global;
break;
}
i_assert(cmd->export_iter != NULL);
return TRUE;
}
int client_export(struct client *client, const char *const *args,
const char **error_r)
{
const char *level_str = args[0];
struct client_export_cmd *cmd;
p_clear(client->cmd_pool);
cmd = p_new(client->cmd_pool, struct client_export_cmd, 1);
cmd->str = str_new(client->cmd_pool, 256);
if (level_str == NULL) {
*error_r = "Missing level parameter";
return -1;
}
if (mail_export_level_parse(level_str, &cmd->level) < 0) {
*error_r = "Invalid level";
return -1;
}
if (mail_export_parse_filter(args + 1, client->cmd_pool,
&cmd->filter, error_r) < 0)
return -1;
client->cmd_export = cmd;
if (!client_export_iter_init(client)) {
/* nothing to export */
o_stream_nsend_str(client->output, "\n");
return 1;
}
client->cmd_more = client_export_more;
return client_export_more(client);
}
dovecot-2.3.21.1/src/old-stats/mail-stats.h 0000644 0000000 0000000 00000005075 14656633576 015254 0000000 0000000 #ifndef MAIL_STATS_H
#define MAIL_STATS_H
#include
#include "net.h"
#include "guid.h"
#include "stats.h"
struct stats_send_ctx;
struct mail_command {
struct mail_command *stable_prev, *stable_next;
struct mail_command *session_prev, *session_next;
struct mail_session *session;
char *name, *args;
/* non-zero id means the command is still running */
unsigned int id;
struct timeval last_update;
struct stats *stats;
int refcount;
};
struct mail_session {
struct mail_session *stable_prev, *stable_next;
struct mail_session *sorted_prev, *sorted_next;
struct mail_session *user_prev, *user_next;
struct mail_session *ip_prev, *ip_next;
/* if id="", the session no longer exists */
char *id;
struct mail_user *user;
const char *service;
pid_t pid;
/* ip address may be NULL if there's none */
struct mail_ip *ip;
struct timeout *to_idle;
struct stats *stats;
struct timeval last_update;
unsigned int num_cmds;
bool disconnected;
unsigned int highest_cmd_id;
int refcount;
struct mail_command *commands;
};
struct mail_user {
struct mail_user *stable_prev, *stable_next;
struct mail_user *sorted_prev, *sorted_next;
struct mail_user *domain_prev, *domain_next;
char *name;
struct mail_domain *domain;
time_t reset_timestamp;
struct timeval last_update;
struct stats *stats;
unsigned int num_logins;
unsigned int num_cmds;
int refcount;
struct mail_session *sessions;
};
struct mail_domain {
struct mail_domain *stable_prev, *stable_next;
struct mail_domain *sorted_prev, *sorted_next;
char *name;
time_t reset_timestamp;
struct timeval last_update;
struct stats *stats;
unsigned int num_logins;
unsigned int num_cmds;
unsigned int num_connected_sessions;
int refcount;
struct mail_user *users;
};
struct mail_ip {
struct mail_ip *stable_prev, *stable_next;
struct mail_ip *sorted_prev, *sorted_next;
struct ip_addr ip;
time_t reset_timestamp;
struct timeval last_update;
struct stats *stats;
unsigned int num_logins;
unsigned int num_cmds;
unsigned int num_connected_sessions;
int refcount;
struct mail_session *sessions;
};
struct mail_global {
time_t reset_timestamp;
struct timeval last_update;
struct stats *stats;
unsigned int num_logins;
unsigned int num_cmds;
unsigned int num_connected_sessions;
struct timeout *to_stats_send;
struct stats_send_ctx *stats_send_ctx;
};
extern struct mail_global mail_global_stats;
void mail_global_init(void);
void mail_global_deinit(void);
void mail_global_login(void);
void mail_global_disconnected(void);
void mail_global_refresh(const struct stats *diff_stats);
#endif
dovecot-2.3.21.1/src/old-stats/stats-carbon.h 0000644 0000000 0000000 00000000423 14656633576 015566 0000000 0000000 #ifndef STATS_CARBON
#define STATS_CARBON 1
struct stats_send_ctx;
int
stats_carbon_send(const char *endpoint, const char *data,
void (*callback)(void *), void *cb_ctx,
struct stats_send_ctx **ctx_r);
void
stats_carbon_destroy(struct stats_send_ctx **ctx);
#endif
dovecot-2.3.21.1/src/old-stats/mail-command.c 0000644 0000000 0000000 00000013623 14656633576 015525 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "base64.h"
#include "ioloop.h"
#include "llist.h"
#include "global-memory.h"
#include "stats-settings.h"
#include "mail-stats.h"
#include "mail-session.h"
#include "mail-command.h"
#define MAIL_COMMAND_TIMEOUT_SECS (60*15)
/* commands are sorted by their last_update timestamp, oldest first */
struct mail_command *stable_mail_commands_head;
struct mail_command *stable_mail_commands_tail;
static size_t mail_command_memsize(const struct mail_command *cmd)
{
return sizeof(*cmd) + strlen(cmd->name) + 1 + strlen(cmd->args) + 1;
}
static struct mail_command *
mail_command_find(struct mail_session *session, unsigned int id)
{
struct mail_command *cmd;
i_assert(id != 0);
if (id > session->highest_cmd_id) {
/* fast path for new commands */
return NULL;
}
for (cmd = session->commands; cmd != NULL; cmd = cmd->session_next) {
if (cmd->id == id)
return cmd;
}
/* expired */
return NULL;
}
static struct mail_command *
mail_command_add(struct mail_session *session, const char *name,
const char *args)
{
struct mail_command *cmd;
cmd = i_malloc(MALLOC_ADD(sizeof(struct mail_command), stats_alloc_size()));
cmd->stats = (void *)(cmd + 1);
cmd->refcount = 1; /* unrefed at "done" */
cmd->session = session;
cmd->name = i_strdup(name);
cmd->args = i_strdup(args);
cmd->last_update = ioloop_timeval;
DLLIST2_APPEND_FULL(&stable_mail_commands_head,
&stable_mail_commands_tail, cmd,
stable_prev, stable_next);
DLLIST_PREPEND_FULL(&session->commands, cmd,
session_prev, session_next);
mail_session_ref(cmd->session);
global_memory_alloc(mail_command_memsize(cmd));
return cmd;
}
static void mail_command_free(struct mail_command *cmd)
{
i_assert(cmd->refcount == 0);
global_memory_free(mail_command_memsize(cmd));
DLLIST2_REMOVE_FULL(&stable_mail_commands_head,
&stable_mail_commands_tail, cmd,
stable_prev, stable_next);
DLLIST_REMOVE_FULL(&cmd->session->commands, cmd,
session_prev, session_next);
mail_session_unref(&cmd->session);
i_free(cmd->name);
i_free(cmd->args);
i_free(cmd);
}
void mail_command_ref(struct mail_command *cmd)
{
cmd->refcount++;
}
void mail_command_unref(struct mail_command **_cmd)
{
struct mail_command *cmd = *_cmd;
i_assert(cmd->refcount > 0);
cmd->refcount--;
*_cmd = NULL;
}
int mail_command_update_parse(const char *const *args, const char **error_r)
{
struct mail_session *session;
struct mail_command *cmd;
struct stats *new_stats, *diff_stats;
buffer_t *buf;
const char *error;
unsigned int i, cmd_id;
bool done = FALSE, continued = FALSE;
/* [d]
c[d] */
if (str_array_length(args) < 3) {
*error_r = "UPDATE-CMD: Too few parameters";
return -1;
}
if (mail_session_get(args[0], &session, error_r) < 0)
return -1;
if (str_to_uint(args[1], &cmd_id) < 0 || cmd_id == 0) {
*error_r = "UPDATE-CMD: Invalid command id";
return -1;
}
for (i = 0; args[2][i] != '\0'; i++) {
switch (args[2][i]) {
case 'd':
done = TRUE;
break;
case 'c':
continued = TRUE;
break;
default:
*error_r = "UPDATE-CMD: Invalid flags parameter";
return -1;
}
}
cmd = mail_command_find(session, cmd_id);
if (!continued) {
/* new command */
if (cmd != NULL) {
*error_r = "UPDATE-CMD: Duplicate new command id";
return -1;
}
if (str_array_length(args) < 5) {
*error_r = "UPDATE-CMD: Too few parameters";
return -1;
}
cmd = mail_command_add(session, args[3], args[4]);
cmd->id = cmd_id;
session->highest_cmd_id =
I_MAX(session->highest_cmd_id, cmd_id);
session->num_cmds++;
session->user->num_cmds++;
session->user->domain->num_cmds++;
if (session->ip != NULL)
session->ip->num_cmds++;
mail_global_stats.num_cmds++;
args += 5;
} else {
if (cmd == NULL) {
/* already expired command, ignore */
i_warning("UPDATE-CMD: Already expired");
return 0;
}
args += 3;
cmd->last_update = ioloop_timeval;
}
buf = t_buffer_create(256);
if (args[0] == NULL ||
base64_decode(args[0], strlen(args[0]), NULL, buf) < 0) {
*error_r = t_strdup_printf("UPDATE-CMD: Invalid base64 input");
return -1;
}
new_stats = stats_alloc(pool_datastack_create());
diff_stats = stats_alloc(pool_datastack_create());
if (!stats_import(buf->data, buf->used, cmd->stats, new_stats, &error)) {
*error_r = t_strdup_printf("UPDATE-CMD: %s", error);
return -1;
}
if (!stats_diff(cmd->stats, new_stats, diff_stats, &error)) {
*error_r = t_strdup_printf("UPDATE-CMD: stats shrank: %s", error);
return -1;
}
stats_add(cmd->stats, diff_stats);
if (done) {
cmd->id = 0;
mail_command_unref(&cmd);
}
mail_session_refresh(session, NULL);
return 0;
}
static bool mail_command_is_timed_out(struct mail_command *cmd)
{
/* some commands like IDLE can run forever */
return ioloop_time - cmd->last_update.tv_sec >
MAIL_COMMAND_TIMEOUT_SECS;
}
void mail_commands_free_memory(void)
{
unsigned int diff;
while (stable_mail_commands_head != NULL) {
struct mail_command *cmd = stable_mail_commands_head;
if (cmd->refcount == 0)
i_assert(cmd->id == 0);
else if (cmd->refcount == 1 &&
(cmd->session->disconnected ||
mail_command_is_timed_out(cmd))) {
/* session was probably lost */
mail_command_unref(&cmd);
} else {
break;
}
mail_command_free(stable_mail_commands_head);
if (global_used_memory < stats_settings->memory_limit ||
stable_mail_commands_head == NULL)
break;
diff = ioloop_time - stable_mail_commands_head->last_update.tv_sec;
if (diff < stats_settings->command_min_time)
break;
}
}
void mail_commands_init(void)
{
}
void mail_commands_deinit(void)
{
while (stable_mail_commands_head != NULL) {
struct mail_command *cmd = stable_mail_commands_head;
if (cmd->id != 0)
mail_command_unref(&cmd);
mail_command_free(stable_mail_commands_head);
}
}
dovecot-2.3.21.1/src/old-stats/Makefile.in 0000644 0000000 0000000 00000070675 14656633611 015070 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = old-stats$(EXEEXT)
subdir = src/old-stats
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_old_stats_OBJECTS = client.$(OBJEXT) client-export.$(OBJEXT) \
client-reset.$(OBJEXT) fifo-input-connection.$(OBJEXT) \
global-memory.$(OBJEXT) mail-command.$(OBJEXT) \
mail-domain.$(OBJEXT) mail-ip.$(OBJEXT) mail-session.$(OBJEXT) \
mail-stats.$(OBJEXT) mail-user.$(OBJEXT) main.$(OBJEXT) \
stats-carbon.$(OBJEXT) stats-settings.$(OBJEXT)
old_stats_OBJECTS = $(am_old_stats_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/client-export.Po \
./$(DEPDIR)/client-reset.Po ./$(DEPDIR)/client.Po \
./$(DEPDIR)/fifo-input-connection.Po \
./$(DEPDIR)/global-memory.Po ./$(DEPDIR)/mail-command.Po \
./$(DEPDIR)/mail-domain.Po ./$(DEPDIR)/mail-ip.Po \
./$(DEPDIR)/mail-session.Po ./$(DEPDIR)/mail-stats.Po \
./$(DEPDIR)/mail-user.Po ./$(DEPDIR)/main.Po \
./$(DEPDIR)/stats-carbon.Po ./$(DEPDIR)/stats-settings.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(old_stats_SOURCES)
DIST_SOURCES = $(old_stats_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(noinst_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
old_stats_moduledir = $(moduledir)/old-stats
AM_CPPFLAGS = \
-DSTATS_MODULE_DIR=\""$(old_stats_moduledir)"\" \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-old-stats \
$(BINARY_CFLAGS)
old_stats_LDADD = $(LIBDOVECOT) \
$(BINARY_LDFLAGS)
old_stats_DEPENDENCIES = $(LIBDOVECOT_DEPS)
old_stats_SOURCES = \
client.c \
client-export.c \
client-reset.c \
fifo-input-connection.c \
global-memory.c \
mail-command.c \
mail-domain.c \
mail-ip.c \
mail-session.c \
mail-stats.c \
mail-user.c \
main.c \
stats-carbon.c \
stats-settings.c
noinst_HEADERS = \
client.h \
client-export.h \
client-reset.h \
fifo-input-connection.h \
global-memory.h \
mail-command.h \
mail-domain.h \
mail-ip.h \
mail-session.h \
mail-stats.h \
mail-user.h \
stats-carbon.h \
stats-settings.h
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/old-stats/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/old-stats/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
old-stats$(EXEEXT): $(old_stats_OBJECTS) $(old_stats_DEPENDENCIES) $(EXTRA_old_stats_DEPENDENCIES)
@rm -f old-stats$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(old_stats_OBJECTS) $(old_stats_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-export.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-reset.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fifo-input-connection.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global-memory.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-command.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-domain.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-ip.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-session.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-stats.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-user.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-carbon.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-settings.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/client-export.Po
-rm -f ./$(DEPDIR)/client-reset.Po
-rm -f ./$(DEPDIR)/client.Po
-rm -f ./$(DEPDIR)/fifo-input-connection.Po
-rm -f ./$(DEPDIR)/global-memory.Po
-rm -f ./$(DEPDIR)/mail-command.Po
-rm -f ./$(DEPDIR)/mail-domain.Po
-rm -f ./$(DEPDIR)/mail-ip.Po
-rm -f ./$(DEPDIR)/mail-session.Po
-rm -f ./$(DEPDIR)/mail-stats.Po
-rm -f ./$(DEPDIR)/mail-user.Po
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/stats-carbon.Po
-rm -f ./$(DEPDIR)/stats-settings.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/client-export.Po
-rm -f ./$(DEPDIR)/client-reset.Po
-rm -f ./$(DEPDIR)/client.Po
-rm -f ./$(DEPDIR)/fifo-input-connection.Po
-rm -f ./$(DEPDIR)/global-memory.Po
-rm -f ./$(DEPDIR)/mail-command.Po
-rm -f ./$(DEPDIR)/mail-domain.Po
-rm -f ./$(DEPDIR)/mail-ip.Po
-rm -f ./$(DEPDIR)/mail-session.Po
-rm -f ./$(DEPDIR)/mail-stats.Po
-rm -f ./$(DEPDIR)/mail-user.Po
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/stats-carbon.Po
-rm -f ./$(DEPDIR)/stats-settings.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-pkglibexecPROGRAMS install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/old-stats/fifo-input-connection.c 0000644 0000000 0000000 00000005103 14656633576 017376 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "llist.h"
#include "strescape.h"
#include "istream.h"
#include "ostream.h"
#include "master-service.h"
#include "mail-session.h"
#include "mail-user.h"
#include "mail-command.h"
#include "fifo-input-connection.h"
#include
#define MAX_INBUF_SIZE (PIPE_BUF*2)
struct fifo_input_connection {
struct fifo_input_connection *prev, *next;
int fd;
struct istream *input;
struct io *io;
};
static struct fifo_input_connection *fifo_conns = NULL;
static int
fifo_input_connection_request(const char *const *args, const char **error_r)
{
const char *cmd = args[0];
if (cmd == NULL) {
*error_r = "Missing command";
return -1;
}
args++;
if (strcmp(cmd, "CONNECT") == 0)
return mail_session_connect_parse(args, error_r);
if (strcmp(cmd, "DISCONNECT") == 0)
return mail_session_disconnect_parse(args, error_r);
if (strcmp(cmd, "UPDATE-SESSION") == 0)
return mail_session_update_parse(args, error_r);
if (strcmp(cmd, "ADD-USER") == 0)
return mail_user_add_parse(args, error_r);
if (strcmp(cmd, "UPDATE-CMD") == 0)
return mail_command_update_parse(args, error_r);
*error_r = "Unknown command";
return -1;
}
static void fifo_input_connection_input(struct fifo_input_connection *conn)
{
const char *line, *const *args, *error;
switch (i_stream_read(conn->input)) {
case -2:
i_error("BUG: Mail server sent too much data");
fifo_input_connection_destroy(&conn);
return;
case -1:
fifo_input_connection_destroy(&conn);
return;
}
while ((line = i_stream_next_line(conn->input)) != NULL) T_BEGIN {
args = t_strsplit_tabescaped(line);
if (fifo_input_connection_request(args, &error) < 0)
i_error("FIFO input error: %s", error);
} T_END;
}
struct fifo_input_connection *fifo_input_connection_create(int fd)
{
struct fifo_input_connection *conn;
conn = i_new(struct fifo_input_connection, 1);
conn->fd = fd;
conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
conn->io = io_add(fd, IO_READ, fifo_input_connection_input, conn);
DLLIST_PREPEND(&fifo_conns, conn);
return conn;
}
void fifo_input_connection_destroy(struct fifo_input_connection **_conn)
{
struct fifo_input_connection *conn = *_conn;
*_conn = NULL;
DLLIST_REMOVE(&fifo_conns, conn);
io_remove(&conn->io);
i_stream_destroy(&conn->input);
if (close(conn->fd) < 0)
i_error("close(conn) failed: %m");
i_free(conn);
}
void fifo_input_connections_destroy_all(void)
{
while (fifo_conns != NULL) {
struct fifo_input_connection *conn = fifo_conns;
fifo_input_connection_destroy(&conn);
}
}
dovecot-2.3.21.1/src/old-stats/mail-user.h 0000644 0000000 0000000 00000001176 14656633576 015072 0000000 0000000 #ifndef MAIL_USER_H
#define MAIL_USER_H
struct stats;
extern struct mail_user *stable_mail_users;
struct mail_user *mail_user_login(const char *username);
void mail_user_disconnected(struct mail_user *user);
struct mail_user *mail_user_lookup(const char *username);
void mail_user_refresh(struct mail_user *user,
const struct stats *diff_stats) ATTR_NULL(2);
int mail_user_add_parse(const char *const *args, const char **error_r);
void mail_user_ref(struct mail_user *user);
void mail_user_unref(struct mail_user **user);
void mail_users_free_memory(void);
void mail_users_init(void);
void mail_users_deinit(void);
#endif
dovecot-2.3.21.1/src/old-stats/client-reset.h 0000644 0000000 0000000 00000000250 14656633576 015562 0000000 0000000 #ifndef CLIENT_RESET_H
#define CLIENT_RESET_H
struct client;
int client_stats_reset(struct client *client, const char *const *args,
const char **error_r);
#endif
dovecot-2.3.21.1/src/old-stats/mail-ip.h 0000644 0000000 0000000 00000001002 14656633576 014510 0000000 0000000 #ifndef MAIL_IP_H
#define MAIL_IP_H
extern struct mail_ip *stable_mail_ips;
struct mail_ip *mail_ip_login(const struct ip_addr *ip_addr);
void mail_ip_disconnected(struct mail_ip *ip);
struct mail_ip *mail_ip_lookup(const struct ip_addr *ip_addr);
void mail_ip_refresh(struct mail_ip *ip, const struct stats *diff_stats)
ATTR_NULL(2);
void mail_ip_ref(struct mail_ip *ip);
void mail_ip_unref(struct mail_ip **ip);
void mail_ips_free_memory(void);
void mail_ips_init(void);
void mail_ips_deinit(void);
#endif
dovecot-2.3.21.1/src/old-stats/mail-ip.c 0000644 0000000 0000000 00000006033 14656633576 014514 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "hash.h"
#include "llist.h"
#include "global-memory.h"
#include "stats-settings.h"
#include "mail-stats.h"
#include "mail-ip.h"
static HASH_TABLE(struct ip_addr *, struct mail_ip *) mail_ips_hash;
/* ips are sorted by their last_update timestamp, oldest first */
static struct mail_ip *mail_ips_head, *mail_ips_tail;
struct mail_ip *stable_mail_ips;
static size_t mail_ip_memsize(const struct mail_ip *ip)
{
return sizeof(*ip);
}
struct mail_ip *mail_ip_login(const struct ip_addr *ip_addr)
{
struct mail_ip *ip;
ip = hash_table_lookup(mail_ips_hash, ip_addr);
if (ip != NULL) {
ip->num_logins++;
ip->num_connected_sessions++;
mail_ip_refresh(ip, NULL);
return ip;
}
ip = i_malloc(MALLOC_ADD(sizeof(struct mail_ip), stats_alloc_size()));
ip->stats = (void *)(ip + 1);
ip->ip = *ip_addr;
ip->reset_timestamp = ioloop_time;
hash_table_insert(mail_ips_hash, &ip->ip, ip);
DLLIST_PREPEND_FULL(&stable_mail_ips, ip, stable_prev, stable_next);
DLLIST2_APPEND_FULL(&mail_ips_head, &mail_ips_tail, ip,
sorted_prev, sorted_next);
ip->num_logins++;
ip->num_connected_sessions++;
ip->last_update = ioloop_timeval;
global_memory_alloc(mail_ip_memsize(ip));
return ip;
}
void mail_ip_disconnected(struct mail_ip *ip)
{
i_assert(ip->num_connected_sessions > 0);
ip->num_connected_sessions--;
}
struct mail_ip *mail_ip_lookup(const struct ip_addr *ip_addr)
{
return hash_table_lookup(mail_ips_hash, ip_addr);
}
void mail_ip_ref(struct mail_ip *ip)
{
ip->refcount++;
}
void mail_ip_unref(struct mail_ip **_ip)
{
struct mail_ip *ip = *_ip;
i_assert(ip->refcount > 0);
ip->refcount--;
*_ip = NULL;
}
static void mail_ip_free(struct mail_ip *ip)
{
i_assert(ip->refcount == 0);
i_assert(ip->sessions == NULL);
global_memory_free(mail_ip_memsize(ip));
hash_table_remove(mail_ips_hash, &ip->ip);
DLLIST_REMOVE_FULL(&stable_mail_ips, ip, stable_prev, stable_next);
DLLIST2_REMOVE_FULL(&mail_ips_head, &mail_ips_tail, ip,
sorted_prev, sorted_next);
i_free(ip);
}
void mail_ip_refresh(struct mail_ip *ip, const struct stats *diff_stats)
{
if (diff_stats != NULL)
stats_add(ip->stats, diff_stats);
ip->last_update = ioloop_timeval;
DLLIST2_REMOVE_FULL(&mail_ips_head, &mail_ips_tail, ip,
sorted_prev, sorted_next);
DLLIST2_APPEND_FULL(&mail_ips_head, &mail_ips_tail, ip,
sorted_prev, sorted_next);
}
void mail_ips_free_memory(void)
{
unsigned int diff;
while (mail_ips_head != NULL && mail_ips_head->refcount == 0) {
mail_ip_free(mail_ips_head);
if (global_used_memory < stats_settings->memory_limit ||
mail_ips_head == NULL)
break;
diff = ioloop_time - mail_ips_head->last_update.tv_sec;
if (diff < stats_settings->ip_min_time)
break;
}
}
void mail_ips_init(void)
{
hash_table_create(&mail_ips_hash, default_pool, 0,
net_ip_hash, net_ip_cmp);
}
void mail_ips_deinit(void)
{
while (mail_ips_head != NULL)
mail_ip_free(mail_ips_head);
hash_table_destroy(&mail_ips_hash);
}
dovecot-2.3.21.1/src/old-stats/client.h 0000644 0000000 0000000 00000001506 14656633576 014447 0000000 0000000 #ifndef CLIENT_H
#define CLIENT_H
struct client {
struct client *prev, *next;
int fd;
struct io *io;
struct istream *input;
struct ostream *output;
struct timeout *to_pending;
pool_t cmd_pool;
struct client_export_cmd *cmd_export;
int (*cmd_more)(struct client *client);
/* command iterators. while non-NULL, they've increased the
struct's refcount so it won't be deleted during iteration */
unsigned int iter_count;
struct mail_command *mail_cmd_iter;
struct mail_session *mail_session_iter;
struct mail_user *mail_user_iter;
struct mail_domain *mail_domain_iter;
struct mail_ip *mail_ip_iter;
};
struct client *client_create(int fd);
void client_destroy(struct client **client);
bool client_is_busy(struct client *client);
void client_enable_io(struct client *client);
void clients_destroy_all(void);
#endif
dovecot-2.3.21.1/src/old-stats/mail-domain.h 0000644 0000000 0000000 00000001221 14656633576 015352 0000000 0000000 #ifndef MAIL_DOMAIN_H
#define MAIL_DOMAIN_H
struct stats;
extern struct mail_domain *stable_mail_domains;
struct mail_domain *mail_domain_login_create(const char *name);
void mail_domain_login(struct mail_domain *domain);
void mail_domain_disconnected(struct mail_domain *domain);
struct mail_domain *mail_domain_lookup(const char *name);
void mail_domain_refresh(struct mail_domain *domain,
const struct stats *diff_stats) ATTR_NULL(2);
void mail_domain_ref(struct mail_domain *domain);
void mail_domain_unref(struct mail_domain **domain);
void mail_domains_free_memory(void);
void mail_domains_init(void);
void mail_domains_deinit(void);
#endif
dovecot-2.3.21.1/src/old-stats/mail-session.c 0000644 0000000 0000000 00000023575 14656633576 015601 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "base64.h"
#include "ioloop.h"
#include "hash.h"
#include "llist.h"
#include "str-table.h"
#include "global-memory.h"
#include "stats-settings.h"
#include "mail-stats.h"
#include "mail-user.h"
#include "mail-ip.h"
#include "mail-session.h"
#include "mail-domain.h"
/* If session doesn't receive any updates for this long, assume that the
process associated with it has crashed, and forcibly disconnect the
session. Must be larger than SESSION_STATS_FORCE_REFRESH_SECS in
stats plugin */
#define MAIL_SESSION_IDLE_TIMEOUT_MSECS (1000*60*15)
/* If stats process crashes/restarts, existing processes keep sending status
updates to it, but this process doesn't know their session IDs. If these
missing IDs are found within this many seconds of starting the stats process,
don't log a warning about them. (On a larger installation this avoids
flooding the error log with hundreds of warnings.) */
#define SESSION_ID_WARN_HIDE_SECS (60*5)
static HASH_TABLE(char *, struct mail_session *) mail_sessions_hash;
/* sessions are sorted by their last_update timestamp, oldest first */
static struct mail_session *mail_sessions_head, *mail_sessions_tail;
static time_t session_id_warn_hide_until;
static bool session_id_hide_warned = FALSE;
static struct str_table *services;
struct mail_session *stable_mail_sessions;
static size_t mail_session_memsize(const struct mail_session *session)
{
return sizeof(*session) + strlen(session->id) + 1;
}
static void mail_session_disconnect(struct mail_session *session)
{
i_assert(!session->disconnected);
mail_user_disconnected(session->user);
if (session->ip != NULL)
mail_ip_disconnected(session->ip);
hash_table_remove(mail_sessions_hash, session->id);
session->disconnected = TRUE;
timeout_remove(&session->to_idle);
mail_session_unref(&session);
}
static void mail_session_idle_timeout(struct mail_session *session)
{
/* user="" service="" pid=0 is used for incoming sessions that were
received after we detected a stats process crash/restart. there's
no point in logging anything about them, since they contain no
useful information. */
if (session->user->name[0] == '\0' && session->service[0] != '\0' &&
session->pid == 0) {
i_warning("Session %s (user %s, service %s) "
"appears to have crashed, disconnecting it",
session->id, session->user->name, session->service);
}
mail_session_disconnect(session);
}
int mail_session_connect_parse(const char *const *args, const char **error_r)
{
struct mail_session *session;
const char *session_id;
pid_t pid;
struct ip_addr ip;
unsigned int i;
/* [key=value ..] */
if (str_array_length(args) < 4) {
*error_r = "CONNECT: Too few parameters";
return -1;
}
session_id = args[0];
if (str_to_pid(args[3], &pid) < 0) {
*error_r = t_strdup_printf("CONNECT: Invalid pid %s for session ID %s",
args[3], session_id);
return -1;
}
session = hash_table_lookup(mail_sessions_hash, session_id);
if (session != NULL) {
*error_r = t_strdup_printf(
"CONNECT: Duplicate session ID %s for user %s service %s (old PID %ld, new PID %ld)",
session_id, args[1], args[2], (long)session->pid, (long)pid);
return -1;
}
session = i_malloc(MALLOC_ADD(sizeof(struct mail_session), stats_alloc_size()));
session->stats = (void *)(session + 1);
session->refcount = 1; /* unrefed at disconnect */
session->id = i_strdup(session_id);
session->service = str_table_ref(services, args[2]);
session->pid = pid;
session->last_update = ioloop_timeval;
session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS,
mail_session_idle_timeout, session);
session->user = mail_user_login(args[1]);
session->user->num_logins++;
mail_domain_login(session->user->domain);
for (i = 3; args[i] != NULL; i++) {
if (str_begins(args[i], "rip=") &&
net_addr2ip(args[i] + 4, &ip) == 0)
session->ip = mail_ip_login(&ip);
}
hash_table_insert(mail_sessions_hash, session->id, session);
DLLIST_PREPEND_FULL(&stable_mail_sessions, session,
stable_prev, stable_next);
DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
sorted_prev, sorted_next);
DLLIST_PREPEND_FULL(&session->user->sessions, session,
user_prev, user_next);
mail_user_ref(session->user);
if (session->ip != NULL) {
DLLIST_PREPEND_FULL(&session->ip->sessions, session,
ip_prev, ip_next);
mail_ip_ref(session->ip);
}
global_memory_alloc(mail_session_memsize(session));
mail_global_login();
return 0;
}
void mail_session_ref(struct mail_session *session)
{
session->refcount++;
}
void mail_session_unref(struct mail_session **_session)
{
struct mail_session *session = *_session;
i_assert(session->refcount > 0);
session->refcount--;
*_session = NULL;
}
static void mail_session_free(struct mail_session *session)
{
i_assert(session->refcount == 0);
global_memory_free(mail_session_memsize(session));
timeout_remove(&session->to_idle);
if (!session->disconnected)
hash_table_remove(mail_sessions_hash, session->id);
DLLIST_REMOVE_FULL(&stable_mail_sessions, session,
stable_prev, stable_next);
DLLIST2_REMOVE_FULL(&mail_sessions_head, &mail_sessions_tail, session,
sorted_prev, sorted_next);
DLLIST_REMOVE_FULL(&session->user->sessions, session,
user_prev, user_next);
mail_user_unref(&session->user);
if (session->ip != NULL) {
DLLIST_REMOVE_FULL(&session->ip->sessions, session,
ip_prev, ip_next);
mail_ip_unref(&session->ip);
}
str_table_unref(services, &session->service);
i_free(session->id);
i_free(session);
}
static void mail_session_id_lost(const char *session_id)
{
if (ioloop_time < session_id_warn_hide_until) {
if (session_id_hide_warned)
return;
session_id_hide_warned = TRUE;
i_warning("stats process appears to have crashed/restarted, "
"hiding missing session ID warnings for %d seconds",
(int)(session_id_warn_hide_until - ioloop_time));
return;
}
i_warning("Couldn't find session ID: %s", session_id);
}
int mail_session_lookup(const char *id, struct mail_session **session_r,
const char **error_r)
{
if (id == NULL) {
*error_r = "Too few parameters";
return -1;
}
*session_r = hash_table_lookup(mail_sessions_hash, id);
if (*session_r == NULL) {
mail_session_id_lost(id);
return 0;
}
return 1;
}
int mail_session_get(const char *id, struct mail_session **session_r,
const char **error_r)
{
const char *new_args[5];
int ret;
if ((ret = mail_session_lookup(id, session_r, error_r)) != 0)
return ret;
/* Create a new dummy session to avoid repeated warnings */
new_args[0] = id;
new_args[1] = ""; /* username */
new_args[2] = ""; /* service */
new_args[3] = "0"; /* pid */
new_args[4] = NULL;
if (mail_session_connect_parse(new_args, error_r) < 0)
i_unreached();
if (mail_session_lookup(id, session_r, error_r) != 1)
i_unreached();
return 0;
}
int mail_session_disconnect_parse(const char *const *args, const char **error_r)
{
struct mail_session *session;
int ret;
/* */
if ((ret = mail_session_lookup(args[0], &session, error_r)) <= 0)
return ret;
if (!session->disconnected)
mail_session_disconnect(session);
return 0;
}
void mail_session_refresh(struct mail_session *session,
const struct stats *diff_stats)
{
timeout_reset(session->to_idle);
if (diff_stats != NULL)
stats_add(session->stats, diff_stats);
session->last_update = ioloop_timeval;
DLLIST2_REMOVE_FULL(&mail_sessions_head, &mail_sessions_tail, session,
sorted_prev, sorted_next);
DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
sorted_prev, sorted_next);
mail_user_refresh(session->user, diff_stats);
if (session->ip != NULL)
mail_ip_refresh(session->ip, diff_stats);
}
int mail_session_update_parse(const char *const *args, const char **error_r)
{
struct mail_session *session;
struct stats *new_stats, *diff_stats;
buffer_t *buf;
const char *error;
/* */
if (mail_session_get(args[0], &session, error_r) < 0)
return -1;
buf = t_buffer_create(256);
if (args[1] == NULL ||
base64_decode(args[1], strlen(args[1]), NULL, buf) < 0) {
*error_r = t_strdup_printf("UPDATE-SESSION %s %s %s: Invalid base64 input",
session->user->name,
session->service, session->id);
return -1;
}
new_stats = stats_alloc(pool_datastack_create());
diff_stats = stats_alloc(pool_datastack_create());
if (!stats_import(buf->data, buf->used, session->stats, new_stats, &error)) {
*error_r = t_strdup_printf("UPDATE-SESSION %s %s %s: %s",
session->user->name,
session->service, session->id, error);
return -1;
}
if (!stats_diff(session->stats, new_stats, diff_stats, &error)) {
*error_r = t_strdup_printf("UPDATE-SESSION %s %s %s: stats shrank: %s",
session->user->name,
session->service, session->id, error);
return -1;
}
mail_session_refresh(session, diff_stats);
return 0;
}
void mail_sessions_free_memory(void)
{
unsigned int diff;
while (mail_sessions_head != NULL &&
mail_sessions_head->refcount == 0) {
i_assert(mail_sessions_head->disconnected);
mail_session_free(mail_sessions_head);
if (global_used_memory < stats_settings->memory_limit ||
mail_sessions_head == NULL)
break;
diff = ioloop_time - mail_sessions_head->last_update.tv_sec;
if (diff < stats_settings->session_min_time)
break;
}
}
void mail_sessions_init(void)
{
session_id_warn_hide_until =
ioloop_time + SESSION_ID_WARN_HIDE_SECS;
hash_table_create(&mail_sessions_hash, default_pool, 0,
str_hash, strcmp);
services = str_table_init();
}
void mail_sessions_deinit(void)
{
while (mail_sessions_head != NULL) {
struct mail_session *session = mail_sessions_head;
if (!session->disconnected)
mail_session_unref(&session);
mail_session_free(mail_sessions_head);
}
hash_table_destroy(&mail_sessions_hash);
str_table_deinit(&services);
}
dovecot-2.3.21.1/src/old-stats/client-export.h 0000644 0000000 0000000 00000000246 14656633576 015766 0000000 0000000 #ifndef CLIENT_EXPORT_H
#define CLIENT_EXPORT_H
struct client;
int client_export(struct client *client, const char *const *args,
const char **error_r);
#endif
dovecot-2.3.21.1/src/old-stats/stats-settings.c 0000644 0000000 0000000 00000005465 14656633576 016170 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "stats-settings.h"
/* */
static struct file_listener_settings old_stats_unix_listeners_array[] = {
{ "old-stats", 0600, "", "" }
};
static struct file_listener_settings *old_stats_unix_listeners[] = {
&old_stats_unix_listeners_array[0]
};
static buffer_t old_stats_unix_listeners_buf = {
{ { old_stats_unix_listeners, sizeof(old_stats_unix_listeners) } }
};
static struct file_listener_settings old_stats_fifo_listeners_array[] = {
{ "old-stats-mail", 0600, "", "" },
{ "old-stats-user", 0600, "", "" }
};
static struct file_listener_settings *old_stats_fifo_listeners[] = {
&old_stats_fifo_listeners_array[0],
&old_stats_fifo_listeners_array[1]
};
static buffer_t old_stats_fifo_listeners_buf = {
{ { old_stats_fifo_listeners, sizeof(old_stats_fifo_listeners) } }
};
/* */
struct service_settings old_stats_service_settings = {
.name = "old-stats",
.protocol = "",
.type = "",
.executable = "old-stats",
.user = "$default_internal_user",
.group = "",
.privileged_group = "",
.extra_groups = "",
.chroot = "empty",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 1,
.client_limit = 0,
.service_count = 0,
.idle_kill = UINT_MAX,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &old_stats_unix_listeners_buf,
sizeof(old_stats_unix_listeners[0]) } },
.fifo_listeners = { { &old_stats_fifo_listeners_buf,
sizeof(old_stats_fifo_listeners[0]) } },
.inet_listeners = ARRAY_INIT,
.process_limit_1 = TRUE
};
/* we're kind of kludging here to avoid "stats_" prefix in the struct fields */
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type("old_stats_"#name, name, struct old_stats_settings)
static const struct setting_define old_stats_setting_defines[] = {
DEF(SIZE, memory_limit),
DEF(TIME, command_min_time),
DEF(TIME, session_min_time),
DEF(TIME, user_min_time),
DEF(TIME, domain_min_time),
DEF(TIME, ip_min_time),
DEF(STR, carbon_server),
DEF(TIME, carbon_interval),
DEF(STR, carbon_name),
SETTING_DEFINE_LIST_END
};
const struct old_stats_settings old_stats_default_settings = {
.memory_limit = 1024*1024*16,
.command_min_time = 60,
.session_min_time = 60*15,
.user_min_time = 60*60,
.domain_min_time = 60*60*12,
.ip_min_time = 60*60*12,
.carbon_interval = 30,
.carbon_server = "",
.carbon_name = ""
};
const struct setting_parser_info old_stats_setting_parser_info = {
.module_name = "stats",
.defines = old_stats_setting_defines,
.defaults = &old_stats_default_settings,
.type_offset = SIZE_MAX,
.struct_size = sizeof(struct old_stats_settings),
.parent_offset = SIZE_MAX
};
const struct old_stats_settings *stats_settings;
dovecot-2.3.21.1/src/old-stats/client-reset.c 0000644 0000000 0000000 00000001056 14656633576 015562 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ostream.h"
#include "strescape.h"
#include "mail-stats.h"
#include "client.h"
#include "client-reset.h"
int client_stats_reset(struct client *client, const char *const *args ATTR_UNUSED,
const char **error_r ATTR_UNUSED)
{
struct mail_global *g = &mail_global_stats;
stats_reset(g->stats);
g->num_logins = 0;
g->num_cmds = 0;
g->reset_timestamp = ioloop_time;
i_zero(&g->last_update);
o_stream_nsend_str(client->output, "OK\n");
return 0;
}
dovecot-2.3.21.1/src/old-stats/fifo-input-connection.h 0000644 0000000 0000000 00000000406 14656633576 017404 0000000 0000000 #ifndef FIFO_INPUT_CONNECTION_H
#define FIFO_INPUT_CONNECTION_H
struct fifo_input_connection *fifo_input_connection_create(int fd);
void fifo_input_connection_destroy(struct fifo_input_connection **conn);
void fifo_input_connections_destroy_all(void);
#endif
dovecot-2.3.21.1/src/old-stats/global-memory.h 0000644 0000000 0000000 00000000251 14656633576 015733 0000000 0000000 #ifndef GLOBAL_MEMORY_H
#define GLOBAL_MEMORY_H
extern size_t global_used_memory;
void global_memory_alloc(size_t size);
void global_memory_free(size_t size);
#endif
dovecot-2.3.21.1/src/old-stats/mail-session.h 0000644 0000000 0000000 00000001733 14656633576 015576 0000000 0000000 #ifndef MAIL_SESSION_H
#define MAIL_SESSION_H
struct stats;
struct mail_session;
extern struct mail_session *stable_mail_sessions;
int mail_session_connect_parse(const char *const *args, const char **error_r);
int mail_session_disconnect_parse(const char *const *args, const char **error_r);
int mail_session_update_parse(const char *const *args, const char **error_r);
int mail_session_cmd_update_parse(const char *const *args, const char **error_r);
void mail_session_ref(struct mail_session *session);
void mail_session_unref(struct mail_session **session);
int mail_session_lookup(const char *guid, struct mail_session **session_r,
const char **error_r);
int mail_session_get(const char *guid, struct mail_session **session_r,
const char **error_r);
void mail_session_refresh(struct mail_session *session,
const struct stats *diff_stats) ATTR_NULL(2);
void mail_sessions_free_memory(void);
void mail_sessions_init(void);
void mail_sessions_deinit(void);
#endif
dovecot-2.3.21.1/src/old-stats/stats-carbon.c 0000644 0000000 0000000 00000005513 14656633576 015566 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "time-util.h"
#include "stats-settings.h"
#include "mail-stats.h"
#include "istream.h"
#include "ostream.h"
#include "net.h"
#include "str.h"
#include "write-full.h"
#include "stats-carbon.h"
#define CARBON_SERVER_DEFAULT_PORT 2003
struct stats_send_ctx {
pool_t pool;
int fd;
unsigned long to_msecs;
const char *endpoint;
const char *str;
struct io *io;
struct timeout *to;
void (*callback)(void *);
void *ctx;
};
void
stats_carbon_destroy(struct stats_send_ctx **_ctx)
{
struct stats_send_ctx *ctx = *_ctx;
*_ctx = NULL;
io_remove(&ctx->io);
timeout_remove(&ctx->to);
i_close_fd(&ctx->fd);
pool_unref(&ctx->pool);
}
static void
stats_carbon_callback(struct stats_send_ctx *ctx)
{
i_assert(ctx->callback != NULL);
void (*callback)(void *) = ctx->callback;
ctx->callback = NULL;
callback(ctx->ctx);
}
static void
stats_carbon_timeout(struct stats_send_ctx *ctx)
{
i_error("Stats submit(%s) failed: endpoint timeout after %lu msecs",
ctx->endpoint, ctx->to_msecs);
stats_carbon_callback(ctx);
}
static void
stats_carbon_connected(struct stats_send_ctx *ctx)
{
io_remove(&ctx->io);
if ((errno = net_geterror(ctx->fd)) != 0) {
i_error("connect(%s) failed: %m",
ctx->endpoint);
stats_carbon_callback(ctx);
return;
}
if (write_full(ctx->fd, ctx->str, strlen(ctx->str)) < 0)
i_error("write(%s) failed: %m",
ctx->endpoint);
stats_carbon_callback(ctx);
}
int
stats_carbon_send(const char *endpoint, const char *data,
void (*callback)(void *), void *cb_ctx,
struct stats_send_ctx **ctx_r)
{
const char *host;
in_port_t port;
struct ip_addr ip;
if (net_str2hostport(endpoint, CARBON_SERVER_DEFAULT_PORT,
&host, &port) < 0 ||
net_addr2ip(host, &ip) < 0) {
i_error("stats_submit: Cannot parse endpoint '%s'",
endpoint);
return -1;
}
pool_t pool = pool_alloconly_create("stats carbon send", 1024);
struct stats_send_ctx *ctx = p_new(pool,
struct stats_send_ctx, 1);
ctx->pool = pool;
ctx->str = p_strdup(ctx->pool, data);
ctx->fd = net_connect_ip(&ip, port, NULL);
if (ctx->fd < 0) {
i_error("connect(%s) failed: %m", endpoint);
stats_carbon_callback(ctx);
return -1;
}
ctx->io = io_add(ctx->fd, IO_WRITE,
stats_carbon_connected,
ctx);
/* give time for almost until next update
this is to ensure we leave a little pause between
attempts. Multiplier 800 gives us 20% window, and
ensures the number stays positive. */
ctx->to_msecs = stats_settings->carbon_interval*800;
ctx->to = timeout_add(ctx->to_msecs,
stats_carbon_timeout,
ctx);
if (net_ipport2str(&ip, port, &host) < 0)
i_unreached();
ctx->endpoint = p_strdup(ctx->pool, host);
ctx->callback = callback;
ctx->ctx = cb_ctx;
*ctx_r = ctx;
return 0;
}
dovecot-2.3.21.1/src/old-stats/mail-user.c 0000644 0000000 0000000 00000011022 14656633576 015054 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "ioloop.h"
#include "hash.h"
#include "llist.h"
#include "base64.h"
#include "global-memory.h"
#include "stats-settings.h"
#include "mail-stats.h"
#include "mail-domain.h"
#include "mail-user.h"
static HASH_TABLE(char *, struct mail_user *) mail_users_hash;
/* users are sorted by their last_update timestamp, oldest first */
static struct mail_user *mail_users_head, *mail_users_tail;
struct mail_user *stable_mail_users;
static size_t mail_user_memsize(const struct mail_user *user)
{
return sizeof(*user) + strlen(user->name) + 1;
}
struct mail_user *mail_user_login(const char *username)
{
struct mail_user *user;
const char *domain;
user = hash_table_lookup(mail_users_hash, username);
if (user != NULL) {
mail_user_refresh(user, NULL);
return user;
}
domain = i_strchr_to_next(username, '@');
if (domain == NULL)
domain = "";
user = i_malloc(MALLOC_ADD(sizeof(struct mail_user), stats_alloc_size()));
user->stats = (void *)(user + 1);
user->name = i_strdup(username);
user->reset_timestamp = ioloop_time;
user->domain = mail_domain_login_create(domain);
hash_table_insert(mail_users_hash, user->name, user);
DLLIST_PREPEND_FULL(&stable_mail_users, user,
stable_prev, stable_next);
DLLIST2_APPEND_FULL(&mail_users_head, &mail_users_tail, user,
sorted_prev, sorted_next);
DLLIST_PREPEND_FULL(&user->domain->users, user,
domain_prev, domain_next);
mail_domain_ref(user->domain);
user->last_update = ioloop_timeval;
global_memory_alloc(mail_user_memsize(user));
return user;
}
void mail_user_disconnected(struct mail_user *user)
{
mail_domain_disconnected(user->domain);
}
struct mail_user *mail_user_lookup(const char *username)
{
return hash_table_lookup(mail_users_hash, username);
}
void mail_user_ref(struct mail_user *user)
{
user->refcount++;
}
void mail_user_unref(struct mail_user **_user)
{
struct mail_user *user = *_user;
i_assert(user->refcount > 0);
user->refcount--;
*_user = NULL;
}
static void mail_user_free(struct mail_user *user)
{
i_assert(user->refcount == 0);
i_assert(user->sessions == NULL);
global_memory_free(mail_user_memsize(user));
hash_table_remove(mail_users_hash, user->name);
DLLIST_REMOVE_FULL(&stable_mail_users, user,
stable_prev, stable_next);
DLLIST2_REMOVE_FULL(&mail_users_head, &mail_users_tail, user,
sorted_prev, sorted_next);
DLLIST_REMOVE_FULL(&user->domain->users, user,
domain_prev, domain_next);
mail_domain_unref(&user->domain);
i_free(user->name);
i_free(user);
}
void mail_user_refresh(struct mail_user *user,
const struct stats *diff_stats)
{
if (diff_stats != NULL)
stats_add(user->stats, diff_stats);
user->last_update = ioloop_timeval;
DLLIST2_REMOVE_FULL(&mail_users_head, &mail_users_tail, user,
sorted_prev, sorted_next);
DLLIST2_APPEND_FULL(&mail_users_head, &mail_users_tail, user,
sorted_prev, sorted_next);
mail_domain_refresh(user->domain, diff_stats);
}
int mail_user_add_parse(const char *const *args, const char **error_r)
{
struct mail_user *user;
struct stats *empty_stats, *diff_stats;
buffer_t *buf;
const char *service, *error;
/* */
if (str_array_length(args) < 3) {
*error_r = "ADD-USER: Too few parameters";
return -1;
}
user = mail_user_login(args[0]);
service = args[1];
buf = t_buffer_create(256);
if (base64_decode(args[2], strlen(args[2]), NULL, buf) < 0) {
*error_r = t_strdup_printf("ADD-USER %s %s: Invalid base64 input",
user->name, service);
return -1;
}
empty_stats = stats_alloc(pool_datastack_create());
diff_stats = stats_alloc(pool_datastack_create());
if (!stats_import(buf->data, buf->used, empty_stats, diff_stats, &error)) {
*error_r = t_strdup_printf("ADD-USER %s %s: %s",
user->name, service, error);
return -1;
}
mail_user_refresh(user, diff_stats);
return 0;
}
void mail_users_free_memory(void)
{
unsigned int diff;
while (mail_users_head != NULL && mail_users_head->refcount == 0) {
mail_user_free(mail_users_head);
if (global_used_memory < stats_settings->memory_limit ||
mail_users_head == NULL)
break;
diff = ioloop_time - mail_users_head->last_update.tv_sec;
if (diff < stats_settings->user_min_time)
break;
}
}
void mail_users_init(void)
{
hash_table_create(&mail_users_hash, default_pool, 0, str_hash, strcmp);
}
void mail_users_deinit(void)
{
while (mail_users_head != NULL)
mail_user_free(mail_users_head);
hash_table_destroy(&mail_users_hash);
}
dovecot-2.3.21.1/src/old-stats/main.c 0000644 0000000 0000000 00000004611 14656633576 014110 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "module-dir.h"
#include "restrict-access.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "global-memory.h"
#include "stats-settings.h"
#include "fifo-input-connection.h"
#include "mail-command.h"
#include "mail-session.h"
#include "mail-user.h"
#include "mail-domain.h"
#include "mail-ip.h"
#include "mail-stats.h"
#include "client.h"
static struct module *modules = NULL;
static void client_connected(struct master_service_connection *conn)
{
if (conn->fifo)
(void)fifo_input_connection_create(conn->fd);
else
(void)client_create(conn->fd);
master_service_client_connection_accept(conn);
}
static void main_preinit(void)
{
struct module_dir_load_settings mod_set;
i_zero(&mod_set);
mod_set.abi_version = DOVECOT_ABI_VERSION;
mod_set.require_init_funcs = TRUE;
modules = module_dir_load(STATS_MODULE_DIR, NULL, &mod_set);
module_dir_init(modules);
restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
restrict_access_allow_coredumps(TRUE);
}
int main(int argc, char *argv[])
{
const struct setting_parser_info *set_roots[] = {
&old_stats_setting_parser_info,
NULL
};
const enum master_service_flags service_flags =
MASTER_SERVICE_FLAG_DONT_SEND_STATS |
MASTER_SERVICE_FLAG_NO_IDLE_DIE |
MASTER_SERVICE_FLAG_UPDATE_PROCTITLE;
const char *error;
void **sets;
master_service = master_service_init("stats", service_flags,
&argc, &argv, "");
if (master_getopt(master_service) > 0)
return FATAL_DEFAULT;
if (master_service_settings_read_simple(master_service, set_roots,
&error) < 0)
i_fatal("Error reading configuration: %s", error);
master_service_init_log(master_service);
main_preinit();
sets = master_service_settings_get_others(master_service);
stats_settings = sets[0];
mail_commands_init();
mail_sessions_init();
mail_users_init();
mail_domains_init();
mail_ips_init();
mail_global_init();
master_service_init_finish(master_service);
master_service_run(master_service, client_connected);
clients_destroy_all();
fifo_input_connections_destroy_all();
mail_commands_deinit();
mail_sessions_deinit();
mail_users_deinit();
mail_domains_deinit();
mail_ips_deinit();
mail_global_deinit();
module_dir_unload(&modules);
i_assert(global_used_memory == 0);
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/old-stats/global-memory.c 0000644 0000000 0000000 00000002215 14656633576 015730 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "mail-command.h"
#include "mail-session.h"
#include "mail-user.h"
#include "mail-domain.h"
#include "mail-ip.h"
#include "stats-settings.h"
#include "global-memory.h"
size_t global_used_memory = 0;
static bool global_memory_free_something(void)
{
size_t orig_used_memory = global_used_memory;
mail_commands_free_memory();
if (global_used_memory > stats_settings->memory_limit)
mail_sessions_free_memory();
if (global_used_memory > stats_settings->memory_limit)
mail_users_free_memory();
if (global_used_memory > stats_settings->memory_limit)
mail_ips_free_memory();
if (global_used_memory > stats_settings->memory_limit)
mail_domains_free_memory();
return global_used_memory < orig_used_memory;
}
void global_memory_alloc(size_t size)
{
i_assert(size < SIZE_MAX - global_used_memory);
global_used_memory += size;
while (global_used_memory > stats_settings->memory_limit) {
if (!global_memory_free_something())
break;
}
}
void global_memory_free(size_t size)
{
i_assert(size <= global_used_memory);
global_used_memory -= size;
}
dovecot-2.3.21.1/src/old-stats/Makefile.am 0000644 0000000 0000000 00000001660 14656633576 015055 0000000 0000000 old_stats_moduledir = $(moduledir)/old-stats
pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = old-stats
AM_CPPFLAGS = \
-DSTATS_MODULE_DIR=\""$(old_stats_moduledir)"\" \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-old-stats \
$(BINARY_CFLAGS)
old_stats_LDADD = $(LIBDOVECOT) \
$(BINARY_LDFLAGS)
old_stats_DEPENDENCIES = $(LIBDOVECOT_DEPS)
old_stats_SOURCES = \
client.c \
client-export.c \
client-reset.c \
fifo-input-connection.c \
global-memory.c \
mail-command.c \
mail-domain.c \
mail-ip.c \
mail-session.c \
mail-stats.c \
mail-user.c \
main.c \
stats-carbon.c \
stats-settings.c
noinst_HEADERS = \
client.h \
client-export.h \
client-reset.h \
fifo-input-connection.h \
global-memory.h \
mail-command.h \
mail-domain.h \
mail-ip.h \
mail-session.h \
mail-stats.h \
mail-user.h \
stats-carbon.h \
stats-settings.h
dovecot-2.3.21.1/src/old-stats/mail-stats.c 0000644 0000000 0000000 00000004772 14656633576 015252 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "mail-stats.h"
#include "stats-carbon.h"
#include "stats-settings.h"
#include "str.h"
struct mail_global mail_global_stats;
static void
mail_global_stats_sent(void *ctx)
{
struct mail_global *stats = ctx;
stats_carbon_destroy(&stats->stats_send_ctx);
}
static void
mail_global_stats_send(void *u0 ATTR_UNUSED)
{
time_t ts = ioloop_time;
if (*stats_settings->carbon_name != '\0' &&
*stats_settings->carbon_server != '\0') {
string_t *str = t_str_new(256);
const char *prefix = t_strdup_printf("dovecot.%s.global",
stats_settings->carbon_name);
str_printfa(str, "%s.logins %u %"PRIdTIME_T"\r\n", prefix,
mail_global_stats.num_logins, ts);
str_printfa(str, "%s.cmds %u %"PRIdTIME_T"\r\n", prefix,
mail_global_stats.num_cmds, ts);
str_printfa(str, "%s.connected_sessions %u %"PRIdTIME_T"\r\n",
prefix, mail_global_stats.num_connected_sessions,
ts);
str_printfa(str, "%s.last_reset %"PRIdTIME_T" %"PRIdTIME_T"\r\n",
prefix, mail_global_stats.reset_timestamp, ts);
/* then export rest of the stats */
for(size_t i = 0; i < stats_field_count(); i++) {
str_printfa(str, "%s.%s ", prefix,
stats_field_name(i));
stats_field_value(str, mail_global_stats.stats, i);
str_printfa(str, " %"PRIdTIME_T"\r\n", ts);
}
/* and send them along */
(void)stats_carbon_send(stats_settings->carbon_server, str_c(str),
mail_global_stats_sent, &mail_global_stats,
&mail_global_stats.stats_send_ctx);
}
}
void mail_global_init(void)
{
mail_global_stats.reset_timestamp = ioloop_time;
mail_global_stats.stats = stats_alloc(default_pool);
mail_global_stats.to_stats_send = timeout_add(stats_settings->carbon_interval*1000,
mail_global_stats_send,
NULL);
}
void mail_global_deinit(void)
{
if (mail_global_stats.stats_send_ctx != NULL)
stats_carbon_destroy(&mail_global_stats.stats_send_ctx);
timeout_remove(&mail_global_stats.to_stats_send);
i_free(mail_global_stats.stats);
}
void mail_global_login(void)
{
mail_global_stats.num_logins++;
mail_global_stats.num_connected_sessions++;
}
void mail_global_disconnected(void)
{
i_assert(mail_global_stats.num_connected_sessions > 0);
mail_global_stats.num_connected_sessions--;
}
void mail_global_refresh(const struct stats *diff_stats)
{
if (diff_stats != NULL)
stats_add(mail_global_stats.stats, diff_stats);
mail_global_stats.last_update = ioloop_timeval;
}
dovecot-2.3.21.1/src/old-stats/client.c 0000644 0000000 0000000 00000010637 14656633576 014447 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "llist.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "strescape.h"
#include "master-service.h"
#include "mail-command.h"
#include "mail-session.h"
#include "mail-user.h"
#include "mail-domain.h"
#include "mail-ip.h"
#include "client-export.h"
#include "client-reset.h"
#include "client.h"
#include
#define CLIENT_MAX_SIMULTANEOUS_ITER_COUNT 1000
#define MAX_INBUF_SIZE 1024
#define OUTBUF_THROTTLE_SIZE (1024*64)
static struct client *clients;
bool client_is_busy(struct client *client)
{
client->iter_count++;
if (client->iter_count % CLIENT_MAX_SIMULTANEOUS_ITER_COUNT == 0)
return TRUE;
if (o_stream_get_buffer_used_size(client->output) < OUTBUF_THROTTLE_SIZE)
return FALSE;
if (o_stream_flush(client->output) < 0)
return TRUE;
return o_stream_get_buffer_used_size(client->output) >= OUTBUF_THROTTLE_SIZE;
}
static int
client_handle_request(struct client *client, const char *const *args,
const char **error_r)
{
const char *cmd = args[0];
if (cmd == NULL) {
*error_r = "Missing command";
return -1;
}
args++;
if (strcmp(cmd, "EXPORT") == 0)
return client_export(client, args, error_r);
if (strcmp(cmd, "RESET") == 0)
return client_stats_reset(client, args, error_r);
*error_r = "Unknown command";
return -1;
}
static const char *const*
client_read_next_line(struct client *client)
{
const char *line;
line = i_stream_next_line(client->input);
if (line == NULL)
return NULL;
return t_strsplit_tabescaped(line);
}
static void client_input(struct client *client)
{
const char *const *args, *error;
int ret;
timeout_remove(&client->to_pending);
switch (i_stream_read(client->input)) {
case -2:
i_error("BUG: Stats client sent too much data");
client_destroy(&client);
return;
case -1:
client_destroy(&client);
return;
}
o_stream_cork(client->output);
while ((args = client_read_next_line(client)) != NULL) {
ret = client_handle_request(client, args, &error);
if (ret < 0) {
i_error("Stats client input error: %s", error);
client_destroy(&client);
return;
}
if (ret == 0) {
o_stream_set_flush_pending(client->output, TRUE);
io_remove(&client->io);
break;
}
client->cmd_more = NULL;
}
o_stream_uncork(client->output);
}
static int client_output(struct client *client)
{
int ret = 1;
if (o_stream_flush(client->output) < 0) {
client_destroy(&client);
return 1;
}
if (client->cmd_more != NULL)
ret = client->cmd_more(client);
if (ret > 0) {
client->cmd_more = NULL;
if (client->io == NULL)
client_enable_io(client);
}
return ret;
}
void client_enable_io(struct client *client)
{
i_assert(client->io == NULL);
client->io = io_add(client->fd, IO_READ, client_input, client);
if (client->to_pending == NULL)
client->to_pending = timeout_add(0, client_input, client);
}
struct client *client_create(int fd)
{
struct client *client;
client = i_new(struct client, 1);
client->fd = fd;
client->io = io_add(fd, IO_READ, client_input, client);
client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
client->output = o_stream_create_fd(fd, SIZE_MAX);
o_stream_set_no_error_handling(client->output, TRUE);
o_stream_set_flush_callback(client->output, client_output, client);
client->cmd_pool = pool_alloconly_create("cmd pool", 1024);
DLLIST_PREPEND(&clients, client);
return client;
}
static void client_unref_iters(struct client *client)
{
if (client->mail_cmd_iter != NULL)
mail_command_unref(&client->mail_cmd_iter);
if (client->mail_session_iter != NULL)
mail_session_unref(&client->mail_session_iter);
if (client->mail_user_iter != NULL)
mail_user_unref(&client->mail_user_iter);
if (client->mail_domain_iter != NULL)
mail_domain_unref(&client->mail_domain_iter);
if (client->mail_ip_iter != NULL)
mail_ip_unref(&client->mail_ip_iter);
}
void client_destroy(struct client **_client)
{
struct client *client = *_client;
*_client = NULL;
DLLIST_REMOVE(&clients, client);
io_remove(&client->io);
i_stream_destroy(&client->input);
o_stream_destroy(&client->output);
if (close(client->fd) < 0)
i_error("close(client) failed: %m");
client_unref_iters(client);
pool_unref(&client->cmd_pool);
i_free(client);
master_service_client_connection_destroyed(master_service);
}
void clients_destroy_all(void)
{
while (clients != NULL) {
struct client *client = clients;
client_destroy(&client);
}
}
dovecot-2.3.21.1/src/old-stats/mail-domain.c 0000644 0000000 0000000 00000006616 14656633576 015362 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "hash.h"
#include "llist.h"
#include "global-memory.h"
#include "stats-settings.h"
#include "mail-stats.h"
#include "mail-domain.h"
static HASH_TABLE(char *, struct mail_domain *) mail_domains_hash;
/* domains are sorted by their last_update timestamp, oldest first */
static struct mail_domain *mail_domains_head, *mail_domains_tail;
struct mail_domain *stable_mail_domains;
static size_t mail_domain_memsize(const struct mail_domain *domain)
{
return sizeof(*domain) + strlen(domain->name) + 1;
}
struct mail_domain *mail_domain_login_create(const char *name)
{
struct mail_domain *domain;
domain = hash_table_lookup(mail_domains_hash, name);
if (domain != NULL) {
return domain;
}
domain = i_malloc(MALLOC_ADD(sizeof(struct mail_domain), stats_alloc_size()));
domain->stats = (void *)(domain + 1);
domain->name = i_strdup(name);
domain->reset_timestamp = ioloop_time;
hash_table_insert(mail_domains_hash, domain->name, domain);
DLLIST_PREPEND_FULL(&stable_mail_domains, domain,
stable_prev, stable_next);
global_memory_alloc(mail_domain_memsize(domain));
return domain;
}
void mail_domain_login(struct mail_domain *domain)
{
domain->num_logins++;
domain->num_connected_sessions++;
mail_domain_refresh(domain, NULL);
}
void mail_domain_disconnected(struct mail_domain *domain)
{
i_assert(domain->num_connected_sessions > 0);
domain->num_connected_sessions--;
mail_global_disconnected();
}
struct mail_domain *mail_domain_lookup(const char *name)
{
return hash_table_lookup(mail_domains_hash, name);
}
void mail_domain_ref(struct mail_domain *domain)
{
domain->refcount++;
}
void mail_domain_unref(struct mail_domain **_domain)
{
struct mail_domain *domain = *_domain;
i_assert(domain->refcount > 0);
domain->refcount--;
*_domain = NULL;
}
static void mail_domain_free(struct mail_domain *domain)
{
i_assert(domain->refcount == 0);
i_assert(domain->users == NULL);
global_memory_free(mail_domain_memsize(domain));
hash_table_remove(mail_domains_hash, domain->name);
DLLIST_REMOVE_FULL(&stable_mail_domains, domain,
stable_prev, stable_next);
DLLIST2_REMOVE_FULL(&mail_domains_head, &mail_domains_tail, domain,
sorted_prev, sorted_next);
i_free(domain->name);
i_free(domain);
}
void mail_domain_refresh(struct mail_domain *domain,
const struct stats *diff_stats)
{
if (diff_stats != NULL)
stats_add(domain->stats, diff_stats);
domain->last_update = ioloop_timeval;
DLLIST2_REMOVE_FULL(&mail_domains_head, &mail_domains_tail, domain,
sorted_prev, sorted_next);
DLLIST2_APPEND_FULL(&mail_domains_head, &mail_domains_tail, domain,
sorted_prev, sorted_next);
mail_global_refresh(diff_stats);
}
void mail_domains_free_memory(void)
{
unsigned int diff;
while (mail_domains_head != NULL && mail_domains_head->refcount == 0) {
mail_domain_free(mail_domains_head);
if (global_used_memory < stats_settings->memory_limit ||
mail_domains_head == NULL)
break;
diff = ioloop_time - mail_domains_head->last_update.tv_sec;
if (diff < stats_settings->domain_min_time)
break;
}
}
void mail_domains_init(void)
{
hash_table_create(&mail_domains_hash, default_pool, 0, str_hash, strcmp);
}
void mail_domains_deinit(void)
{
while (mail_domains_head != NULL)
mail_domain_free(mail_domains_head);
hash_table_destroy(&mail_domains_hash);
}
dovecot-2.3.21.1/src/old-stats/stats-settings.h 0000644 0000000 0000000 00000000737 14656633576 016172 0000000 0000000 #ifndef STATS_SETTINGS_H
#define STATS_SETTINGS_H
struct old_stats_settings {
uoff_t memory_limit;
unsigned int command_min_time;
unsigned int session_min_time;
unsigned int user_min_time;
unsigned int domain_min_time;
unsigned int ip_min_time;
unsigned int carbon_interval;
const char *carbon_server;
const char *carbon_name;
};
extern const struct setting_parser_info old_stats_setting_parser_info;
extern const struct old_stats_settings *stats_settings;
#endif
dovecot-2.3.21.1/src/lib-dict-backend/ 0000755 0000000 0000000 00000000000 14656633637 014236 5 0000000 0000000 dovecot-2.3.21.1/src/lib-dict-backend/dict-sql.h 0000644 0000000 0000000 00000000155 14656633576 016052 0000000 0000000 #ifndef DICT_SQL_H
#define DICT_SQL_H
void dict_sql_register(void);
void dict_sql_unregister(void);
#endif
dovecot-2.3.21.1/src/lib-dict-backend/dict-ldap-settings.c 0000644 0000000 0000000 00000017561 14656633576 020035 0000000 0000000 /* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
#include "array.h"
#include "str.h"
#include "settings.h"
#include "dict-ldap-settings.h"
#include
static const char *dict_ldap_commonName = "cn";
static const char *dict_ldap_empty_filter = "";
enum section_type {
SECTION_ROOT = 0,
SECTION_MAP,
SECTION_FIELDS
};
struct dict_ldap_map_attribute {
const char *name;
const char *variable;
};
struct setting_parser_ctx {
pool_t pool;
struct dict_ldap_settings *set;
enum section_type type;
struct dict_ldap_map cur_map;
ARRAY(struct dict_ldap_map_attribute) cur_attributes;
};
#undef DEF_STR
#undef DEF_BOOL
#undef DEF_UINT
#define DEF_STR(name) DEF_STRUCT_STR(name, dict_ldap_map)
#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, dict_ldap_map)
#define DEF_UINT(name) DEF_STRUCT_UINT(name ,dict_ldap_map)
static const struct setting_def dict_ldap_map_setting_defs[] = {
DEF_STR(pattern),
DEF_STR(filter),
DEF_STR(filter_iter),
DEF_STR(username_attribute),
DEF_STR(value_attribute),
DEF_STR(base_dn),
DEF_STR(scope),
{ 0, NULL, 0 }
};
static const char *pattern_read_name(const char **pattern)
{
const char *p = *pattern, *name;
if (*p == '{') {
/* ${name} */
name = ++p;
p = strchr(p, '}');
if (p == NULL) {
/* error, but allow anyway */
*pattern += strlen(*pattern);
return "";
}
*pattern = p + 1;
} else {
/* $name - ends at the first non-alnum_ character */
name = p;
for (; *p != '\0'; p++) {
if (!i_isalnum(*p) && *p != '_')
break;
}
*pattern = p;
}
name = t_strdup_until(name, p);
return name;
}
static const char *dict_ldap_attributes_map(struct setting_parser_ctx *ctx)
{
struct dict_ldap_map_attribute *attributes;
string_t *pattern;
const char *p, *name;
unsigned int i, count;
/* go through the variables in the pattern, replace them with plain
'$' character and add its ldap attribute */
pattern = t_str_new(strlen(ctx->cur_map.pattern) + 1);
attributes = array_get_modifiable(&ctx->cur_attributes, &count);
p_array_init(&ctx->cur_map.ldap_attributes, ctx->pool, count);
for (p = ctx->cur_map.pattern; *p != '\0';) {
if (*p != '$') {
str_append_c(pattern, *p);
p++;
continue;
}
p++;
str_append_c(pattern, '$');
name = pattern_read_name(&p);
for (i = 0; i < count; i++) {
if (attributes[i].variable != NULL &&
strcmp(attributes[i].variable, name) == 0)
break;
}
if (i == count) {
return t_strconcat("Missing LDAP attribute for variable: ",
name, NULL);
}
/* mark this attribute as used */
attributes[i].variable = NULL;
array_push_back(&ctx->cur_map.ldap_attributes,
&attributes[i].name);
}
/* make sure there aren't any unused attributes */
for (i = 0; i < count; i++) {
if (attributes[i].variable != NULL) {
return t_strconcat("Unused variable: ",
attributes[i].variable, NULL);
}
}
if (ctx->set->max_attribute_count < count)
ctx->set->max_attribute_count = count;
ctx->cur_map.pattern = p_strdup(ctx->pool, str_c(pattern));
return NULL;
}
static const char *dict_ldap_map_finish(struct setting_parser_ctx *ctx)
{
if (ctx->cur_map.pattern == NULL)
return "Missing setting: pattern";
if (ctx->cur_map.filter == NULL)
ctx->cur_map.filter = dict_ldap_empty_filter;
if (*ctx->cur_map.filter != '\0') {
const char *ptr = ctx->cur_map.filter;
if (*ptr != '(')
return "Filter must start with (";
while(*ptr != '\0') ptr++;
ptr--;
if (*ptr != ')')
return "Filter must end with )";
}
if (ctx->cur_map.value_attribute == NULL)
return "Missing setting: value_attribute";
if (ctx->cur_map.username_attribute == NULL) {
/* default to commonName */
ctx->cur_map.username_attribute = dict_ldap_commonName;
}
if (ctx->cur_map.scope == NULL) {
ctx->cur_map.scope_val = 2; /* subtree */
} else {
if (strcasecmp(ctx->cur_map.scope, "one") == 0) ctx->cur_map.scope_val = 1;
else if (strcasecmp(ctx->cur_map.scope, "base") == 0) ctx->cur_map.scope_val = 0;
else if (strcasecmp(ctx->cur_map.scope, "subtree") == 0) ctx->cur_map.scope_val = 2;
else return "Scope must be one, base or subtree";
}
if (!array_is_created(&ctx->cur_map.ldap_attributes)) {
/* no attributes besides value. allocate the array anyway. */
p_array_init(&ctx->cur_map.ldap_attributes, ctx->pool, 1);
if (strchr(ctx->cur_map.pattern, '$') != NULL)
return "Missing attributes for pattern variables";
}
array_push_back(&ctx->set->maps, &ctx->cur_map);
i_zero(&ctx->cur_map);
return NULL;
}
static const char *
parse_setting(const char *key, const char *value,
struct setting_parser_ctx *ctx)
{
struct dict_ldap_map_attribute *attribute;
switch (ctx->type) {
case SECTION_ROOT:
if (strcmp(key, "uri") == 0) {
ctx->set->uri = p_strdup(ctx->pool, value);
return NULL;
}
if (strcmp(key, "bind_dn") == 0) {
ctx->set->bind_dn = p_strdup(ctx->pool, value);
return NULL;
}
if (strcmp(key, "password") == 0) {
ctx->set->password = p_strdup(ctx->pool, value);
return NULL;
}
if (strcmp(key, "timeout") == 0) {
if (str_to_uint(value, &ctx->set->timeout) != 0) {
return "Invalid timeout value";
}
return NULL;
}
if (strcmp(key, "max_idle_time") == 0) {
if (str_to_uint(value, &ctx->set->max_idle_time) != 0) {
return "Invalid max_idle_time value";
}
return NULL;
}
if (strcmp(key, "debug") == 0) {
if (str_to_uint(value, &ctx->set->debug) != 0) {
return "invalid debug value";
}
return NULL;
}
if (strcmp(key, "tls") == 0) {
if (strcasecmp(value, "yes") == 0) {
ctx->set->require_ssl = TRUE;
ctx->set->start_tls = TRUE;
} else if (strcasecmp(value, "no") == 0) {
ctx->set->require_ssl = FALSE;
ctx->set->start_tls = FALSE;
} else if (strcasecmp(value, "try") == 0) {
ctx->set->require_ssl = FALSE;
ctx->set->start_tls = TRUE;
} else {
return "tls must be yes, try or no";
}
return NULL;
}
break;
case SECTION_MAP:
return parse_setting_from_defs(ctx->pool,
dict_ldap_map_setting_defs,
&ctx->cur_map, key, value);
case SECTION_FIELDS:
if (*value != '$') {
return t_strconcat("Value is missing '$' for attribute: ",
key, NULL);
}
attribute = array_append_space(&ctx->cur_attributes);
attribute->name = p_strdup(ctx->pool, key);
attribute->variable = p_strdup(ctx->pool, value + 1);
return NULL;
}
return t_strconcat("Unknown setting: ", key, NULL);
}
static bool
parse_section(const char *type, const char *name ATTR_UNUSED,
struct setting_parser_ctx *ctx, const char **error_r)
{
switch (ctx->type) {
case SECTION_ROOT:
if (type == NULL)
return FALSE;
if (strcmp(type, "map") == 0) {
array_clear(&ctx->cur_attributes);
ctx->type = SECTION_MAP;
return TRUE;
}
break;
case SECTION_MAP:
if (type == NULL) {
ctx->type = SECTION_ROOT;
*error_r = dict_ldap_map_finish(ctx);
return FALSE;
}
if (strcmp(type, "fields") == 0) {
ctx->type = SECTION_FIELDS;
return TRUE;
}
break;
case SECTION_FIELDS:
if (type == NULL) {
ctx->type = SECTION_MAP;
*error_r = dict_ldap_attributes_map(ctx);
return FALSE;
}
break;
}
*error_r = t_strconcat("Unknown section: ", type, NULL);
return FALSE;
}
struct dict_ldap_settings *
dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r)
{
struct setting_parser_ctx ctx;
i_zero(&ctx);
ctx.pool = pool;
ctx.set = p_new(pool, struct dict_ldap_settings, 1);
t_array_init(&ctx.cur_attributes, 16);
p_array_init(&ctx.set->maps, pool, 8);
ctx.set->timeout = 30; /* default timeout */
ctx.set->require_ssl = FALSE; /* try to start SSL */
ctx.set->start_tls = TRUE;
if (!settings_read(path, NULL, parse_setting, parse_section,
&ctx, error_r))
return NULL;
if (ctx.set->uri == NULL) {
*error_r = t_strdup_printf("Error in configuration file %s: "
"Missing ldap uri", path);
return NULL;
}
return ctx.set;
}
#endif
dovecot-2.3.21.1/src/lib-dict-backend/dict.conf 0000644 0000000 0000000 00000001314 14656633576 015751 0000000 0000000 connect = host=localhost
map {
pattern = shared/dictmap/$key1/$key2
table = table
value_field = value
value_type = string
fields {
a = $key1
b = $key2
}
}
map {
pattern = shared/counters/$class/$name
table = counters
value_field = value
value_type = uint
fields {
class = $class
name = $name
}
}
map {
pattern = priv/quota/bytes
table = quota
username_field = username
value_field = bytes
value_type = uint
}
map {
pattern = priv/quota/count
table = quota
username_field = username
value_field = count
value_type = uint
}
map {
pattern = priv/quota/folders
table = quota
username_field = username
value_field = folders
value_type = uint
}
dovecot-2.3.21.1/src/lib-dict-backend/Makefile.in 0000644 0000000 0000000 00000112071 14656633610 016214 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
@HAVE_LDAP_TRUE@@LDAP_PLUGIN_FALSE@am__append_1 = $(LIBDOVECOT_LDAP)
@HAVE_LDAP_TRUE@@LDAP_PLUGIN_FALSE@am__append_2 = ldap
noinst_PROGRAMS = $(am__EXEEXT_1)
subdir = src/lib-dict-backend
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = test-dict-sql$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(module_dictdir)"
LTLIBRARIES = $(module_dict_LTLIBRARIES) $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 =
@HAVE_LDAP_TRUE@@LDAP_PLUGIN_FALSE@am__DEPENDENCIES_2 = \
@HAVE_LDAP_TRUE@@LDAP_PLUGIN_FALSE@ $(am__DEPENDENCIES_1)
libdict_backend_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am__objects_1 = dict-ldap.lo dict-ldap-settings.lo
am_libdict_backend_la_OBJECTS = dict-cdb.lo dict-sql.lo \
dict-sql-settings.lo $(am__objects_1)
nodist_libdict_backend_la_OBJECTS = dict-drivers-register.lo
libdict_backend_la_OBJECTS = $(am_libdict_backend_la_OBJECTS) \
$(nodist_libdict_backend_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am__libdict_ldap_la_SOURCES_DIST = dict-ldap.c dict-ldap-settings.c
am__objects_2 = libdict_ldap_la-dict-ldap.lo \
libdict_ldap_la-dict-ldap-settings.lo
@LDAP_PLUGIN_TRUE@am_libdict_ldap_la_OBJECTS = $(am__objects_2)
libdict_ldap_la_OBJECTS = $(am_libdict_ldap_la_OBJECTS)
libdict_ldap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libdict_ldap_la_LDFLAGS) $(LDFLAGS) \
-o $@
@LDAP_PLUGIN_TRUE@am_libdict_ldap_la_rpath = -rpath $(module_dictdir)
am_test_dict_sql_OBJECTS = test_dict_sql-test-dict-sql.$(OBJEXT)
test_dict_sql_OBJECTS = $(am_test_dict_sql_OBJECTS)
test_dict_sql_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(test_dict_sql_CFLAGS) \
$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/dict-cdb.Plo \
./$(DEPDIR)/dict-drivers-register.Plo \
./$(DEPDIR)/dict-ldap-settings.Plo ./$(DEPDIR)/dict-ldap.Plo \
./$(DEPDIR)/dict-sql-settings.Plo ./$(DEPDIR)/dict-sql.Plo \
./$(DEPDIR)/libdict_ldap_la-dict-ldap-settings.Plo \
./$(DEPDIR)/libdict_ldap_la-dict-ldap.Plo \
./$(DEPDIR)/test_dict_sql-test-dict-sql.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libdict_backend_la_SOURCES) \
$(nodist_libdict_backend_la_SOURCES) \
$(libdict_ldap_la_SOURCES) $(test_dict_sql_SOURCES)
DIST_SOURCES = $(libdict_backend_la_SOURCES) \
$(am__libdict_ldap_la_SOURCES_DIST) $(test_dict_sql_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(noinst_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS =
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@ $(am__append_2)
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
noinst_LTLIBRARIES = libdict_backend.la
module_dictdir = $(moduledir)/dict
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-ldap \
-I$(top_srcdir)/src/lib-sql \
-I$(top_srcdir)/src/lib-settings \
$(SQL_CFLAGS)
ldap_sources = \
dict-ldap.c \
dict-ldap-settings.c
libdict_backend_la_SOURCES = \
dict-cdb.c \
dict-sql.c \
dict-sql-settings.c \
$(ldap_sources)
libdict_backend_la_LIBADD = $(am__append_1)
nodist_libdict_backend_la_SOURCES = \
dict-drivers-register.c
noinst_HEADERS = \
dict-ldap-settings.h \
dict-sql.h \
dict-sql-private.h \
dict-sql-settings.h
@LDAP_PLUGIN_TRUE@LIBDICT_LDAP = libdict_ldap.la
@LDAP_PLUGIN_TRUE@libdict_ldap_la_DEPENDENCIES = $(LIBDOVECOT_LDAP) $(LIBDOVECOT_DEPS)
@LDAP_PLUGIN_TRUE@libdict_ldap_la_LDFLAGS = -module -avoid-version
@LDAP_PLUGIN_TRUE@libdict_ldap_la_LIBADD = $(LIBDOVECOT_LDAP) $(LIBDOVECOT)
@LDAP_PLUGIN_TRUE@libdict_ldap_la_CPPFLAGS = $(AM_CPPFLAGS) -DPLUGIN_BUILD
@LDAP_PLUGIN_TRUE@libdict_ldap_la_SOURCES = $(ldap_sources)
module_dict_LTLIBRARIES = \
$(LIBDICT_LDAP)
EXTRA_DIST = dict.conf
test_programs = \
test-dict-sql
test_dict_sql_CFLAGS = $(AM_CPPFLAGS) -DDICT_SRC_DIR=\"$(top_srcdir)/src/lib-dict-backend\"
test_dict_sql_SOURCES = \
test-dict-sql.c
test_dict_sql_LDADD = \
$(noinst_LTLIBRARIES) \
$(DICT_LIBS) \
../lib-sql/libdriver_test.la \
../lib-sql/libsql.la \
../lib-dovecot/libdovecot.la
test_dict_sql_DEPENDENCIES = \
$(noinst_LTLIBRARIES) \
../lib-sql/libdriver_test.la \
../lib-sql/libsql.la \
../lib-dovecot/libdovecot.la
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-dict-backend/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/lib-dict-backend/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
install-module_dictLTLIBRARIES: $(module_dict_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(module_dict_LTLIBRARIES)'; test -n "$(module_dictdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(module_dictdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(module_dictdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(module_dictdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(module_dictdir)"; \
}
uninstall-module_dictLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(module_dict_LTLIBRARIES)'; test -n "$(module_dictdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(module_dictdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(module_dictdir)/$$f"; \
done
clean-module_dictLTLIBRARIES:
-test -z "$(module_dict_LTLIBRARIES)" || rm -f $(module_dict_LTLIBRARIES)
@list='$(module_dict_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libdict_backend.la: $(libdict_backend_la_OBJECTS) $(libdict_backend_la_DEPENDENCIES) $(EXTRA_libdict_backend_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(libdict_backend_la_OBJECTS) $(libdict_backend_la_LIBADD) $(LIBS)
libdict_ldap.la: $(libdict_ldap_la_OBJECTS) $(libdict_ldap_la_DEPENDENCIES) $(EXTRA_libdict_ldap_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdict_ldap_la_LINK) $(am_libdict_ldap_la_rpath) $(libdict_ldap_la_OBJECTS) $(libdict_ldap_la_LIBADD) $(LIBS)
test-dict-sql$(EXEEXT): $(test_dict_sql_OBJECTS) $(test_dict_sql_DEPENDENCIES) $(EXTRA_test_dict_sql_DEPENDENCIES)
@rm -f test-dict-sql$(EXEEXT)
$(AM_V_CCLD)$(test_dict_sql_LINK) $(test_dict_sql_OBJECTS) $(test_dict_sql_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict-cdb.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict-drivers-register.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict-ldap-settings.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict-ldap.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict-sql-settings.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict-sql.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdict_ldap_la-dict-ldap-settings.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdict_ldap_la-dict-ldap.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_dict_sql-test-dict-sql.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
libdict_ldap_la-dict-ldap.lo: dict-ldap.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdict_ldap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdict_ldap_la-dict-ldap.lo -MD -MP -MF $(DEPDIR)/libdict_ldap_la-dict-ldap.Tpo -c -o libdict_ldap_la-dict-ldap.lo `test -f 'dict-ldap.c' || echo '$(srcdir)/'`dict-ldap.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdict_ldap_la-dict-ldap.Tpo $(DEPDIR)/libdict_ldap_la-dict-ldap.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dict-ldap.c' object='libdict_ldap_la-dict-ldap.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdict_ldap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdict_ldap_la-dict-ldap.lo `test -f 'dict-ldap.c' || echo '$(srcdir)/'`dict-ldap.c
libdict_ldap_la-dict-ldap-settings.lo: dict-ldap-settings.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdict_ldap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdict_ldap_la-dict-ldap-settings.lo -MD -MP -MF $(DEPDIR)/libdict_ldap_la-dict-ldap-settings.Tpo -c -o libdict_ldap_la-dict-ldap-settings.lo `test -f 'dict-ldap-settings.c' || echo '$(srcdir)/'`dict-ldap-settings.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdict_ldap_la-dict-ldap-settings.Tpo $(DEPDIR)/libdict_ldap_la-dict-ldap-settings.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dict-ldap-settings.c' object='libdict_ldap_la-dict-ldap-settings.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdict_ldap_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdict_ldap_la-dict-ldap-settings.lo `test -f 'dict-ldap-settings.c' || echo '$(srcdir)/'`dict-ldap-settings.c
test_dict_sql-test-dict-sql.o: test-dict-sql.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_dict_sql_CFLAGS) $(CFLAGS) -MT test_dict_sql-test-dict-sql.o -MD -MP -MF $(DEPDIR)/test_dict_sql-test-dict-sql.Tpo -c -o test_dict_sql-test-dict-sql.o `test -f 'test-dict-sql.c' || echo '$(srcdir)/'`test-dict-sql.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_dict_sql-test-dict-sql.Tpo $(DEPDIR)/test_dict_sql-test-dict-sql.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-dict-sql.c' object='test_dict_sql-test-dict-sql.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_dict_sql_CFLAGS) $(CFLAGS) -c -o test_dict_sql-test-dict-sql.o `test -f 'test-dict-sql.c' || echo '$(srcdir)/'`test-dict-sql.c
test_dict_sql-test-dict-sql.obj: test-dict-sql.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_dict_sql_CFLAGS) $(CFLAGS) -MT test_dict_sql-test-dict-sql.obj -MD -MP -MF $(DEPDIR)/test_dict_sql-test-dict-sql.Tpo -c -o test_dict_sql-test-dict-sql.obj `if test -f 'test-dict-sql.c'; then $(CYGPATH_W) 'test-dict-sql.c'; else $(CYGPATH_W) '$(srcdir)/test-dict-sql.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_dict_sql-test-dict-sql.Tpo $(DEPDIR)/test_dict_sql-test-dict-sql.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-dict-sql.c' object='test_dict_sql-test-dict-sql.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_dict_sql_CFLAGS) $(CFLAGS) -c -o test_dict_sql-test-dict-sql.obj `if test -f 'test-dict-sql.c'; then $(CYGPATH_W) 'test-dict-sql.c'; else $(CYGPATH_W) '$(srcdir)/test-dict-sql.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-local
check: check-am
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(module_dictdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-module_dictLTLIBRARIES \
clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/dict-cdb.Plo
-rm -f ./$(DEPDIR)/dict-drivers-register.Plo
-rm -f ./$(DEPDIR)/dict-ldap-settings.Plo
-rm -f ./$(DEPDIR)/dict-ldap.Plo
-rm -f ./$(DEPDIR)/dict-sql-settings.Plo
-rm -f ./$(DEPDIR)/dict-sql.Plo
-rm -f ./$(DEPDIR)/libdict_ldap_la-dict-ldap-settings.Plo
-rm -f ./$(DEPDIR)/libdict_ldap_la-dict-ldap.Plo
-rm -f ./$(DEPDIR)/test_dict_sql-test-dict-sql.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-module_dictLTLIBRARIES
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/dict-cdb.Plo
-rm -f ./$(DEPDIR)/dict-drivers-register.Plo
-rm -f ./$(DEPDIR)/dict-ldap-settings.Plo
-rm -f ./$(DEPDIR)/dict-ldap.Plo
-rm -f ./$(DEPDIR)/dict-sql-settings.Plo
-rm -f ./$(DEPDIR)/dict-sql.Plo
-rm -f ./$(DEPDIR)/libdict_ldap_la-dict-ldap-settings.Plo
-rm -f ./$(DEPDIR)/libdict_ldap_la-dict-ldap.Plo
-rm -f ./$(DEPDIR)/test_dict_sql-test-dict-sql.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-module_dictLTLIBRARIES
.MAKE: check-am install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \
check-local clean clean-generic clean-libtool \
clean-module_dictLTLIBRARIES clean-noinstLTLIBRARIES \
clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-module_dictLTLIBRARIES install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am \
uninstall-module_dictLTLIBRARIES
.PRECIOUS: Makefile
dict-drivers-register.c: Makefile $(top_builddir)/config.h
rm -f $@
echo '/* this file automatically generated by Makefile */' >$@
echo '#include "lib.h"' >>$@
echo '#include "dict.h"' >>$@
echo '#include "ldap-client.h"' >>$@
echo '#include "dict-sql.h"' >>$@
for i in $(dict_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "extern struct dict dict_driver_$${i};" >>$@ ; \
fi; \
done
echo 'void dict_drivers_register_all(void) {' >>$@
echo 'dict_drivers_register_builtin();' >>$@
echo 'dict_sql_register();' >>$@
for i in $(dict_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "dict_driver_register(&dict_driver_$${i});" >>$@ ; \
fi; \
done
echo '}' >>$@
echo 'void dict_drivers_unregister_all(void) {' >>$@
echo '#ifdef BUILTIN_LDAP' >>$@
echo 'ldap_clients_cleanup();' >>$@
echo '#endif' >>$@
echo 'dict_drivers_unregister_builtin();' >>$@
echo 'dict_sql_unregister();' >>$@
for i in $(dict_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "dict_driver_unregister(&dict_driver_$${i});" >>$@ ; \
fi; \
done
echo '}' >>$@
distclean-generic:
rm -f Makefile dict-drivers-register.c
check-local:
for bin in $(test_programs) $(check_PROGRAMS); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/lib-dict-backend/dict-sql-private.h 0000644 0000000 0000000 00000000262 14656633576 017521 0000000 0000000 #ifndef DICT_SQL_PRIVATE_H
#define DICT_SQL_PRIVATE_H 1
struct sql_dict {
struct dict dict;
pool_t pool;
struct sql_db *db;
const struct dict_sql_settings *set;
};
#endif
dovecot-2.3.21.1/src/lib-dict-backend/dict-sql-settings.h 0000644 0000000 0000000 00000002037 14656633576 017711 0000000 0000000 #ifndef DICT_SQL_SETTINGS_H
#define DICT_SQL_SETTINGS_H
enum dict_sql_type {
DICT_SQL_TYPE_STRING = 0,
DICT_SQL_TYPE_INT,
DICT_SQL_TYPE_UINT,
DICT_SQL_TYPE_HEXBLOB
};
struct dict_sql_field {
const char *name;
enum dict_sql_type value_type;
};
struct dict_sql_map {
/* pattern is in simplified form: all variables are stored as simple
'$' character. fields array is sorted by the variable index. */
const char *pattern;
const char *table;
const char *username_field;
const char *value_field;
const char *value_type;
bool value_hexblob;
/* SQL field names, one for each $ variable in the pattern */
ARRAY(struct dict_sql_field) pattern_fields;
/* generated: */
unsigned int values_count;
const char *const *value_fields;
const enum dict_sql_type *value_types;
};
struct dict_sql_settings {
const char *connect;
unsigned int max_pattern_fields_count;
ARRAY(struct dict_sql_map) maps;
};
struct dict_sql_settings *
dict_sql_settings_read(const char *path, const char **error_r);
void dict_sql_settings_deinit(void);
#endif
dovecot-2.3.21.1/src/lib-dict-backend/dict-cdb.c 0000644 0000000 0000000 00000013655 14656633576 016007 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#ifdef BUILD_CDB
#include "dict-private.h"
#include
#include
#include
#include
#define CDB_WITH_NULL 1
#define CDB_WITHOUT_NULL 2
struct cdb_dict {
struct dict dict;
struct cdb cdb;
char *path;
int fd, flag;
};
struct cdb_dict_iterate_context {
struct dict_iterate_context ctx;
enum dict_iterate_flags flags;
buffer_t *buffer;
const char *values[2];
char *path;
unsigned cptr;
char *error;
};
static void cdb_dict_deinit(struct dict *_dict);
static int
cdb_dict_init(struct dict *driver, const char *uri,
const struct dict_settings *set ATTR_UNUSED,
struct dict **dict_r, const char **error_r)
{
struct cdb_dict *dict;
dict = i_new(struct cdb_dict, 1);
dict->dict = *driver;
dict->path = i_strdup(uri);
dict->flag = CDB_WITH_NULL | CDB_WITHOUT_NULL;
/* initialize cdb to 0 (unallocated) */
i_zero(&dict->cdb);
dict->fd = open(dict->path, O_RDONLY);
if (dict->fd == -1) {
*error_r = t_strdup_printf("open(%s) failed: %m", dict->path);
cdb_dict_deinit(&dict->dict);
return -1;
}
#ifdef TINYCDB_VERSION
if (cdb_init(&dict->cdb, dict->fd) < 0) {
*error_r = t_strdup_printf("cdb_init(%s) failed: %m", dict->path);
cdb_dict_deinit(&dict->dict);
return -1;
}
#else
cdb_init(&dict->cdb, dict->fd);
#endif
*dict_r = &dict->dict;
return 0;
}
static void cdb_dict_deinit(struct dict *_dict)
{
struct cdb_dict *dict = (struct cdb_dict *)_dict;
/* we can safely deinit unallocated cdb */
cdb_free(&dict->cdb);
i_close_fd_path(&dict->fd, dict->path);
i_free(dict->path);
i_free(dict);
}
static int
cdb_dict_lookup(struct dict *_dict,
const struct dict_op_settings *set ATTR_UNUSED,
pool_t pool,
const char *key, const char **value_r,
const char **error_r)
{
struct cdb_dict *dict = (struct cdb_dict *)_dict;
unsigned datalen;
int ret = 0;
char *data;
/* keys and values may be null terminated... */
if ((dict->flag & CDB_WITH_NULL) != 0) {
ret = cdb_find(&dict->cdb, key, (unsigned)strlen(key)+1);
if (ret > 0)
dict->flag &= ENUM_NEGATE(CDB_WITHOUT_NULL);
}
/* ...or not */
if (ret == 0 && (dict->flag & CDB_WITHOUT_NULL) != 0) {
ret = cdb_find(&dict->cdb, key, (unsigned)strlen(key));
if (ret > 0)
dict->flag &= ENUM_NEGATE(CDB_WITH_NULL);
}
if (ret <= 0) {
*value_r = NULL;
/* something bad with db */
if (ret < 0) {
*error_r = t_strdup_printf("cdb_find(%s) failed: %m", dict->path);
return -1;
}
/* found nothing */
return 0;
}
datalen = cdb_datalen(&dict->cdb);
data = p_malloc(pool, datalen + 1);
if (cdb_read(&dict->cdb, data, datalen, cdb_datapos(&dict->cdb)) < 0) {
*error_r = t_strdup_printf("cdb_read(%s) failed: %m", dict->path);
return -1;
}
*value_r = data;
return 1;
}
static struct dict_iterate_context *
cdb_dict_iterate_init(struct dict *_dict,
const struct dict_op_settings *set ATTR_UNUSED,
const char *path, enum dict_iterate_flags flags)
{
struct cdb_dict_iterate_context *ctx =
i_new(struct cdb_dict_iterate_context, 1);
struct cdb_dict *dict = (struct cdb_dict *)_dict;
ctx->ctx.dict = &dict->dict;
ctx->path = i_strdup(path);
ctx->flags = flags;
ctx->buffer = buffer_create_dynamic(default_pool, 256);
cdb_seqinit(&ctx->cptr, &dict->cdb);
return &ctx->ctx;
}
static bool
cdb_dict_next(struct cdb_dict_iterate_context *ctx, const char **key_r)
{
struct cdb_dict *dict = (struct cdb_dict *)ctx->ctx.dict;
char *data;
unsigned datalen;
int ret;
if ((ret = cdb_seqnext(&ctx->cptr, &dict->cdb)) < 1) {
if (ret < 0)
ctx->error = i_strdup_printf("cdb_seqnext(%s) failed: %m",
dict->path);
return FALSE;
}
buffer_set_used_size(ctx->buffer, 0);
datalen = cdb_keylen(&dict->cdb);
data = buffer_append_space_unsafe(ctx->buffer, datalen + 1);
if (cdb_read(&dict->cdb, data, datalen, cdb_keypos(&dict->cdb)) < 0) {
ctx->error = i_strdup_printf("cdb_read(%s) failed: %m",
dict->path);
return FALSE;
}
data[datalen] = '\0';
*key_r = data;
return TRUE;
}
static bool cdb_dict_iterate(struct dict_iterate_context *_ctx,
const char **key_r, const char *const **values_r)
{
struct cdb_dict_iterate_context *ctx =
(struct cdb_dict_iterate_context *)_ctx;
struct cdb_dict *dict = (struct cdb_dict *)_ctx->dict;
const char *key;
bool match = FALSE;
char *data;
unsigned datalen;
if (ctx->error != NULL)
return FALSE;
while(!match && cdb_dict_next(ctx, &key)) {
if (((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0 &&
strcmp(key, ctx->path) == 0) ||
((ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0 &&
str_begins(key, ctx->path)) ||
((ctx->flags & DICT_ITERATE_FLAG_RECURSE) == 0 &&
str_begins(key, ctx->path) &&
strchr(key + strlen(ctx->path), '/') == NULL)) {
match = TRUE;
break;
}
}
if (!match)
return FALSE;
*key_r = key;
if ((ctx->flags & DICT_ITERATE_FLAG_NO_VALUE) != 0)
return TRUE;
datalen = cdb_datalen(&dict->cdb);
data = buffer_append_space_unsafe(ctx->buffer, datalen + 1);
if (cdb_read(&dict->cdb, data, datalen, cdb_datapos(&dict->cdb)) < 0) {
ctx->error = i_strdup_printf("cdb_read(%s) failed: %m",
dict->path);
return FALSE;
}
data[datalen] = '\0';
ctx->values[0] = data;
*values_r = ctx->values;
return TRUE;
}
static int cdb_dict_iterate_deinit(struct dict_iterate_context *_ctx,
const char **error_r)
{
int ret = 0;
struct cdb_dict_iterate_context *ctx =
(struct cdb_dict_iterate_context *)_ctx;
if (ctx->error != NULL) {
*error_r = t_strdup(ctx->error);
ret = -1;
}
buffer_free(&ctx->buffer);
i_free(ctx->error);
i_free(ctx->path);
i_free(ctx);
return ret;
}
struct dict dict_driver_cdb = {
.name = "cdb",
{
.init = cdb_dict_init,
.deinit = cdb_dict_deinit,
.lookup = cdb_dict_lookup,
.iterate_init = cdb_dict_iterate_init,
.iterate = cdb_dict_iterate,
.iterate_deinit = cdb_dict_iterate_deinit,
}
};
#endif
dovecot-2.3.21.1/src/lib-dict-backend/dict-sql-settings.c 0000644 0000000 0000000 00000021610 14656633576 017702 0000000 0000000 /* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "hash.h"
#include "settings.h"
#include "dict-sql-settings.h"
#include
enum section_type {
SECTION_ROOT = 0,
SECTION_MAP,
SECTION_FIELDS
};
struct dict_sql_map_field {
struct dict_sql_field sql_field;
const char *variable;
};
struct setting_parser_ctx {
pool_t pool;
struct dict_sql_settings *set;
enum section_type type;
struct dict_sql_map cur_map;
ARRAY(struct dict_sql_map_field) cur_fields;
};
#define DEF_STR(name) DEF_STRUCT_STR(name, dict_sql_map)
#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, dict_sql_map)
static const struct setting_def dict_sql_map_setting_defs[] = {
DEF_STR(pattern),
DEF_STR(table),
DEF_STR(username_field),
DEF_STR(value_field),
DEF_STR(value_type),
DEF_BOOL(value_hexblob),
{ 0, NULL, 0 }
};
struct dict_sql_settings_cache {
pool_t pool;
const char *path;
struct dict_sql_settings *set;
};
static HASH_TABLE(const char *, struct dict_sql_settings_cache *) dict_sql_settings_cache;
static const char *pattern_read_name(const char **pattern)
{
const char *p = *pattern, *name;
if (*p == '{') {
/* ${name} */
name = ++p;
p = strchr(p, '}');
if (p == NULL) {
/* error, but allow anyway */
*pattern += strlen(*pattern);
return "";
}
*pattern = p + 1;
} else {
/* $name - ends at the first non-alnum_ character */
name = p;
for (; *p != '\0'; p++) {
if (!i_isalnum(*p) && *p != '_')
break;
}
*pattern = p;
}
name = t_strdup_until(name, p);
return name;
}
static const char *dict_sql_fields_map(struct setting_parser_ctx *ctx)
{
struct dict_sql_map_field *fields;
string_t *pattern;
const char *p, *name;
unsigned int i, count;
/* go through the variables in the pattern, replace them with plain
'$' character and add its sql field */
pattern = t_str_new(strlen(ctx->cur_map.pattern) + 1);
fields = array_get_modifiable(&ctx->cur_fields, &count);
p_array_init(&ctx->cur_map.pattern_fields, ctx->pool, count);
for (p = ctx->cur_map.pattern; *p != '\0';) {
if (*p != '$') {
str_append_c(pattern, *p);
p++;
continue;
}
p++;
str_append_c(pattern, '$');
name = pattern_read_name(&p);
for (i = 0; i < count; i++) {
if (fields[i].variable != NULL &&
strcmp(fields[i].variable, name) == 0)
break;
}
if (i == count) {
return t_strconcat("Missing SQL field for variable: ",
name, NULL);
}
/* mark this field as used */
fields[i].variable = NULL;
array_push_back(&ctx->cur_map.pattern_fields,
&fields[i].sql_field);
}
/* make sure there aren't any unused fields */
for (i = 0; i < count; i++) {
if (fields[i].variable != NULL) {
return t_strconcat("Unused variable: ",
fields[i].variable, NULL);
}
}
if (ctx->set->max_pattern_fields_count < count)
ctx->set->max_pattern_fields_count = count;
ctx->cur_map.pattern = p_strdup(ctx->pool, str_c(pattern));
return NULL;
}
static bool
dict_sql_value_type_parse(const char *value_type, enum dict_sql_type *type_r)
{
if (strcmp(value_type, "string") == 0)
*type_r = DICT_SQL_TYPE_STRING;
else if (strcmp(value_type, "hexblob") == 0)
*type_r = DICT_SQL_TYPE_HEXBLOB;
else if (strcmp(value_type, "int") == 0)
*type_r = DICT_SQL_TYPE_INT;
else if (strcmp(value_type, "uint") == 0)
*type_r = DICT_SQL_TYPE_UINT;
else
return FALSE;
return TRUE;
}
static const char *dict_sql_map_finish(struct setting_parser_ctx *ctx)
{
unsigned int i;
if (ctx->cur_map.pattern == NULL)
return "Missing setting: pattern";
if (ctx->cur_map.table == NULL)
return "Missing setting: table";
if (ctx->cur_map.value_field == NULL)
return "Missing setting: value_field";
ctx->cur_map.value_fields = (const char *const *)
p_strsplit_spaces(ctx->pool, ctx->cur_map.value_field, ",");
ctx->cur_map.values_count = str_array_length(ctx->cur_map.value_fields);
enum dict_sql_type *value_types =
p_new(ctx->pool, enum dict_sql_type, ctx->cur_map.values_count);
if (ctx->cur_map.value_type != NULL) {
const char *const *types =
t_strsplit_spaces(ctx->cur_map.value_type, ",");
if (str_array_length(types) != ctx->cur_map.values_count)
return "Number of fields in value_fields doesn't match value_type";
for (i = 0; i < ctx->cur_map.values_count; i++) {
if (!dict_sql_value_type_parse(types[i], &value_types[i]))
return "Invalid value in value_type";
}
} else {
for (i = 0; i < ctx->cur_map.values_count; i++) {
value_types[i] = ctx->cur_map.value_hexblob ?
DICT_SQL_TYPE_HEXBLOB : DICT_SQL_TYPE_STRING;
}
}
ctx->cur_map.value_types = value_types;
if (ctx->cur_map.username_field == NULL) {
/* not all queries require this */
ctx->cur_map.username_field = "'username_field not set'";
}
if (!array_is_created(&ctx->cur_map.pattern_fields)) {
/* no fields besides value. allocate the array anyway. */
p_array_init(&ctx->cur_map.pattern_fields, ctx->pool, 1);
if (strchr(ctx->cur_map.pattern, '$') != NULL)
return "Missing fields for pattern variables";
}
array_push_back(&ctx->set->maps, &ctx->cur_map);
i_zero(&ctx->cur_map);
return NULL;
}
static const char *
parse_setting(const char *key, const char *value,
struct setting_parser_ctx *ctx)
{
struct dict_sql_map_field *field;
size_t value_len;
switch (ctx->type) {
case SECTION_ROOT:
if (strcmp(key, "connect") == 0) {
ctx->set->connect = p_strdup(ctx->pool, value);
return NULL;
}
break;
case SECTION_MAP:
return parse_setting_from_defs(ctx->pool,
dict_sql_map_setting_defs,
&ctx->cur_map, key, value);
case SECTION_FIELDS:
if (*value != '$') {
return t_strconcat("Value is missing '$' for field: ",
key, NULL);
}
field = array_append_space(&ctx->cur_fields);
field->sql_field.name = p_strdup(ctx->pool, key);
value_len = strlen(value);
if (str_begins(value, "${hexblob:") &&
value[value_len-1] == '}') {
field->variable = p_strndup(ctx->pool, value + 10,
value_len-10-1);
field->sql_field.value_type = DICT_SQL_TYPE_HEXBLOB;
} else if (str_begins(value, "${int:") &&
value[value_len-1] == '}') {
field->variable = p_strndup(ctx->pool, value + 6,
value_len-6-1);
field->sql_field.value_type = DICT_SQL_TYPE_INT;
} else if (str_begins(value, "${uint:") &&
value[value_len-1] == '}') {
field->variable = p_strndup(ctx->pool, value + 7,
value_len-7-1);
field->sql_field.value_type = DICT_SQL_TYPE_UINT;
} else {
field->variable = p_strdup(ctx->pool, value + 1);
}
return NULL;
}
return t_strconcat("Unknown setting: ", key, NULL);
}
static bool
parse_section(const char *type, const char *name ATTR_UNUSED,
struct setting_parser_ctx *ctx, const char **error_r)
{
switch (ctx->type) {
case SECTION_ROOT:
if (type == NULL)
return FALSE;
if (strcmp(type, "map") == 0) {
array_clear(&ctx->cur_fields);
ctx->type = SECTION_MAP;
return TRUE;
}
break;
case SECTION_MAP:
if (type == NULL) {
ctx->type = SECTION_ROOT;
*error_r = dict_sql_map_finish(ctx);
return FALSE;
}
if (strcmp(type, "fields") == 0) {
ctx->type = SECTION_FIELDS;
return TRUE;
}
break;
case SECTION_FIELDS:
if (type == NULL) {
ctx->type = SECTION_MAP;
*error_r = dict_sql_fields_map(ctx);
return FALSE;
}
break;
}
*error_r = t_strconcat("Unknown section: ", type, NULL);
return FALSE;
}
struct dict_sql_settings *
dict_sql_settings_read(const char *path, const char **error_r)
{
struct setting_parser_ctx ctx;
struct dict_sql_settings_cache *cache;
pool_t pool;
if (!hash_table_is_created(dict_sql_settings_cache)) {
hash_table_create(&dict_sql_settings_cache, default_pool, 0,
str_hash, strcmp);
}
cache = hash_table_lookup(dict_sql_settings_cache, path);
if (cache != NULL)
return cache->set;
i_zero(&ctx);
pool = pool_alloconly_create("dict sql settings", 1024);
ctx.pool = pool;
ctx.set = p_new(pool, struct dict_sql_settings, 1);
t_array_init(&ctx.cur_fields, 16);
p_array_init(&ctx.set->maps, pool, 8);
if (!settings_read(path, NULL, parse_setting, parse_section,
&ctx, error_r)) {
pool_unref(&pool);
return NULL;
}
if (ctx.set->connect == NULL) {
*error_r = t_strdup_printf("Error in configuration file %s: "
"Missing connect setting", path);
pool_unref(&pool);
return NULL;
}
cache = p_new(pool, struct dict_sql_settings_cache, 1);
cache->pool = pool;
cache->path = p_strdup(pool, path);
cache->set = ctx.set;
hash_table_insert(dict_sql_settings_cache, cache->path, cache);
return ctx.set;
}
void dict_sql_settings_deinit(void)
{
struct hash_iterate_context *iter;
struct dict_sql_settings_cache *cache;
const char *key;
if (!hash_table_is_created(dict_sql_settings_cache))
return;
iter = hash_table_iterate_init(dict_sql_settings_cache);
while (hash_table_iterate(iter, dict_sql_settings_cache, &key, &cache))
pool_unref(&cache->pool);
hash_table_iterate_deinit(&iter);
hash_table_destroy(&dict_sql_settings_cache);
}
dovecot-2.3.21.1/src/lib-dict-backend/dict-ldap.c 0000644 0000000 0000000 00000030547 14656633576 016176 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING memcached */
#include "lib.h"
#if defined(BUILTIN_LDAP) || defined(PLUGIN_BUILD)
#include "array.h"
#include "module-dir.h"
#include "str.h"
#include "istream.h"
#include "ostream.h"
#include "var-expand.h"
#include "connection.h"
#include "llist.h"
#include "ldap-client.h"
#include "dict.h"
#include "dict-private.h"
#include "dict-ldap-settings.h"
static const char *LDAP_ESCAPE_CHARS = "*,\\#+<>;\"()= ";
struct ldap_dict;
struct dict_ldap_op {
struct ldap_dict *dict;
const struct dict_ldap_map *map;
pool_t pool;
unsigned long txid;
struct dict_lookup_result res;
dict_lookup_callback_t *callback;
void *callback_ctx;
};
struct ldap_dict {
struct dict dict;
struct dict_ldap_settings *set;
const char *uri;
const char *base_dn;
enum ldap_scope scope;
pool_t pool;
struct ldap_client *client;
unsigned long last_txid;
unsigned int pending;
struct ldap_dict *prev,*next;
};
static
void ldap_dict_lookup_async(struct dict *dict,
const struct dict_op_settings *set, const char *key,
dict_lookup_callback_t *callback, void *context);
static bool
dict_ldap_map_match(const struct dict_ldap_map *map, const char *path,
ARRAY_TYPE(const_string) *values, size_t *pat_len_r,
size_t *path_len_r, bool partial_ok, bool recurse)
{
const char *path_start = path;
const char *pat, *attribute, *p;
size_t len;
array_clear(values);
pat = map->pattern;
while (*pat != '\0' && *path != '\0') {
if (*pat == '$') {
/* variable */
pat++;
if (*pat == '\0') {
/* pattern ended with this variable,
it'll match the rest of the path */
len = strlen(path);
if (partial_ok) {
/* iterating - the last field never
matches fully. if there's a trailing
'/', drop it. */
pat--;
if (path[len-1] == '/') {
attribute = t_strndup(path, len-1);
array_push_back(values,
&attribute);
} else {
array_push_back(values, &path);
}
} else {
array_push_back(values, &path);
path += len;
}
*path_len_r = path - path_start;
*pat_len_r = pat - map->pattern;
return TRUE;
}
/* pattern matches until the next '/' in path */
p = strchr(path, '/');
if (p != NULL) {
attribute = t_strdup_until(path, p);
array_push_back(values, &attribute);
path = p;
} else {
/* no '/' anymore, but it'll still match a
partial */
array_push_back(values, &path);
path += strlen(path);
pat++;
}
} else if (*pat == *path) {
pat++;
path++;
} else {
return FALSE;
}
}
*path_len_r = path - path_start;
*pat_len_r = pat - map->pattern;
if (*pat == '\0')
return *path == '\0';
else if (!partial_ok)
return FALSE;
else {
/* partial matches must end with '/'. */
if (pat != map->pattern && pat[-1] != '/')
return FALSE;
/* if we're not recursing, there should be only one $variable
left. */
if (recurse)
return TRUE;
return pat[0] == '$' && strchr(pat, '/') == NULL;
}
}
static const struct dict_ldap_map *
ldap_dict_find_map(struct ldap_dict *dict, const char *path,
ARRAY_TYPE(const_string) *values)
{
const struct dict_ldap_map *maps;
unsigned int i, count;
size_t len;
t_array_init(values, dict->set->max_attribute_count);
maps = array_get(&dict->set->maps, &count);
for (i = 0; i < count; i++) {
if (dict_ldap_map_match(&maps[i], path, values,
&len, &len, FALSE, FALSE))
return &maps[i];
}
return NULL;
}
static
int dict_ldap_connect(struct ldap_dict *dict, const char **error_r)
{
struct ldap_client_settings set;
i_zero(&set);
set.uri = dict->set->uri;
set.bind_dn = dict->set->bind_dn;
set.password = dict->set->password;
set.timeout_secs = dict->set->timeout;
set.max_idle_time_secs = dict->set->max_idle_time;
set.debug = dict->set->debug;
set.require_ssl = dict->set->require_ssl;
set.start_tls = dict->set->start_tls;
return ldap_client_init(&set, &dict->client, error_r);
}
#define IS_LDAP_ESCAPED_CHAR(c) \
((((unsigned char)(c)) & 0x80) != 0 || strchr(LDAP_ESCAPE_CHARS, (c)) != NULL)
static const char *ldap_escape(const char *str)
{
string_t *ret = NULL;
for (const char *p = str; *p != '\0'; p++) {
if (IS_LDAP_ESCAPED_CHAR(*p)) {
if (ret == NULL) {
ret = t_str_new((size_t) (p - str) + 64);
str_append_data(ret, str, (size_t) (p - str));
}
str_printfa(ret, "\\%02X", (unsigned char)*p);
} else if (ret != NULL)
str_append_c(ret, *p);
}
return ret == NULL ? str : str_c(ret);
}
static bool
ldap_dict_build_query(const struct dict_op_settings *set,
const struct dict_ldap_map *map,
ARRAY_TYPE(const_string) *values, bool priv,
string_t *query_r, const char **error_r)
{
const char *template, *error;
ARRAY(struct var_expand_table) exp;
struct var_expand_table entry;
t_array_init(&exp, 8);
entry.key = '\0';
entry.value = ldap_escape(set->username);
entry.long_key = "username";
array_push_back(&exp, &entry);
if (priv) {
template = t_strdup_printf("(&(%s=%s)%s)", map->username_attribute, "%{username}", map->filter);
} else {
template = map->filter;
}
for(size_t i = 0; i < array_count(values) && i < array_count(&map->ldap_attributes); i++) {
struct var_expand_table entry;
const char *value = array_idx_elem(values, i);
const char *long_key = array_idx_elem(&map->ldap_attributes, i);
entry.value = ldap_escape(value);
entry.long_key = long_key;
array_push_back(&exp, &entry);
}
array_append_zero(&exp);
if (var_expand(query_r, template, array_front(&exp), &error) <= 0) {
*error_r = t_strdup_printf("Failed to expand %s: %s", template, error);
return FALSE;
}
return TRUE;
}
static
int ldap_dict_init(struct dict *dict_driver, const char *uri,
const struct dict_settings *set ATTR_UNUSED,
struct dict **dict_r, const char **error_r)
{
pool_t pool = pool_alloconly_create("ldap dict", 2048);
struct ldap_dict *dict = p_new(pool, struct ldap_dict, 1);
dict->pool = pool;
dict->dict = *dict_driver;
dict->uri = p_strdup(pool, uri);
dict->set = dict_ldap_settings_read(pool, uri, error_r);
if (dict->set == NULL) {
pool_unref(&pool);
return -1;
}
if (dict_ldap_connect(dict, error_r) < 0) {
pool_unref(&pool);
return -1;
}
*dict_r = (struct dict*)dict;
*error_r = NULL;
return 0;
}
static
void ldap_dict_deinit(struct dict *dict)
{
struct ldap_dict *ctx = (struct ldap_dict *)dict;
ldap_client_deinit(&ctx->client);
pool_unref(&ctx->pool);
}
static void ldap_dict_wait(struct dict *dict)
{
struct ldap_dict *ctx = (struct ldap_dict *)dict;
i_assert(ctx->dict.ioloop == NULL);
ctx->dict.prev_ioloop = current_ioloop;
ctx->dict.ioloop = io_loop_create();
dict_switch_ioloop(dict);
do {
io_loop_run(current_ioloop);
} while (ctx->pending > 0);
io_loop_set_current(ctx->dict.prev_ioloop);
dict_switch_ioloop(dict);
io_loop_set_current(ctx->dict.ioloop);
io_loop_destroy(&ctx->dict.ioloop);
ctx->dict.prev_ioloop = NULL;
}
static bool ldap_dict_switch_ioloop(struct dict *dict)
{
struct ldap_dict *ctx = (struct ldap_dict *)dict;
ldap_client_switch_ioloop(ctx->client);
return ctx->pending > 0;
}
static
void ldap_dict_lookup_done(const struct dict_lookup_result *result, void *ctx)
{
struct dict_lookup_result *res = ctx;
res->ret = result->ret;
res->value = t_strdup(result->value);
res->error = t_strdup(result->error);
}
static void
ldap_dict_lookup_callback(struct ldap_result *result, struct dict_ldap_op *op)
{
pool_t pool = op->pool;
struct ldap_search_iterator *iter;
const struct ldap_entry *entry;
op->dict->pending--;
if (ldap_result_has_failed(result)) {
op->res.ret = -1;
op->res.error = ldap_result_get_error(result);
} else {
iter = ldap_search_iterator_init(result);
entry = ldap_search_iterator_next(iter);
if (entry != NULL) {
if (op->dict->set->debug > 0)
i_debug("ldap_dict_lookup_callback got dn %s", ldap_entry_dn(entry));
/* try extract value */
const char *const *values = ldap_entry_get_attribute(entry, op->map->value_attribute);
if (values != NULL) {
const char **new_values;
if (op->dict->set->debug > 0)
i_debug("ldap_dict_lookup_callback got attribute %s", op->map->value_attribute);
op->res.ret = 1;
new_values = p_new(op->pool, const char *, 2);
new_values[0] = p_strdup(op->pool, values[0]);
op->res.values = new_values;
op->res.value = op->res.values[0];
} else {
if (op->dict->set->debug > 0)
i_debug("ldap_dict_lookup_callback dit not get attribute %s", op->map->value_attribute);
op->res.value = NULL;
}
}
ldap_search_iterator_deinit(&iter);
}
if (op->dict->dict.prev_ioloop != NULL)
io_loop_set_current(op->dict->dict.prev_ioloop);
op->callback(&op->res, op->callback_ctx);
if (op->dict->dict.prev_ioloop != NULL) {
io_loop_set_current(op->dict->dict.ioloop);
io_loop_stop(op->dict->dict.ioloop);
}
pool_unref(&pool);
}
static int
ldap_dict_lookup(struct dict *dict, const struct dict_op_settings *set,
pool_t pool, const char *key,
const char **value_r, const char **error_r)
{
struct dict_lookup_result res;
ldap_dict_lookup_async(dict, set, key, ldap_dict_lookup_done, &res);
ldap_dict_wait(dict);
if (res.ret < 0) {
*error_r = res.error;
return -1;
}
if (res.ret > 0)
*value_r = p_strdup(pool, res.value);
return res.ret;
}
/*
static
struct dict_iterate_context *ldap_dict_iterate_init(struct dict *dict,
const char *const *paths,
enum dict_iterate_flags flags)
{
return NULL;
}
static
bool ldap_dict_iterate(struct dict_iterate_context *ctx,
const char **key_r, const char **value_r)
{
return FALSE;
}
static
int ldap_dict_iterate_deinit(struct dict_iterate_context *ctx)
{
return -1;
}
static
struct dict_transaction_context ldap_dict_transaction_init(struct dict *dict);
static
int ldap_dict_transaction_commit(struct dict_transaction_context *ctx,
bool async,
dict_transaction_commit_callback_t *callback,
void *context);
static
void ldap_dict_transaction_rollback(struct dict_transaction_context *ctx);
static
void ldap_dict_set(struct dict_transaction_context *ctx,
const char *key, const char *value);
static
void ldap_dict_unset(struct dict_transaction_context *ctx,
const char *key);
static
void ldap_dict_atomic_inc(struct dict_transaction_context *ctx,
const char *key, long long diff);
*/
static
void ldap_dict_lookup_async(struct dict *dict,
const struct dict_op_settings *set,
const char *key,
dict_lookup_callback_t *callback, void *context)
{
struct ldap_search_input input;
struct ldap_dict *ctx = (struct ldap_dict*)dict;
struct dict_ldap_op *op;
const char *error;
pool_t oppool = pool_alloconly_create("ldap dict lookup", 64);
string_t *query = str_new(oppool, 64);
op = p_new(oppool, struct dict_ldap_op, 1);
op->pool = oppool;
op->dict = ctx;
op->callback = callback;
op->callback_ctx = context;
op->txid = ctx->last_txid++;
/* key needs to be transformed into something else */
ARRAY_TYPE(const_string) values;
const char *attributes[2] = {0, 0};
t_array_init(&values, 8);
const struct dict_ldap_map *map = ldap_dict_find_map(ctx, key, &values);
if (map != NULL) {
op->map = map;
attributes[0] = map->value_attribute;
/* build lookup */
i_zero(&input);
input.base_dn = map->base_dn;
input.scope = map->scope_val;
if (!ldap_dict_build_query(set, map, &values, strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE))==0, query, &error)) {
op->res.error = error;
callback(&op->res, context);
pool_unref(&oppool);
return;
}
input.filter = str_c(query);
input.attributes = attributes;
input.timeout_secs = ctx->set->timeout;
ctx->pending++;
ldap_search_start(ctx->client, &input, ldap_dict_lookup_callback, op);
} else {
op->res.error = "no such key";
callback(&op->res, context);
pool_unref(&oppool);
}
}
struct dict dict_driver_ldap = {
.name = "ldap",
{
.init = ldap_dict_init,
.deinit = ldap_dict_deinit,
.wait = ldap_dict_wait,
.lookup = ldap_dict_lookup,
.lookup_async = ldap_dict_lookup_async,
.switch_ioloop = ldap_dict_switch_ioloop,
}
};
#ifndef BUILTIN_LDAP
/* Building a plugin */
void dict_ldap_init(struct module *module ATTR_UNUSED);
void dict_ldap_deinit(void);
void dict_ldap_init(struct module *module ATTR_UNUSED)
{
dict_driver_register(&dict_driver_ldap);
}
void dict_ldap_deinit(void)
{
ldap_clients_cleanup();
dict_driver_unregister(&dict_driver_ldap);
}
const char *dict_ldap_plugin_dependencies[] = { NULL };
#endif
#endif
dovecot-2.3.21.1/src/lib-dict-backend/test-dict-sql.c 0000644 0000000 0000000 00000021110 14656633576 017014 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "test-lib.h"
#include "sql-api.h"
#include "dict.h"
#include "dict-private.h"
#include "dict-sql.h"
#include "dict-sql-private.h"
#include "driver-test.h"
struct dict_op_settings dict_op_settings = {
.username = "testuser",
};
static void test_setup(struct dict **dict_r)
{
const char *error = NULL;
struct dict_settings set = {
.base_dir = "."
};
struct dict *dict = NULL;
if (dict_init("mysql:" DICT_SRC_DIR "/dict.conf", &set, &dict, &error) < 0)
i_fatal("cannot initialize dict: %s", error);
*dict_r = dict;
}
static void test_teardown(struct dict **_dict)
{
struct dict *dict = *_dict;
*_dict = NULL;
if (dict != NULL) {
dict_deinit(&dict);
}
}
static void test_set_expected(struct dict *_dict,
const struct test_driver_result *result)
{
struct sql_dict *dict =
(struct sql_dict *)_dict;
sql_driver_test_add_expected_result(dict->db, result);
}
static void test_lookup_one(void)
{
const char *value = NULL, *error = NULL;
struct test_driver_result_set rset = {
.rows = 1,
.cols = 1,
.col_names = (const char *[]){"value", NULL},
.row_data = (const char **[]){(const char*[]){"one", NULL}},
};
struct test_driver_result res = {
.nqueries = 1,
.queries = (const char *[]){"SELECT value FROM table WHERE a = 'hello' AND b = 'world'", NULL},
.result = &rset,
};
const struct dict_op_settings set = {
.username = "testuser",
};
struct dict *dict;
pool_t pool = pool_datastack_create();
test_begin("dict lookup one");
test_setup(&dict);
test_set_expected(dict, &res);
test_assert(dict_lookup(dict, &set, pool, "shared/dictmap/hello/world", &value, &error) == 1);
test_assert_strcmp(value, "one");
if (error != NULL)
i_error("dict_lookup failed: %s", error);
test_teardown(&dict);
test_end();
}
static void test_atomic_inc(void)
{
const char *error;
struct test_driver_result res = {
.nqueries = 3,
.queries = (const char *[]){
"UPDATE counters SET value=value+128 WHERE class = 'global' AND name = 'counter'",
"UPDATE quota SET bytes=bytes+128,count=count+1 WHERE username = 'testuser'",
"UPDATE quota SET bytes=bytes+128,count=count+1,folders=folders+123 WHERE username = 'testuser'",
NULL},
.result = NULL,
};
struct dict_op_settings set = {
.username = "testuser",
};
struct dict *dict;
test_begin("dict atomic inc");
test_setup(&dict);
test_set_expected(dict, &res);
/* 1 field */
struct dict_transaction_context *ctx = dict_transaction_begin(dict, &set);
dict_atomic_inc(ctx, "shared/counters/global/counter", 128);
test_assert(dict_transaction_commit(&ctx, &error) == 0);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
error = NULL;
/* 2 fields */
ctx = dict_transaction_begin(dict, &set);
dict_atomic_inc(ctx, "priv/quota/bytes", 128);
dict_atomic_inc(ctx, "priv/quota/count", 1);
test_assert(dict_transaction_commit(&ctx, &error) == 0);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
error = NULL;
/* 3 fields */
ctx = dict_transaction_begin(dict, &set);
dict_atomic_inc(ctx, "priv/quota/bytes", 128);
dict_atomic_inc(ctx, "priv/quota/count", 1);
dict_atomic_inc(ctx, "priv/quota/folders", 123);
test_assert(dict_transaction_commit(&ctx, &error) == 0);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
test_teardown(&dict);
test_end();
}
static void test_set(void)
{
const char *error;
struct test_driver_result res = {
.affected_rows = 1,
.nqueries = 3,
.queries = (const char *[]){
"INSERT INTO counters (value,class,name) VALUES (128,'global','counter') ON DUPLICATE KEY UPDATE value=128",
"INSERT INTO quota (bytes,count,username) VALUES (128,1,'testuser') ON DUPLICATE KEY UPDATE bytes=128,count=1",
"INSERT INTO quota (bytes,count,folders,username) VALUES (128,1,123,'testuser') ON DUPLICATE KEY UPDATE bytes=128,count=1,folders=123",
NULL},
.result = NULL,
};
struct dict *dict;
test_begin("dict set");
test_setup(&dict);
test_set_expected(dict, &res);
/* 1 field */
struct dict_transaction_context *ctx = dict_transaction_begin(dict, &dict_op_settings);
dict_set(ctx, "shared/counters/global/counter", "128");
test_assert(dict_transaction_commit(&ctx, &error) == 1);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
error = NULL;
/* 2 fields */
ctx = dict_transaction_begin(dict, &dict_op_settings);
dict_set(ctx, "priv/quota/bytes", "128");
dict_set(ctx, "priv/quota/count", "1");
test_assert(dict_transaction_commit(&ctx, &error) == 1);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
error = NULL;
/* 3 fields */
ctx = dict_transaction_begin(dict, &dict_op_settings);
dict_set(ctx, "priv/quota/bytes", "128");
dict_set(ctx, "priv/quota/count", "1");
dict_set(ctx, "priv/quota/folders", "123");
test_assert(dict_transaction_commit(&ctx, &error) == 1);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
test_teardown(&dict);
test_end();
}
static void test_unset(void)
{
const char *error;
struct test_driver_result res = {
.affected_rows = 1,
.nqueries = 3,
.queries = (const char *[]){
"DELETE FROM counters WHERE class = 'global' AND name = 'counter'",
"DELETE FROM quota WHERE username = 'testuser'",
"DELETE FROM quota WHERE username = 'testuser'",
NULL},
.result = NULL,
};
struct dict *dict;
test_begin("dict unset");
test_setup(&dict);
test_set_expected(dict, &res);
struct dict_transaction_context *ctx = dict_transaction_begin(dict, &dict_op_settings);
dict_unset(ctx, "shared/counters/global/counter");
test_assert(dict_transaction_commit(&ctx, &error) == 1);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
error = NULL;
ctx = dict_transaction_begin(dict, &dict_op_settings);
dict_unset(ctx, "priv/quota/bytes");
dict_unset(ctx, "priv/quota/count");
test_assert(dict_transaction_commit(&ctx, &error) == 1);
if (error != NULL)
i_error("dict_transaction_commit failed: %s", error);
test_teardown(&dict);
test_end();
}
static void test_iterate(void)
{
const char *key = NULL, *value = NULL, *error;
struct test_driver_result_set rset = {
.rows = 5,
.cols = 2,
.col_names = (const char *[]){"value", "name", NULL},
.row_data = (const char **[]){
(const char*[]){"one", "counter", NULL},
(const char*[]){"two", "counter", NULL},
(const char*[]){"three", "counter", NULL},
(const char*[]){"four", "counter", NULL},
(const char*[]){"five", "counter", NULL},
},
};
struct test_driver_result res = {
.nqueries = 1,
.queries = (const char *[]){
"SELECT value,name FROM counters WHERE class = 'global' AND name = 'counter'",
NULL},
.result = &rset,
};
struct dict *dict;
test_begin("dict iterate");
test_setup(&dict);
test_set_expected(dict, &res);
struct dict_iterate_context *iter =
dict_iterate_init(dict, &dict_op_settings, "shared/counters/global/counter",
DICT_ITERATE_FLAG_EXACT_KEY);
size_t idx = 0;
while(dict_iterate(iter, &key, &value)) {
i_assert(idx < rset.rows);
test_assert_strcmp_idx(key, "shared/counters/global/counter", idx);
test_assert_strcmp_idx(value, rset.row_data[idx][0], idx);
idx++;
}
test_assert(idx == rset.rows);
test_assert(dict_iterate_deinit(&iter, &error) == 0);
if (error != NULL)
i_error("dict_iterate_deinit failed: %s", error);
error = NULL;
res.queries = (const char*[]){
"SELECT value,name FROM counters WHERE class = 'global' AND name LIKE '%' AND name NOT LIKE '%/%'",
NULL
};
res.cur = 0;
res.result->cur = 0;
test_set_expected(dict, &res);
iter = dict_iterate_init(dict, &dict_op_settings, "shared/counters/global/", 0);
idx = 0;
while(dict_iterate(iter, &key, &value)) {
i_assert(idx < rset.rows);
test_assert_strcmp_idx(key, "shared/counters/global/counter", idx);
test_assert_strcmp_idx(value, rset.row_data[idx][0], idx);
idx++;
}
test_assert(idx == rset.rows);
test_assert(dict_iterate_deinit(&iter, &error) == 0);
if (error != NULL)
i_error("dict_iterate_deinit failed: %s", error);
test_teardown(&dict);
test_end();
}
int main(void) {
sql_drivers_init();
sql_driver_test_register();
dict_sql_register();
static void (*const test_functions[])(void) = {
test_lookup_one,
test_atomic_inc,
test_set,
test_unset,
test_iterate,
NULL
};
int ret = test_run(test_functions);
dict_sql_unregister();
sql_driver_test_unregister();
sql_drivers_deinit();
return ret;
}
dovecot-2.3.21.1/src/lib-dict-backend/Makefile.am 0000644 0000000 0000000 00000005654 14656633576 016226 0000000 0000000 noinst_LTLIBRARIES = libdict_backend.la
module_dictdir = $(moduledir)/dict
dict_drivers = @dict_drivers@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-ldap \
-I$(top_srcdir)/src/lib-sql \
-I$(top_srcdir)/src/lib-settings \
$(SQL_CFLAGS)
NOPLUGIN_LDFLAGS =
ldap_sources = \
dict-ldap.c \
dict-ldap-settings.c
libdict_backend_la_SOURCES = \
dict-cdb.c \
dict-sql.c \
dict-sql-settings.c \
$(ldap_sources)
libdict_backend_la_LIBADD =
nodist_libdict_backend_la_SOURCES = \
dict-drivers-register.c
noinst_HEADERS = \
dict-ldap-settings.h \
dict-sql.h \
dict-sql-private.h \
dict-sql-settings.h
if LDAP_PLUGIN
LIBDICT_LDAP = libdict_ldap.la
libdict_ldap_la_DEPENDENCIES = $(LIBDOVECOT_LDAP) $(LIBDOVECOT_DEPS)
libdict_ldap_la_LDFLAGS = -module -avoid-version
libdict_ldap_la_LIBADD = $(LIBDOVECOT_LDAP) $(LIBDOVECOT)
libdict_ldap_la_CPPFLAGS = $(AM_CPPFLAGS) -DPLUGIN_BUILD
libdict_ldap_la_SOURCES = $(ldap_sources)
else
if HAVE_LDAP
libdict_backend_la_LIBADD += $(LIBDOVECOT_LDAP)
dict_drivers += ldap
endif
endif
module_dict_LTLIBRARIES = \
$(LIBDICT_LDAP)
EXTRA_DIST = dict.conf
dict-drivers-register.c: Makefile $(top_builddir)/config.h
rm -f $@
echo '/* this file automatically generated by Makefile */' >$@
echo '#include "lib.h"' >>$@
echo '#include "dict.h"' >>$@
echo '#include "ldap-client.h"' >>$@
echo '#include "dict-sql.h"' >>$@
for i in $(dict_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "extern struct dict dict_driver_$${i};" >>$@ ; \
fi; \
done
echo 'void dict_drivers_register_all(void) {' >>$@
echo 'dict_drivers_register_builtin();' >>$@
echo 'dict_sql_register();' >>$@
for i in $(dict_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "dict_driver_register(&dict_driver_$${i});" >>$@ ; \
fi; \
done
echo '}' >>$@
echo 'void dict_drivers_unregister_all(void) {' >>$@
echo '#ifdef BUILTIN_LDAP' >>$@
echo 'ldap_clients_cleanup();' >>$@
echo '#endif' >>$@
echo 'dict_drivers_unregister_builtin();' >>$@
echo 'dict_sql_unregister();' >>$@
for i in $(dict_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "dict_driver_unregister(&dict_driver_$${i});" >>$@ ; \
fi; \
done
echo '}' >>$@
distclean-generic:
rm -f Makefile dict-drivers-register.c
test_programs = \
test-dict-sql
noinst_PROGRAMS = $(test_programs)
test_dict_sql_CFLAGS = $(AM_CPPFLAGS) -DDICT_SRC_DIR=\"$(top_srcdir)/src/lib-dict-backend\"
test_dict_sql_SOURCES = \
test-dict-sql.c
test_dict_sql_LDADD = \
$(noinst_LTLIBRARIES) \
$(DICT_LIBS) \
../lib-sql/libdriver_test.la \
../lib-sql/libsql.la \
../lib-dovecot/libdovecot.la
test_dict_sql_DEPENDENCIES = \
$(noinst_LTLIBRARIES) \
../lib-sql/libdriver_test.la \
../lib-sql/libsql.la \
../lib-dovecot/libdovecot.la
check-local:
for bin in $(test_programs) $(check_PROGRAMS); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
dovecot-2.3.21.1/src/lib-dict-backend/dict-sql.c 0000644 0000000 0000000 00000127275 14656633576 016062 0000000 0000000 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "hex-binary.h"
#include "hash.h"
#include "str.h"
#include "sql-api-private.h"
#include "sql-db-cache.h"
#include "dict-private.h"
#include "dict-sql-settings.h"
#include "dict-sql.h"
#include "dict-sql-private.h"
#include
#include
#define DICT_SQL_MAX_UNUSED_CONNECTIONS 10
enum sql_recurse_type {
SQL_DICT_RECURSE_NONE,
SQL_DICT_RECURSE_ONE,
SQL_DICT_RECURSE_FULL
};
struct sql_dict_param {
enum dict_sql_type value_type;
const char *value_str;
int64_t value_int64;
const void *value_binary;
size_t value_binary_size;
};
ARRAY_DEFINE_TYPE(sql_dict_param, struct sql_dict_param);
struct sql_dict_iterate_context {
struct dict_iterate_context ctx;
pool_t pool;
enum dict_iterate_flags flags;
const char *path;
struct sql_result *result;
string_t *key;
const struct dict_sql_map *map;
size_t key_prefix_len, pattern_prefix_len;
unsigned int sql_fields_start_idx, next_map_idx;
bool destroyed;
bool synchronous_result;
bool iter_query_sent;
bool allow_null_map; /* allow next map to be NULL */
const char *error;
};
struct sql_dict_inc_row {
struct sql_dict_inc_row *prev;
unsigned int rows;
};
struct sql_dict_prev {
const struct dict_sql_map *map;
char *key;
union {
char *str;
long long diff;
} value;
};
struct sql_dict_transaction_context {
struct dict_transaction_context ctx;
struct sql_transaction_context *sql_ctx;
pool_t inc_row_pool;
struct sql_dict_inc_row *inc_row;
ARRAY(struct sql_dict_prev) prev_inc;
ARRAY(struct sql_dict_prev) prev_set;
dict_transaction_commit_callback_t *async_callback;
void *async_context;
char *error;
};
static struct sql_db_cache *dict_sql_db_cache;
static void sql_dict_prev_inc_flush(struct sql_dict_transaction_context *ctx);
static void sql_dict_prev_set_flush(struct sql_dict_transaction_context *ctx);
static void sql_dict_prev_inc_free(struct sql_dict_transaction_context *ctx);
static void sql_dict_prev_set_free(struct sql_dict_transaction_context *ctx);
static int
sql_dict_init(struct dict *driver, const char *uri,
const struct dict_settings *set,
struct dict **dict_r, const char **error_r)
{
struct sql_settings sql_set;
struct sql_dict *dict;
pool_t pool;
pool = pool_alloconly_create("sql dict", 2048);
dict = p_new(pool, struct sql_dict, 1);
dict->pool = pool;
dict->dict = *driver;
dict->set = dict_sql_settings_read(uri, error_r);
if (dict->set == NULL) {
pool_unref(&pool);
return -1;
}
i_zero(&sql_set);
sql_set.driver = driver->name;
sql_set.connect_string = dict->set->connect;
sql_set.event_parent = set->event_parent;
if (sql_db_cache_new(dict_sql_db_cache, &sql_set, &dict->db, error_r) < 0) {
pool_unref(&pool);
return -1;
}
*dict_r = &dict->dict;
return 0;
}
static void sql_dict_deinit(struct dict *_dict)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
sql_unref(&dict->db);
pool_unref(&dict->pool);
}
static void sql_dict_wait(struct dict *_dict)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
sql_wait(dict->db);
}
/* Try to match path to map->pattern. For example pattern="shared/x/$/$/y"
and path="shared/x/1/2/y", this is match and pattern_values=[1, 2]. */
static bool
dict_sql_map_match(const struct dict_sql_map *map, const char *path,
ARRAY_TYPE(const_string) *pattern_values, size_t *pat_len_r,
size_t *path_len_r, bool partial_ok, bool recurse)
{
const char *path_start = path;
const char *pat, *field, *p;
size_t len;
array_clear(pattern_values);
pat = map->pattern;
while (*pat != '\0' && *path != '\0') {
if (*pat == '$') {
/* variable */
pat++;
if (*pat == '\0') {
/* pattern ended with this variable,
it'll match the rest of the path */
len = strlen(path);
if (partial_ok) {
/* iterating - the last field never
matches fully. if there's a trailing
'/', drop it. */
pat--;
if (path[len-1] == '/') {
field = t_strndup(path, len-1);
array_push_back(pattern_values,
&field);
} else {
array_push_back(pattern_values,
&path);
}
} else {
array_push_back(pattern_values, &path);
path += len;
}
*path_len_r = path - path_start;
*pat_len_r = pat - map->pattern;
return TRUE;
}
/* pattern matches until the next '/' in path */
p = strchr(path, '/');
if (p != NULL) {
field = t_strdup_until(path, p);
array_push_back(pattern_values, &field);
path = p;
} else {
/* no '/' anymore, but it'll still match a
partial */
array_push_back(pattern_values, &path);
path += strlen(path);
pat++;
}
} else if (*pat == *path) {
pat++;
path++;
} else {
return FALSE;
}
}
*path_len_r = path - path_start;
*pat_len_r = pat - map->pattern;
if (*pat == '\0')
return *path == '\0';
else if (!partial_ok)
return FALSE;
else {
/* partial matches must end with '/'. */
if (pat != map->pattern && pat[-1] != '/')
return FALSE;
/* if we're not recursing, there should be only one $variable
left. */
if (recurse)
return TRUE;
return pat[0] == '$' && strchr(pat, '/') == NULL;
}
}
static const struct dict_sql_map *
sql_dict_find_map(struct sql_dict *dict, const char *path,
ARRAY_TYPE(const_string) *pattern_values)
{
const struct dict_sql_map *maps;
unsigned int i, count;
size_t len;
t_array_init(pattern_values, dict->set->max_pattern_fields_count);
maps = array_get(&dict->set->maps, &count);
for (i = 0; i < count; i++) {
if (dict_sql_map_match(&maps[i], path, pattern_values,
&len, &len, FALSE, FALSE))
return &maps[i];
}
return NULL;
}
static void
sql_dict_statement_bind(struct sql_statement *stmt, unsigned int column_idx,
const struct sql_dict_param *param)
{
switch (param->value_type) {
case DICT_SQL_TYPE_STRING:
sql_statement_bind_str(stmt, column_idx, param->value_str);
break;
case DICT_SQL_TYPE_INT:
case DICT_SQL_TYPE_UINT:
sql_statement_bind_int64(stmt, column_idx, param->value_int64);
break;
case DICT_SQL_TYPE_HEXBLOB:
sql_statement_bind_binary(stmt, column_idx, param->value_binary,
param->value_binary_size);
break;
}
}
static struct sql_statement *
sql_dict_statement_init(struct sql_dict *dict, const char *query,
const ARRAY_TYPE(sql_dict_param) *params)
{
struct sql_statement *stmt;
struct sql_prepared_statement *prep_stmt;
const struct sql_dict_param *param;
if ((sql_get_flags(dict->db) & SQL_DB_FLAG_PREP_STATEMENTS) != 0) {
prep_stmt = sql_prepared_statement_init(dict->db, query);
stmt = sql_statement_init_prepared(prep_stmt);
sql_prepared_statement_unref(&prep_stmt);
} else {
/* Prepared statements not supported by the backend.
Just use regular statements to avoid wasting memory. */
stmt = sql_statement_init(dict->db, query);
}
array_foreach(params, param) {
sql_dict_statement_bind(stmt, array_foreach_idx(params, param),
param);
}
return stmt;
}
static int
sql_dict_value_get(const struct dict_sql_map *map,
enum dict_sql_type value_type, const char *field_name,
const char *value, const char *value_suffix,
ARRAY_TYPE(sql_dict_param) *params, const char **error_r)
{
struct sql_dict_param *param;
buffer_t *buf;
param = array_append_space(params);
param->value_type = value_type;
switch (value_type) {
case DICT_SQL_TYPE_STRING:
if (value_suffix[0] != '\0')
value = t_strconcat(value, value_suffix, NULL);
param->value_str = value;
return 0;
case DICT_SQL_TYPE_INT:
if (value_suffix[0] != '\0' ||
str_to_int64(value, ¶m->value_int64) < 0) {
*error_r = t_strdup_printf(
"%s field's value isn't 64bit signed integer: %s%s (in pattern: %s)",
field_name, value, value_suffix, map->pattern);
return -1;
}
return 0;
case DICT_SQL_TYPE_UINT:
if (value_suffix[0] != '\0' || value[0] == '-' ||
str_to_int64(value, ¶m->value_int64) < 0) {
*error_r = t_strdup_printf(
"%s field's value isn't 64bit unsigned integer: %s%s (in pattern: %s)",
field_name, value, value_suffix, map->pattern);
return -1;
}
return 0;
case DICT_SQL_TYPE_HEXBLOB:
break;
}
buf = t_buffer_create(strlen(value)/2);
if (hex_to_binary(value, buf) < 0) {
/* we shouldn't get untrusted input here. it's also a bit
annoying to handle this error. */
*error_r = t_strdup_printf("%s field's value isn't hexblob: %s (in pattern: %s)",
field_name, value, map->pattern);
return -1;
}
str_append(buf, value_suffix);
param->value_binary = buf->data;
param->value_binary_size = buf->used;
return 0;
}
static int
sql_dict_field_get_value(const struct dict_sql_map *map,
const struct dict_sql_field *field,
const char *value, const char *value_suffix,
ARRAY_TYPE(sql_dict_param) *params,
const char **error_r)
{
return sql_dict_value_get(map, field->value_type, field->name,
value, value_suffix, params, error_r);
}
static int
sql_dict_where_build(const char *username, const struct dict_sql_map *map,
const ARRAY_TYPE(const_string) *values_arr,
bool add_username, enum sql_recurse_type recurse_type,
string_t *query, ARRAY_TYPE(sql_dict_param) *params,
const char **error_r)
{
const struct dict_sql_field *pattern_fields;
const char *const *pattern_values;
unsigned int i, count, count2, exact_count;
pattern_fields = array_get(&map->pattern_fields, &count);
pattern_values = array_get(values_arr, &count2);
/* if we came here from iteration code there may be fewer
pattern_values */
i_assert(count2 <= count);
if (count2 == 0 && !add_username) {
/* we want everything */
return 0;
}
str_append(query, " WHERE");
exact_count = count == count2 && recurse_type != SQL_DICT_RECURSE_NONE ?
count2-1 : count2;
if (exact_count != array_count(values_arr)) {
*error_r = t_strdup_printf("Key continues past the matched pattern %s", map->pattern);
return -1;
}
for (i = 0; i < exact_count; i++) {
if (i > 0)
str_append(query, " AND");
str_printfa(query, " %s = ?", pattern_fields[i].name);
if (sql_dict_field_get_value(map, &pattern_fields[i],
pattern_values[i], "",
params, error_r) < 0)
return -1;
}
switch (recurse_type) {
case SQL_DICT_RECURSE_NONE:
break;
case SQL_DICT_RECURSE_ONE:
if (i > 0)
str_append(query, " AND");
if (i < count2) {
str_printfa(query, " %s LIKE ?", pattern_fields[i].name);
if (sql_dict_field_get_value(map, &pattern_fields[i],
pattern_values[i], "/%",
params, error_r) < 0)
return -1;
str_printfa(query, " AND %s NOT LIKE ?", pattern_fields[i].name);
if (sql_dict_field_get_value(map, &pattern_fields[i],
pattern_values[i], "/%/%",
params, error_r) < 0)
return -1;
} else {
str_printfa(query, " %s LIKE '%%' AND "
"%s NOT LIKE '%%/%%'",
pattern_fields[i].name,
pattern_fields[i].name);
}
break;
case SQL_DICT_RECURSE_FULL:
if (i < count2) {
if (i > 0)
str_append(query, " AND");
str_printfa(query, " %s LIKE ",
pattern_fields[i].name);
if (sql_dict_field_get_value(map, &pattern_fields[i],
pattern_values[i], "/%",
params, error_r) < 0)
return -1;
}
break;
}
if (add_username) {
struct sql_dict_param *param = array_append_space(params);
if (count2 > 0)
str_append(query, " AND");
str_printfa(query, " %s = ?", map->username_field);
param->value_type = DICT_SQL_TYPE_STRING;
param->value_str = t_strdup(username);
}
return 0;
}
static int
sql_lookup_get_query(struct sql_dict *dict,
const struct dict_op_settings *set,
const char *key,
const struct dict_sql_map **map_r,
struct sql_statement **stmt_r,
const char **error_r)
{
const struct dict_sql_map *map;
ARRAY_TYPE(const_string) pattern_values;
const char *error;
map = *map_r = sql_dict_find_map(dict, key, &pattern_values);
if (map == NULL) {
*error_r = t_strdup_printf(
"sql dict lookup: Invalid/unmapped key: %s", key);
return -1;
}
string_t *query = t_str_new(256);
ARRAY_TYPE(sql_dict_param) params;
t_array_init(¶ms, 4);
str_printfa(query, "SELECT %s FROM %s",
map->value_field, map->table);
if (sql_dict_where_build(set->username, map, &pattern_values,
key[0] == DICT_PATH_PRIVATE[0],
SQL_DICT_RECURSE_NONE, query,
¶ms, &error) < 0) {
*error_r = t_strdup_printf(
"sql dict lookup: Failed to lookup key %s: %s", key, error);
return -1;
}
*stmt_r = sql_dict_statement_init(dict, str_c(query), ¶ms);
return 0;
}
static const char *
sql_dict_result_unescape(enum dict_sql_type type, pool_t pool,
struct sql_result *result, unsigned int result_idx)
{
const unsigned char *data;
size_t size;
const char *value;
string_t *str;
switch (type) {
case DICT_SQL_TYPE_STRING:
case DICT_SQL_TYPE_INT:
case DICT_SQL_TYPE_UINT:
value = sql_result_get_field_value(result, result_idx);
return value == NULL ? "" : p_strdup(pool, value);
case DICT_SQL_TYPE_HEXBLOB:
break;
}
data = sql_result_get_field_value_binary(result, result_idx, &size);
str = str_new(pool, size*2 + 1);
binary_to_hex_append(str, data, size);
return str_c(str);
}
static const char *
sql_dict_result_unescape_value(const struct dict_sql_map *map, pool_t pool,
struct sql_result *result)
{
return sql_dict_result_unescape(map->value_types[0], pool, result, 0);
}
static const char *const *
sql_dict_result_unescape_values(const struct dict_sql_map *map, pool_t pool,
struct sql_result *result)
{
const char **values;
unsigned int i;
values = p_new(pool, const char *, map->values_count + 1);
for (i = 0; i < map->values_count; i++) {
values[i] = sql_dict_result_unescape(map->value_types[i],
pool, result, i);
}
return values;
}
static const char *
sql_dict_result_unescape_field(const struct dict_sql_map *map, pool_t pool,
struct sql_result *result, unsigned int result_idx,
unsigned int sql_field_idx)
{
const struct dict_sql_field *sql_field;
sql_field = array_idx(&map->pattern_fields, sql_field_idx);
return sql_dict_result_unescape(sql_field->value_type, pool,
result, result_idx);
}
static int sql_dict_lookup(struct dict *_dict, const struct dict_op_settings *set,
pool_t pool, const char *key,
const char **value_r, const char **error_r)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
const struct dict_sql_map *map;
struct sql_statement *stmt;
struct sql_result *result = NULL;
int ret;
*value_r = NULL;
if (sql_lookup_get_query(dict, set, key, &map, &stmt, error_r) < 0)
return -1;
result = sql_statement_query_s(&stmt);
ret = sql_result_next_row(result);
if (ret < 0) {
*error_r = t_strdup_printf("dict sql lookup failed: %s",
sql_result_get_error(result));
} else if (ret > 0) {
*value_r = sql_dict_result_unescape_value(map, pool, result);
}
sql_result_unref(result);
return ret;
}
struct sql_dict_lookup_context {
const struct dict_sql_map *map;
dict_lookup_callback_t *callback;
void *context;
};
static void
sql_dict_lookup_async_callback(struct sql_result *sql_result,
struct sql_dict_lookup_context *ctx)
{
struct dict_lookup_result result;
i_zero(&result);
result.ret = sql_result_next_row(sql_result);
if (result.ret < 0)
result.error = sql_result_get_error(sql_result);
else if (result.ret > 0) {
result.values = sql_dict_result_unescape_values(ctx->map,
pool_datastack_create(), sql_result);
result.value = result.values[0];
if (result.value == NULL) {
/* NULL value returned. we'll treat this as
"not found", which is probably what is usually
wanted. */
result.ret = 0;
}
}
ctx->callback(&result, ctx->context);
i_free(ctx);
}
static void
sql_dict_lookup_async(struct dict *_dict,
const struct dict_op_settings *set,
const char *key,
dict_lookup_callback_t *callback, void *context)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
const struct dict_sql_map *map;
struct sql_dict_lookup_context *ctx;
struct sql_statement *stmt;
const char *error;
if (sql_lookup_get_query(dict, set, key, &map, &stmt, &error) < 0) {
struct dict_lookup_result result;
i_zero(&result);
result.ret = -1;
result.error = error;
callback(&result, context);
} else {
ctx = i_new(struct sql_dict_lookup_context, 1);
ctx->callback = callback;
ctx->context = context;
ctx->map = map;
sql_statement_query(&stmt, sql_dict_lookup_async_callback, ctx);
}
}
static const struct dict_sql_map *
sql_dict_iterate_find_next_map(struct sql_dict_iterate_context *ctx,
ARRAY_TYPE(const_string) *pattern_values)
{
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict;
const struct dict_sql_map *maps;
unsigned int i, count;
size_t pat_len, path_len;
bool recurse = (ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0;
t_array_init(pattern_values, dict->set->max_pattern_fields_count);
maps = array_get(&dict->set->maps, &count);
for (i = ctx->next_map_idx; i < count; i++) {
if (dict_sql_map_match(&maps[i], ctx->path,
pattern_values, &pat_len, &path_len,
TRUE, recurse) &&
(recurse ||
array_count(pattern_values)+1 >= array_count(&maps[i].pattern_fields))) {
ctx->key_prefix_len = path_len;
ctx->pattern_prefix_len = pat_len;
ctx->next_map_idx = i + 1;
str_truncate(ctx->key, 0);
str_append(ctx->key, ctx->path);
return &maps[i];
}
}
return NULL;
}
static int
sql_dict_iterate_build_next_query(struct sql_dict_iterate_context *ctx,
struct sql_statement **stmt_r,
const char **error_r)
{
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict;
const struct dict_op_settings_private *set = &ctx->ctx.set;
const struct dict_sql_map *map;
ARRAY_TYPE(const_string) pattern_values;
const struct dict_sql_field *pattern_fields;
enum sql_recurse_type recurse_type;
unsigned int i, count;
map = sql_dict_iterate_find_next_map(ctx, &pattern_values);
/* NULL map is allowed if we have already done some lookups */
if (map == NULL) {
if (!ctx->allow_null_map) {
*error_r = "Invalid/unmapped path";
return -1;
}
return 0;
}
if (ctx->result != NULL) {
sql_result_unref(ctx->result);
ctx->result = NULL;
}
string_t *query = t_str_new(256);
str_append(query, "SELECT ");
if ((ctx->flags & DICT_ITERATE_FLAG_NO_VALUE) == 0)
str_printfa(query, "%s,", map->value_field);
/* get all missing fields */
pattern_fields = array_get(&map->pattern_fields, &count);
i = array_count(&pattern_values);
if (i == count) {
/* we always want to know the last field since we're
iterating its children */
i_assert(i > 0);
i--;
}
ctx->sql_fields_start_idx = i;
for (; i < count; i++)
str_printfa(query, "%s,", pattern_fields[i].name);
str_truncate(query, str_len(query)-1);
str_printfa(query, " FROM %s", map->table);
if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0)
recurse_type = SQL_DICT_RECURSE_FULL;
else if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0)
recurse_type = SQL_DICT_RECURSE_NONE;
else
recurse_type = SQL_DICT_RECURSE_ONE;
ARRAY_TYPE(sql_dict_param) params;
t_array_init(¶ms, 4);
bool add_username = (ctx->path[0] == DICT_PATH_PRIVATE[0]);
if (sql_dict_where_build(set->username, map, &pattern_values, add_username,
recurse_type, query, ¶ms, error_r) < 0)
return -1;
if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_KEY) != 0) {
str_append(query, " ORDER BY ");
for (i = 0; i < count; i++) {
str_printfa(query, "%s", pattern_fields[i].name);
if (i < count-1)
str_append_c(query, ',');
}
} else if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_VALUE) != 0)
str_printfa(query, " ORDER BY %s", map->value_field);
if (ctx->ctx.max_rows > 0) {
i_assert(ctx->ctx.row_count < ctx->ctx.max_rows);
str_printfa(query, " LIMIT %"PRIu64,
ctx->ctx.max_rows - ctx->ctx.row_count);
}
*stmt_r = sql_dict_statement_init(dict, str_c(query), ¶ms);
ctx->map = map;
return 1;
}
static void sql_dict_iterate_callback(struct sql_result *result,
struct sql_dict_iterate_context *ctx)
{
if (!ctx->destroyed) {
sql_result_ref(result);
ctx->result = result;
if (ctx->ctx.async_callback != NULL && !ctx->synchronous_result)
ctx->ctx.async_callback(ctx->ctx.async_context);
}
pool_t pool_copy = ctx->pool;
pool_unref(&pool_copy);
}
static int sql_dict_iterate_next_query(struct sql_dict_iterate_context *ctx)
{
struct sql_statement *stmt;
const char *error;
int ret;
ret = sql_dict_iterate_build_next_query(ctx, &stmt, &error);
if (ret <= 0) {
/* this is expected error */
if (ret == 0)
return ret;
/* failed */
ctx->error = p_strdup_printf(ctx->pool,
"sql dict iterate failed for %s: %s",
ctx->path, error);
return -1;
}
if ((ctx->flags & DICT_ITERATE_FLAG_ASYNC) == 0) {
ctx->result = sql_statement_query_s(&stmt);
} else {
i_assert(ctx->result == NULL);
ctx->synchronous_result = TRUE;
pool_ref(ctx->pool);
sql_statement_query(&stmt, sql_dict_iterate_callback, ctx);
ctx->synchronous_result = FALSE;
}
return ret;
}
static struct dict_iterate_context *
sql_dict_iterate_init(struct dict *_dict,
const struct dict_op_settings *set ATTR_UNUSED,
const char *path, enum dict_iterate_flags flags)
{
struct sql_dict_iterate_context *ctx;
pool_t pool;
pool = pool_alloconly_create("sql dict iterate", 512);
ctx = p_new(pool, struct sql_dict_iterate_context, 1);
ctx->ctx.dict = _dict;
ctx->pool = pool;
ctx->flags = flags;
ctx->path = p_strdup(pool, path);
ctx->key = str_new(pool, 256);
return &ctx->ctx;
}
static bool sql_dict_iterate(struct dict_iterate_context *_ctx,
const char **key_r, const char *const **values_r)
{
struct sql_dict_iterate_context *ctx =
(struct sql_dict_iterate_context *)_ctx;
const char *p, *value;
unsigned int i, sql_field_i, count;
int ret;
_ctx->has_more = FALSE;
if (ctx->error != NULL)
return FALSE;
if (!ctx->iter_query_sent) {
ctx->iter_query_sent = TRUE;
if (sql_dict_iterate_next_query(ctx) <= 0)
return FALSE;
}
if (ctx->result == NULL) {
/* wait for async lookup to finish */
i_assert((ctx->flags & DICT_ITERATE_FLAG_ASYNC) != 0);
_ctx->has_more = TRUE;
return FALSE;
}
ret = sql_result_next_row(ctx->result);
while (ret == SQL_RESULT_NEXT_MORE) {
if ((ctx->flags & DICT_ITERATE_FLAG_ASYNC) == 0)
sql_result_more_s(&ctx->result);
else {
/* get more results asynchronously */
ctx->synchronous_result = TRUE;
pool_ref(ctx->pool);
sql_result_more(&ctx->result, sql_dict_iterate_callback, ctx);
ctx->synchronous_result = FALSE;
if (ctx->result == NULL) {
_ctx->has_more = TRUE;
return FALSE;
}
}
ret = sql_result_next_row(ctx->result);
}
if (ret == 0) {
/* see if there are more results in the next map.
don't do it if we're looking for an exact match, since we
already should have handled it. */
if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0)
return FALSE;
ctx->iter_query_sent = FALSE;
/* we have gotten *SOME* results, so can allow
unmapped next key now. */
ctx->allow_null_map = TRUE;
return sql_dict_iterate(_ctx, key_r, values_r);
}
if (ret < 0) {
ctx->error = p_strdup_printf(ctx->pool,
"dict sql iterate failed: %s",
sql_result_get_error(ctx->result));
return FALSE;
}
/* convert fetched row to dict key */
str_truncate(ctx->key, ctx->key_prefix_len);
if (ctx->key_prefix_len > 0 &&
str_c(ctx->key)[ctx->key_prefix_len-1] != '/')
str_append_c(ctx->key, '/');
count = sql_result_get_fields_count(ctx->result);
i = (ctx->flags & DICT_ITERATE_FLAG_NO_VALUE) != 0 ? 0 :
ctx->map->values_count;
sql_field_i = ctx->sql_fields_start_idx;
for (p = ctx->map->pattern + ctx->pattern_prefix_len; *p != '\0'; p++) {
if (*p != '$')
str_append_c(ctx->key, *p);
else {
i_assert(i < count);
value = sql_dict_result_unescape_field(ctx->map,
pool_datastack_create(), ctx->result, i, sql_field_i);
if (value != NULL)
str_append(ctx->key, value);
i++; sql_field_i++;
}
}
*key_r = str_c(ctx->key);
if ((ctx->flags & DICT_ITERATE_FLAG_NO_VALUE) == 0) {
*values_r = sql_dict_result_unescape_values(ctx->map,
pool_datastack_create(), ctx->result);
}
return TRUE;
}
static int sql_dict_iterate_deinit(struct dict_iterate_context *_ctx,
const char **error_r)
{
struct sql_dict_iterate_context *ctx =
(struct sql_dict_iterate_context *)_ctx;
int ret = ctx->error != NULL ? -1 : 0;
*error_r = t_strdup(ctx->error);
if (ctx->result != NULL)
sql_result_unref(ctx->result);
ctx->destroyed = TRUE;
pool_t pool_copy = ctx->pool;
pool_unref(&pool_copy);
return ret;
}
static struct dict_transaction_context *
sql_dict_transaction_init(struct dict *_dict)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
struct sql_dict_transaction_context *ctx;
ctx = i_new(struct sql_dict_transaction_context, 1);
ctx->ctx.dict = _dict;
ctx->sql_ctx = sql_transaction_begin(dict->db);
return &ctx->ctx;
}
static void sql_dict_transaction_free(struct sql_dict_transaction_context *ctx)
{
if (array_is_created(&ctx->prev_inc))
sql_dict_prev_inc_free(ctx);
if (array_is_created(&ctx->prev_set))
sql_dict_prev_set_free(ctx);
pool_unref(&ctx->inc_row_pool);
i_free(ctx->error);
i_free(ctx);
}
static bool
sql_dict_transaction_has_nonexistent(struct sql_dict_transaction_context *ctx)
{
struct sql_dict_inc_row *inc_row;
for (inc_row = ctx->inc_row; inc_row != NULL; inc_row = inc_row->prev) {
i_assert(inc_row->rows != UINT_MAX);
if (inc_row->rows == 0)
return TRUE;
}
return FALSE;
}
static void
sql_dict_transaction_commit_callback(const struct sql_commit_result *sql_result,
struct sql_dict_transaction_context *ctx)
{
struct dict_commit_result result;
i_zero(&result);
if (sql_result->error == NULL)
result.ret = sql_dict_transaction_has_nonexistent(ctx) ?
DICT_COMMIT_RET_NOTFOUND : DICT_COMMIT_RET_OK;
else {
result.error = t_strdup_printf("sql dict: commit failed: %s",
sql_result->error);
switch (sql_result->error_type) {
case SQL_RESULT_ERROR_TYPE_UNKNOWN:
default:
result.ret = DICT_COMMIT_RET_FAILED;
break;
case SQL_RESULT_ERROR_TYPE_WRITE_UNCERTAIN:
result.ret = DICT_COMMIT_RET_WRITE_UNCERTAIN;
break;
}
}
if (ctx->async_callback != NULL)
ctx->async_callback(&result, ctx->async_context);
else if (result.ret < 0)
i_error("%s", result.error);
sql_dict_transaction_free(ctx);
}
static void
sql_dict_transaction_commit(struct dict_transaction_context *_ctx, bool async,
dict_transaction_commit_callback_t *callback,
void *context)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
const char *error;
struct dict_commit_result result;
/* flush any pending set/inc */
if (array_is_created(&ctx->prev_inc))
sql_dict_prev_inc_flush(ctx);
if (array_is_created(&ctx->prev_set))
sql_dict_prev_set_flush(ctx);
/* note that the above calls might still set ctx->error */
i_zero(&result);
result.ret = DICT_COMMIT_RET_FAILED;
result.error = t_strdup(ctx->error);
if (ctx->error != NULL) {
sql_transaction_rollback(&ctx->sql_ctx);
} else if (!_ctx->changed) {
/* nothing changed, no need to commit */
sql_transaction_rollback(&ctx->sql_ctx);
result.ret = DICT_COMMIT_RET_OK;
} else if (async) {
ctx->async_callback = callback;
ctx->async_context = context;
sql_transaction_commit(&ctx->sql_ctx,
sql_dict_transaction_commit_callback, ctx);
return;
} else if (sql_transaction_commit_s(&ctx->sql_ctx, &error) < 0) {
result.error = t_strdup_printf(
"sql dict: commit failed: %s", error);
} else {
if (sql_dict_transaction_has_nonexistent(ctx))
result.ret = DICT_COMMIT_RET_NOTFOUND;
else
result.ret = DICT_COMMIT_RET_OK;
}
sql_dict_transaction_free(ctx);
callback(&result, context);
}
static void sql_dict_transaction_rollback(struct dict_transaction_context *_ctx)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
sql_transaction_rollback(&ctx->sql_ctx);
sql_dict_transaction_free(ctx);
}
static struct sql_statement *
sql_dict_transaction_stmt_init(struct sql_dict_transaction_context *ctx,
const char *query,
const ARRAY_TYPE(sql_dict_param) *params)
{
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict;
struct sql_statement *stmt =
sql_dict_statement_init(dict, query, params);
if (ctx->ctx.timestamp.tv_sec != 0)
sql_statement_set_timestamp(stmt, &ctx->ctx.timestamp);
if (ctx->ctx.set.hide_log_values)
sql_statement_set_no_log_expanded_values(stmt, ctx->ctx.set.hide_log_values);
return stmt;
}
struct dict_sql_build_query_field {
const struct dict_sql_map *map;
const char *value;
};
struct dict_sql_build_query {
struct sql_dict *dict;
ARRAY(struct dict_sql_build_query_field) fields;
const ARRAY_TYPE(const_string) *pattern_values;
bool add_username;
};
static int sql_dict_set_query(struct sql_dict_transaction_context *ctx,
const struct dict_sql_build_query *build,
struct sql_statement **stmt_r,
const char **error_r)
{
struct sql_dict *dict = build->dict;
const struct dict_sql_build_query_field *fields;
const struct dict_sql_field *pattern_fields;
ARRAY_TYPE(sql_dict_param) params;
const char *const *pattern_values;
unsigned int i, field_count, count, count2;
string_t *prefix, *suffix;
fields = array_get(&build->fields, &field_count);
i_assert(field_count > 0);
t_array_init(¶ms, 4);
prefix = t_str_new(64);
suffix = t_str_new(256);
/* SQL table is guaranteed to be the same for all fields.
Build all the SQL field names into prefix and '?' placeholders for
each value into the suffix. The actual field values will be added
into params[]. */
str_printfa(prefix, "INSERT INTO %s", fields[0].map->table);
str_append(prefix, " (");
str_append(suffix, ") VALUES (");
for (i = 0; i < field_count; i++) {
if (i > 0) {
str_append_c(prefix, ',');
str_append_c(suffix, ',');
}
str_append(prefix, t_strcut(fields[i].map->value_field, ','));
enum dict_sql_type value_type =
fields[i].map->value_types[0];
str_append_c(suffix, '?');
if (sql_dict_value_get(fields[i].map,
value_type, "value", fields[i].value,
"", ¶ms, error_r) < 0)
return -1;
}
if (build->add_username) {
struct sql_dict_param *param = array_append_space(¶ms);
str_printfa(prefix, ",%s", fields[0].map->username_field);
str_append(suffix, ",?");
param->value_type = DICT_SQL_TYPE_STRING;
param->value_str = ctx->ctx.set.username;
}
/* add the variable fields that were parsed from the path */
pattern_fields = array_get(&fields[0].map->pattern_fields, &count);
pattern_values = array_get(build->pattern_values, &count2);
i_assert(count == count2);
for (i = 0; i < count; i++) {
str_printfa(prefix, ",%s", pattern_fields[i].name);
str_append(suffix, ",?");
if (sql_dict_field_get_value(fields[0].map, &pattern_fields[i],
pattern_values[i], "",
¶ms, error_r) < 0)
return -1;
}
str_append_str(prefix, suffix);
str_append_c(prefix, ')');
enum sql_db_flags flags = sql_get_flags(dict->db);
if ((flags & SQL_DB_FLAG_ON_DUPLICATE_KEY) != 0)
str_append(prefix, " ON DUPLICATE KEY UPDATE ");
else if ((flags & SQL_DB_FLAG_ON_CONFLICT_DO) != 0) {
str_append(prefix, " ON CONFLICT (");
for (i = 0; i < count; i++) {
if (i > 0)
str_append_c(prefix, ',');
str_append(prefix, pattern_fields[i].name);
}
if (build->add_username) {
if (count > 0)
str_append_c(prefix, ',');
str_append(prefix, fields[0].map->username_field);
}
str_append(prefix, ") DO UPDATE SET ");
} else {
*stmt_r = sql_dict_transaction_stmt_init(ctx, str_c(prefix), ¶ms);
return 0;
}
/* If the row already exists, UPDATE it instead. The pattern_values
don't need to be updated here, because they are expected to be part
of the row's primary key. */
for (i = 0; i < field_count; i++) {
const char *first_value_field =
t_strcut(fields[i].map->value_field, ',');
if (i > 0)
str_append_c(prefix, ',');
str_append(prefix, first_value_field);
str_append_c(prefix, '=');
enum dict_sql_type value_type =
fields[i].map->value_types[0];
str_append_c(prefix, '?');
if (sql_dict_value_get(fields[i].map,
value_type, "value", fields[i].value,
"", ¶ms, error_r) < 0)
return -1;
}
*stmt_r = sql_dict_transaction_stmt_init(ctx, str_c(prefix), ¶ms);
return 0;
}
static int
sql_dict_update_query(const struct dict_sql_build_query *build,
const struct dict_op_settings_private *set,
const char **query_r, ARRAY_TYPE(sql_dict_param) *params,
const char **error_r)
{
const struct dict_sql_build_query_field *fields;
unsigned int i, field_count;
string_t *query;
fields = array_get(&build->fields, &field_count);
i_assert(field_count > 0);
query = t_str_new(64);
str_printfa(query, "UPDATE %s SET ", fields[0].map->table);
for (i = 0; i < field_count; i++) {
const char *first_value_field =
t_strcut(fields[i].map->value_field, ',');
if (i > 0)
str_append_c(query, ',');
str_printfa(query, "%s=%s+?", first_value_field,
first_value_field);
}
if (sql_dict_where_build(set->username, fields[0].map, build->pattern_values,
build->add_username, SQL_DICT_RECURSE_NONE,
query, params, error_r) < 0)
return -1;
*query_r = str_c(query);
return 0;
}
static void sql_dict_prev_set_free(struct sql_dict_transaction_context *ctx)
{
struct sql_dict_prev *prev_set;
array_foreach_modifiable(&ctx->prev_set, prev_set) {
i_free(prev_set->value.str);
i_free(prev_set->key);
}
array_free(&ctx->prev_set);
}
static void sql_dict_prev_set_flush(struct sql_dict_transaction_context *ctx)
{
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict;
const struct sql_dict_prev *prev_sets;
unsigned int count;
struct sql_statement *stmt;
ARRAY_TYPE(const_string) pattern_values;
struct dict_sql_build_query build;
struct dict_sql_build_query_field *field;
const char *error;
i_assert(array_is_created(&ctx->prev_set));
if (ctx->error != NULL) {
sql_dict_prev_set_free(ctx);
return;
}
prev_sets = array_get(&ctx->prev_set, &count);
i_assert(count > 0);
/* Get the variable values from the dict path. We already verified that
these are all exactly the same for everything in prev_sets. */
if (sql_dict_find_map(dict, prev_sets[0].key, &pattern_values) == NULL)
i_unreached(); /* this was already checked */
i_zero(&build);
build.dict = dict;
build.pattern_values = &pattern_values;
build.add_username = (prev_sets[0].key[0] == DICT_PATH_PRIVATE[0]);
/* build.fields[] is used to get the map { value_field } for the
SQL field names, as well as the values for them.
Example: INSERT INTO ... (build.fields[0].map->value_field,
...[1], ...) VALUES (build.fields[0].value, ...[1], ...) */
t_array_init(&build.fields, count);
for (unsigned int i = 0; i < count; i++) {
i_assert(build.add_username ==
(prev_sets[i].key[0] == DICT_PATH_PRIVATE[0]));
field = array_append_space(&build.fields);
field->map = prev_sets[i].map;
field->value = prev_sets[i].value.str;
}
if (sql_dict_set_query(ctx, &build, &stmt, &error) < 0) {
ctx->error = i_strdup_printf(
"dict-sql: Failed to set %u fields (first %s): %s",
count, prev_sets[0].key, error);
} else {
sql_update_stmt(ctx->sql_ctx, &stmt);
}
sql_dict_prev_set_free(ctx);
}
static void sql_dict_unset(struct dict_transaction_context *_ctx,
const char *key)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
const struct dict_op_settings_private *set = &_ctx->set;
const struct dict_sql_map *map;
ARRAY_TYPE(const_string) pattern_values;
string_t *query = t_str_new(256);
ARRAY_TYPE(sql_dict_param) params;
const char *error;
if (ctx->error != NULL)
return;
/* In theory we could unset one of the previous set/incs in this
same transaction, so flush them first. */
if (array_is_created(&ctx->prev_inc))
sql_dict_prev_inc_flush(ctx);
if (array_is_created(&ctx->prev_set))
sql_dict_prev_set_flush(ctx);
map = sql_dict_find_map(dict, key, &pattern_values);
if (map == NULL) {
ctx->error = i_strdup_printf("dict-sql: Invalid/unmapped key: %s", key);
return;
}
str_printfa(query, "DELETE FROM %s", map->table);
t_array_init(¶ms, 4);
if (sql_dict_where_build(set->username, map, &pattern_values,
key[0] == DICT_PATH_PRIVATE[0],
SQL_DICT_RECURSE_NONE, query,
¶ms, &error) < 0) {
ctx->error = i_strdup_printf(
"dict-sql: Failed to delete %s: %s", key, error);
} else {
struct sql_statement *stmt =
sql_dict_transaction_stmt_init(ctx, str_c(query), ¶ms);
sql_update_stmt(ctx->sql_ctx, &stmt);
}
}
static unsigned int *
sql_dict_next_inc_row(struct sql_dict_transaction_context *ctx)
{
struct sql_dict_inc_row *row;
if (ctx->inc_row_pool == NULL) {
ctx->inc_row_pool =
pool_alloconly_create("sql dict inc rows", 128);
}
row = p_new(ctx->inc_row_pool, struct sql_dict_inc_row, 1);
row->prev = ctx->inc_row;
row->rows = UINT_MAX;
ctx->inc_row = row;
return &row->rows;
}
static void sql_dict_prev_inc_free(struct sql_dict_transaction_context *ctx)
{
struct sql_dict_prev *prev_inc;
array_foreach_modifiable(&ctx->prev_inc, prev_inc)
i_free(prev_inc->key);
array_free(&ctx->prev_inc);
}
static void sql_dict_prev_inc_flush(struct sql_dict_transaction_context *ctx)
{
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict;
const struct dict_op_settings_private *set = &ctx->ctx.set;
const struct sql_dict_prev *prev_incs;
unsigned int count;
ARRAY_TYPE(const_string) pattern_values;
struct dict_sql_build_query build;
struct dict_sql_build_query_field *field;
ARRAY_TYPE(sql_dict_param) params;
struct sql_dict_param *param;
const char *query, *error;
i_assert(array_is_created(&ctx->prev_inc));
if (ctx->error != NULL) {
sql_dict_prev_inc_free(ctx);
return;
}
prev_incs = array_get(&ctx->prev_inc, &count);
i_assert(count > 0);
/* Get the variable values from the dict path. We already verified that
these are all exactly the same for everything in prev_incs. */
if (sql_dict_find_map(dict, prev_incs[0].key, &pattern_values) == NULL)
i_unreached(); /* this was already checked */
i_zero(&build);
build.dict = dict;
build.pattern_values = &pattern_values;
build.add_username = (prev_incs[0].key[0] == DICT_PATH_PRIVATE[0]);
/* build.fields[] is an array of maps, which are used to get the
map { value_field } for the SQL field names.
params[] specifies the list of values to use for each field.
Example: UPDATE .. SET build.fields[0].map->value_field =
...->value_field + params[0]->value_int64, ...[1]... */
t_array_init(&build.fields, count);
t_array_init(¶ms, count);
for (unsigned int i = 0; i < count; i++) {
i_assert(build.add_username ==
(prev_incs[i].key[0] == DICT_PATH_PRIVATE[0]));
field = array_append_space(&build.fields);
field->map = prev_incs[i].map;
field->value = NULL; /* unused */
param = array_append_space(¶ms);
param->value_type = DICT_SQL_TYPE_INT;
param->value_int64 = prev_incs[i].value.diff;
}
if (sql_dict_update_query(&build, set, &query, ¶ms, &error) < 0) {
ctx->error = i_strdup_printf(
"dict-sql: Failed to increase %u fields (first %s): %s",
count, prev_incs[0].key, error);
} else {
struct sql_statement *stmt =
sql_dict_transaction_stmt_init(ctx, query, ¶ms);
sql_update_stmt_get_rows(ctx->sql_ctx, &stmt,
sql_dict_next_inc_row(ctx));
}
sql_dict_prev_inc_free(ctx);
}
static bool
sql_dict_maps_are_mergeable(struct sql_dict *dict,
const struct sql_dict_prev *prev1,
const struct dict_sql_map *map2,
const char *map2_key,
const ARRAY_TYPE(const_string) *map2_pattern_values)
{
const struct dict_sql_map *map3;
ARRAY_TYPE(const_string) map1_pattern_values;
/* sql table names must equal */
if (strcmp(prev1->map->table, map2->table) != 0)
return FALSE;
/* private vs shared prefix must equal */
if (prev1->key[0] != map2_key[0])
return FALSE;
if (prev1->key[0] == DICT_PATH_PRIVATE[0]) {
/* for private keys, username must equal */
if (strcmp(prev1->map->username_field, map2->username_field) != 0)
return FALSE;
}
/* variable values in the paths must equal exactly */
map3 = sql_dict_find_map(dict, prev1->key, &map1_pattern_values);
i_assert(map3 == prev1->map);
return array_equal_fn(&map1_pattern_values, map2_pattern_values,
i_strcmp_p);
}
static void sql_dict_set(struct dict_transaction_context *_ctx,
const char *key, const char *value)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
const struct dict_sql_map *map;
ARRAY_TYPE(const_string) pattern_values;
if (ctx->error != NULL)
return;
/* In theory we could set the previous inc in this same transaction,
so flush it first. */
if (array_is_created(&ctx->prev_inc))
sql_dict_prev_inc_flush(ctx);
map = sql_dict_find_map(dict, key, &pattern_values);
if (map == NULL) {
ctx->error = i_strdup_printf(
"sql dict set: Invalid/unmapped key: %s", key);
return;
}
if (array_is_created(&ctx->prev_set) &&
!sql_dict_maps_are_mergeable(dict, array_front(&ctx->prev_set),
map, key, &pattern_values)) {
/* couldn't merge to the previous set - flush it */
sql_dict_prev_set_flush(ctx);
}
if (!array_is_created(&ctx->prev_set))
i_array_init(&ctx->prev_set, 4);
/* Either this is the first set, or this can be merged with the
previous set. */
struct sql_dict_prev *prev_set = array_append_space(&ctx->prev_set);
prev_set->map = map;
prev_set->key = i_strdup(key);
prev_set->value.str = i_strdup(value);
}
static void sql_dict_atomic_inc(struct dict_transaction_context *_ctx,
const char *key, long long diff)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
const struct dict_sql_map *map;
ARRAY_TYPE(const_string) pattern_values;
if (ctx->error != NULL)
return;
/* In theory we could inc the previous set in this same transaction,
so flush it first. */
if (array_is_created(&ctx->prev_set))
sql_dict_prev_set_flush(ctx);
map = sql_dict_find_map(dict, key, &pattern_values);
if (map == NULL) {
ctx->error = i_strdup_printf(
"sql dict atomic inc: Invalid/unmapped key: %s", key);
return;
}
if (array_is_created(&ctx->prev_inc) &&
!sql_dict_maps_are_mergeable(dict, array_front(&ctx->prev_inc),
map, key, &pattern_values)) {
/* couldn't merge to the previous inc - flush it */
sql_dict_prev_inc_flush(ctx);
}
if (!array_is_created(&ctx->prev_inc))
i_array_init(&ctx->prev_inc, 4);
/* Either this is the first inc, or this can be merged with the
previous inc. */
struct sql_dict_prev *prev_inc = array_append_space(&ctx->prev_inc);
prev_inc->map = map;
prev_inc->key = i_strdup(key);
prev_inc->value.diff = diff;
}
static struct dict sql_dict = {
.name = "sql",
{
.init = sql_dict_init,
.deinit = sql_dict_deinit,
.wait = sql_dict_wait,
.lookup = sql_dict_lookup,
.iterate_init = sql_dict_iterate_init,
.iterate = sql_dict_iterate,
.iterate_deinit = sql_dict_iterate_deinit,
.transaction_init = sql_dict_transaction_init,
.transaction_commit = sql_dict_transaction_commit,
.transaction_rollback = sql_dict_transaction_rollback,
.set = sql_dict_set,
.unset = sql_dict_unset,
.atomic_inc = sql_dict_atomic_inc,
.lookup_async = sql_dict_lookup_async,
}
};
static struct dict *dict_sql_drivers;
void dict_sql_register(void)
{
const struct sql_db *const *drivers;
unsigned int i, count;
dict_sql_db_cache = sql_db_cache_init(DICT_SQL_MAX_UNUSED_CONNECTIONS);
/* @UNSAFE */
drivers = array_get(&sql_drivers, &count);
dict_sql_drivers = i_new(struct dict, count + 1);
for (i = 0; i < count; i++) {
dict_sql_drivers[i] = sql_dict;
dict_sql_drivers[i].name = drivers[i]->name;
dict_driver_register(&dict_sql_drivers[i]);
}
}
void dict_sql_unregister(void)
{
int i;
for (i = 0; dict_sql_drivers[i].name != NULL; i++)
dict_driver_unregister(&dict_sql_drivers[i]);
i_free(dict_sql_drivers);
sql_db_cache_deinit(&dict_sql_db_cache);
dict_sql_settings_deinit();
}
dovecot-2.3.21.1/src/lib-dict-backend/dict-ldap-settings.h 0000644 0000000 0000000 00000001545 14656633576 020035 0000000 0000000 #ifndef DICT_LDAP_SETTINGS_H
#define DICT_LDAP_SETTINGS_H
struct dict_ldap_map {
/* pattern is in simplified form: all variables are stored as simple
'$' character. fields array is sorted by the variable index. */
const char *pattern;
const char *filter;
const char *filter_iter;
const char *username_attribute;
const char *value_attribute;
const char *base_dn;
const char *scope;
int scope_val;
unsigned int timeout;
ARRAY_TYPE(const_string) ldap_attributes;
};
struct dict_ldap_settings {
const char *uri;
const char *bind_dn;
const char *password;
unsigned int timeout;
unsigned int max_idle_time;
unsigned int debug;
unsigned int max_attribute_count;
bool require_ssl;
bool start_tls;
ARRAY(struct dict_ldap_map) maps;
};
struct dict_ldap_settings *
dict_ldap_settings_read(pool_t pool, const char *path, const char **error_r);
#endif
dovecot-2.3.21.1/src/submission/ 0000755 0000000 0000000 00000000000 14656633640 013347 5 0000000 0000000 dovecot-2.3.21.1/src/submission/submission-common.h 0000644 0000000 0000000 00000003067 14656633576 017137 0000000 0000000 #ifndef SUBMISSION_COMMON_H
#define SUBMISSION_COMMON_H
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "smtp-reply.h"
#include "smtp-server.h"
#include "submission-client.h"
#include "submission-settings.h"
#define URL_HOST_ALLOW_ANY "*"
/* Maximum number of bytes added to a relayed message. This is used to
calculate the SIZE capability based on what the backend server states. */
#define SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE 1024
#define SUBMISSION_MAIL_DATA_MAX_INMEMORY_SIZE (1024*128)
/* Maximum time to wait for QUIT reply from relay server */
#define SUBMISSION_MAX_WAIT_QUIT_REPLY_MSECS 2000
#define SUBMISSION_SUPPORTED_SMTP_CAPABILITIES \
(SMTP_CAPABILITY_AUTH | SMTP_CAPABILITY_PIPELINING | \
SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES | \
SMTP_CAPABILITY_8BITMIME | SMTP_CAPABILITY_CHUNKING | \
SMTP_CAPABILITY_BINARYMIME | SMTP_CAPABILITY_BURL | \
SMTP_CAPABILITY_DSN | SMTP_CAPABILITY_VRFY)
typedef void submission_client_created_func_t(struct client **client);
extern submission_client_created_func_t *hook_client_created;
extern bool submission_debug;
extern struct smtp_server *smtp_server;
extern struct smtp_client *smtp_client;
/* Sets the hook_client_created and returns the previous hook,
which the new_hook should call if it's non-NULL. */
submission_client_created_func_t *
submission_client_created_hook_set(submission_client_created_func_t *new_hook);
void submission_refresh_proctitle(void);
void client_handshake(struct client *client);
#endif
dovecot-2.3.21.1/src/submission/submission-settings.c 0000644 0000000 0000000 00000013566 14656633576 017507 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "hostpid.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "mail-storage-settings.h"
#include "submission-settings.h"
#include
#include
static bool submission_settings_verify(void *_set, pool_t pool,
const char **error_r);
/* */
static struct file_listener_settings submission_unix_listeners_array[] = {
{ "login/submission", 0666, "", "" }
};
static struct file_listener_settings *submission_unix_listeners[] = {
&submission_unix_listeners_array[0]
};
static buffer_t submission_unix_listeners_buf = {
{ { submission_unix_listeners, sizeof(submission_unix_listeners) } }
};
/* */
struct service_settings submission_service_settings = {
.name = "submission",
.protocol = "submission",
.type = "",
.executable = "submission",
.user = "",
.group = "",
.privileged_group = "",
.extra_groups = "$default_internal_group",
.chroot = "",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 1024,
.client_limit = 1,
.service_count = 1,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &submission_unix_listeners_buf,
sizeof(submission_unix_listeners[0]) } },
.fifo_listeners = ARRAY_INIT,
.inet_listeners = ARRAY_INIT
};
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct submission_settings)
static const struct setting_define submission_setting_defines[] = {
DEF(BOOL, verbose_proctitle),
DEF(STR_VARS, rawlog_dir),
DEF(STR, hostname),
DEF(STR, login_greeting),
DEF(STR, login_trusted_networks),
DEF(STR, recipient_delimiter),
DEF(SIZE, submission_max_mail_size),
DEF(UINT, submission_max_recipients),
DEF(STR, submission_client_workarounds),
DEF(STR, submission_logout_format),
DEF(STR, submission_backend_capabilities),
DEF(STR, submission_relay_host),
DEF(IN_PORT, submission_relay_port),
DEF(BOOL, submission_relay_trusted),
DEF(STR, submission_relay_user),
DEF(STR, submission_relay_master_user),
DEF(STR, submission_relay_password),
DEF(ENUM, submission_relay_ssl),
DEF(BOOL, submission_relay_ssl_verify),
DEF(STR_VARS, submission_relay_rawlog_dir),
DEF(TIME, submission_relay_max_idle_time),
DEF(TIME_MSECS, submission_relay_connect_timeout),
DEF(TIME_MSECS, submission_relay_command_timeout),
DEF(STR, imap_urlauth_host),
DEF(IN_PORT, imap_urlauth_port),
SETTING_DEFINE_LIST_END
};
static const struct submission_settings submission_default_settings = {
.verbose_proctitle = FALSE,
.rawlog_dir = "",
.hostname = "",
.login_greeting = PACKAGE_NAME" ready.",
.login_trusted_networks = "",
.recipient_delimiter = "+",
.submission_max_mail_size = 40*1024*1024,
.submission_max_recipients = 0,
.submission_client_workarounds = "",
.submission_logout_format = "in=%i out=%o",
.submission_backend_capabilities = NULL,
.submission_relay_host = "",
.submission_relay_port = 25,
.submission_relay_trusted = FALSE,
.submission_relay_user = "",
.submission_relay_master_user = "",
.submission_relay_password = "",
.submission_relay_ssl = "no:smtps:starttls",
.submission_relay_ssl_verify = TRUE,
.submission_relay_rawlog_dir = "",
.submission_relay_max_idle_time = 60*29,
.submission_relay_connect_timeout = 30*1000,
.submission_relay_command_timeout = 60*5*1000,
.imap_urlauth_host = "",
.imap_urlauth_port = 143,
};
static const struct setting_parser_info *submission_setting_dependencies[] = {
&mail_user_setting_parser_info,
NULL
};
const struct setting_parser_info submission_setting_parser_info = {
.module_name = "submission",
.defines = submission_setting_defines,
.defaults = &submission_default_settings,
.type_offset = SIZE_MAX,
.struct_size = sizeof(struct submission_settings),
.parent_offset = SIZE_MAX,
.check_func = submission_settings_verify,
.dependencies = submission_setting_dependencies
};
/* */
struct submission_client_workaround_list {
const char *name;
enum submission_client_workarounds num;
};
/* These definitions need to be kept in sync with equivalent definitions present
in src/submission-login/submission-login-settings.c. Workarounds that are not
relevant to the submission service are defined as 0 here to prevent "Unknown
workaround" errors below. */
static const struct submission_client_workaround_list
submission_client_workaround_list[] = {
{ "whitespace-before-path",
SUBMISSION_WORKAROUND_WHITESPACE_BEFORE_PATH },
{ "mailbox-for-path",
SUBMISSION_WORKAROUND_MAILBOX_FOR_PATH },
{ "implicit-auth-external", 0 },
{ "exotic-backend", 0 },
{ NULL, 0 }
};
static int
submission_settings_parse_workarounds(struct submission_settings *set,
const char **error_r)
{
enum submission_client_workarounds client_workarounds = 0;
const struct submission_client_workaround_list *list;
const char *const *str;
str = t_strsplit_spaces(set->submission_client_workarounds, " ,");
for (; *str != NULL; str++) {
list = submission_client_workaround_list;
for (; list->name != NULL; list++) {
if (strcasecmp(*str, list->name) == 0) {
client_workarounds |= list->num;
break;
}
}
if (list->name == NULL) {
*error_r = t_strdup_printf(
"submission_client_workarounds: "
"Unknown workaround: %s", *str);
return -1;
}
}
set->parsed_workarounds = client_workarounds;
return 0;
}
static bool
submission_settings_verify(void *_set, pool_t pool ATTR_UNUSED, const char **error_r)
{
struct submission_settings *set = _set;
if (submission_settings_parse_workarounds(set, error_r) < 0)
return FALSE;
#ifndef CONFIG_BINARY
if (set->submission_relay_max_idle_time == 0) {
*error_r = "submission_relay_max_idle_time must not be 0";
return FALSE;
}
if (*set->hostname == '\0')
set->hostname = p_strdup(pool, my_hostdomain());
#endif
return TRUE;
}
/* */
dovecot-2.3.21.1/src/submission/submission-recipient.h 0000644 0000000 0000000 00000001367 14656633576 017632 0000000 0000000 #ifndef SUBMISSION_RECIPIENT_H
#define SUBMISSION_RECIPIENT_H
struct submission_backend;
struct client;
struct submission_recipient {
struct smtp_server_recipient *rcpt;
struct submission_backend *backend;
void *backend_context;
/* Module-specific contexts. */
ARRAY(union submission_recipient_module_context *) module_contexts;
bool anonymous_allowed:1;
};
struct submission_recipient_module_register {
unsigned int id;
};
union submission_recipient_module_context {
struct submission_recipient_module_register *reg;
};
extern struct submission_recipient_module_register
submission_recipient_module_register;
struct submission_recipient *
submission_recipient_create(struct client *client,
struct smtp_server_recipient *rcpt);
#endif
dovecot-2.3.21.1/src/submission/submission-settings.h 0000644 0000000 0000000 00000002677 14656633576 017515 0000000 0000000 #ifndef SUBMISSION_SETTINGS_H
#define SUBMISSION_SETTINGS_H
#include "smtp-server.h"
/* */
enum submission_client_workarounds {
SUBMISSION_WORKAROUND_WHITESPACE_BEFORE_PATH = BIT(0),
SUBMISSION_WORKAROUND_MAILBOX_FOR_PATH = BIT(1),
};
/* */
struct submission_settings {
bool verbose_proctitle;
const char *rawlog_dir;
const char *hostname;
const char *login_greeting;
const char *login_trusted_networks;
const char *recipient_delimiter;
/* submission: */
uoff_t submission_max_mail_size;
unsigned int submission_max_recipients;
const char *submission_client_workarounds;
const char *submission_logout_format;
/* submission backend: */
const char *submission_backend_capabilities;
/* submission relay: */
const char *submission_relay_host;
in_port_t submission_relay_port;
bool submission_relay_trusted;
const char *submission_relay_user;
const char *submission_relay_master_user;
const char *submission_relay_password;
const char *submission_relay_ssl;
bool submission_relay_ssl_verify;
const char *submission_relay_rawlog_dir;
unsigned int submission_relay_max_idle_time;
unsigned int submission_relay_connect_timeout;
unsigned int submission_relay_command_timeout;
/* imap urlauth: */
const char *imap_urlauth_host;
in_port_t imap_urlauth_port;
enum submission_client_workarounds parsed_workarounds;
};
extern const struct setting_parser_info submission_setting_parser_info;
#endif
dovecot-2.3.21.1/src/submission/Makefile.in 0000644 0000000 0000000 00000073634 14656633613 015351 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = submission$(EXEEXT)
subdir = src/submission
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(pkginc_lib_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)" \
"$(DESTDIR)$(pkginc_libdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_submission_OBJECTS = main.$(OBJEXT) submission-backend.$(OBJEXT) \
submission-backend-relay.$(OBJEXT) \
submission-recipient.$(OBJEXT) submission-client.$(OBJEXT) \
submission-commands.$(OBJEXT) submission-settings.$(OBJEXT)
submission_OBJECTS = $(am_submission_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
submission_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(submission_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/main.Po \
./$(DEPDIR)/submission-backend-relay.Po \
./$(DEPDIR)/submission-backend.Po \
./$(DEPDIR)/submission-client.Po \
./$(DEPDIR)/submission-commands.Po \
./$(DEPDIR)/submission-recipient.Po \
./$(DEPDIR)/submission-settings.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(submission_SOURCES)
DIST_SOURCES = $(submission_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
HEADERS = $(pkginc_lib_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-imap-storage \
-I$(top_srcdir)/src/lib-imap-urlauth \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index \
-I$(top_srcdir)/src/lib-storage/index/raw \
-I$(top_srcdir)/src/lib-smtp
urlauth_libs = \
$(top_builddir)/src/lib-imap-urlauth/libimap-urlauth.la
submission_LDFLAGS = -export-dynamic
submission_LDADD = \
$(urlauth_libs) \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT) \
$(MODULE_LIBS)
submission_DEPENDENCIES = \
$(urlauth_libs) \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
submission_SOURCES = \
main.c \
submission-backend.c \
submission-backend-relay.c \
submission-recipient.c \
submission-client.c \
submission-commands.c \
submission-settings.c
headers = \
submission-common.h \
submission-backend.h \
submission-backend-relay.h \
submission-commands.h \
submission-recipient.h \
submission-client.h \
submission-settings.h
pkginc_libdir = $(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/submission/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/submission/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
submission$(EXEEXT): $(submission_OBJECTS) $(submission_DEPENDENCIES) $(EXTRA_submission_DEPENDENCIES)
@rm -f submission$(EXEEXT)
$(AM_V_CCLD)$(submission_LINK) $(submission_OBJECTS) $(submission_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/submission-backend-relay.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/submission-backend.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/submission-client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/submission-commands.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/submission-recipient.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/submission-settings.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
done
uninstall-pkginc_libHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(pkginc_libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/submission-backend-relay.Po
-rm -f ./$(DEPDIR)/submission-backend.Po
-rm -f ./$(DEPDIR)/submission-client.Po
-rm -f ./$(DEPDIR)/submission-commands.Po
-rm -f ./$(DEPDIR)/submission-recipient.Po
-rm -f ./$(DEPDIR)/submission-settings.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkginc_libHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/submission-backend-relay.Po
-rm -f ./$(DEPDIR)/submission-backend.Po
-rm -f ./$(DEPDIR)/submission-client.Po
-rm -f ./$(DEPDIR)/submission-commands.Po
-rm -f ./$(DEPDIR)/submission-recipient.Po
-rm -f ./$(DEPDIR)/submission-settings.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-pkginc_libHEADERS \
install-pkglibexecPROGRAMS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/submission/submission-backend.h 0000644 0000000 0000000 00000014375 14656633576 017242 0000000 0000000 #ifndef SUBMISSION_BACKEND_H
#define SUBMISSION_BACKEND_H
struct submission_recipient;
struct submission_backend;
union submission_backend_module_context;
struct submission_backend_vfuncs {
void (*destroy)(struct submission_backend *backend);
void (*start)(struct submission_backend *backend);
void (*ready)(struct submission_backend *backend,
enum smtp_capability caps);
void (*fail)(struct submission_backend *backend, const char *enh_code,
const char *reason);
void (*client_input_pre)(struct submission_backend *backend);
void (*client_input_post)(struct submission_backend *backend);
uoff_t (*get_max_mail_size)(struct submission_backend *backend);
void (*trans_start)(struct submission_backend *backend,
struct smtp_server_transaction *trans,
const struct smtp_address *path,
const struct smtp_params_mail *params);
void (*trans_free)(struct submission_backend *backend,
struct smtp_server_transaction *trans);
/* Command handlers:
These implement the behavior of the various core SMTP commands.
SMTP commands are handled asynchronously, which means that the
command is not necessarily finished when these handlers end. A
command is finished either when 1 is returned or a reply is submitted
for it. When a handler returns 0, the command implementation is
waiting for an external event and when it returns -1 an error
occurred. When 1 is returned, a default success reply is submitted
implicitly. Not submitting an error reply when -1 is returned causes
an assert fail. See src/lib-smtp/smtp-server.h for details.
When overriding these handler vfuncs, the base implementation should
usually be called at some point. When it is called immediately, its
result can be returned as normal. When the override returns 0, the
base implementation would be called at a later time when some
external state is achieved. Note that the overriding function then
assumes the responsibility to submit the default reply when none is
submitted and the base implementation returns 1.
Also note that only the default backend actually triggers all of
these command callbacks. Secondary backends only get called for
transaction commands and only when that backend is tied to the
transaction somehow; e.g., as the primary transaction backend or when
it is tied to one of the approved recipients.
*/
int (*cmd_helo)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
int (*cmd_mail)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
int (*cmd_rcpt)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct submission_recipient *srcpt);
int (*cmd_rset)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd);
int (*cmd_data)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size);
int (*cmd_vrfy)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
const char *param);
int (*cmd_noop)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd);
int (*cmd_quit)(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd);
};
struct submission_backend {
pool_t pool;
struct client *client;
struct submission_backend *prev, *next;
struct submission_backend_vfuncs v;
struct istream *data_input;
uoff_t data_size;
char *fail_enh_code;
char *fail_reason;
/* Module-specific contexts. */
ARRAY(union submission_backend_module_context *) module_contexts;
bool started:1;
bool ready:1;
bool trans_started:1;
};
struct submission_backend_module_register {
unsigned int id;
};
union submission_backend_module_context {
struct submission_backend_module_register *reg;
};
extern struct submission_backend_module_register
submission_backend_module_register;
void submission_backend_init(struct submission_backend *backend,
pool_t pool, struct client *client,
const struct submission_backend_vfuncs *vfunc);
void submission_backends_destroy_all(struct client *client);
void submission_backend_start(struct submission_backend *backend);
void submission_backend_started(struct submission_backend *backend,
enum smtp_capability caps);
void submission_backend_fail(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
const char *enh_code, const char *reason)
ATTR_NULL(2);
void submission_backends_client_input_pre(struct client *client);
void submission_backends_client_input_post(struct client *client);
uoff_t submission_backend_get_max_mail_size(struct submission_backend *backend);
void submission_backend_trans_start(struct submission_backend *backend,
struct smtp_server_transaction *trans);
void submission_backends_trans_start(struct client *client,
struct smtp_server_transaction *trans);
void submission_backends_trans_free(struct client *client,
struct smtp_server_transaction *trans);
void submission_backend_helo_reply_submit(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
int submission_backend_cmd_helo(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
int submission_backend_cmd_mail(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
int submission_backend_cmd_rcpt(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct submission_recipient *srcpt);
int submission_backend_cmd_rset(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd);
int submission_backends_cmd_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size);
int submission_backend_cmd_vrfy(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
const char *param);
int submission_backend_cmd_noop(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd);
int submission_backend_cmd_quit(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd);
#endif
dovecot-2.3.21.1/src/submission/submission-commands.h 0000644 0000000 0000000 00000004435 14656633576 017450 0000000 0000000 #ifndef SUBMISSION_COMMANDS_H
#define SUBMISSION_COMMANDS_H
/*
* HELO command
*/
void submission_helo_reply_submit(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
int cmd_helo(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
int client_default_cmd_helo(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
/*
* MAIL command
*/
int cmd_mail(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
int client_default_cmd_mail(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
/*
* RCPT command
*/
int cmd_rcpt(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_recipient *rcpt);
int client_default_cmd_rcpt(struct client *client ATTR_UNUSED,
struct smtp_server_cmd_ctx *cmd,
struct submission_recipient *srcpt);
/*
* RSET command
*/
int cmd_rset(void *conn_ctx, struct smtp_server_cmd_ctx *cmd);
int client_default_cmd_rset(struct client *client,
struct smtp_server_cmd_ctx *cmd);
/*
* DATA/BDAT commands
*/
int cmd_data_begin(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input);
int cmd_data_continue(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans);
int client_default_cmd_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size);
/*
* BURL command
*/
void cmd_burl(struct smtp_server_cmd_ctx *cmd, const char *params);
/*
* VRFY command
*/
int cmd_vrfy(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
const char *param);
int client_default_cmd_vrfy(struct client *client,
struct smtp_server_cmd_ctx *cmd, const char *param);
/*
* NOOP command
*/
int cmd_noop(void *conn_ctx, struct smtp_server_cmd_ctx *cmd);
int client_default_cmd_noop(struct client *client,
struct smtp_server_cmd_ctx *cmd);
/*
* QUIT command
*/
int cmd_quit(void *conn_ctx, struct smtp_server_cmd_ctx *cmd);
int client_default_cmd_quit(struct client *client,
struct smtp_server_cmd_ctx *cmd);
#endif
dovecot-2.3.21.1/src/submission/submission-client.h 0000644 0000000 0000000 00000012044 14656633576 017120 0000000 0000000 #ifndef CLIENT_H
#define CLIENT_H
#include "net.h"
struct smtp_reply;
struct submission_recipient;
struct submission_backend;
struct submission_backend_relay;
struct client;
struct client_state {
pool_t pool;
enum smtp_server_state state;
char *args;
struct submission_backend *backend;
struct istream *data_input;
uoff_t data_size;
bool anonymous_allowed:1;
};
struct client_extra_capability {
const char *capability;
const char *params;
};
struct submission_client_vfuncs {
void (*destroy)(struct client *client);
void (*trans_start)(struct client *client,
struct smtp_server_transaction *trans);
void (*trans_free)(struct client *client,
struct smtp_server_transaction *trans);
/* Command handlers:
These implement the behavior of the various core SMTP commands.
SMTP commands are handled asynchronously, which means that the
command is not necessarily finished when these handlers end. A
command is finished either when 1 is returned or a reply is submitted
for it. When a handler returns 0, the command implementation is
waiting for an external event and when it returns -1 an error
occurred. When 1 is returned, a default success reply is submitted
implicitly. Not submitting an error reply when -1 is returned causes
an assert fail. See src/lib-smtp/smtp-server.h for details.
When overriding these handler vfuncs, the base implementation should
usually be called at some point. When it is called immediately, its
result can be returned as normal. When the override returns 0, the
base implementation would be called at a later time when some
external state is achieved. Note that the overriding function then
assumes the responsibility to submit the default reply when none is
submitted and the base implementation returns 1.
*/
int (*cmd_helo)(struct client *client, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data);
int (*cmd_mail)(struct client *client, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
int (*cmd_rcpt)(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct submission_recipient *srcpt);
int (*cmd_rset)(struct client *client, struct smtp_server_cmd_ctx *cmd);
int (*cmd_data)(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size);
int (*cmd_vrfy)(struct client *client, struct smtp_server_cmd_ctx *cmd,
const char *param);
int (*cmd_noop)(struct client *client, struct smtp_server_cmd_ctx *cmd);
int (*cmd_quit)(struct client *client, struct smtp_server_cmd_ctx *cmd);
};
struct client {
struct client *prev, *next;
pool_t pool;
struct submission_client_vfuncs v;
const struct setting_parser_info *user_set_info;
const struct submission_settings *set;
struct smtp_server_connection *conn;
struct client_state state;
ARRAY(struct submission_backend *) pending_backends;
ARRAY(struct submission_recipient *) rcpt_to;
ARRAY(struct submission_backend *) rcpt_backends;
struct mail_storage_service_user *service_user;
struct mail_user *user;
/* IMAP URLAUTH context (RFC4467) for BURL (RFC4468) */
struct imap_urlauth_context *urlauth_ctx;
struct timeout *to_quit;
enum smtp_capability backend_capabilities;
struct submission_backend *backend_default;
struct submission_backend_relay *backend_default_relay;
struct submission_backend *backends;
unsigned int backends_count;
/* Extra (non-standard) capabilities */
ARRAY(struct client_extra_capability) extra_capabilities;
/* Module-specific contexts. */
ARRAY(union submission_module_context *) module_contexts;
bool standalone:1;
bool disconnected:1;
bool destroyed:1;
bool anvil_sent:1;
bool backend_capabilities_configured:1;
bool anonymous_allowed:1;
};
struct submission_module_register {
unsigned int id;
};
union submission_module_context {
struct submission_client_vfuncs super;
struct submission_module_register *reg;
};
extern struct submission_module_register submission_module_register;
extern struct client *submission_clients;
extern unsigned int submission_client_count;
struct client *
client_create(int fd_in, int fd_out, struct mail_user *user,
struct mail_storage_service_user *service_user,
const struct submission_settings *set, const char *helo,
const struct smtp_proxy_data *proxy_data,
const unsigned char *pdata, unsigned int pdata_len,
bool no_greeting);
void client_destroy(struct client **client, const char *prefix,
const char *reason) ATTR_NULL(2, 3);
typedef void (*client_input_callback_t)(struct client *context);
void client_apply_backend_capabilities(struct client *client);
void client_default_backend_started(struct client *client,
enum smtp_capability caps);
uoff_t client_get_max_mail_size(struct client *client);
void client_add_extra_capability(struct client *client, const char *capability,
const char *params) ATTR_NULL(2);
int client_input_read(struct client *client);
int client_handle_input(struct client *client);
void clients_destroy_all(void);
#endif
dovecot-2.3.21.1/src/submission/submission-backend-relay.c 0000644 0000000 0000000 00000105461 14656633576 020344 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "submission-common.h"
#include "str.h"
#include "str-sanitize.h"
#include "mail-user.h"
#include "iostream-ssl.h"
#include "smtp-client.h"
#include "smtp-client-connection.h"
#include "smtp-client-transaction.h"
#include "smtp-client-command.h"
#include "submission-recipient.h"
#include "submission-backend-relay.h"
struct submission_backend_relay {
struct submission_backend backend;
struct smtp_client_connection *conn;
struct smtp_client_transaction *trans;
bool trans_started:1;
bool trusted:1;
bool quit_confirmed:1;
};
static struct submission_backend_vfuncs backend_relay_vfuncs;
/*
* Common
*/
/* The command handling of the submission relay service aims to follow the
following rules:
- Attempt to keep pipelined commands pipelined when relaying them to the
actual relay service.
- Don't forward commands if they're known to fail at the relay server. Errors
can still occur if pipelined commands fail. Abort subsequent pending
commands if such failures affect those commands.
- Keep predictable errors consistent as much as possible; send our own reply
if the error condition is clear (e.g. missing MAIL, RCPT).
*/
static bool
backend_relay_handle_relay_reply(struct submission_backend_relay *backend,
struct smtp_server_cmd_ctx *cmd,
const struct smtp_reply *reply,
struct smtp_reply *reply_r) ATTR_NULL(2)
{
struct client *client = backend->backend.client;
struct mail_user *user = client->user;
const char *enh_code, *msg, *log_msg = NULL;
const char *const *reply_lines;
bool result = TRUE;
*reply_r = *reply;
switch (reply->status) {
case SMTP_CLIENT_COMMAND_ERROR_ABORTED:
return FALSE;
case SMTP_CLIENT_COMMAND_ERROR_HOST_LOOKUP_FAILED:
case SMTP_CLIENT_COMMAND_ERROR_CONNECT_FAILED:
case SMTP_CLIENT_COMMAND_ERROR_AUTH_FAILED:
enh_code = "4.4.0";
msg = "Failed to connect to relay server";
result = FALSE;
break;
case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_CLOSED:
enh_code = smtp_reply_get_enh_code(reply);
log_msg = "Lost connection to relay server";
reply_lines = smtp_reply_get_text_lines_omit_prefix(reply);
msg = t_strconcat("Lost connection to relay server:\n",
t_strarray_join(reply_lines, "\n"), NULL);
result = FALSE;
break;
case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_LOST:
case SMTP_CLIENT_COMMAND_ERROR_BAD_REPLY:
case SMTP_CLIENT_COMMAND_ERROR_TIMED_OUT:
enh_code = "4.4.0";
log_msg = msg = "Lost connection to relay server";
result = FALSE;
break;
/* RFC 4954, Section 6: 530 5.7.0 Authentication required
This response SHOULD be returned by any command other than AUTH,
EHLO, HELO, NOOP, RSET, or QUIT when server policy requires
authentication in order to perform the requested action and
authentication is not currently in force. */
case 530:
log_msg = "Relay server requires authentication";
enh_code = "4.3.5",
msg = "Internal error occurred. "
"Refer to server log for more information.";
result = FALSE;
break;
default:
break;
}
if (!result) {
const char *detail = "", *reason;
i_assert(msg != NULL);
switch (reply->status) {
case SMTP_CLIENT_COMMAND_ERROR_ABORTED:
i_unreached();
case SMTP_CLIENT_COMMAND_ERROR_HOST_LOOKUP_FAILED:
detail = " (DNS lookup)";
break;
case SMTP_CLIENT_COMMAND_ERROR_CONNECT_FAILED:
case SMTP_CLIENT_COMMAND_ERROR_AUTH_FAILED:
detail = " (connect)";
break;
case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_LOST:
case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_CLOSED:
if (backend->quit_confirmed)
return FALSE;
detail = " (connection lost)";
break;
case SMTP_CLIENT_COMMAND_ERROR_BAD_REPLY:
detail = " (bad reply)";
break;
case SMTP_CLIENT_COMMAND_ERROR_TIMED_OUT:
detail = " (timed out)";
break;
default:
break;
}
reason = t_strdup_printf("%s%s", msg, detail);
smtp_client_transaction_destroy(&backend->trans);
if (log_msg != NULL) {
if (smtp_reply_is_remote(reply)) {
i_error("%s: %s",
log_msg, smtp_reply_log(reply));
} else if (user->mail_debug) {
i_debug("%s: %s",
log_msg, smtp_reply_log(reply));
}
}
submission_backend_fail(&backend->backend, cmd,
enh_code, reason);
return FALSE;
}
if (!smtp_reply_has_enhanced_code(reply)) {
reply_r->enhanced_code =
SMTP_REPLY_ENH_CODE(reply->status / 100, 0, 0);
}
return TRUE;
}
/*
* Mail transaction
*/
static void
backend_relay_trans_finished(struct submission_backend_relay *backend)
{
backend->trans = NULL;
}
static void
backend_relay_trans_start_callback(
const struct smtp_reply *relay_reply ATTR_UNUSED,
struct submission_backend_relay *backend ATTR_UNUSED)
{
/* nothing to do */
}
static void
backend_relay_trans_start(struct submission_backend *_backend,
struct smtp_server_transaction *trans ATTR_UNUSED,
const struct smtp_address *path,
const struct smtp_params_mail *params)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
if (backend->trans == NULL) {
backend->trans_started = TRUE;
backend->trans = smtp_client_transaction_create(
backend->conn, path, params, 0,
backend_relay_trans_finished, backend);
smtp_client_transaction_set_immediate(backend->trans, TRUE);
smtp_client_transaction_start(
backend->trans, backend_relay_trans_start_callback,
backend);
} else if (!backend->trans_started) {
backend->trans_started = TRUE;
smtp_client_transaction_start_empty(
backend->trans, path, params,
backend_relay_trans_start_callback, backend);
}
}
static void
backend_relay_trans_free(struct submission_backend *_backend,
struct smtp_server_transaction *trans ATTR_UNUSED)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
backend->trans_started = FALSE;
if (backend->trans == NULL)
return;
smtp_client_transaction_destroy(&backend->trans);
}
struct smtp_client_transaction *
submission_backend_relay_init_transaction(
struct submission_backend_relay *backend,
enum smtp_client_transaction_flags flags)
{
i_assert(backend->trans == NULL);
backend->trans = smtp_client_transaction_create_empty(
backend->conn, flags,
backend_relay_trans_finished, backend);
smtp_client_transaction_set_immediate(backend->trans, TRUE);
return backend->trans;
}
/*
* EHLO, HELO commands
*/
struct relay_cmd_helo_context {
struct submission_backend_relay *backend;
struct smtp_server_cmd_ctx *cmd;
struct smtp_server_cmd_helo *data;
struct smtp_client_command *cmd_relayed;
};
static void
relay_cmd_helo_destroy(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_helo_context *helo_cmd)
{
i_assert(helo_cmd != NULL);
if (helo_cmd->cmd_relayed != NULL)
smtp_client_command_abort(&helo_cmd->cmd_relayed);
}
static void
relay_cmd_helo_update_xclient(struct submission_backend_relay *backend,
struct smtp_server_cmd_helo *data)
{
struct smtp_proxy_data proxy_data;
if (!backend->trusted)
return;
i_zero(&proxy_data);
proxy_data.helo = data->helo.domain;
smtp_client_connection_update_proxy_data(backend->conn, &proxy_data);
}
static void
relay_cmd_helo_reply(struct smtp_server_cmd_ctx *cmd,
struct relay_cmd_helo_context *helo_cmd)
{
struct submission_backend_relay *backend = helo_cmd->backend;
if (helo_cmd->data->changed)
relay_cmd_helo_update_xclient(backend, helo_cmd->data);
T_BEGIN {
submission_backend_helo_reply_submit(&backend->backend, cmd,
helo_cmd->data);
} T_END;
}
static void
relay_cmd_helo_callback(const struct smtp_reply *relay_reply,
struct relay_cmd_helo_context *helo_cmd)
{
i_assert(helo_cmd != NULL);
struct smtp_server_cmd_ctx *cmd = helo_cmd->cmd;
struct submission_backend_relay *backend = helo_cmd->backend;
struct smtp_reply reply;
/* finished relaying EHLO command to relay server */
helo_cmd->cmd_relayed = NULL;
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
if (smtp_reply_is_success(&reply)) {
relay_cmd_helo_reply(cmd, helo_cmd);
} else {
/* RFC 2034, Section 4:
These codes must appear in all 2xx, 4xx, and 5xx response
lines other than initial greeting and any response to HELO
or EHLO.
*/
reply.enhanced_code = SMTP_REPLY_ENH_CODE_NONE;
smtp_server_reply_forward(cmd, &reply);
}
}
static void
relay_cmd_helo_start(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_helo_context *helo_cmd)
{
struct submission_backend_relay *backend = helo_cmd->backend;
if (helo_cmd->data->changed)
relay_cmd_helo_update_xclient(backend, helo_cmd->data);
}
static int
backend_relay_cmd_helo(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
struct relay_cmd_helo_context *helo_cmd;
helo_cmd = p_new(cmd->pool, struct relay_cmd_helo_context, 1);
helo_cmd->backend = backend;
helo_cmd->cmd = cmd;
helo_cmd->data = data;
/* This is not the first HELO/EHLO; just relay a RSET command */
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_NEXT,
relay_cmd_helo_start, helo_cmd);
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_DESTROY,
relay_cmd_helo_destroy, helo_cmd);
helo_cmd->cmd_relayed = smtp_client_command_rset_submit(
backend->conn, 0, relay_cmd_helo_callback, helo_cmd);
return 0;
}
/*
* MAIL command
*/
struct relay_cmd_mail_context {
struct submission_backend_relay *backend;
struct smtp_server_cmd_ctx *cmd;
struct smtp_server_cmd_mail *data;
struct smtp_client_transaction_mail *relay_mail;
};
static void
relay_cmd_mail_replied(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_mail_context *mail_cmd)
{
if (mail_cmd->relay_mail != NULL)
smtp_client_transaction_mail_abort(&mail_cmd->relay_mail);
}
static void
relay_cmd_mail_callback(const struct smtp_reply *relay_reply,
struct relay_cmd_mail_context *mail_cmd)
{
i_assert(mail_cmd != NULL);
struct smtp_server_cmd_ctx *cmd = mail_cmd->cmd;
struct submission_backend_relay *backend = mail_cmd->backend;
struct smtp_reply reply;
/* finished relaying MAIL command to relay server */
mail_cmd->relay_mail = NULL;
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
if (smtp_reply_is_success(relay_reply)) {
/* if relay accepts it, we accept it too */
/* the default 2.0.0 code won't do */
if (!smtp_reply_has_enhanced_code(relay_reply))
reply.enhanced_code = SMTP_REPLY_ENH_CODE(2, 1, 0);
}
/* forward reply */
smtp_server_reply_forward(cmd, &reply);
}
static int
relay_cmd_mail_parameter_auth(struct submission_backend_relay *backend,
struct smtp_server_cmd_ctx *cmd,
enum smtp_capability relay_caps,
struct smtp_server_cmd_mail *data)
{
struct client *client = backend->backend.client;
struct smtp_params_mail *params = &data->params;
struct smtp_address *auth_addr;
const char *error;
if ((relay_caps & SMTP_CAPABILITY_AUTH) == 0)
return 0;
auth_addr = NULL;
if (smtp_address_parse_username(cmd->pool, client->user->username,
&auth_addr, &error) < 0) {
i_warning("Username `%s' is not a valid SMTP address: %s",
client->user->username, error);
}
params->auth = auth_addr;
return 0;
}
static int
relay_cmd_mail_parameter_size(struct submission_backend_relay *backend,
struct smtp_server_cmd_ctx *cmd,
enum smtp_capability relay_caps,
struct smtp_server_cmd_mail *data)
{
struct client *client = backend->backend.client;
uoff_t max_size;
/* SIZE=: RFC 1870 */
if (data->params.size == 0 || (relay_caps & SMTP_CAPABILITY_SIZE) == 0)
return 0;
/* determine actual size limit (account for our additions) */
max_size = client_get_max_mail_size(client);
if (max_size > 0 && data->params.size > max_size) {
smtp_server_reply(
cmd, 552, "5.3.4",
"Message size exceeds fixed maximum message size");
return -1;
}
/* relay the SIZE parameter (account for additional size) */
data->params.size += SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE;
return 0;
}
static int
backend_relay_cmd_mail(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
enum smtp_capability relay_caps =
smtp_client_connection_get_capabilities(backend->conn);
struct relay_cmd_mail_context *mail_cmd;
/* check and adjust parameters where necessary */
if (relay_cmd_mail_parameter_auth(backend, cmd, relay_caps, data) < 0)
return -1;
if (relay_cmd_mail_parameter_size(backend, cmd, relay_caps, data) < 0)
return -1;
/* queue command (pipeline) */
mail_cmd = p_new(cmd->pool, struct relay_cmd_mail_context, 1);
mail_cmd->backend = backend;
mail_cmd->cmd = cmd;
mail_cmd->data = data;
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_REPLIED,
relay_cmd_mail_replied, mail_cmd);
if (backend->trans == NULL) {
/* start client transaction */
backend->trans_started = TRUE;
backend->trans = smtp_client_transaction_create(
backend->conn, data->path, &data->params, 0,
backend_relay_trans_finished, backend);
smtp_client_transaction_set_immediate(backend->trans, TRUE);
smtp_client_transaction_start(
backend->trans, relay_cmd_mail_callback, mail_cmd);
} else {
/* forward pipelined MAIL command */
i_assert(backend->trans_started);
mail_cmd->relay_mail = smtp_client_transaction_add_mail(
backend->trans, data->path, &data->params,
relay_cmd_mail_callback, mail_cmd);
}
return 0;
}
/*
* RCPT command
*/
struct relay_cmd_rcpt_context {
struct submission_backend_relay *backend;
struct submission_recipient *rcpt;
struct smtp_server_cmd_ctx *cmd;
struct smtp_client_transaction_rcpt *relay_rcpt;
};
static void
relay_cmd_rcpt_replied(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_rcpt_context *rcpt_cmd)
{
if (rcpt_cmd->relay_rcpt != NULL)
smtp_client_transaction_rcpt_abort(&rcpt_cmd->relay_rcpt);
}
static void
relay_cmd_rcpt_callback(const struct smtp_reply *relay_reply,
struct relay_cmd_rcpt_context *rcpt_cmd)
{
i_assert(rcpt_cmd != NULL);
struct smtp_server_cmd_ctx *cmd = rcpt_cmd->cmd;
struct submission_backend_relay *backend = rcpt_cmd->backend;
struct submission_recipient *srcpt = rcpt_cmd->rcpt;
struct smtp_server_recipient *rcpt = srcpt->rcpt;
struct smtp_client_transaction_rcpt *relay_rcpt = rcpt_cmd->relay_rcpt;
struct smtp_reply reply;
/* finished relaying RCPT command to relay server */
rcpt_cmd->relay_rcpt = NULL;
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
if (smtp_reply_is_success(&reply)) {
/* the default 2.0.0 code won't do */
if (!smtp_reply_has_enhanced_code(&reply))
reply.enhanced_code = SMTP_REPLY_ENH_CODE(2, 1, 5);
i_assert(relay_rcpt != NULL);
srcpt->backend_context = relay_rcpt;
}
/* forward reply */
smtp_server_recipient_reply_forward(rcpt, &reply);
}
static int
backend_relay_cmd_rcpt(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd,
struct submission_recipient *srcpt)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
struct smtp_server_recipient *rcpt = srcpt->rcpt;
struct relay_cmd_rcpt_context *rcpt_cmd;
/* queue command (pipeline) */
rcpt_cmd = p_new(cmd->pool, struct relay_cmd_rcpt_context, 1);
rcpt_cmd->backend = backend;
rcpt_cmd->cmd = cmd;
rcpt_cmd->rcpt = srcpt;
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_REPLIED,
relay_cmd_rcpt_replied, rcpt_cmd);
if (backend->trans == NULL)
(void)submission_backend_relay_init_transaction(backend, 0);
rcpt_cmd->relay_rcpt = smtp_client_transaction_add_pool_rcpt(
backend->trans, rcpt->pool, rcpt->path, &rcpt->params,
relay_cmd_rcpt_callback, rcpt_cmd);
return 0;
}
/*
* RSET command
*/
struct relay_cmd_rset_context {
struct submission_backend_relay *backend;
struct smtp_server_cmd_ctx *cmd;
struct smtp_client_command *cmd_relayed;
};
static void
relay_cmd_rset_destroy(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_rset_context *rset_cmd)
{
i_assert(rset_cmd != NULL);
if (rset_cmd->cmd_relayed != NULL)
smtp_client_command_abort(&rset_cmd->cmd_relayed);
}
static void
relay_cmd_rset_callback(const struct smtp_reply *relay_reply,
struct relay_cmd_rset_context *rset_cmd)
{
i_assert(rset_cmd != NULL);
struct smtp_server_cmd_ctx *cmd = rset_cmd->cmd;
struct submission_backend_relay *backend = rset_cmd->backend;
struct smtp_reply reply;
/* finished relaying MAIL command to relay server */
rset_cmd->cmd_relayed = NULL;
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
/* forward reply */
smtp_server_reply_forward(cmd, &reply);
}
static int
backend_relay_cmd_rset(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
struct relay_cmd_rset_context *rset_cmd;
rset_cmd = p_new(cmd->pool, struct relay_cmd_rset_context, 1);
rset_cmd->backend = backend;
rset_cmd->cmd = cmd;
if (backend->trans != NULL) {
/* RSET pipelined after MAIL */
smtp_client_transaction_reset(backend->trans,
relay_cmd_rset_callback,
rset_cmd);
} else {
/* RSET alone */
smtp_server_command_add_hook(cmd->cmd,
SMTP_SERVER_COMMAND_HOOK_DESTROY,
relay_cmd_rset_destroy, rset_cmd);
rset_cmd->cmd_relayed = smtp_client_command_rset_submit(
backend->conn, 0, relay_cmd_rset_callback, rset_cmd);
}
return 0;
}
/*
* DATA/BDAT commands
*/
struct relay_cmd_data_context {
struct submission_backend_relay *backend;
struct smtp_server_cmd_ctx *cmd;
struct smtp_server_transaction *trans;
};
static void
relay_cmd_data_rcpt_callback(const struct smtp_reply *relay_reply,
struct submission_recipient *srcpt)
{
struct smtp_server_recipient *rcpt = srcpt->rcpt;
struct smtp_server_cmd_ctx *cmd = rcpt->cmd;
struct submission_backend_relay *backend =
(struct submission_backend_relay *)srcpt->backend;
struct client *client = srcpt->backend->client;
struct smtp_server_transaction *trans =
smtp_server_connection_get_transaction(client->conn);
struct smtp_reply reply;
i_assert(HAS_ALL_BITS(trans->flags,
SMTP_SERVER_TRANSACTION_FLAG_REPLY_PER_RCPT));
/* check for fatal problems */
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
if (smtp_reply_is_success(&reply)) {
i_info("Successfully relayed message: "
"from=<%s>, to=<%s>, size=%"PRIuUOFF_T", "
"id=%s, rcpt=%u/%u, reply=`%s'",
smtp_address_encode(trans->mail_from),
smtp_address_encode(rcpt->path),
client->state.data_size, trans->id,
rcpt->index, array_count(&trans->rcpt_to),
str_sanitize(smtp_reply_log(&reply), 128));
} else {
i_info("Failed to relay message: "
"from=<%s>, to=<%s>, size=%"PRIuUOFF_T", "
"rcpt=%u/%u, reply=`%s'",
smtp_address_encode(trans->mail_from),
smtp_address_encode(rcpt->path),
client->state.data_size, rcpt->index,
array_count(&trans->rcpt_to),
str_sanitize(smtp_reply_log(&reply), 128));
}
smtp_server_recipient_reply_forward(rcpt, &reply);
}
static void
relay_cmd_data_callback(const struct smtp_reply *relay_reply,
struct relay_cmd_data_context *data_ctx)
{
i_assert(data_ctx != NULL);
struct smtp_server_cmd_ctx *cmd = data_ctx->cmd;
struct smtp_server_transaction *trans = data_ctx->trans;
struct submission_backend_relay *backend = data_ctx->backend;
struct client *client = backend->backend.client;
struct smtp_reply reply;
/* finished relaying message to relay server */
if (HAS_ALL_BITS(trans->flags,
SMTP_SERVER_TRANSACTION_FLAG_REPLY_PER_RCPT)) {
/* handled recipient replies individually */
return;
}
/* check for fatal problems */
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
if (smtp_reply_is_success(&reply)) {
i_info("Successfully relayed message: "
"from=<%s>, size=%"PRIuUOFF_T", "
"id=%s, nrcpt=%u, reply=`%s'",
smtp_address_encode(trans->mail_from),
client->state.data_size, trans->id,
array_count(&trans->rcpt_to),
str_sanitize(smtp_reply_log(&reply), 128));
} else {
i_info("Failed to relay message: "
"from=<%s>, size=%"PRIuUOFF_T", nrcpt=%u, reply=`%s'",
smtp_address_encode(trans->mail_from),
client->state.data_size, array_count(&trans->rcpt_to),
str_sanitize(smtp_reply_log(&reply), 128));
}
smtp_server_reply_forward(cmd, &reply);
}
static void
backend_relay_cmd_data_init_callbacks(struct submission_backend_relay *backend,
struct smtp_server_transaction *trans)
{
struct client *client = backend->backend.client;
struct submission_recipient *rcpt;
if (!HAS_ALL_BITS(trans->flags,
SMTP_SERVER_TRANSACTION_FLAG_REPLY_PER_RCPT))
return;
array_foreach_elem(&client->rcpt_to, rcpt) {
struct smtp_client_transaction_rcpt *relay_rcpt =
rcpt->backend_context;
smtp_client_transaction_rcpt_set_data_callback(
relay_rcpt, relay_cmd_data_rcpt_callback, rcpt);
}
}
static int
backend_relay_cmd_data(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size ATTR_UNUSED)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
struct relay_cmd_data_context *data_ctx;
/* start relaying to relay server */
data_ctx = p_new(trans->pool, struct relay_cmd_data_context, 1);
data_ctx->backend = backend;
data_ctx->cmd = cmd;
data_ctx->trans = trans;
trans->context = (void*)data_ctx;
i_assert(backend->trans != NULL);
backend_relay_cmd_data_init_callbacks(backend, trans);
smtp_client_transaction_send(backend->trans, data_input,
relay_cmd_data_callback, data_ctx);
return 0;
}
/*
* VRFY command
*/
struct relay_cmd_vrfy_context {
struct submission_backend_relay *backend;
struct smtp_server_cmd_ctx *cmd;
struct smtp_client_command *cmd_relayed;
};
static void
relay_cmd_vrfy_destroy(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_vrfy_context *vrfy_cmd)
{
i_assert(vrfy_cmd != NULL);
if (vrfy_cmd->cmd_relayed != NULL)
smtp_client_command_abort(&vrfy_cmd->cmd_relayed);
}
static void
relay_cmd_vrfy_callback(const struct smtp_reply *relay_reply,
struct relay_cmd_vrfy_context *vrfy_cmd)
{
i_assert(vrfy_cmd != NULL);
struct smtp_server_cmd_ctx *cmd = vrfy_cmd->cmd;
struct submission_backend_relay *backend = vrfy_cmd->backend;
struct smtp_reply reply;
/* finished relaying VRFY command to relay server */
vrfy_cmd->cmd_relayed = NULL;
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
/* RFC 5321, Section 3.5.3:
A server MUST NOT return a 250 code in response to a VRFY or EXPN
command unless it has actually verified the address. In particular,
a server MUST NOT return 250 if all it has done is to verify that the
syntax given is valid. In that case, 502 (Command not implemented)
or 500 (Syntax error, command unrecognized) SHOULD be returned. As
stated elsewhere, implementation (in the sense of actually validating
addresses and returning information) of VRFY and EXPN are strongly
recommended. Hence, implementations that return 500 or 502 for VRFY
are not in full compliance with this specification.
*/
if (reply.status == 500 || reply.status == 502) {
smtp_server_cmd_vrfy_reply_default(cmd);
return;
}
if (!smtp_reply_has_enhanced_code(&reply)) {
switch (relay_reply->status) {
case 250:
case 251:
case 252:
reply.enhanced_code = SMTP_REPLY_ENH_CODE(2, 5, 0);
break;
default:
break;
}
}
smtp_server_reply_forward(cmd, &reply);
}
static int
backend_relay_cmd_vrfy(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd, const char *param)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
struct relay_cmd_vrfy_context *vrfy_cmd;
vrfy_cmd = p_new(cmd->pool, struct relay_cmd_vrfy_context, 1);
vrfy_cmd->backend = backend;
vrfy_cmd->cmd = cmd;
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_DESTROY,
relay_cmd_vrfy_destroy, vrfy_cmd);
vrfy_cmd->cmd_relayed = smtp_client_command_vrfy_submit(
backend->conn, 0, param, relay_cmd_vrfy_callback, vrfy_cmd);
return 0;
}
/*
* NOOP command
*/
struct relay_cmd_noop_context {
struct submission_backend_relay *backend;
struct smtp_server_cmd_ctx *cmd;
struct smtp_client_command *cmd_relayed;
};
static void
relay_cmd_noop_destroy(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_noop_context *noop_cmd)
{
i_assert(noop_cmd != NULL);
if (noop_cmd->cmd_relayed != NULL)
smtp_client_command_abort(&noop_cmd->cmd_relayed);
}
static void
relay_cmd_noop_callback(const struct smtp_reply *relay_reply,
struct relay_cmd_noop_context *noop_cmd)
{
i_assert(noop_cmd != NULL);
struct smtp_server_cmd_ctx *cmd = noop_cmd->cmd;
struct submission_backend_relay *backend = noop_cmd->backend;
struct smtp_reply reply;
/* finished relaying NOOP command to relay server */
noop_cmd->cmd_relayed = NULL;
if (!backend_relay_handle_relay_reply(backend, cmd, relay_reply,
&reply))
return;
if (smtp_reply_is_success(&reply))
smtp_server_cmd_noop_reply_success(cmd);
else
smtp_server_reply_forward(cmd, &reply);
}
static int
backend_relay_cmd_noop(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
struct relay_cmd_noop_context *noop_cmd;
noop_cmd = p_new(cmd->pool, struct relay_cmd_noop_context, 1);
noop_cmd->backend = backend;
noop_cmd->cmd = cmd;
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_DESTROY,
relay_cmd_noop_destroy, noop_cmd);
noop_cmd->cmd_relayed = smtp_client_command_noop_submit(
backend->conn, 0, relay_cmd_noop_callback, noop_cmd);
return 0;
}
/*
* QUIT command
*/
struct relay_cmd_quit_context {
struct submission_backend_relay *backend;
struct smtp_server_cmd_ctx *cmd;
struct smtp_client_command *cmd_relayed;
};
static void
relay_cmd_quit_destroy(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_quit_context *quit_cmd)
{
i_assert(quit_cmd != NULL);
if (quit_cmd->cmd_relayed != NULL)
smtp_client_command_abort(&quit_cmd->cmd_relayed);
}
static void relay_cmd_quit_relayed_destroy(void *context)
{
struct relay_cmd_quit_context *quit_cmd = context;
i_assert(quit_cmd != NULL);
quit_cmd->cmd_relayed = NULL;
}
static void
relay_cmd_quit_replied(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_quit_context *quit_cmd)
{
if (quit_cmd->cmd_relayed != NULL)
smtp_client_command_abort(&quit_cmd->cmd_relayed);
}
static void relay_cmd_quit_finish(struct relay_cmd_quit_context *quit_cmd)
{
struct smtp_server_cmd_ctx *cmd = quit_cmd->cmd;
quit_cmd->backend->quit_confirmed = TRUE;
if (quit_cmd->cmd_relayed != NULL)
smtp_client_command_abort(&quit_cmd->cmd_relayed);
smtp_server_reply_quit(cmd);
}
static void
relay_cmd_quit_callback(const struct smtp_reply *relay_reply ATTR_UNUSED,
struct relay_cmd_quit_context *quit_cmd)
{
i_assert(quit_cmd != NULL);
quit_cmd->cmd_relayed = NULL;
relay_cmd_quit_finish(quit_cmd);
}
static void relay_cmd_quit_relay(struct relay_cmd_quit_context *quit_cmd)
{
struct submission_backend_relay *backend = quit_cmd->backend;
struct smtp_server_cmd_ctx *cmd = quit_cmd->cmd;
if (quit_cmd->cmd_relayed != NULL)
return;
if (smtp_client_connection_get_state(backend->conn)
< SMTP_CLIENT_CONNECTION_STATE_READY) {
/* Don't bother relaying QUIT command when relay is not
fully initialized. */
quit_cmd->backend->quit_confirmed = TRUE;
smtp_server_reply_quit(cmd);
return;
}
/* RFC 5321, Section 4.1.1.10:
The sender MUST NOT intentionally close the transmission channel
until it sends a QUIT command, and it SHOULD wait until it receives
the reply (even if there was an error response to a previous
command). */
quit_cmd->cmd_relayed =
smtp_client_command_new(backend->conn, 0,
relay_cmd_quit_callback, quit_cmd);
smtp_client_command_write(quit_cmd->cmd_relayed, "QUIT");
smtp_client_command_set_abort_callback(
quit_cmd->cmd_relayed,
relay_cmd_quit_relayed_destroy, quit_cmd);
smtp_client_command_submit(quit_cmd->cmd_relayed);
}
static void
relay_cmd_quit_next(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct relay_cmd_quit_context *quit_cmd)
{
/* QUIT command is next to reply */
relay_cmd_quit_relay(quit_cmd);
}
static int
backend_relay_cmd_quit(struct submission_backend *_backend,
struct smtp_server_cmd_ctx *cmd)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
struct relay_cmd_quit_context *quit_cmd;
quit_cmd = p_new(cmd->pool, struct relay_cmd_quit_context, 1);
quit_cmd->backend = backend;
quit_cmd->cmd = cmd;
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_NEXT,
relay_cmd_quit_next, quit_cmd);
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_REPLIED,
relay_cmd_quit_replied, quit_cmd);
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_DESTROY,
relay_cmd_quit_destroy, quit_cmd);
if (smtp_client_connection_get_state(backend->conn)
>= SMTP_CLIENT_CONNECTION_STATE_READY)
relay_cmd_quit_relay(quit_cmd);
return 0;
}
/*
* Relay backend
*/
struct submission_backend_relay *
submission_backend_relay_create(
struct client *client,
const struct submision_backend_relay_settings *set)
{
struct submission_backend_relay *backend;
struct mail_user *user = client->user;
struct ssl_iostream_settings ssl_set;
struct smtp_client_settings smtp_set;
pool_t pool;
pool = pool_alloconly_create("submission relay backend", 1024);
backend = p_new(pool, struct submission_backend_relay, 1);
submission_backend_init(&backend->backend, pool, client,
&backend_relay_vfuncs);
mail_user_init_ssl_client_settings(user, &ssl_set);
if (set->ssl_verify)
ssl_set.verbose_invalid_cert = TRUE;
else
ssl_set.allow_invalid_cert = TRUE;
/* make relay connection */
i_zero(&smtp_set);
smtp_set.my_hostname = set->my_hostname;
smtp_set.extra_capabilities = set->extra_capabilities;
smtp_set.ssl = &ssl_set;
smtp_set.debug = user->mail_debug;
if (set->rawlog_dir != NULL) {
smtp_set.rawlog_dir =
mail_user_home_expand(user, set->rawlog_dir);
}
if (set->trusted) {
backend->trusted = TRUE;
smtp_set.peer_trusted = TRUE;
smtp_server_connection_get_proxy_data(client->conn,
&smtp_set.proxy_data);
if (user->conn.remote_ip != NULL) {
smtp_set.proxy_data.source_ip =
*user->conn.remote_ip;
smtp_set.proxy_data.source_port =
user->conn.remote_port;
}
smtp_set.proxy_data.login = user->username;
smtp_set.xclient_defer = TRUE;
}
smtp_set.username = set->user;
smtp_set.master_user = set->master_user;
smtp_set.password = set->password;
smtp_set.sasl_mech = set->sasl_mech;
smtp_set.connect_timeout_msecs = set->connect_timeout_msecs;
smtp_set.command_timeout_msecs = set->command_timeout_msecs;
if (set->path != NULL) {
backend->conn = smtp_client_connection_create_unix(
smtp_client, set->protocol, set->path, &smtp_set);
} else if (set->ip.family == 0) {
backend->conn = smtp_client_connection_create(
smtp_client, set->protocol, set->host, set->port,
set->ssl_mode, &smtp_set);
} else {
backend->conn = smtp_client_connection_create_ip(
smtp_client, set->protocol, &set->ip, set->port,
set->host, set->ssl_mode, &smtp_set);
}
return backend;
}
struct submission_backend *
submission_backend_relay_get(struct submission_backend_relay *backend)
{
return &backend->backend;
}
struct smtp_client_connection *
submission_backend_relay_get_connection(
struct submission_backend_relay *backend)
{
return backend->conn;
}
struct smtp_client_transaction *
submission_backend_relay_get_transaction(
struct submission_backend_relay *backend)
{
return backend->trans;
}
static void backend_relay_destroy(struct submission_backend *_backend)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
if (backend->trans != NULL)
smtp_client_transaction_destroy(&backend->trans);
if (backend->conn != NULL)
smtp_client_connection_close(&backend->conn);
}
static void backend_relay_ready_cb(const struct smtp_reply *reply,
void *context)
{
struct submission_backend_relay *backend = context;
struct smtp_reply dummy;
/* check relay status */
if (!backend_relay_handle_relay_reply(backend, NULL, reply, &dummy))
return;
if (!smtp_reply_is_success(reply)) {
i_error("Failed to establish relay connection: %s",
smtp_reply_log(reply));
submission_backend_fail(
&backend->backend, NULL, "4.4.0",
"Failed to establish relay connection");
return;
}
/* notify the backend API about the fact that we're ready and propagate
our capabilities */
submission_backend_started(&backend->backend,
smtp_client_connection_get_capabilities(backend->conn));
}
static void backend_relay_start(struct submission_backend *_backend)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
smtp_client_connection_connect(backend->conn,
backend_relay_ready_cb, backend);
}
/* try to proxy pipelined commands in a similarly pipelined fashion */
static void
backend_relay_client_input_pre(struct submission_backend *_backend)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
if (backend->conn != NULL)
smtp_client_connection_cork(backend->conn);
}
static void
backend_relay_client_input_post(struct submission_backend *_backend)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
if (backend->conn != NULL)
smtp_client_connection_uncork(backend->conn);
}
static uoff_t
backend_relay_get_max_mail_size(struct submission_backend *_backend)
{
struct submission_backend_relay *backend =
(struct submission_backend_relay *)_backend;
return smtp_client_connection_get_size_capability(backend->conn);
}
static struct submission_backend_vfuncs backend_relay_vfuncs = {
.destroy = backend_relay_destroy,
.start = backend_relay_start,
.client_input_pre = backend_relay_client_input_pre,
.client_input_post = backend_relay_client_input_post,
.get_max_mail_size = backend_relay_get_max_mail_size,
.trans_start = backend_relay_trans_start,
.trans_free = backend_relay_trans_free,
.cmd_helo = backend_relay_cmd_helo,
.cmd_mail = backend_relay_cmd_mail,
.cmd_rcpt = backend_relay_cmd_rcpt,
.cmd_rset = backend_relay_cmd_rset,
.cmd_data = backend_relay_cmd_data,
.cmd_vrfy = backend_relay_cmd_vrfy,
.cmd_noop = backend_relay_cmd_noop,
.cmd_quit = backend_relay_cmd_quit,
};
dovecot-2.3.21.1/src/submission/submission-client.c 0000644 0000000 0000000 00000037223 14656633576 017121 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "submission-common.h"
#include "array.h"
#include "ioloop.h"
#include "base64.h"
#include "str.h"
#include "llist.h"
#include "net.h"
#include "istream.h"
#include "ostream.h"
#include "hostpid.h"
#include "var-expand.h"
#include "settings-parser.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "mail-namespace.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "raw-storage.h"
#include "imap-urlauth.h"
#include "smtp-syntax.h"
#include "smtp-client-connection.h"
#include "submission-backend-relay.h"
#include "submission-recipient.h"
#include "submission-commands.h"
#include "submission-settings.h"
#include
/* max. length of input command line */
#define MAX_INBUF_SIZE 4096
/* Stop reading input when output buffer has this many bytes. Once the buffer
size has dropped to half of it, start reading input again. */
#define OUTBUF_THROTTLE_SIZE 4096
/* Disconnect client when it sends too many bad commands in a row */
#define CLIENT_MAX_BAD_COMMANDS 20
/* Disconnect client after idling this many milliseconds */
#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
static const struct smtp_server_callbacks smtp_callbacks;
static const struct submission_client_vfuncs submission_client_vfuncs;
struct submission_module_register submission_module_register = { 0 };
struct client *submission_clients;
unsigned int submission_client_count;
static void client_input_pre(void *context)
{
struct client *client = context;
submission_backends_client_input_pre(client);
}
static void client_input_post(void *context)
{
struct client *client = context;
submission_backends_client_input_post(client);
}
static void client_parse_backend_capabilities(struct client *client)
{
const struct submission_settings *set = client->set;
const char *const *str;
client->backend_capabilities = SMTP_CAPABILITY_NONE;
if (set->submission_backend_capabilities == NULL)
return;
str = t_strsplit_spaces(set->submission_backend_capabilities, " ,");
for (; *str != NULL; str++) {
enum smtp_capability cap = smtp_capability_find_by_name(*str);
if (cap == SMTP_CAPABILITY_NONE) {
i_warning("Unknown SMTP capability in submission_backend_capabilities: "
"%s", *str);
continue;
}
client->backend_capabilities |= cap;
}
/* Make sure CHUNKING support is always enabled when BINARYMIME is
enabled by explicit configuration. */
if (HAS_ALL_BITS(client->backend_capabilities,
SMTP_CAPABILITY_BINARYMIME)) {
client->backend_capabilities |= SMTP_CAPABILITY_CHUNKING;
}
client->backend_capabilities_configured = TRUE;
}
void client_apply_backend_capabilities(struct client *client)
{
enum smtp_capability caps = client->backend_capabilities;
/* propagate capabilities */
caps |= SMTP_CAPABILITY_AUTH | SMTP_CAPABILITY_PIPELINING |
SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES |
SMTP_CAPABILITY_CHUNKING | SMTP_CAPABILITY_BURL;
caps &= SUBMISSION_SUPPORTED_SMTP_CAPABILITIES;
smtp_server_connection_set_capabilities(client->conn, caps);
}
void client_default_backend_started(struct client *client,
enum smtp_capability caps)
{
/* propagate capabilities from backend to frontend */
if (!client->backend_capabilities_configured) {
client->backend_capabilities = caps;
client_apply_backend_capabilities(client);
/* resume the server now that we have the backend
capabilities */
smtp_server_connection_resume(client->conn);
}
}
static void
client_create_backend_default(struct client *client,
const struct submission_settings *set)
{
struct submision_backend_relay_settings relay_set;
i_zero(&relay_set);
relay_set.my_hostname = set->hostname;
relay_set.protocol = SMTP_PROTOCOL_SMTP;
relay_set.host = set->submission_relay_host;
relay_set.port = set->submission_relay_port;
relay_set.user = set->submission_relay_user;
relay_set.master_user = set->submission_relay_master_user;
relay_set.password = set->submission_relay_password;
relay_set.rawlog_dir = set->submission_relay_rawlog_dir;
relay_set.max_idle_time = set->submission_relay_max_idle_time;
relay_set.connect_timeout_msecs = set->submission_relay_connect_timeout;
relay_set.command_timeout_msecs = set->submission_relay_command_timeout;
relay_set.trusted = set->submission_relay_trusted;
if (strcmp(set->submission_relay_ssl, "smtps") == 0)
relay_set.ssl_mode = SMTP_CLIENT_SSL_MODE_IMMEDIATE;
else if (strcmp(set->submission_relay_ssl, "starttls") == 0)
relay_set.ssl_mode = SMTP_CLIENT_SSL_MODE_STARTTLS;
else
relay_set.ssl_mode = SMTP_CLIENT_SSL_MODE_NONE;
relay_set.ssl_verify = set->submission_relay_ssl_verify;
client->backend_default_relay =
submission_backend_relay_create(client, &relay_set);
client->backend_default =
submission_backend_relay_get(client->backend_default_relay);
}
static void client_init_urlauth(struct client *client)
{
static const char *access_apps[] = { "submit+", NULL };
struct imap_urlauth_config config;
i_zero(&config);
config.url_host = client->set->imap_urlauth_host;
config.url_port = client->set->imap_urlauth_port;
config.socket_path = t_strconcat(client->user->set->base_dir,
"/"IMAP_URLAUTH_SOCKET_NAME, NULL);
config.session_id = client->user->session_id;
config.access_anonymous = client->user->anonymous;
config.access_user = client->user->username;
config.access_service = "submission";
config.access_applications = access_apps;
client->urlauth_ctx = imap_urlauth_init(client->user, &config);
}
struct client *
client_create(int fd_in, int fd_out, struct mail_user *user,
struct mail_storage_service_user *service_user,
const struct submission_settings *set, const char *helo,
const struct smtp_proxy_data *proxy_data,
const unsigned char *pdata, unsigned int pdata_len,
bool no_greeting)
{
enum submission_client_workarounds workarounds =
set->parsed_workarounds;
const struct mail_storage_settings *mail_set;
struct smtp_server_settings smtp_set;
const char *ident;
struct client *client;
pool_t pool;
/* always use nonblocking I/O */
net_set_nonblock(fd_in, TRUE);
net_set_nonblock(fd_out, TRUE);
pool = pool_alloconly_create("submission client", 2048);
client = p_new(pool, struct client, 1);
client->pool = pool;
client->v = submission_client_vfuncs;
client->user = user;
client->service_user = service_user;
client->set = set;
i_array_init(&client->pending_backends, 4);
i_array_init(&client->rcpt_to, 8);
i_array_init(&client->rcpt_backends, 8);
i_zero(&smtp_set);
smtp_set.hostname = set->hostname;
smtp_set.login_greeting = set->login_greeting;
smtp_set.max_recipients = set->submission_max_recipients;
smtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS;
smtp_set.max_message_size = set->submission_max_mail_size;
smtp_set.rawlog_dir = set->rawlog_dir;
smtp_set.no_greeting = no_greeting;
smtp_set.debug = user->mail_debug;
if ((workarounds & SUBMISSION_WORKAROUND_WHITESPACE_BEFORE_PATH) != 0) {
smtp_set.workarounds |=
SMTP_SERVER_WORKAROUND_WHITESPACE_BEFORE_PATH;
}
if ((workarounds & SUBMISSION_WORKAROUND_MAILBOX_FOR_PATH) != 0) {
smtp_set.workarounds |=
SMTP_SERVER_WORKAROUND_MAILBOX_FOR_PATH;
}
client_parse_backend_capabilities(client);
p_array_init(&client->module_contexts, client->pool, 5);
client->conn = smtp_server_connection_create(smtp_server,
fd_in, fd_out, user->conn.remote_ip, user->conn.remote_port,
FALSE, &smtp_set, &smtp_callbacks, client);
smtp_server_connection_set_proxy_data(client->conn, proxy_data);
smtp_server_connection_login(client->conn, client->user->username, helo,
pdata, pdata_len, user->conn.ssl_secured);
client_create_backend_default(client, set);
mail_set = mail_user_set_get_storage_set(user);
if (*set->imap_urlauth_host != '\0' &&
*mail_set->mail_attribute_dict != '\0') {
/* Enable BURL capability only when urlauth dict is
configured correctly */
client_init_urlauth(client);
}
submission_client_count++;
DLLIST_PREPEND(&submission_clients, client);
ident = mail_user_get_anvil_userip_ident(client->user);
if (ident != NULL) {
master_service_anvil_send(
master_service, t_strconcat(
"CONNECT\t", my_pid, "\tsubmission/", ident,
"\n", NULL));
client->anvil_sent = TRUE;
}
if (hook_client_created != NULL)
hook_client_created(&client);
if (user->anonymous && !client->anonymous_allowed) {
smtp_server_connection_abort(
&client->conn, 534, "5.7.9",
"Anonymous login is not allowed for submission");
} else if (client->backend_capabilities_configured) {
client_apply_backend_capabilities(client);
smtp_server_connection_start(client->conn);
} else {
submission_backend_start(client->backend_default);
smtp_server_connection_start_pending(client->conn);
}
submission_refresh_proctitle();
return client;
}
static void client_state_reset(struct client *client)
{
i_free(client->state.args);
i_stream_unref(&client->state.data_input);
pool_unref(&client->state.pool);
i_zero(&client->state);
}
void client_destroy(struct client **_client, const char *prefix,
const char *reason)
{
struct client *client = *_client;
struct smtp_server_connection *conn = client->conn;
*_client = NULL;
smtp_server_connection_terminate(
&conn, (prefix == NULL ? "4.0.0" : prefix), reason);
}
static void
client_default_destroy(struct client *client)
{
i_assert(client->disconnected);
if (client->destroyed)
return;
client->destroyed = TRUE;
submission_backends_destroy_all(client);
array_free(&client->pending_backends);
array_free(&client->rcpt_to);
array_free(&client->rcpt_backends);
submission_client_count--;
DLLIST_REMOVE(&submission_clients, client);
if (client->anvil_sent) {
master_service_anvil_send(
master_service, t_strconcat(
"DISCONNECT\t", my_pid, "\tsubmission/",
mail_user_get_anvil_userip_ident(client->user),
"\n", NULL));
}
if (client->urlauth_ctx != NULL)
imap_urlauth_deinit(&client->urlauth_ctx);
mail_user_deinit(&client->user);
mail_storage_service_user_unref(&client->service_user);
client_state_reset(client);
pool_unref(&client->pool);
master_service_client_connection_destroyed(master_service);
submission_refresh_proctitle();
}
static void
client_connection_trans_start(void *context,
struct smtp_server_transaction *trans)
{
struct client *client = context;
client->state.pool =
pool_alloconly_create("submission client state", 1024);
client->v.trans_start(client, trans);
}
static void
client_default_trans_start(struct client *client,
struct smtp_server_transaction *trans)
{
submission_backends_trans_start(client, trans);
}
static void
client_connection_trans_free(void *context,
struct smtp_server_transaction *trans)
{
struct client *client = context;
client->v.trans_free(client, trans);
}
static void
client_default_trans_free(struct client *client,
struct smtp_server_transaction *trans)
{
array_clear(&client->rcpt_to);
submission_backends_trans_free(client, trans);
client_state_reset(client);
}
static void
client_connection_state_changed(void *context ATTR_UNUSED,
enum smtp_server_state new_state,
const char *new_args)
{
struct client *client = context;
i_free(client->state.args);
client->state.state = new_state;
client->state.args = i_strdup(new_args);
if (submission_client_count == 1)
submission_refresh_proctitle();
}
static const char *client_stats(struct client *client)
{
const struct smtp_server_stats *stats =
smtp_server_connection_get_stats(client->conn);
const char *trans_id =
smtp_server_connection_get_transaction_id(client->conn);
const struct var_expand_table logout_tab[] = {
{ 'i', dec2str(stats->input), "input" },
{ 'o', dec2str(stats->output), "output" },
{ '\0', dec2str(stats->command_count), "command_count" },
{ '\0', dec2str(stats->reply_count), "reply_count" },
{ '\0', trans_id, "transaction_id" },
{ '\0', NULL, NULL }
};
const struct var_expand_table *user_tab =
mail_user_var_expand_table(client->user);
const struct var_expand_table *tab =
t_var_expand_merge_tables(logout_tab, user_tab);
string_t *str;
const char *error;
str = t_str_new(128);
if (var_expand_with_funcs(str, client->set->submission_logout_format,
tab, mail_user_var_expand_func_table,
client->user, &error) < 0) {
i_error("Failed to expand submission_logout_format=%s: %s",
client->set->submission_logout_format, error);
}
return str_c(str);
}
static void client_connection_disconnect(void *context, const char *reason)
{
struct client *client = context;
const char *log_reason;
if (client->disconnected)
return;
client->disconnected = TRUE;
timeout_remove(&client->to_quit);
submission_backends_destroy_all(client);
if (array_is_created(&client->rcpt_to))
array_clear(&client->rcpt_to);
if (reason == NULL)
log_reason = "Connection closed";
else
log_reason = t_str_oneline(reason);
i_info("Disconnected: %s %s", log_reason, client_stats(client));
}
static void client_connection_free(void *context)
{
struct client *client = context;
client->v.destroy(client);
}
uoff_t client_get_max_mail_size(struct client *client)
{
struct submission_backend *backend;
uoff_t max_size, limit;
/* Account for backend SIZE limits and calculate our own relative to
those. */
max_size = client->set->submission_max_mail_size;
if (max_size == 0)
max_size = UOFF_T_MAX;
for (backend = client->backends; backend != NULL;
backend = backend->next) {
limit = submission_backend_get_max_mail_size(backend);
if (limit <= SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE)
continue;
limit -= SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE;
if (limit < max_size)
max_size = limit;
}
return max_size;
}
void client_add_extra_capability(struct client *client, const char *capability,
const char *params)
{
struct client_extra_capability cap;
/* Don't add capabilties handled by lib-smtp here */
i_assert(smtp_capability_find_by_name(capability)
== SMTP_CAPABILITY_NONE);
/* Avoid committing protocol errors */
i_assert(smtp_ehlo_keyword_is_valid(capability));
i_assert(params == NULL || smtp_ehlo_params_str_is_valid(params));
i_zero(&cap);
cap.capability = p_strdup(client->pool, capability);
cap.params = p_strdup(client->pool, params);
if (!array_is_created(&client->extra_capabilities))
p_array_init(&client->extra_capabilities, client->pool, 5);
array_push_back(&client->extra_capabilities, &cap);
}
void clients_destroy_all(void)
{
while (submission_clients != NULL) {
struct client *client = submission_clients;
mail_storage_service_io_activate_user(client->service_user);
client_destroy(&client, "4.3.2", "Shutting down");
}
}
static const struct smtp_server_callbacks smtp_callbacks = {
.conn_cmd_helo = cmd_helo,
.conn_cmd_mail = cmd_mail,
.conn_cmd_rcpt = cmd_rcpt,
.conn_cmd_rset = cmd_rset,
.conn_cmd_data_begin = cmd_data_begin,
.conn_cmd_data_continue = cmd_data_continue,
.conn_cmd_vrfy = cmd_vrfy,
.conn_cmd_noop = cmd_noop,
.conn_cmd_quit = cmd_quit,
.conn_cmd_input_pre = client_input_pre,
.conn_cmd_input_post = client_input_post,
.conn_trans_start = client_connection_trans_start,
.conn_trans_free = client_connection_trans_free,
.conn_state_changed = client_connection_state_changed,
.conn_disconnect = client_connection_disconnect,
.conn_free = client_connection_free,
};
static const struct submission_client_vfuncs submission_client_vfuncs = {
client_default_destroy,
.trans_start = client_default_trans_start,
.trans_free = client_default_trans_free,
.cmd_helo = client_default_cmd_helo,
.cmd_mail = client_default_cmd_mail,
.cmd_rcpt = client_default_cmd_rcpt,
.cmd_rset = client_default_cmd_rset,
.cmd_data = client_default_cmd_data,
.cmd_vrfy = client_default_cmd_vrfy,
.cmd_noop = client_default_cmd_noop,
.cmd_quit = client_default_cmd_quit,
};
dovecot-2.3.21.1/src/submission/submission-commands.c 0000644 0000000 0000000 00000037515 14656633576 017450 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "submission-common.h"
#include "str.h"
#include "istream.h"
#include "istream-concat.h"
#include "istream-seekable.h"
#include "mail-storage.h"
#include "imap-url.h"
#include "imap-msgpart.h"
#include "imap-msgpart-url.h"
#include "imap-urlauth.h"
#include "imap-urlauth-fetch.h"
#include "submission-recipient.h"
#include "submission-commands.h"
#include "submission-backend-relay.h"
/*
* EHLO, HELO commands
*/
static void
submission_helo_reply_add_extra(struct client *client,
struct smtp_server_reply *reply)
{
const struct client_extra_capability *cap;
if (!array_is_created(&client->extra_capabilities))
return;
array_foreach(&client->extra_capabilities, cap) {
if (cap->params == NULL) {
smtp_server_reply_ehlo_add(reply, cap->capability);
} else {
smtp_server_reply_ehlo_add_param(reply, cap->capability,
"%s", cap->params);
}
}
}
void submission_helo_reply_submit(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data)
{
struct client *client = smtp_server_connection_get_context(cmd->conn);
enum smtp_capability backend_caps = client->backend_capabilities;
struct smtp_server_reply *reply;
uoff_t cap_size;
reply = smtp_server_reply_create_ehlo(cmd->cmd);
if (!data->helo.old_smtp) {
string_t *burl_params = t_str_new(256);
str_append(burl_params, "imap");
if (*client->set->imap_urlauth_host == '\0' ||
strcmp(client->set->imap_urlauth_host,
URL_HOST_ALLOW_ANY) == 0) {
str_printfa(burl_params, " imap://%s",
client->set->hostname);
} else {
str_printfa(burl_params, " imap://%s",
client->set->imap_urlauth_host);
}
if (client->set->imap_urlauth_port != 143) {
str_printfa(burl_params, ":%u",
client->set->imap_urlauth_port);
}
if ((backend_caps & SMTP_CAPABILITY_8BITMIME) != 0)
smtp_server_reply_ehlo_add(reply, "8BITMIME");
smtp_server_reply_ehlo_add(reply, "AUTH");
if ((backend_caps & SMTP_CAPABILITY_BINARYMIME) != 0 &&
(backend_caps & SMTP_CAPABILITY_CHUNKING) != 0)
smtp_server_reply_ehlo_add(reply, "BINARYMIME");
smtp_server_reply_ehlo_add_param(reply,
"BURL", "%s", str_c(burl_params));
smtp_server_reply_ehlo_add(reply, "CHUNKING");
if ((backend_caps & SMTP_CAPABILITY_DSN) != 0)
smtp_server_reply_ehlo_add(reply, "DSN");
smtp_server_reply_ehlo_add(reply,
"ENHANCEDSTATUSCODES");
smtp_server_reply_ehlo_add(reply,
"PIPELINING");
cap_size = client_get_max_mail_size(client);
if (cap_size > 0) {
smtp_server_reply_ehlo_add_param(reply,
"SIZE", "%"PRIuUOFF_T, cap_size);
} else {
smtp_server_reply_ehlo_add(reply, "SIZE");
}
if ((backend_caps & SMTP_CAPABILITY_VRFY) != 0)
smtp_server_reply_ehlo_add(reply, "VRFY");
submission_helo_reply_add_extra(client, reply);
}
smtp_server_reply_submit(reply);
}
int cmd_helo(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data)
{
struct client *client = conn_ctx;
if (!data->first ||
smtp_server_connection_get_state(client->conn, NULL)
>= SMTP_SERVER_STATE_READY)
return client->v.cmd_helo(client, cmd, data);
/* respond right away */
submission_helo_reply_submit(cmd, data);
return 1;
}
int client_default_cmd_helo(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data)
{
return submission_backend_cmd_helo(client->backend_default, cmd, data);
}
/*
* MAIL command
*/
int cmd_mail(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data)
{
struct client *client = conn_ctx;
client->state.backend = client->backend_default;
return client->v.cmd_mail(client, cmd, data);
}
int client_default_cmd_mail(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data)
{
if (client->user->anonymous && !client->state.anonymous_allowed) {
/* NOTE: may need to allow anonymous BURL access in the future,
but while that is not supported, deny all anonymous access
explicitly. */
smtp_server_reply(cmd, 554, "5.7.1",
"Access denied (anonymous user)");
return -1;
}
return submission_backend_cmd_mail(client->state.backend, cmd, data);
}
/*
* RCPT command
*/
int cmd_rcpt(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_recipient *rcpt)
{
struct client *client = conn_ctx;
struct submission_recipient *srcpt;
srcpt = submission_recipient_create(client, rcpt);
return client->v.cmd_rcpt(client, cmd, srcpt);
}
int client_default_cmd_rcpt(struct client *client ATTR_UNUSED,
struct smtp_server_cmd_ctx *cmd,
struct submission_recipient *srcpt)
{
if (client->user->anonymous && !srcpt->anonymous_allowed) {
/* NOTE: may need to allow anonymous BURL access in the future,
but while that is not supported, deny all anonymous access
explicitly. */
smtp_server_recipient_reply(
srcpt->rcpt, 554, "5.7.1",
"Access denied (anonymous user)");
return -1;
}
return submission_backend_cmd_rcpt(srcpt->backend, cmd, srcpt);
}
/*
* RSET command
*/
int cmd_rset(void *conn_ctx, struct smtp_server_cmd_ctx *cmd)
{
struct client *client = conn_ctx;
return client->v.cmd_rset(client, cmd);
}
int client_default_cmd_rset(struct client *client,
struct smtp_server_cmd_ctx *cmd)
{
struct submission_backend *backend = client->state.backend;
if (backend == NULL)
backend = client->backend_default;
/* all backends will also be notified through trans_free(), but that
doesn't allow changing the RSET command response. */
return submission_backend_cmd_rset(backend, cmd);
}
/*
* DATA/BDAT commands
*/
int cmd_data_continue(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans)
{
struct client *client = conn_ctx;
struct istream *data_input = client->state.data_input;
uoff_t data_size;
struct istream *inputs[3];
string_t *added_headers;
const unsigned char *data;
size_t size;
int ret;
while ((ret = i_stream_read_more(data_input, &data, &size)) > 0) {
i_stream_skip(data_input, size);
if (!smtp_server_cmd_data_check_size(cmd))
return -1;
}
if (ret == 0)
return 0;
if (ret < 0 && data_input->stream_errno != 0)
return -1;
/* Done reading DATA stream; remove it from state and continue with
local variable. */
client->state.data_input = NULL;
/* Current data stream position is the data size */
client->state.data_size = data_input->v_offset;
/* prepend our own headers */
added_headers = t_str_new(200);
smtp_server_transaction_write_trace_record(
added_headers, trans, SMTP_SERVER_TRACE_RCPT_TO_ADDRESS_FINAL);
i_stream_seek(data_input, 0);
inputs[0] = i_stream_create_copy_from_data(
str_data(added_headers), str_len(added_headers));
inputs[1] = data_input;
inputs[2] = NULL;
data_input = i_stream_create_concat(inputs);
i_stream_set_name(data_input, "");
data_size = client->state.data_size + str_len(added_headers);
i_stream_unref(&inputs[0]);
i_stream_unref(&inputs[1]);
ret = client->v.cmd_data(client, cmd, trans, data_input, data_size);
i_stream_unref(&data_input);
return ret;
}
int cmd_data_begin(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_transaction *trans ATTR_UNUSED,
struct istream *data_input)
{
struct client *client = conn_ctx;
struct istream *inputs[2];
string_t *path;
if (client->user->anonymous && !client->state.anonymous_allowed) {
smtp_server_reply(cmd, 554, "5.7.1",
"Access denied (anonymous user)");
return -1;
}
inputs[0] = data_input;
inputs[1] = NULL;
path = t_str_new(256);
mail_user_set_get_temp_prefix(path, client->user->set);
client->state.data_input = i_stream_create_seekable_path(inputs,
SUBMISSION_MAIL_DATA_MAX_INMEMORY_SIZE, str_c(path));
return 0;
}
int client_default_cmd_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size)
{
return submission_backends_cmd_data(client, cmd, trans,
data_input, data_size);
}
/*
* BURL command
*/
/* FIXME: RFC 4468
If the URL argument to BURL refers to binary data, then the submit server
MAY refuse the command or down convert as described in Binary SMTP.
*/
struct cmd_burl_context {
struct client *client;
struct smtp_server_cmd_ctx *cmd;
struct imap_urlauth_fetch *urlauth_fetch;
struct imap_msgpart_url *url_fetch;
bool chunk_last:1;
};
static void
cmd_burl_destroy(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct cmd_burl_context *burl_cmd)
{
if (burl_cmd->urlauth_fetch != NULL)
imap_urlauth_fetch_deinit(&burl_cmd->urlauth_fetch);
if (burl_cmd->url_fetch != NULL)
imap_msgpart_url_free(&burl_cmd->url_fetch);
}
static int
cmd_burl_fetch_cb(struct imap_urlauth_fetch_reply *reply,
bool last, void *context)
{
struct cmd_burl_context *burl_cmd = context;
struct smtp_server_cmd_ctx *cmd = burl_cmd->cmd;
int ret;
i_assert(last);
if (reply == NULL) {
/* fatal failure */
// FIXME: make this an internal error
smtp_server_reply(cmd, 554, "5.6.6",
"IMAP URLAUTH resolution failed");
return -1;
}
if (!reply->succeeded) {
/* URL fetch failed */
if (reply->error != NULL) {
smtp_server_reply(cmd, 554, "5.6.6",
"IMAP URLAUTH resolution failed: %s",
reply->error);
} else {
smtp_server_reply(cmd, 554, "5.6.6",
"IMAP URLAUTH resolution failed");
}
return 1;
}
/* URL fetch succeeded */
ret = smtp_server_connection_data_chunk_add(cmd,
reply->input, reply->size, burl_cmd->chunk_last, FALSE);
if (ret < 0)
return -1;
/* Command is likely not yet complete at this point, so return 0 */
return 0;
}
static int
cmd_burl_fetch_trusted(struct cmd_burl_context *burl_cmd,
struct imap_url *imap_url)
{
struct smtp_server_cmd_ctx *cmd = burl_cmd->cmd;
struct client *client = burl_cmd->client;
const char *host_name = client->set->imap_urlauth_host;
in_port_t host_port = client->set->imap_urlauth_port;
struct imap_msgpart_open_result result;
const char *error;
/* validate host */
if (imap_url->host.name == NULL ||
(strcmp(host_name, URL_HOST_ALLOW_ANY) != 0 &&
strcmp(imap_url->host.name, host_name) != 0)) {
smtp_server_reply(cmd, 554, "5.6.6",
"IMAP URL resolution failed: "
"Inappropriate or missing host name");
return -1;
}
/* validate port */
if ((imap_url->port == 0 && host_port != 143) ||
(imap_url->port != 0 && host_port != imap_url->port)) {
smtp_server_reply(cmd, 554, "5.6.6",
"IMAP URL resolution failed: "
"Inappropriate server port");
return -1;
}
/* retrieve URL */
if (imap_msgpart_url_create
(client->user, imap_url, &burl_cmd->url_fetch, &error) < 0) {
smtp_server_reply(cmd, 554, "5.6.6",
"IMAP URL resolution failed: %s", error);
return -1;
}
if (imap_msgpart_url_read_part(burl_cmd->url_fetch,
&result, &error) <= 0) {
smtp_server_reply(cmd, 554, "5.6.6",
"IMAP URL resolution failed: %s", error);
return -1;
}
return smtp_server_connection_data_chunk_add(cmd,
result.input, result.size, burl_cmd->chunk_last, FALSE);
}
static int
cmd_burl_fetch(struct cmd_burl_context *burl_cmd, const char *url,
struct imap_url *imap_url)
{
struct smtp_server_cmd_ctx *cmd = burl_cmd->cmd;
struct client *client = burl_cmd->client;
if (client->urlauth_ctx == NULL) {
/* RFC5248, Section 2.4:
554 5.7.14 Trust relationship required
The submission server requires a configured trust
relationship with a third-party server in order to access
the message content. This value replaces the prior use of
X.7.8 for this error condition, thereby updating [RFC4468].
*/
smtp_server_reply(cmd, 554, "5.7.14",
"No IMAP URLAUTH access available");
return -1;
}
/* urlauth */
burl_cmd->urlauth_fetch =
imap_urlauth_fetch_init(client->urlauth_ctx,
cmd_burl_fetch_cb, burl_cmd);
if (imap_urlauth_fetch_url_parsed(burl_cmd->urlauth_fetch,
url, imap_url, IMAP_URLAUTH_FETCH_FLAG_BODY) == 0) {
/* wait for URL fetch */
return 0;
}
return 1;
}
void cmd_burl(struct smtp_server_cmd_ctx *cmd, const char *params)
{
struct smtp_server_connection *conn = cmd->conn;
struct client *client = smtp_server_connection_get_context(conn);
struct cmd_burl_context *burl_cmd;
const char *const *argv;
enum imap_url_parse_flags url_parse_flags =
IMAP_URL_PARSE_ALLOW_URLAUTH;
struct imap_url *imap_url;
const char *url, *error;
bool chunk_last = FALSE;
int ret = 1;
smtp_server_connection_data_chunk_init(cmd);
/* burl-cmd = "BURL" SP absolute-URI [SP end-marker] CRLF
end-marker = "LAST"
*/
argv = t_strsplit(params, " ");
url = argv[0];
if (url == NULL) {
smtp_server_reply(cmd, 501, "5.5.4",
"Missing chunk URL parameter");
ret = -1;
} else if (imap_url_parse(url, NULL, url_parse_flags,
&imap_url, &error) < 0) {
smtp_server_reply(cmd, 501, "5.5.4",
"Invalid chunk URL: %s", error);
ret = -1;
} else if (argv[1] != NULL) {
if (strcasecmp(argv[1], "LAST") != 0) {
smtp_server_reply(cmd, 501, "5.5.4",
"Invalid end marker parameter");
ret = -1;
} else if (argv[2] != NULL) {
smtp_server_reply(cmd, 501, "5.5.4",
"Invalid parameters");
ret = -1;
} else {
chunk_last = TRUE;
}
}
if (ret < 0 || !smtp_server_connection_data_check_state(cmd))
return;
if (client->user->anonymous) {
smtp_server_reply(cmd, 554, "5.7.1",
"Access denied (anonymous user)");
return;
}
burl_cmd = p_new(cmd->pool, struct cmd_burl_context, 1);
burl_cmd->client = client;
burl_cmd->cmd = cmd;
burl_cmd->chunk_last = chunk_last;
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_DESTROY,
cmd_burl_destroy, burl_cmd);
if (imap_url->uauth_rumpurl == NULL) {
/* direct local url */
ret = cmd_burl_fetch_trusted(burl_cmd, imap_url);
} else {
ret = cmd_burl_fetch(burl_cmd, url, imap_url);
}
if (ret == 0 && chunk_last)
smtp_server_command_input_lock(cmd);
}
/*
* VRFY command
*/
int cmd_vrfy(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
const char *param)
{
struct client *client = conn_ctx;
if (client->user->anonymous) {
smtp_server_reply(cmd, 550, "5.7.1",
"Access denied (anonymous user)");
return -1;
}
return client->v.cmd_vrfy(client, cmd, param);
}
int client_default_cmd_vrfy(struct client *client,
struct smtp_server_cmd_ctx *cmd, const char *param)
{
return submission_backend_cmd_vrfy(client->backend_default, cmd, param);
}
/*
* NOOP command
*/
int cmd_noop(void *conn_ctx, struct smtp_server_cmd_ctx *cmd)
{
struct client *client = conn_ctx;
return client->v.cmd_noop(client, cmd);
}
int client_default_cmd_noop(struct client *client,
struct smtp_server_cmd_ctx *cmd)
{
return submission_backend_cmd_noop(client->backend_default, cmd);
}
/*
* QUIT command
*/
struct cmd_quit_context {
struct client *client;
struct smtp_server_cmd_ctx *cmd;
};
static void cmd_quit_finish(struct cmd_quit_context *quit_cmd)
{
struct client *client = quit_cmd->client;
struct smtp_server_cmd_ctx *cmd = quit_cmd->cmd;
timeout_remove(&client->to_quit);
smtp_server_reply_quit(cmd);
}
static void
cmd_quit_next(struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct cmd_quit_context *quit_cmd)
{
struct client *client = quit_cmd->client;
/* give backend a brief interval to generate a quit reply */
client->to_quit = timeout_add(SUBMISSION_MAX_WAIT_QUIT_REPLY_MSECS,
cmd_quit_finish, quit_cmd);
}
int cmd_quit(void *conn_ctx, struct smtp_server_cmd_ctx *cmd)
{
struct client *client = conn_ctx;
struct cmd_quit_context *quit_cmd;
quit_cmd = p_new(cmd->pool, struct cmd_quit_context, 1);
quit_cmd->client = client;
quit_cmd->cmd = cmd;
smtp_server_command_add_hook(cmd->cmd, SMTP_SERVER_COMMAND_HOOK_NEXT,
cmd_quit_next, quit_cmd);
return client->v.cmd_quit(client, cmd);
}
int client_default_cmd_quit(struct client *client,
struct smtp_server_cmd_ctx *cmd)
{
return submission_backend_cmd_quit(client->backend_default, cmd);
}
dovecot-2.3.21.1/src/submission/submission-backend.c 0000644 0000000 0000000 00000027237 14656633576 017236 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "submission-common.h"
#include "llist.h"
#include "istream.h"
#include "istream-sized.h"
#include "submission-recipient.h"
#include "submission-client.h"
#include "submission-commands.h"
#include "submission-backend.h"
struct submission_backend_module_register
submission_backend_module_register = { 0 };
void submission_backend_init(struct submission_backend *backend,
pool_t pool, struct client *client,
const struct submission_backend_vfuncs *vfunc)
{
backend->pool = pool;
backend->client = client;
backend->v = *vfunc;
p_array_init(&backend->module_contexts, pool, 5);
client->backends_count++;
DLLIST_PREPEND(&client->backends, backend);
}
static void submission_backend_destroy(struct submission_backend *backend)
{
struct client *client = backend->client;
i_stream_unref(&backend->data_input);
i_free(backend->fail_enh_code);
i_free(backend->fail_reason);
DLLIST_REMOVE(&client->backends, backend);
backend->v.destroy(backend);
pool_unref(&backend->pool);
}
void submission_backends_destroy_all(struct client *client)
{
while (client->backends != NULL)
submission_backend_destroy(client->backends);
array_clear(&client->rcpt_backends);
client->state.backend = NULL;
}
void submission_backend_start(struct submission_backend *backend)
{
if (backend->started)
return;
if (backend->fail_reason != NULL) {
/* Don't restart until failure is reset at transaction end */
return;
}
backend->started = TRUE;
backend->v.start(backend);
}
void submission_backend_started(struct submission_backend *backend,
enum smtp_capability caps)
{
struct client *client = backend->client;
if (backend == client->backend_default)
client_default_backend_started(client, caps);
backend->ready = TRUE;
if (backend->v.ready != NULL)
backend->v.ready(backend, caps);
}
static void
submission_backend_fail_rcpts(struct submission_backend *backend)
{
struct client *client = backend->client;
struct submission_recipient *srcpt;
const char *enh_code = backend->fail_enh_code;
const char *reason = backend->fail_reason;
i_assert(array_count(&client->rcpt_to) > 0);
i_assert(reason != NULL);
if (enh_code == NULL)
enh_code = "4.0.0";
array_foreach_elem(&client->rcpt_to, srcpt) {
struct smtp_server_recipient *rcpt = srcpt->rcpt;
if (srcpt->backend != backend)
continue;
if (rcpt->cmd == NULL)
continue;
smtp_server_recipient_reply(rcpt, 451, enh_code, "%s", reason);
}
}
static inline void
submission_backend_reply_failure(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd)
{
const char *enh_code = backend->fail_enh_code;
const char *reason = backend->fail_reason;
if (enh_code == NULL)
enh_code = "4.0.0";
i_assert(smtp_server_command_get_reply_count(cmd->cmd) == 1);
smtp_server_reply(cmd, 451, enh_code, "%s", reason);
}
static inline bool
submission_backend_handle_failure(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd)
{
if (backend->fail_reason == NULL)
return TRUE;
/* already failed */
submission_backend_reply_failure(backend, cmd);
return TRUE;
}
void submission_backend_fail(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
const char *enh_code, const char *reason)
{
struct client *client = backend->client;
bool failed_before = (backend->fail_reason != NULL);
/* Can be called several times */
if (backend == client->backend_default) {
/* default backend: fail the whole client */
client_destroy(&client, enh_code, reason);
return;
}
/* Non-default backend for this transaction (maybe even for only
some of the approved recipients): fail only the affected
transaction and/or specific recipients. */
/* Remember the failure only once */
if (!failed_before) {
backend->fail_enh_code = i_strdup(enh_code);
backend->fail_reason = i_strdup(reason);
}
if (cmd == NULL) {
/* Called outside command context: just remember the failure */
} else if (smtp_server_command_get_reply_count(cmd->cmd) > 1) {
/* Fail DATA/BDAT/BURL command expecting several replies */
submission_backend_fail_rcpts(backend);
} else {
/* Single command */
submission_backend_reply_failure(backend, cmd);
}
/* Call the fail vfunc only once */
if (!failed_before && backend->v.fail != NULL)
backend->v.fail(backend, enh_code, reason);
backend->started = FALSE;
backend->ready = FALSE;
}
void submission_backends_client_input_pre(struct client *client)
{
struct submission_backend *backend;
for (backend = client->backends; backend != NULL;
backend = backend->next) {
if (!backend->started)
continue;
if (backend->v.client_input_pre != NULL)
backend->v.client_input_pre(backend);
}
}
void submission_backends_client_input_post(struct client *client)
{
struct submission_backend *backend;
for (backend = client->backends; backend != NULL;
backend = backend->next) {
if (!backend->started)
continue;
if (backend->v.client_input_post != NULL)
backend->v.client_input_post(backend);
}
}
uoff_t submission_backend_get_max_mail_size(struct submission_backend *backend)
{
if (backend->v.get_max_mail_size != NULL)
return backend->v.get_max_mail_size(backend);
return UOFF_T_MAX;
}
void submission_backend_trans_start(struct submission_backend *backend,
struct smtp_server_transaction *trans)
{
submission_backend_start(backend);
if (backend->trans_started)
return;
backend->trans_started = TRUE;
if (backend->v.trans_start != NULL) {
backend->v.trans_start(backend, trans,
trans->mail_from, &trans->params);
}
}
static void
submission_backend_trans_free(struct submission_backend *backend,
struct smtp_server_transaction *trans)
{
i_stream_unref(&backend->data_input);
if (backend->v.trans_free != NULL)
backend->v.trans_free(backend, trans);
backend->trans_started = FALSE;
i_free(backend->fail_enh_code);
i_free(backend->fail_reason);
}
void submission_backends_trans_start(struct client *client,
struct smtp_server_transaction *trans)
{
struct submission_backend *backend;
i_assert(client->state.backend != NULL);
submission_backend_trans_start(client->state.backend, trans);
array_foreach_elem(&client->pending_backends, backend)
submission_backend_trans_start(backend, trans);
array_clear(&client->pending_backends);
}
void submission_backends_trans_free(struct client *client,
struct smtp_server_transaction *trans)
{
struct submission_backend *backend;
i_assert(client->state.backend != NULL ||
array_count(&client->rcpt_backends) == 0);
array_foreach_elem(&client->rcpt_backends, backend)
submission_backend_trans_free(backend, trans);
array_clear(&client->pending_backends);
array_clear(&client->rcpt_backends);
client->state.backend = NULL;
}
int submission_backend_cmd_helo(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data)
{
/* failure on default backend closes the client connection */
i_assert(backend->fail_reason == NULL);
if (!backend->started || backend->v.cmd_helo == NULL) {
/* default backend is not interested, respond right away */
submission_helo_reply_submit(cmd, data);
return 1;
}
return backend->v.cmd_helo(backend, cmd, data);
}
void submission_backend_helo_reply_submit(
struct submission_backend *backend ATTR_UNUSED,
struct smtp_server_cmd_ctx *cmd, struct smtp_server_cmd_helo *data)
{
submission_helo_reply_submit(cmd, data);
}
int submission_backend_cmd_mail(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data)
{
if (!submission_backend_handle_failure(backend, cmd))
return -1;
submission_backend_start(backend);
if (backend->v.cmd_mail == NULL) {
/* mail backend is not interested, respond right away */
return 1;
}
return backend->v.cmd_mail(backend, cmd, data);
}
static void
submission_backend_add_pending(struct submission_backend *backend)
{
struct client *client = backend->client;
struct submission_backend *pending_backend;
array_foreach_elem(&client->pending_backends, pending_backend) {
if (backend == pending_backend)
return;
}
array_push_back(&client->pending_backends, &backend);
}
int submission_backend_cmd_rcpt(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct submission_recipient *srcpt)
{
struct smtp_server_transaction *trans;
if (!submission_backend_handle_failure(backend, cmd))
return -1;
i_assert(backend->started);
if (backend->v.cmd_rcpt == NULL) {
/* backend is not interested, respond right away */
return 1;
}
trans = smtp_server_connection_get_transaction(cmd->conn);
if (trans != NULL)
submission_backend_trans_start(srcpt->backend, trans);
else
submission_backend_add_pending(srcpt->backend);
return backend->v.cmd_rcpt(backend, cmd, srcpt);
}
int submission_backend_cmd_rset(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd)
{
if (!submission_backend_handle_failure(backend, cmd))
return -1;
submission_backend_start(backend);
if (backend->v.cmd_rset == NULL) {
/* backend is not interested, respond right away */
return 1;
}
return backend->v.cmd_rset(backend, cmd);
}
static int
submission_backend_cmd_data(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans)
{
if (backend->fail_reason != NULL) {
submission_backend_fail_rcpts(backend);
return 0;
}
i_assert(backend->started);
return backend->v.cmd_data(backend, cmd, trans,
backend->data_input, backend->data_size);
}
int submission_backends_cmd_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size)
{
struct submission_backend *backend;
int ret = 0;
i_assert(array_count(&client->rcpt_backends) > 0);
/* Make sure data input stream is at the beginning (plugins may have
messed with it. */
i_stream_seek(data_input, 0);
/* create the data_input streams first */
array_foreach_elem(&client->rcpt_backends, backend) {
backend->data_input =
i_stream_create_sized(data_input, data_size);
backend->data_size = data_size;
}
/* now that all the streams are created, start reading them
(reading them earlier could have caused the data_input parent's
offset to change) */
array_foreach_elem(&client->rcpt_backends, backend) {
ret = submission_backend_cmd_data(backend, cmd, trans);
if (ret < 0)
break;
}
return ret;
}
int submission_backend_cmd_vrfy(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd,
const char *param)
{
/* failure on default backend closes the client connection */
i_assert(backend->fail_reason == NULL);
submission_backend_start(backend);
if (backend->v.cmd_vrfy == NULL) {
/* backend is not interested, respond right away */
return 1;
}
return backend->v.cmd_vrfy(backend, cmd, param);
}
int submission_backend_cmd_noop(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd)
{
/* failure on default backend closes the client connection */
i_assert(backend->fail_reason == NULL);
submission_backend_start(backend);
if (backend->v.cmd_noop == NULL) {
/* backend is not interested, respond right away */
return 1;
}
return backend->v.cmd_noop(backend, cmd);
}
int submission_backend_cmd_quit(struct submission_backend *backend,
struct smtp_server_cmd_ctx *cmd)
{
/* failure on default backend closes the client connection */
i_assert(backend->fail_reason == NULL);
if (!backend->started) {
/* quit before backend even started */
return 1;
}
if (backend->v.cmd_quit == NULL) {
/* backend is not interested, respond right away */
return 1;
}
return backend->v.cmd_quit(backend, cmd);
}
dovecot-2.3.21.1/src/submission/submission-backend-relay.h 0000644 0000000 0000000 00000003343 14656633576 020345 0000000 0000000 #ifndef SUBMISSION_BACKEND_RELAY_H
#define SUBMISSION_BACKEND_RELAY_H
#include "smtp-client-connection.h"
#include "smtp-client-transaction.h"
#include "submission-backend.h"
struct client;
struct submission_backend_relay;
struct submision_backend_relay_settings {
const char *my_hostname;
enum smtp_protocol protocol;
const char *path, *host;
struct ip_addr ip; /* if empty, resolve host */
in_port_t port;
const char *const *extra_capabilities;
const char *user, *master_user;
const char *password;
const struct dsasl_client_mech *sasl_mech;
enum smtp_client_connection_ssl_mode ssl_mode;
const char *rawlog_dir;
unsigned int max_idle_time;
unsigned int connect_timeout_msecs;
unsigned int command_timeout_msecs;
bool ssl_verify:1;
bool trusted:1;
};
struct submission_backend_relay *
submission_backend_relay_create(
struct client *client,
const struct submision_backend_relay_settings *set);
/* Returns the base backend object for this relay backend */
struct submission_backend *
submission_backend_relay_get(struct submission_backend_relay *backend)
ATTR_PURE;
/* Returns the client connection for this relay backend */
struct smtp_client_connection *
submission_backend_relay_get_connection(
struct submission_backend_relay *backend) ATTR_PURE;
/* Returns the current client transaction for this relay backend */
struct smtp_client_transaction *
submission_backend_relay_get_transaction(
struct submission_backend_relay *backend) ATTR_PURE;
/* Initializes the client transaction manually, which allows providing
alternative transaction flags. */
struct smtp_client_transaction *
submission_backend_relay_init_transaction(
struct submission_backend_relay *backend,
enum smtp_client_transaction_flags flags);
#endif
dovecot-2.3.21.1/src/submission/main.c 0000644 0000000 0000000 00000030027 14656633576 014371 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "submission-common.h"
#include "buffer.h"
#include "str.h"
#include "istream.h"
#include "ostream.h"
#include "array.h"
#include "base64.h"
#include "hostpid.h"
#include "path-util.h"
#include "process-title.h"
#include "restrict-access.h"
#include "fd-util.h"
#include "settings-parser.h"
#include "master-service.h"
#include "master-login.h"
#include "master-service-settings.h"
#include "master-interface.h"
#include "var-expand.h"
#include "mail-error.h"
#include "mail-user.h"
#include "mail-storage-service.h"
#include "smtp-server.h"
#include "smtp-client.h"
#include "submission-commands.h"
#include
#include
#define DNS_CLIENT_SOCKET_PATH "dns-client"
#define LMTP_MASTER_FIRST_LISTEN_FD 3
#define IS_STANDALONE() \
(getenv(MASTER_IS_PARENT_ENV) == NULL)
struct smtp_server *smtp_server = NULL;
struct smtp_client *smtp_client = NULL;
static bool verbose_proctitle = FALSE;
static struct mail_storage_service_ctx *storage_service;
static struct master_login *master_login = NULL;
submission_client_created_func_t *hook_client_created = NULL;
bool submission_debug = FALSE;
submission_client_created_func_t *
submission_client_created_hook_set(submission_client_created_func_t *new_hook)
{
submission_client_created_func_t *old_hook = hook_client_created;
hook_client_created = new_hook;
return old_hook;
}
void submission_refresh_proctitle(void)
{
struct client *client;
string_t *title = t_str_new(128);
if (!verbose_proctitle)
return;
str_append_c(title, '[');
switch (submission_client_count) {
case 0:
str_append(title, "idling");
break;
case 1:
client = submission_clients;
str_append(title, client->user->username);
if (client->user->conn.remote_ip != NULL) {
str_append_c(title, ' ');
str_append(title,
net_ip2addr(client->user->conn.remote_ip));
}
str_append_c(title, ' ');
str_append(title, smtp_server_state_names[client->state.state]);
if (client->state.args != NULL && *client->state.args != '\0') {
str_append_c(title, ' ');
str_append(title, client->state.args);
}
break;
default:
str_printfa(title, "%u connections", submission_client_count);
break;
}
str_append_c(title, ']');
process_title_set(str_c(title));
}
static void submission_die(void)
{
/* do nothing. submission connections typically die pretty quick anyway.
*/
}
static void
send_error(int fd_out, const char *hostname, const char *error_code,
const char *error_msg)
{
const char *msg;
msg = t_strdup_printf("451 %s %s\r\n"
"421 4.3.2 %s Shutting down due to fatal error\r\n",
error_code, error_msg, hostname);
if (write(fd_out, msg, strlen(msg)) < 0) {
if (errno != EAGAIN && errno != EPIPE && errno != ECONNRESET)
i_error("write(client) failed: %m");
}
}
static bool
extract_input_data_field(const unsigned char **data, size_t *data_len,
const char **value_r)
{
size_t value_len = 0;
if (*data_len == 0)
return FALSE;
if (**data == '\0') {
value_len = 1;
} else {
*value_r = t_strndup(*data, *data_len);
value_len = strlen(*value_r) + 1;
}
if (value_len > *data_len) {
*data = &uchar_nul;
*data_len = 0;
} else {
*data = *data + value_len;
*data_len = *data_len - value_len;
}
return TRUE;
}
static int
client_create_from_input(const struct mail_storage_service_input *input,
enum mail_auth_request_flags login_flags,
int fd_in, int fd_out, const buffer_t *input_buf,
const char **error_r)
{
struct mail_storage_service_user *user;
struct mail_user *mail_user;
struct submission_settings *set;
bool no_greeting = HAS_ALL_BITS(login_flags,
MAIL_AUTH_REQUEST_FLAG_IMPLICIT);
const char *errstr;
const char *helo = NULL;
struct smtp_proxy_data proxy_data;
const unsigned char *data;
size_t data_len;
if (mail_storage_service_lookup_next(storage_service, input,
&user, &mail_user, error_r) <= 0) {
send_error(fd_out, my_hostname,
"4.7.0", MAIL_ERRSTR_CRITICAL_MSG);
return -1;
}
restrict_access_allow_coredumps(TRUE);
set = mail_storage_service_user_get_set(user)[1];
if (set->verbose_proctitle)
verbose_proctitle = TRUE;
if (settings_var_expand(&submission_setting_parser_info, set,
mail_user->pool, mail_user_var_expand_table(mail_user),
&errstr) <= 0) {
*error_r = t_strdup_printf("Failed to expand settings: %s", errstr);
send_error(fd_out, set->hostname,
"4.3.5", MAIL_ERRSTR_CRITICAL_MSG);
mail_user_deinit(&mail_user);
mail_storage_service_user_unref(&user);
return -1;
}
if (set->submission_relay_host == NULL ||
*set->submission_relay_host == '\0') {
*error_r = "No relay host configured for submission proxy "
"(submission_relay_host is unset)";
send_error(fd_out, set->hostname,
"4.3.5", MAIL_ERRSTR_CRITICAL_MSG);
mail_user_deinit(&mail_user);
mail_storage_service_user_unref(&user);
return -1;
}
/* parse input data */
data = NULL;
data_len = 0;
i_zero(&proxy_data);
if (input_buf != NULL && input_buf->used > 0) {
data = input_buf->data;
data_len = input_buf->used;
if (extract_input_data_field(&data, &data_len, &helo) &&
extract_input_data_field(&data, &data_len,
&proxy_data.helo)) {
/* nothing to do */
}
/* NOTE: actually, pipelining the AUTH command is stricly
speaking not allowed, but we support it anyway.
*/
}
(void)client_create(fd_in, fd_out, mail_user,
user, set, helo, &proxy_data, data, data_len,
no_greeting);
return 0;
}
static void main_stdio_run(const char *username)
{
struct mail_storage_service_input input;
buffer_t *input_buf;
const char *value, *error, *input_base64;
i_zero(&input);
input.module = input.service = "submission";
input.username = username != NULL ? username : getenv("USER");
if (input.username == NULL && IS_STANDALONE())
input.username = getlogin();
if (input.username == NULL)
i_fatal("USER environment missing");
if ((value = getenv("IP")) != NULL)
(void)net_addr2ip(value, &input.remote_ip);
if ((value = getenv("LOCAL_IP")) != NULL)
(void)net_addr2ip(value, &input.local_ip);
input_base64 = getenv("CLIENT_INPUT");
input_buf = input_base64 == NULL ? NULL :
t_base64_decode_str(input_base64);
if (client_create_from_input(&input, 0, STDIN_FILENO, STDOUT_FILENO,
input_buf, &error) < 0)
i_fatal("%s", error);
}
static void
login_client_connected(const struct master_login_client *login_client,
const char *username, const char *const *extra_fields)
{
struct mail_storage_service_input input;
enum mail_auth_request_flags flags = login_client->auth_req.flags;
const char *error;
buffer_t input_buf;
i_zero(&input);
input.module = input.service = "submission";
input.local_ip = login_client->auth_req.local_ip;
input.remote_ip = login_client->auth_req.remote_ip;
input.local_port = login_client->auth_req.local_port;
input.remote_port = login_client->auth_req.remote_port;
input.username = username;
input.userdb_fields = extra_fields;
input.session_id = login_client->session_id;
if ((flags & MAIL_AUTH_REQUEST_FLAG_CONN_SECURED) != 0)
input.conn_secured = TRUE;
if ((flags & MAIL_AUTH_REQUEST_FLAG_CONN_SSL_SECURED) != 0)
input.conn_ssl_secured = TRUE;
buffer_create_from_const_data(&input_buf, login_client->data,
login_client->auth_req.data_size);
if (client_create_from_input(&input, flags,
login_client->fd, login_client->fd,
&input_buf, &error) < 0) {
int fd = login_client->fd;
i_error("%s", error);
i_close_fd(&fd);
master_service_client_connection_destroyed(master_service);
}
}
static void login_client_failed(const struct master_login_client *client,
const char *errormsg)
{
const char *msg;
msg = t_strdup_printf("451 4.7.0 %s\r\n"
"421 4.3.2 %s Shutting down due to fatal error\r\n",
errormsg, my_hostname);
if (write(client->fd, msg, strlen(msg)) < 0) {
/* ignored */
}
}
static void client_connected(struct master_service_connection *conn)
{
/* when running standalone, we shouldn't even get here */
i_assert(master_login != NULL);
master_service_client_connection_accept(conn);
master_login_add(master_login, conn->fd);
}
int main(int argc, char *argv[])
{
static const struct setting_parser_info *set_roots[] = {
&submission_setting_parser_info,
NULL
};
struct master_login_settings login_set;
enum master_service_flags service_flags = 0;
enum mail_storage_service_flags storage_service_flags = 0;
struct smtp_server_settings smtp_server_set;
struct smtp_client_settings smtp_client_set;
const char *username = NULL, *auth_socket_path = "auth-master";
const char *tmp_socket_path;
const char *error;
int c;
i_zero(&login_set);
login_set.postlogin_timeout_secs = MASTER_POSTLOGIN_TIMEOUT_DEFAULT;
login_set.request_auth_token = TRUE;
if (IS_STANDALONE() && getuid() == 0 &&
net_getpeername(1, NULL, NULL) == 0) {
printf("421 5.3.5 The submission binary must not be started "
"from inetd, use submission-login instead.\r\n");
return 1;
}
if (IS_STANDALONE()) {
service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
MASTER_SERVICE_FLAG_STD_CLIENT;
} else {
service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
}
master_service = master_service_init("submission", service_flags,
&argc, &argv, "a:Dt:u:");
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'a':
auth_socket_path = optarg;
break;
case 't':
if (str_to_uint(optarg,
&login_set.postlogin_timeout_secs) < 0 ||
login_set.postlogin_timeout_secs == 0)
i_fatal("Invalid -t parameter: %s", optarg);
break;
case 'u':
storage_service_flags |=
MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
username = optarg;
break;
case 'D':
submission_debug = TRUE;
break;
default:
return FATAL_DEFAULT;
}
}
if (t_abspath(auth_socket_path, &login_set.auth_socket_path,
&error) < 0) {
i_fatal("t_abspath(%s) failed: %s", auth_socket_path,
error);
}
if (argv[optind] != NULL) {
if (t_abspath(argv[optind],
&login_set.postlogin_socket_path, &error) < 0) {
i_fatal("t_abspath(%s) failed: %s",
argv[optind], error);
}
}
login_set.callback = login_client_connected;
login_set.failure_callback = login_client_failed;
login_set.update_proctitle =
getenv(MASTER_VERBOSE_PROCTITLE_ENV) != NULL &&
master_service_get_client_limit(master_service) == 1;
master_service_set_die_callback(master_service, submission_die);
storage_service =
mail_storage_service_init(master_service,
set_roots, storage_service_flags);
/* initialize SMTP server */
i_zero(&smtp_server_set);
smtp_server_set.capabilities = SMTP_CAPABILITY_DSN;
smtp_server_set.protocol = SMTP_PROTOCOL_SMTP;
smtp_server_set.max_pipelined_commands = 5;
smtp_server_set.debug = submission_debug;
smtp_server_set.reason_code_module = "submission";
smtp_server = smtp_server_init(&smtp_server_set);
smtp_server_command_register(smtp_server, "BURL", cmd_burl, 0);
if (t_abspath(DNS_CLIENT_SOCKET_PATH, &tmp_socket_path, &error) < 0)
i_fatal("t_abspath(%s) failed: %s", DNS_CLIENT_SOCKET_PATH, error);
/* initialize SMTP client */
i_zero(&smtp_client_set);
smtp_client_set.my_hostname = my_hostdomain();
smtp_client_set.debug = submission_debug;
smtp_client_set.dns_client_socket_path = tmp_socket_path;
smtp_client = smtp_client_init(&smtp_client_set);
if (!IS_STANDALONE())
master_login = master_login_init(master_service, &login_set);
master_service_init_finish(master_service);
/* NOTE: login_set.*_socket_path are now invalid due to data stack
having been freed */
/* fake that we're running, so we know if client was destroyed
while handling its initial input */
io_loop_set_running(current_ioloop);
if (IS_STANDALONE()) {
T_BEGIN {
main_stdio_run(username);
} T_END;
} else {
io_loop_set_running(current_ioloop);
}
if (io_loop_is_running(current_ioloop))
master_service_run(master_service, client_connected);
clients_destroy_all();
smtp_client_deinit(&smtp_client);
smtp_server_deinit(&smtp_server);
if (master_login != NULL)
master_login_deinit(&master_login);
mail_storage_service_deinit(&storage_service);
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/submission/Makefile.am 0000644 0000000 0000000 00000002463 14656633576 015340 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = submission
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-imap-storage \
-I$(top_srcdir)/src/lib-imap-urlauth \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index \
-I$(top_srcdir)/src/lib-storage/index/raw \
-I$(top_srcdir)/src/lib-smtp
urlauth_libs = \
$(top_builddir)/src/lib-imap-urlauth/libimap-urlauth.la
submission_LDFLAGS = -export-dynamic
submission_LDADD = \
$(urlauth_libs) \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT) \
$(MODULE_LIBS)
submission_DEPENDENCIES = \
$(urlauth_libs) \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
submission_SOURCES = \
main.c \
submission-backend.c \
submission-backend-relay.c \
submission-recipient.c \
submission-client.c \
submission-commands.c \
submission-settings.c
headers = \
submission-common.h \
submission-backend.h \
submission-backend-relay.h \
submission-commands.h \
submission-recipient.h \
submission-client.h \
submission-settings.h
pkginc_libdir=$(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
dovecot-2.3.21.1/src/submission/submission-recipient.c 0000644 0000000 0000000 00000002673 14656633576 017626 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "submission-common.h"
#include "submission-backend.h"
#include "submission-recipient.h"
struct submission_recipient_module_register
submission_recipient_module_register = { 0 };
static void
submission_recipient_approved(struct smtp_server_recipient *rcpt ATTR_UNUSED,
struct submission_recipient *srcpt);
struct submission_recipient *
submission_recipient_create(struct client *client,
struct smtp_server_recipient *rcpt)
{
struct submission_recipient *srcpt;
srcpt = p_new(rcpt->pool, struct submission_recipient, 1);
srcpt->rcpt = rcpt;
srcpt->backend = client->state.backend;
rcpt->context = srcpt;
p_array_init(&srcpt->module_contexts, rcpt->pool, 5);
smtp_server_recipient_add_hook(
rcpt, SMTP_SERVER_RECIPIENT_HOOK_APPROVED,
submission_recipient_approved, srcpt);
return srcpt;
}
static void
submission_recipient_approved(struct smtp_server_recipient *rcpt ATTR_UNUSED,
struct submission_recipient *srcpt)
{
struct submission_backend *backend = srcpt->backend;
struct client *client = backend->client;
struct submission_backend *rcpt_backend;
bool backend_found = FALSE;
array_push_back(&client->rcpt_to, &srcpt);
array_foreach_elem(&client->rcpt_backends, rcpt_backend) {
if (rcpt_backend == backend) {
backend_found = TRUE;
break;
}
}
if (!backend_found)
array_push_back(&client->rcpt_backends, &backend);
}
dovecot-2.3.21.1/src/stats/ 0000755 0000000 0000000 00000000000 14656633641 012313 5 0000000 0000000 dovecot-2.3.21.1/src/stats/client-reader.c 0000644 0000000 0000000 00000015672 14656633576 015137 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "array.h"
#include "str.h"
#include "stats-dist.h"
#include "strescape.h"
#include "connection.h"
#include "ostream.h"
#include "master-service.h"
#include "stats-metrics.h"
#include "stats-settings.h"
#include "client-reader.h"
#include "client-writer.h"
struct reader_client {
struct connection conn;
};
static struct connection_list *reader_clients = NULL;
void client_reader_create(int fd)
{
struct reader_client *client;
client = i_new(struct reader_client, 1);
connection_init_server(reader_clients, &client->conn,
"stats-reader", fd, fd);
}
static void reader_client_destroy(struct connection *conn)
{
connection_deinit(conn);
i_free(conn);
master_service_client_connection_destroyed(master_service);
}
static void reader_client_dump_stats(string_t *str, struct stats_dist *stats,
const char *const *fields)
{
for (unsigned int i = 0; fields[i] != NULL; i++) {
const char *field = fields[i];
str_append_c(str, '\t');
if (strcmp(field, "count") == 0)
str_printfa(str, "%u", stats_dist_get_count(stats));
else if (strcmp(field, "sum") == 0)
str_printfa(str, "%"PRIu64, stats_dist_get_sum(stats));
else if (strcmp(field, "min") == 0)
str_printfa(str, "%"PRIu64, stats_dist_get_min(stats));
else if (strcmp(field, "max") == 0)
str_printfa(str, "%"PRIu64, stats_dist_get_max(stats));
else if (strcmp(field, "avg") == 0)
str_printfa(str, "%.02f", stats_dist_get_avg(stats));
else if (strcmp(field, "median") == 0)
str_printfa(str, "%"PRIu64, stats_dist_get_median(stats));
else if (strcmp(field, "variance") == 0)
str_printfa(str, "%.02f", stats_dist_get_variance(stats));
else if (field[0] == '%') {
str_printfa(str, "%"PRIu64,
stats_dist_get_percentile(stats, strtod(field+1, NULL)/100.0));
} else {
/* return unknown fields as empty */
}
}
}
static void reader_client_dump_metric(string_t *str, const struct metric *metric,
const char *const *fields)
{
reader_client_dump_stats(str, metric->duration_stats, fields);
for (unsigned int i = 0; i < metric->fields_count; i++) {
str_append_c(str, '\t');
str_append_tabescaped(str, metric->fields[i].field_key);
reader_client_dump_stats(str, metric->fields[i].stats, fields);
}
str_append_c(str, '\n');
}
static void
reader_client_append_sub_name(string_t *str, const char *sub_name)
{
for (; *sub_name != '\0'; sub_name++) {
switch (*sub_name) {
case '\t':
case '\n':
case '\r':
case ' ':
str_append_c(str, '_');
break;
default:
str_append_c(str, *sub_name);
}
}
}
static void
reader_client_dump_sub_metrics(struct ostream *output, const struct metric *metric,
const char *sub_name, const char *const *fields)
{
size_t root_pos, name_pos;
struct metric *const *sub_metrics;
if (!array_is_created(&metric->sub_metrics))
return;
string_t *str = t_str_new(128);
reader_client_append_sub_name(str, sub_name);
str_append_c(str, '_');
root_pos = str->used;
array_foreach(&metric->sub_metrics, sub_metrics) {
str_truncate(str, root_pos);
reader_client_append_sub_name(str, (*sub_metrics)->sub_name);
name_pos = str->used;
reader_client_dump_metric(str, *sub_metrics, fields);
o_stream_nsend(output, str_data(str), str_len(str));
str_truncate(str, name_pos);
reader_client_dump_sub_metrics(output, *sub_metrics,
str_c(str), fields);
}
}
static int
reader_client_input_dump(struct reader_client *client, const char *const *args)
{
struct stats_metrics_iter *iter;
const struct metric *metric;
o_stream_cork(client->conn.output);
iter = stats_metrics_iterate_init(stats_metrics);
while ((metric = stats_metrics_iterate(iter)) != NULL) T_BEGIN {
string_t *str = t_str_new(128);
str_append_tabescaped(str, metric->name);
reader_client_dump_metric(str, metric, args);
o_stream_nsend(client->conn.output, str_data(str), str_len(str));
reader_client_dump_sub_metrics(client->conn.output, metric,
metric->name, args);
} T_END;
o_stream_nsend(client->conn.output, "\n", 1);
stats_metrics_iterate_deinit(&iter);
o_stream_uncork(client->conn.output);
return 1;
}
static int
reader_client_input_dump_reset(struct reader_client *client,
const char *const *args)
{
(void)reader_client_input_dump(client, args);
stats_metrics_reset(stats_metrics);
return 1;
}
static int
reader_client_input_metrics_add(struct reader_client *client,
const char *const *args)
{
const char *error;
if (str_array_length(args) < 7) {
e_error(client->conn.event, "METRICS-ADD: Not enough parameters");
return -1;
}
struct stats_metric_settings set = {
.metric_name = args[0],
.description = args[1],
.fields = args[2],
.group_by = args[3],
.filter = args[4],
.exporter = args[5],
.exporter_include = args[6],
};
o_stream_cork(client->conn.output);
if (stats_metrics_add_dynamic(stats_metrics, &set, &error)) {
client_writer_update_connections();
o_stream_nsend(client->conn.output, "+", 1);
} else {
o_stream_nsend(client->conn.output, "-", 1);
o_stream_nsend_str(client->conn.output, "METRICS-ADD: ");
o_stream_nsend_str(client->conn.output, error);
}
o_stream_nsend(client->conn.output, "\n", 1);
o_stream_uncork(client->conn.output);
return 1;
}
static int
reader_client_input_metrics_remove(struct reader_client *client,
const char *const *args)
{
if (str_array_length(args) < 1) {
e_error(client->conn.event, "METRICS-REMOVE: Not enough parameters");
return -1;
}
if (stats_metrics_remove_dynamic(stats_metrics, args[0])) {
client_writer_update_connections();
o_stream_nsend(client->conn.output, "+\n", 2);
} else {
o_stream_nsend_str(client->conn.output,
t_strdup_printf("-metrics '%s' not found\n", args[0]));
}
return 1;
}
static int
reader_client_input_args(struct connection *conn, const char *const *args)
{
struct reader_client *client = (struct reader_client *)conn;
const char *cmd = args[0];
if (cmd == NULL) {
i_error("Client sent empty line");
return 1;
}
args++;
if (strcmp(cmd, "DUMP") == 0)
return reader_client_input_dump(client, args);
else if (strcmp(cmd, "METRICS-ADD") == 0)
return reader_client_input_metrics_add(client, args);
else if (strcmp(cmd, "METRICS-REMOVE") == 0)
return reader_client_input_metrics_remove(client, args);
else if (strcmp(cmd, "DUMP-RESET") == 0)
return reader_client_input_dump_reset(client, args);
return 1;
}
static struct connection_settings client_set = {
.service_name_in = "stats-reader-client",
.service_name_out = "stats-reader-server",
.major_version = 2,
.minor_version = 0,
.input_max_size = 1024,
.output_max_size = SIZE_MAX,
.client = FALSE,
};
static const struct connection_vfuncs client_vfuncs = {
.destroy = reader_client_destroy,
.input_args = reader_client_input_args,
};
void client_readers_init(void)
{
reader_clients = connection_list_init(&client_set, &client_vfuncs);
}
void client_readers_deinit(void)
{
connection_list_deinit(&reader_clients);
}
dovecot-2.3.21.1/src/stats/client-reader.h 0000644 0000000 0000000 00000000266 14656633576 015135 0000000 0000000 #ifndef CLIENT_READER_H
#define CLIENT_READER_H
struct stats_metrics;
void client_reader_create(int fd);
void client_readers_init(void);
void client_readers_deinit(void);
#endif
dovecot-2.3.21.1/src/stats/test-stats-metrics.c 0000644 0000000 0000000 00000027724 14656633576 016201 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "test-stats-common.h"
#include "array.h"
bool test_stats_callback(struct event *event,
enum event_callback_type type ATTR_UNUSED,
struct failure_context *ctx, const char *fmt ATTR_UNUSED,
va_list args ATTR_UNUSED)
{
if (stats_metrics != NULL) {
stats_metrics_event(stats_metrics, event, ctx);
struct event_filter *filter =
stats_metrics_get_event_filter(stats_metrics);
return !event_filter_match(filter, event, ctx);
}
return TRUE;
}
static const char *settings_blob_1 =
"metric=test\n"
"metric/test/metric_name=test\n"
"metric/test/filter=event=test\n"
"\n";
static void test_stats_metrics(void)
{
test_begin("stats metrics (event counting)");
/* register some stats */
test_init(settings_blob_1);
/* push event in */
struct event *event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
test_event_send(event);
event_unref(&event);
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
test_deinit();
test_end();
}
static const char *settings_blob_2 =
"metric=test\n"
"metric/test/metric_name=test\n"
"metric/test/filter=(event=test AND test_field=value)\n"
"\n";
static void test_stats_metrics_filter(void)
{
test_begin("stats metrics (filter)");
test_init(settings_blob_2);
/* check filter */
struct event_filter *filter =
stats_metrics_get_event_filter(stats_metrics);
string_t *str_filter = t_str_new(64);
event_filter_export(filter, str_filter);
test_assert_strcmp("((event=\"test\" AND \"test_field\"=\"value\"))",
str_c(str_filter));
/* send event */
struct event *event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
event_add_str(event, "test_field", "value");
test_event_send(event);
event_unref(&event);
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
/* send another event */
event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
event_add_str(event, "test_field", "nother value");
e_debug(event, "test");
event_unref(&event);
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
test_deinit();
test_end();
}
static void test_stats_metrics_group_by_check_one(const struct metric *metric,
const char *sub_name,
unsigned int total_count,
unsigned int submetric_count,
unsigned int group_by_count,
enum stats_metric_group_by_func group_by_func,
const char *group_by_field,
enum metric_value_type value_type)
{
test_assert_strcmp(metric->name, "test");
if (sub_name != NULL)
test_assert_strcmp(metric->sub_name, sub_name);
else
test_assert(metric->sub_name == NULL);
test_assert(stats_dist_get_count(metric->duration_stats) == total_count);
if (submetric_count > 0) {
test_assert(array_is_created(&metric->sub_metrics));
test_assert(array_count(&metric->sub_metrics) == submetric_count);
} else {
test_assert(!array_is_created(&metric->sub_metrics));
}
if (group_by_count > 0) {
test_assert(metric->group_by_count == group_by_count);
i_assert(metric->group_by != NULL);
test_assert(metric->group_by[0].func == group_by_func);
test_assert_strcmp(metric->group_by[0].field, group_by_field);
} else {
test_assert(metric->group_by_count == 0);
test_assert(metric->group_by == NULL);
}
test_assert(metric->group_value.type == value_type);
}
#define DISCRETE_TEST_VAL_COUNT 3
struct discrete_test {
const char *settings_blob;
unsigned int num_values;
const char *values_first[DISCRETE_TEST_VAL_COUNT];
const char *values_second[DISCRETE_TEST_VAL_COUNT];
};
static const struct discrete_test discrete_tests[] = {
{
"test_name sub_name",
3,
{ "eta", "kappa", "nu", },
{ "upsilon", "pi", "epsilon", },
},
{
"test_name:discrete sub_name:discrete",
3,
{ "apple", "bannana", "orange", },
{ "pie", "yoghurt", "cobbler", },
},
{
"test_name sub_name:discrete",
3,
{ "apollo", "gaia", "hermes", },
{ "thor", "odin", "loki", },
},
};
static void test_stats_metrics_group_by_discrete_real(const struct discrete_test *test)
{
struct event *event;
unsigned int i, j;
test_begin(t_strdup_printf("stats metrics (discrete group by) - %s",
test->settings_blob));
test_init(t_strdup_printf("metric=test\n"
"metric/test/metric_name=test\n"
"metric/test/filter=event=test\n"
"metric/test/group_by=%s\n"
"\n", test->settings_blob));
for (i = 0; i < test->num_values; i++) {
for (j = 0; j < test->num_values; j++) {
event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
event_add_str(event, "test_name", test->values_first[i]);
event_add_str(event, "sub_name", test->values_second[j]);
test_event_send(event);
event_unref(&event);
}
}
/* check total number of events */
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == test->num_values * test->num_values);
/* analyze the structure */
struct stats_metrics_iter *iter = stats_metrics_iterate_init(stats_metrics);
const struct metric *root_metric = stats_metrics_iterate(iter);
stats_metrics_iterate_deinit(&iter);
test_stats_metrics_group_by_check_one(root_metric,
NULL,
test->num_values * test->num_values,
test->num_values,
2, STATS_METRIC_GROUPBY_DISCRETE,
"test_name", 0);
struct metric *const *first = array_idx(&root_metric->sub_metrics, 0);
/* examime each sub-metric */
for (i = 0; i < test->num_values; i++) {
test_stats_metrics_group_by_check_one(first[i],
test->values_first[i],
test->num_values,
test->num_values,
1, STATS_METRIC_GROUPBY_DISCRETE,
"sub_name",
METRIC_VALUE_TYPE_STR);
struct metric *const *second = array_idx(&first[i]->sub_metrics, 0);
/* examine each sub-sub-metric */
for (j = 0; j < test->num_values; j++) {
test_stats_metrics_group_by_check_one(second[j],
test->values_second[j],
1, 0, 0, 0, NULL,
METRIC_VALUE_TYPE_STR);
}
}
test_deinit();
test_end();
}
static void test_stats_metrics_group_by_discrete(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(discrete_tests); i++)
test_stats_metrics_group_by_discrete_real(&discrete_tests[i]);
}
#define QUANTIZED_TEST_VAL_COUNT 15
struct quantized_test {
const char *settings_blob;
unsigned int num_inputs;
intmax_t input_vals[QUANTIZED_TEST_VAL_COUNT];
unsigned int num_sub_metrics;
unsigned int num_ranges;
struct {
struct stats_metric_settings_bucket_range range;
intmax_t count;
} ranges[QUANTIZED_TEST_VAL_COUNT];
};
static const struct quantized_test quantized_tests[] = {
{
"linear:100:1000:100",
13,
{ 0, 50, 100, 101, 200, 201, 250, 301, 900, 901, 1000, 1001, 2000 },
7,
11,
{ { { INTMAX_MIN, 100 }, 3 },
{ { 100, 200 }, 2 },
{ { 200, 300 }, 2 },
{ { 300, 400 }, 1 },
{ { 400, 500 }, 0 },
{ { 500, 600 }, 0 },
{ { 600, 700 }, 0 },
{ { 700, 800 }, 0 },
{ { 800, 900 }, 1 },
{ { 900, 1000 }, 2 },
{ { 1000, INTMAX_MAX }, 2 },
}
},
{
/* start at 0 */
"exponential:0:6:10",
12,
{ 0, 5, 10, 11, 100, 101, 500, 1000, 1001, 1000000, 1000001, 2000000 },
7,
8,
{ { { INTMAX_MIN, 1 }, 1 },
{ { 1, 10 }, 2 },
{ { 10, 100 }, 2 },
{ { 100, 1000 }, 3 },
{ { 1000, 10000 }, 1 },
{ { 10000, 100000 }, 0 },
{ { 100000, 1000000 }, 1 },
{ { 1000000, INTMAX_MAX }, 2 },
}
},
{
/* start at 0 */
"exponential:0:6:2",
9,
{ 0, 1, 2, 4, 5, 20, 64, 65, 100 },
7,
8,
{ { { INTMAX_MIN, 1 }, 2 },
{ { 1, 2 }, 1 },
{ { 2, 4 }, 1 },
{ { 4, 8 }, 1 },
{ { 8, 16 }, 0 },
{ { 16, 32 }, 1 },
{ { 32, 64 }, 1 },
{ { 64, INTMAX_MAX }, 2 },
}
},
{
/* start at >0 */
"exponential:2:6:10",
12,
{ 0, 5, 10, 11, 100, 101, 500, 1000, 1001, 1000000, 1000001, 2000000 },
5,
6,
{ { { INTMAX_MIN, 100 }, 5 },
{ { 100, 1000 }, 3 },
{ { 1000, 10000 }, 1 },
{ { 10000, 100000 }, 0 },
{ { 100000, 1000000 }, 1 },
{ { 1000000, INTMAX_MAX }, 2 },
}
},
{
/* start at >0 */
"exponential:2:6:2",
9,
{ 0, 1, 2, 4, 5, 20, 64, 65, 100 },
5,
6,
{ { { INTMAX_MIN, 4 }, 4 },
{ { 4, 8 }, 1 },
{ { 8, 16 }, 0 },
{ { 16, 32 }, 1 },
{ { 32, 64 }, 1 },
{ { 64, INTMAX_MAX }, 2 },
}
},
};
static void test_stats_metrics_group_by_quantized_real(const struct quantized_test *test)
{
unsigned int i;
test_begin(t_strdup_printf("stats metrics (quantized group by) - %s",
test->settings_blob));
test_init(t_strdup_printf("metric=test\n"
"metric/test/metric_name=test\n"
"metric/test/filter=event=test\n"
"metric/test/group_by=test_name foobar:%s\n"
"\n", test->settings_blob));
struct event *event;
for (i = 0; i < test->num_inputs; i++) {
event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
event_add_str(event, "test_name", "alpha");
event_add_int(event, "foobar", test->input_vals[i]);
test_event_send(event);
event_unref(&event);
}
/* check total number of events */
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == test->num_inputs);
/* analyze the structure */
struct stats_metrics_iter *iter = stats_metrics_iterate_init(stats_metrics);
const struct metric *root_metric = stats_metrics_iterate(iter);
stats_metrics_iterate_deinit(&iter);
test_stats_metrics_group_by_check_one(root_metric, NULL, test->num_inputs,
1, 2, STATS_METRIC_GROUPBY_DISCRETE,
"test_name", 0);
/* examine first level sub-metric */
struct metric *const *first = array_idx(&root_metric->sub_metrics, 0);
test_stats_metrics_group_by_check_one(first[0],
"alpha",
test->num_inputs,
test->num_sub_metrics,
1,
STATS_METRIC_GROUPBY_QUANTIZED,
"foobar",
METRIC_VALUE_TYPE_STR);
/* check the ranges */
test_assert(first[0]->group_by[0].num_ranges == test->num_ranges);
for (i = 0; i < test->num_ranges; i++) {
test_assert(first[0]->group_by[0].ranges[i].min == test->ranges[i].range.min);
test_assert(first[0]->group_by[0].ranges[i].max == test->ranges[i].range.max);
}
/* examine second level sub-metrics */
struct metric *const *second = array_idx(&first[0]->sub_metrics, 0);
for (i = 0; i < test->num_sub_metrics; i++) {
const char *sub_name;
intmax_t range_idx;
/* we check these first, before we use the value below */
test_assert(second[i]->group_value.type == METRIC_VALUE_TYPE_BUCKET_INDEX);
test_assert(second[i]->group_value.intmax < test->num_ranges);
range_idx = second[i]->group_value.intmax;
/* construct the expected sub-metric name */
if (test->ranges[range_idx].range.min == INTMAX_MIN) {
sub_name = t_strdup_printf("foobar_ninf_%jd",
test->ranges[range_idx].range.max);
} else if (test->ranges[range_idx].range.max == INTMAX_MAX) {
sub_name = t_strdup_printf("foobar_%jd_inf",
test->ranges[range_idx].range.min + 1);
} else {
sub_name = t_strdup_printf("foobar_%jd_%jd",
test->ranges[range_idx].range.min + 1,
test->ranges[range_idx].range.max);
}
test_stats_metrics_group_by_check_one(second[i],
sub_name,
test->ranges[second[i]->group_value.intmax].count,
0, 0, 0, NULL,
METRIC_VALUE_TYPE_BUCKET_INDEX);
}
test_deinit();
test_end();
}
static void test_stats_metrics_group_by_quantized(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(quantized_tests); i++)
test_stats_metrics_group_by_quantized_real(&quantized_tests[i]);
}
int main(void) {
void (*const test_functions[])(void) = {
test_stats_metrics,
test_stats_metrics_filter,
test_stats_metrics_group_by_discrete,
test_stats_metrics_group_by_quantized,
NULL
};
int ret = test_run(test_functions);
return ret;
}
dovecot-2.3.21.1/src/stats/test-stats-common.h 0000644 0000000 0000000 00000001612 14656633576 016014 0000000 0000000 #ifndef TEST_STATS_COMMON
#define TEST_STATS_COMMON 1
#include "stats-common.h"
#include "event-filter.h"
#include "istream.h"
#include "settings-parser.h"
#include "str.h"
#include "test-common.h"
#include "lib-event-private.h"
#include "stats-dist.h"
#include "stats-event-category.h"
#include "stats-metrics.h"
extern struct event_category test_category;
extern struct event_category child_test_category;
extern pool_t test_pool;
bool test_stats_callback(struct event *event,
enum event_callback_type type ATTR_UNUSED,
struct failure_context *ctx, const char *fmt ATTR_UNUSED,
va_list args ATTR_UNUSED);
void test_init(const char *settings_blob);
void test_deinit(void);
void test_event_send(struct event *event);
enum stats_dist_field {
STATS_DIST_COUNT,
STATS_DIST_SUM,
};
uint64_t get_stats_dist_field(const char *metric_name, enum stats_dist_field field);
#endif
dovecot-2.3.21.1/src/stats/stats-metrics.h 0000644 0000000 0000000 00000006613 14656633576 015223 0000000 0000000 #ifndef STATS_METRICS_H
#define STATS_METRICS_H
#include "stats-settings.h"
#include "sha1.h"
#define STATS_EVENT_FIELD_NAME_DURATION "duration"
struct metric;
struct stats_metrics;
struct exporter {
const char *name;
/*
* serialization format options
*
* the "how do we encode the event before sending it" knobs
*/
enum event_exporter_time_fmt time_format;
/* Max length for string field values */
size_t format_max_field_len;
/* function to serialize the event */
void (*format)(const struct metric *, struct event *, buffer_t *);
/* mime type for the format */
const char *format_mime_type;
/*
* transport options
*
* the "how do we get the event to the external location" knobs
*/
const char *transport_args;
unsigned int transport_timeout;
/* function to send the event */
void (*transport)(const struct exporter *, const buffer_t *);
};
struct metric_export_info {
const struct exporter *exporter;
enum event_exporter_includes {
EVENT_EXPORTER_INCL_NONE = 0,
EVENT_EXPORTER_INCL_NAME = 0x01,
EVENT_EXPORTER_INCL_HOSTNAME = 0x02,
EVENT_EXPORTER_INCL_TIMESTAMPS = 0x04,
EVENT_EXPORTER_INCL_CATEGORIES = 0x08,
EVENT_EXPORTER_INCL_FIELDS = 0x10,
} include;
};
struct metric_field {
const char *field_key;
struct stats_dist *stats;
};
enum metric_value_type {
METRIC_VALUE_TYPE_STR,
METRIC_VALUE_TYPE_INT,
METRIC_VALUE_TYPE_BUCKET_INDEX,
};
struct metric_value {
enum metric_value_type type;
unsigned char hash[SHA1_RESULTLEN];
intmax_t intmax;
};
struct metric {
const struct stats_metric_settings *set;
const char *name;
/* When this metric is a sub-metric, then this is the
suffix for name and any sub_names before it.
So if we have
struct metric imap_command {
event_name = imap_command_finished
group_by = cmd_name
}
The metric.name will always be imap_command and for each sub-metric
metric.sub_name will be whatever the cmd_name is, such as 'select'.
This is a display name and does not guarantee uniqueness.
*/
const char *sub_name;
/* Timing for how long the event existed */
struct stats_dist *duration_stats;
unsigned int fields_count;
struct metric_field *fields;
unsigned int group_by_count;
const struct stats_metric_settings_group_by *group_by;
struct metric_value group_value;
ARRAY(struct metric *) sub_metrics;
struct metric_export_info export_info;
};
bool stats_metrics_add_dynamic(struct stats_metrics *metrics,
struct stats_metric_settings *set,
const char **error_r);
bool stats_metrics_remove_dynamic(struct stats_metrics *metrics,
const char *name);
struct stats_metrics *stats_metrics_init(const struct stats_settings *set);
void stats_metrics_deinit(struct stats_metrics **metrics);
/* Reset all metrics */
void stats_metrics_reset(struct stats_metrics *metrics);
/* Returns event filter created from the stats_settings. */
struct event_filter *
stats_metrics_get_event_filter(struct stats_metrics *metrics);
/* Update metrics with given event. */
void stats_metrics_event(struct stats_metrics *metrics, struct event *event,
const struct failure_context *ctx);
/* Iterate through all the tracked metrics. */
struct stats_metrics_iter *
stats_metrics_iterate_init(struct stats_metrics *metrics);
const struct metric *stats_metrics_iterate(struct stats_metrics_iter *iter);
void stats_metrics_iterate_deinit(struct stats_metrics_iter **iter);
#endif
dovecot-2.3.21.1/src/stats/event-exporter-fmt.c 0000644 0000000 0000000 00000003724 14656633576 016167 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "hash.h"
#include "ioloop.h"
#include "event-exporter.h"
void event_export_helper_fmt_unix_time(string_t *dest,
const struct timeval *time)
{
str_printfa(dest, "%"PRIdTIME_T".%06u", time->tv_sec,
(unsigned int) time->tv_usec);
}
void event_export_helper_fmt_rfc3339_time(string_t *dest,
const struct timeval *time)
{
const struct tm *tm;
tm = gmtime(&time->tv_sec);
str_printfa(dest, "%04d-%02d-%02dT%02d:%02d:%02d.%06luZ",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
time->tv_usec);
}
HASH_TABLE_DEFINE_TYPE(category_set, void *, const struct event_category *);
static void insert_category(HASH_TABLE_TYPE(category_set) hash,
const struct event_category * const cat)
{
/* insert this category (key == the unique internal pointer) */
hash_table_update(hash, cat->internal, cat);
/* insert parent's categories */
if (cat->parent != NULL)
insert_category(hash, cat->parent);
}
void event_export_helper_fmt_categories(string_t *dest,
struct event_category * const *cats,
unsigned int count,
void (*append)(string_t *, const char *),
const char *separator)
{
HASH_TABLE_TYPE(category_set) hash;
struct hash_iterate_context *iter;
const struct event_category *cat;
void *key ATTR_UNUSED;
unsigned int i;
bool first = TRUE;
if (count == 0)
return;
hash_table_create_direct(&hash, pool_datastack_create(),
3 * count /* estimate */);
/* insert all the categories into the hash table */
for (i = 0; i < count; i++)
insert_category(hash, cats[i]);
/* output each category from hash table */
iter = hash_table_iterate_init(hash);
while (hash_table_iterate(iter, hash, &key, &cat)) {
if (!first)
str_append(dest, separator);
append(dest, cat->name);
first = FALSE;
}
hash_table_iterate_deinit(&iter);
hash_table_destroy(&hash);
}
dovecot-2.3.21.1/src/stats/event-exporter-transport-drop.c 0000644 0000000 0000000 00000000357 14656633576 020376 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "event-exporter.h"
void event_export_transport_drop(const struct exporter *exporter ATTR_UNUSED,
const buffer_t *buf ATTR_UNUSED)
{
}
dovecot-2.3.21.1/src/stats/stats-service-private.h 0000644 0000000 0000000 00000000220 14656633576 016651 0000000 0000000 #ifndef STATS_SERVICE_PRIVATE_H
#define STATS_SERVICE_PRIVATE_H
#include "stats-service.h"
void stats_service_openmetrics_init(void);
#endif
dovecot-2.3.21.1/src/stats/test-client-writer.c 0000644 0000000 0000000 00000007225 14656633576 016161 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "test-stats-common.h"
#include "master-service-private.h"
#include "client-writer.h"
#include "connection.h"
#include "ostream.h"
static struct event *last_sent_event = NULL;
static bool recurse_back = FALSE;
static struct connection_list *conn_list;
static void test_writer_server_destroy(struct connection *conn)
{
io_loop_stop(conn->ioloop);
}
static int test_writer_server_input_args(struct connection *conn,
const char *const *args ATTR_UNUSED)
{
/* check filter */
test_assert_strcmp(args[0], "FILTER");
test_assert_strcmp(args[1], "(event=\"test\")");
/* send commands now */
string_t *send_buf = t_str_new(128);
o_stream_nsend_str(conn->output, "CATEGORY\ttest\n");
str_printfa(send_buf, "BEGIN\t%"PRIu64"\t0\t0\t", last_sent_event->id);
event_export(last_sent_event, send_buf);
str_append_c(send_buf, '\n');
o_stream_nsend(conn->output, str_data(send_buf), str_len(send_buf));
str_truncate(send_buf, 0);
str_printfa(send_buf, "END\t%"PRIu64"\n", last_sent_event->id);
o_stream_nsend(conn->output, str_data(send_buf), str_len(send_buf));
/* disconnect immediately */
return -1;
}
static struct connection_settings client_set = {
.service_name_in = "stats-server",
.service_name_out = "stats-client",
.major_version = 4,
.minor_version = 0,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
.client = TRUE,
};
static const struct connection_vfuncs client_vfuncs = {
.input_args = test_writer_server_input_args,
.destroy = test_writer_server_destroy,
};
static void test_write_one(struct event *event ATTR_UNUSED)
{
int fds[2];
test_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
struct connection *conn = i_new(struct connection, 1);
struct ioloop *loop = io_loop_create();
client_writer_create(fds[1]);
connection_init_client_fd(conn_list, conn, "stats", fds[0], fds[0]);
last_sent_event = event;
io_loop_run(loop);
last_sent_event = NULL;
connection_deinit(conn);
i_free(conn);
/* client-writer needs two loops to deinit */
io_loop_set_running(loop);
io_loop_handler_run(loop);
io_loop_set_running(loop);
io_loop_handler_run(loop);
io_loop_destroy(&loop);
}
bool test_stats_callback(struct event *event,
enum event_callback_type type ATTR_UNUSED,
struct failure_context *ctx ATTR_UNUSED,
const char *fmt ATTR_UNUSED,
va_list args ATTR_UNUSED)
{
if (recurse_back)
return TRUE;
recurse_back = TRUE;
if (stats_metrics != NULL) {
test_write_one(event);
}
recurse_back = FALSE;
return TRUE;
}
static const char *settings_blob_1 =
"metric=test\n"
"metric/test/metric_name=test\n"
"metric/test/filter=event=test\n"
"\n";
static void test_client_writer(void)
{
test_begin("client writer");
/* register some stats */
test_init(settings_blob_1);
client_writers_init();
conn_list = connection_list_init(&client_set, &client_vfuncs);
/* push event in */
struct event *event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
test_event_send(event);
event_unref(&event);
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
test_deinit();
client_writers_deinit();
connection_list_deinit(&conn_list);
test_end();
}
int main(void) {
/* fake master service to pretend destroying
connections. */
struct master_service local_master_service = {
.stopping = TRUE,
.total_available_count = 100,
.service_count_left = 100,
};
void (*const test_functions[])(void) = {
test_client_writer,
NULL
};
master_service = &local_master_service;
int ret = test_run(test_functions);
return ret;
}
dovecot-2.3.21.1/src/stats/Makefile.in 0000644 0000000 0000000 00000104705 14656633613 014306 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = stats$(EXEEXT)
noinst_PROGRAMS = $(am__EXEEXT_1)
subdir = src/stats
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = test-stats-metrics$(EXEEXT) test-client-writer$(EXEEXT) \
test-client-reader$(EXEEXT)
am__installdirs = "$(DESTDIR)$(pkglibexecdir)"
PROGRAMS = $(noinst_PROGRAMS) $(pkglibexec_PROGRAMS)
LTLIBRARIES = $(noinst_LTLIBRARIES)
libstats_local_la_LIBADD =
am__objects_1 = stats-service-openmetrics.lo
am_libstats_local_la_OBJECTS = client-reader.lo client-writer.lo \
client-http.lo event-exporter-fmt.lo \
event-exporter-fmt-json.lo event-exporter-fmt-none.lo \
event-exporter-fmt-tab-text.lo \
event-exporter-transport-drop.lo \
event-exporter-transport-http-post.lo \
event-exporter-transport-log.lo $(am__objects_1) \
stats-service.lo stats-event-category.lo stats-metrics.lo \
stats-settings.lo
libstats_local_la_OBJECTS = $(am_libstats_local_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am_stats_OBJECTS = main.$(OBJEXT)
stats_OBJECTS = $(am_stats_OBJECTS)
am__DEPENDENCIES_1 =
am_test_client_reader_OBJECTS = test-client-reader.$(OBJEXT) \
test-stats-common.$(OBJEXT)
test_client_reader_OBJECTS = $(am_test_client_reader_OBJECTS)
am__DEPENDENCIES_2 = $(noinst_LTLIBRARIES) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
am_test_client_writer_OBJECTS = test-client-writer.$(OBJEXT) \
test-stats-common.$(OBJEXT)
test_client_writer_OBJECTS = $(am_test_client_writer_OBJECTS)
am_test_stats_metrics_OBJECTS = test-stats-metrics.$(OBJEXT) \
test-stats-common.$(OBJEXT)
test_stats_metrics_OBJECTS = $(am_test_stats_metrics_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/client-http.Plo \
./$(DEPDIR)/client-reader.Plo ./$(DEPDIR)/client-writer.Plo \
./$(DEPDIR)/event-exporter-fmt-json.Plo \
./$(DEPDIR)/event-exporter-fmt-none.Plo \
./$(DEPDIR)/event-exporter-fmt-tab-text.Plo \
./$(DEPDIR)/event-exporter-fmt.Plo \
./$(DEPDIR)/event-exporter-transport-drop.Plo \
./$(DEPDIR)/event-exporter-transport-http-post.Plo \
./$(DEPDIR)/event-exporter-transport-log.Plo \
./$(DEPDIR)/main.Po ./$(DEPDIR)/stats-event-category.Plo \
./$(DEPDIR)/stats-metrics.Plo \
./$(DEPDIR)/stats-service-openmetrics.Plo \
./$(DEPDIR)/stats-service.Plo ./$(DEPDIR)/stats-settings.Plo \
./$(DEPDIR)/test-client-reader.Po \
./$(DEPDIR)/test-client-writer.Po \
./$(DEPDIR)/test-stats-common.Po \
./$(DEPDIR)/test-stats-metrics.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libstats_local_la_SOURCES) $(stats_SOURCES) \
$(test_client_reader_SOURCES) $(test_client_writer_SOURCES) \
$(test_stats_metrics_SOURCES)
DIST_SOURCES = $(libstats_local_la_SOURCES) $(stats_SOURCES) \
$(test_client_reader_SOURCES) $(test_client_writer_SOURCES) \
$(test_stats_metrics_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(noinst_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
noinst_LTLIBRARIES = libstats_local.la
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-http \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-test \
$(BINARY_CFLAGS)
stats_LDADD = \
$(noinst_LTLIBRARIES) \
$(LIBDOVECOT) \
$(DOVECOT_SSL_LIBS) \
$(BINARY_LDFLAGS) \
-lm
stats_DEPENDENCIES = \
$(noinst_LTLIBRARIES) \
$(DOVECOT_SSL_LIBS) \
$(LIBDOVECOT_DEPS)
stats_services = \
stats-service-openmetrics.c
stats_SOURCES = \
main.c
libstats_local_la_SOURCES = \
client-reader.c \
client-writer.c \
client-http.c \
event-exporter-fmt.c \
event-exporter-fmt-json.c \
event-exporter-fmt-none.c \
event-exporter-fmt-tab-text.c \
event-exporter-transport-drop.c \
event-exporter-transport-http-post.c \
event-exporter-transport-log.c \
$(stats_services) \
stats-service.c \
stats-event-category.c \
stats-metrics.c \
stats-settings.c
noinst_HEADERS = \
stats-common.h \
client-reader.h \
client-writer.h \
client-http.h\
event-exporter.h \
stats-service.h \
stats-service-private.h \
stats-event-category.h \
stats-metrics.h \
stats-settings.h \
test-stats-common.h
test_libs = \
$(noinst_LTLIBRARIES) \
$(DOVECOT_SSL_LIBS) \
$(LIBDOVECOT) \
$(BINARY_LDFLAGS) \
-lm
test_deps = \
$(noinst_LTLIBRARIES) \
$(DOVECOT_SSL_LIBS) \
$(LIBDOVECOT_DEPS)
test_stats_metrics_SOURCES = test-stats-metrics.c test-stats-common.c
test_stats_metrics_LDADD = $(test_libs)
test_stats_metrics_DEPENDENCIES = $(test_deps)
test_client_writer_SOURCES = test-client-writer.c test-stats-common.c
test_client_writer_LDADD = $(test_libs)
test_client_writer_DEPENDENCIES = $(test_deps)
test_client_reader_SOURCES = test-client-reader.c test-stats-common.c
test_client_reader_LDADD = $(test_libs)
test_client_reader_DEPENDENCIES = $(test_deps)
test_programs = test-stats-metrics test-client-writer test-client-reader
LIBDOVECOT_TEST_DEPS = \
../lib-ssl-iostream/libssl_iostream.la \
../lib-test/libtest.la \
../lib/liblib.la
LIBDOVECOT_TEST = \
$(LIBDOVECOT_TEST_DEPS) \
$(MODULE_LIBS)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/stats/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/stats/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libstats_local.la: $(libstats_local_la_OBJECTS) $(libstats_local_la_DEPENDENCIES) $(EXTRA_libstats_local_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(libstats_local_la_OBJECTS) $(libstats_local_la_LIBADD) $(LIBS)
stats$(EXEEXT): $(stats_OBJECTS) $(stats_DEPENDENCIES) $(EXTRA_stats_DEPENDENCIES)
@rm -f stats$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(stats_OBJECTS) $(stats_LDADD) $(LIBS)
test-client-reader$(EXEEXT): $(test_client_reader_OBJECTS) $(test_client_reader_DEPENDENCIES) $(EXTRA_test_client_reader_DEPENDENCIES)
@rm -f test-client-reader$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_client_reader_OBJECTS) $(test_client_reader_LDADD) $(LIBS)
test-client-writer$(EXEEXT): $(test_client_writer_OBJECTS) $(test_client_writer_DEPENDENCIES) $(EXTRA_test_client_writer_DEPENDENCIES)
@rm -f test-client-writer$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_client_writer_OBJECTS) $(test_client_writer_LDADD) $(LIBS)
test-stats-metrics$(EXEEXT): $(test_stats_metrics_OBJECTS) $(test_stats_metrics_DEPENDENCIES) $(EXTRA_test_stats_metrics_DEPENDENCIES)
@rm -f test-stats-metrics$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_stats_metrics_OBJECTS) $(test_stats_metrics_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-http.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-reader.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-writer.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-exporter-fmt-json.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-exporter-fmt-none.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-exporter-fmt-tab-text.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-exporter-fmt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-exporter-transport-drop.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-exporter-transport-http-post.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-exporter-transport-log.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-event-category.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-metrics.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-service-openmetrics.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-service.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-settings.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-client-reader.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-client-writer.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-stats-common.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-stats-metrics.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-local
check: check-am
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
clean-noinstPROGRAMS clean-pkglibexecPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/client-http.Plo
-rm -f ./$(DEPDIR)/client-reader.Plo
-rm -f ./$(DEPDIR)/client-writer.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt-json.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt-none.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt-tab-text.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt.Plo
-rm -f ./$(DEPDIR)/event-exporter-transport-drop.Plo
-rm -f ./$(DEPDIR)/event-exporter-transport-http-post.Plo
-rm -f ./$(DEPDIR)/event-exporter-transport-log.Plo
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/stats-event-category.Plo
-rm -f ./$(DEPDIR)/stats-metrics.Plo
-rm -f ./$(DEPDIR)/stats-service-openmetrics.Plo
-rm -f ./$(DEPDIR)/stats-service.Plo
-rm -f ./$(DEPDIR)/stats-settings.Plo
-rm -f ./$(DEPDIR)/test-client-reader.Po
-rm -f ./$(DEPDIR)/test-client-writer.Po
-rm -f ./$(DEPDIR)/test-stats-common.Po
-rm -f ./$(DEPDIR)/test-stats-metrics.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/client-http.Plo
-rm -f ./$(DEPDIR)/client-reader.Plo
-rm -f ./$(DEPDIR)/client-writer.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt-json.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt-none.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt-tab-text.Plo
-rm -f ./$(DEPDIR)/event-exporter-fmt.Plo
-rm -f ./$(DEPDIR)/event-exporter-transport-drop.Plo
-rm -f ./$(DEPDIR)/event-exporter-transport-http-post.Plo
-rm -f ./$(DEPDIR)/event-exporter-transport-log.Plo
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/stats-event-category.Plo
-rm -f ./$(DEPDIR)/stats-metrics.Plo
-rm -f ./$(DEPDIR)/stats-service-openmetrics.Plo
-rm -f ./$(DEPDIR)/stats-service.Plo
-rm -f ./$(DEPDIR)/stats-settings.Plo
-rm -f ./$(DEPDIR)/test-client-reader.Po
-rm -f ./$(DEPDIR)/test-client-writer.Po
-rm -f ./$(DEPDIR)/test-stats-common.Po
-rm -f ./$(DEPDIR)/test-stats-metrics.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkglibexecPROGRAMS
.MAKE: check-am install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \
check-local clean clean-generic clean-libtool \
clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
clean-pkglibexecPROGRAMS cscopelist-am ctags ctags-am \
distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-pkglibexecPROGRAMS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
check-local:
for bin in $(test_programs); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/stats/event-exporter-fmt-json.c 0000644 0000000 0000000 00000013771 14656633576 017141 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "lib-event-private.h"
#include "event-exporter.h"
#include "str.h"
#include "json-parser.h"
#include "hostpid.h"
static void append_str(string_t *dest, const char *str)
{
str_append_c(dest, '"');
json_append_escaped(dest, str);
str_append_c(dest, '"');
}
static void append_str_max_len(string_t *dest, const char *str,
const struct metric_export_info *info)
{
str_append_c(dest, '"');
if (info->exporter->format_max_field_len == 0)
json_append_escaped(dest, str);
else {
size_t len = strlen(str);
json_append_escaped_data(dest, (const unsigned char *)str,
I_MIN(len, info->exporter->format_max_field_len));
if (len > info->exporter->format_max_field_len)
str_append(dest, "...");
}
str_append_c(dest, '"');
}
static void
append_strlist(string_t *dest, const ARRAY_TYPE(const_string) *strlist,
const struct metric_export_info *info)
{
const char *value;
bool first = TRUE;
str_append_c(dest, '[');
array_foreach_elem(strlist, value) {
if (first)
first = FALSE;
else
str_append_c(dest, ',');
append_str_max_len(dest, value, info);
}
str_append_c(dest, ']');
}
static void append_int(string_t *dest, intmax_t val)
{
str_printfa(dest, "%jd", val);
}
static void append_time(string_t *dest, const struct timeval *time,
enum event_exporter_time_fmt fmt)
{
switch (fmt) {
case EVENT_EXPORTER_TIME_FMT_NATIVE:
i_panic("JSON does not have a native date/time type");
case EVENT_EXPORTER_TIME_FMT_UNIX:
event_export_helper_fmt_unix_time(dest, time);
break;
case EVENT_EXPORTER_TIME_FMT_RFC3339:
str_append_c(dest, '"');
event_export_helper_fmt_rfc3339_time(dest, time);
str_append_c(dest, '"');
break;
}
}
static void append_field_value(string_t *dest, const struct event_field *field,
const struct metric_export_info *info)
{
switch (field->value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
append_str_max_len(dest, field->value.str, info);
break;
case EVENT_FIELD_VALUE_TYPE_INTMAX:
append_int(dest, field->value.intmax);
break;
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
append_time(dest, &field->value.timeval,
info->exporter->time_format);
break;
case EVENT_FIELD_VALUE_TYPE_STRLIST:
append_strlist(dest, &field->value.strlist, info);
break;
}
}
static void json_export_name(string_t *dest, struct event *event,
const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_NAME) == 0)
return;
append_str(dest, "event");
str_append_c(dest, ':');
append_str(dest, event->sending_name);
str_append_c(dest, ',');
}
static void json_export_hostname(string_t *dest,
const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_HOSTNAME) == 0)
return;
append_str(dest, "hostname");
str_append_c(dest, ':');
append_str(dest, my_hostname);
str_append_c(dest, ',');
}
static void json_export_timestamps(string_t *dest, struct event *event,
const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_TIMESTAMPS) == 0)
return;
append_str(dest, "start_time");
str_append_c(dest, ':');
append_time(dest, &event->tv_created, info->exporter->time_format);
str_append_c(dest, ',');
append_str(dest, "end_time");
str_append_c(dest, ':');
append_time(dest, &ioloop_timeval, info->exporter->time_format);
str_append_c(dest, ',');
}
static void json_export_categories(string_t *dest, struct event *event,
const struct metric_export_info *info)
{
struct event_category *const *cats;
unsigned int count;
if ((info->include & EVENT_EXPORTER_INCL_CATEGORIES) == 0)
return;
append_str(dest, "categories");
str_append(dest, ":[");
cats = event_get_categories(event, &count);
event_export_helper_fmt_categories(dest, cats, count,
append_str, ",");
str_append(dest, "],");
}
static void json_export_fields(string_t *dest, struct event *event,
const struct metric_export_info *info,
const unsigned int fields_count,
const struct metric_field *fields)
{
bool appended = FALSE;
if ((info->include & EVENT_EXPORTER_INCL_FIELDS) == 0)
return;
append_str(dest, "fields");
str_append(dest, ":{");
if (fields_count == 0) {
/* include all fields */
const struct event_field *fields;
unsigned int count;
fields = event_get_fields(event, &count);
for (unsigned int i = 0; i < count; i++) {
const struct event_field *field = &fields[i];
append_str(dest, field->key);
str_append_c(dest, ':');
append_field_value(dest, field, info);
str_append_c(dest, ',');
appended = TRUE;
}
} else {
for (unsigned int i = 0; i < fields_count; i++) {
const char *name = fields[i].field_key;
const struct event_field *field;
field = event_find_field_recursive(event, name);
if (field == NULL)
continue; /* doesn't exist, skip it */
append_str(dest, name);
str_append_c(dest, ':');
append_field_value(dest, field, info);
str_append_c(dest, ',');
appended = TRUE;
}
}
/* remove trailing comma */
if (appended)
str_truncate(dest, str_len(dest) - 1);
str_append(dest, "},");
}
/*
* Serialize the event as:
*
* {
* "name": ,
* "hostname": ,
* "start_time": ,
* "end_time": ,
* "categories": [ , ... ],
* "fields": {
* : ,
* ...
* }
* }
*
*/
void event_export_fmt_json(const struct metric *metric,
struct event *event, buffer_t *dest)
{
const struct metric_export_info *info = &metric->export_info;
if (info->include == EVENT_EXPORTER_INCL_NONE) {
str_append(dest, "{}");
return;
}
str_append_c(dest, '{');
json_export_name(dest, event, info);
json_export_hostname(dest, info);
json_export_timestamps(dest, event, info);
json_export_categories(dest, event, info);
json_export_fields(dest, event, info, metric->fields_count,
metric->fields);
/* remove trailing comma */
str_truncate(dest, str_len(dest) - 1);
str_append_c(dest, '}');
}
dovecot-2.3.21.1/src/stats/stats-metrics.c 0000644 0000000 0000000 00000052255 14656633576 015221 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "array.h"
#include "str.h"
#include "str-sanitize.h"
#include "stats-dist.h"
#include "time-util.h"
#include "event-filter.h"
#include "event-exporter.h"
#include "stats-settings.h"
#include "stats-metrics.h"
#include "settings-parser.h"
#include
#define LOG_EXPORTER_LONG_FIELD_TRUNCATE_LEN 1000
struct stats_metrics {
pool_t pool;
struct event_filter *filter; /* stats & export */
ARRAY(struct exporter *) exporters;
ARRAY(struct metric *) metrics;
};
static void
stats_metric_event(struct metric *metric, struct event *event, pool_t pool);
static struct metric *
stats_metric_sub_metric_alloc(struct metric *metric, const char *name, pool_t pool);
static void stats_metric_free(struct metric *metric);
static void stats_exporters_add_set(struct stats_metrics *metrics,
const struct stats_exporter_settings *set)
{
struct exporter *exporter;
exporter = p_new(metrics->pool, struct exporter, 1);
exporter->name = p_strdup(metrics->pool, set->name);
exporter->transport_args = p_strdup(metrics->pool, set->transport_args);
exporter->transport_timeout = set->transport_timeout;
exporter->time_format = set->parsed_time_format;
/* TODO: The following should be plugable.
*
* Note: Make sure to mirror any changes to the below code in
* stats_exporter_settings_check().
*/
if (strcmp(set->format, "none") == 0) {
exporter->format = event_export_fmt_none;
exporter->format_mime_type = "application/octet-stream";
} else if (strcmp(set->format, "json") == 0) {
exporter->format = event_export_fmt_json;
exporter->format_mime_type = "application/json";
} else if (strcmp(set->format, "tab-text") == 0) {
exporter->format = event_export_fmt_tabescaped_text;
exporter->format_mime_type = "text/plain";
} else {
i_unreached();
}
/* TODO: The following should be plugable.
*
* Note: Make sure to mirror any changes to the below code in
* stats_exporter_settings_check().
*/
if (strcmp(set->transport, "drop") == 0) {
exporter->transport = event_export_transport_drop;
} else if (strcmp(set->transport, "http-post") == 0) {
exporter->transport = event_export_transport_http_post;
} else if (strcmp(set->transport, "log") == 0) {
exporter->transport = event_export_transport_log;
exporter->format_max_field_len =
LOG_EXPORTER_LONG_FIELD_TRUNCATE_LEN;
} else {
i_unreached();
}
exporter->transport_args = set->transport_args;
array_push_back(&metrics->exporters, &exporter);
}
static struct metric *
stats_metric_alloc(pool_t pool, const char *name,
const struct stats_metric_settings *set,
const char *const *fields)
{
struct metric *metric = p_new(pool, struct metric, 1);
metric->name = p_strdup(pool, name);
metric->set = set;
metric->duration_stats = stats_dist_init();
metric->fields_count = str_array_length(fields);
if (metric->fields_count > 0) {
metric->fields = p_new(pool, struct metric_field,
metric->fields_count);
for (unsigned int i = 0; i < metric->fields_count; i++) {
metric->fields[i].field_key = p_strdup(pool, fields[i]);
metric->fields[i].stats = stats_dist_init();
}
}
return metric;
}
static void stats_metrics_add_set(struct stats_metrics *metrics,
const struct stats_metric_settings *set)
{
struct exporter *exporter;
struct metric *metric;
const char *const *fields;
const char *const *tmp;
fields = t_strsplit_spaces(set->fields, " ");
metric = stats_metric_alloc(metrics->pool, set->metric_name, set, fields);
if (array_is_created(&set->parsed_group_by))
metric->group_by = array_get(&set->parsed_group_by,
&metric->group_by_count);
array_push_back(&metrics->metrics, &metric);
event_filter_merge_with_context(metrics->filter, set->parsed_filter, metric);
/*
* Metrics may also be exported - make sure exporter info is set
*/
if (set->exporter[0] == '\0')
return; /* not exported */
array_foreach_elem(&metrics->exporters, exporter) {
if (strcmp(set->exporter, exporter->name) == 0) {
metric->export_info.exporter = exporter;
break;
}
}
if (metric->export_info.exporter == NULL)
i_panic("Could not find exporter (%s) for metric (%s)",
set->exporter, set->metric_name);
/* Defaults */
metric->export_info.include = EVENT_EXPORTER_INCL_NONE;
tmp = t_strsplit_spaces(set->exporter_include, " ");
for (; *tmp != NULL; tmp++) {
if (strcmp(*tmp, "name") == 0)
metric->export_info.include |= EVENT_EXPORTER_INCL_NAME;
else if (strcmp(*tmp, "hostname") == 0)
metric->export_info.include |= EVENT_EXPORTER_INCL_HOSTNAME;
else if (strcmp(*tmp, "timestamps") == 0)
metric->export_info.include |= EVENT_EXPORTER_INCL_TIMESTAMPS;
else if (strcmp(*tmp, "categories") == 0)
metric->export_info.include |= EVENT_EXPORTER_INCL_CATEGORIES;
else if (strcmp(*tmp, "fields") == 0)
metric->export_info.include |= EVENT_EXPORTER_INCL_FIELDS;
else
i_warning("Ignoring unknown exporter include '%s'", *tmp);
}
}
static struct stats_metric_settings *
stats_metric_settings_dup(pool_t pool, const struct stats_metric_settings *src)
{
struct stats_metric_settings *set = p_new(pool, struct stats_metric_settings, 1);
set->metric_name = p_strdup(pool, src->metric_name);
set->description = p_strdup(pool, src->description);
set->fields = p_strdup(pool, src->fields);
set->group_by = p_strdup(pool, src->group_by);
set->filter = p_strdup(pool, src->filter);
set->exporter = p_strdup(pool, src->exporter);
set->exporter_include = p_strdup(pool, src->exporter_include);
return set;
}
static struct metric *
stats_metrics_find(struct stats_metrics *metrics,
const char *name, unsigned int *idx_r)
{
struct metric *const *m;
array_foreach(&metrics->metrics, m) {
if (strcmp((*m)->name, name) == 0) {
*idx_r = array_foreach_idx(&metrics->metrics, m);
return *m;
}
}
return NULL;
}
static bool
stats_metrics_check_for_exporter(struct stats_metrics *metrics, const char *name)
{
struct exporter *exporter;
/* Allow registering metrics with empty/missing exporters. */
if (name[0] == '\0')
return TRUE;
if (!array_is_created(&metrics->exporters))
return FALSE;
bool is_found = FALSE;
array_foreach_elem(&metrics->exporters, exporter) {
if (strcmp(exporter->name, name) == 0) {
is_found = TRUE;
break;
}
}
return is_found;
}
bool stats_metrics_add_dynamic(struct stats_metrics *metrics,
struct stats_metric_settings *set,
const char **error_r)
{
unsigned int existing_idx ATTR_UNUSED;
if (stats_metrics_find(metrics, set->metric_name, &existing_idx) != NULL) {
*error_r = "Metric already exists";
return FALSE;
}
struct stats_metric_settings *_set =
stats_metric_settings_dup(metrics->pool, set);
if (!stats_metric_setting_parser_info.check_func(_set, metrics->pool, error_r))
return FALSE;
if (!stats_metrics_check_for_exporter(metrics, set->exporter)) {
*error_r = t_strdup_printf("Exporter '%s' does not exist.",
set->exporter);
return FALSE;
}
stats_metrics_add_set(metrics, _set);
return TRUE;
}
bool stats_metrics_remove_dynamic(struct stats_metrics *metrics,
const char *name)
{
unsigned int m_idx;
bool ret = FALSE;
struct metric *m = stats_metrics_find(metrics, name, &m_idx);
if (m != NULL) {
array_delete(&metrics->metrics, m_idx, 1);
ret = event_filter_remove_queries_with_context(metrics->filter, m);
stats_metric_free(m);
}
return ret;
}
static void
stats_metrics_add_from_settings(struct stats_metrics *metrics,
const struct stats_settings *set)
{
/* add all the exporters first */
if (!array_is_created(&set->exporters)) {
p_array_init(&metrics->exporters, metrics->pool, 0);
} else {
struct stats_exporter_settings *exporter_set;
p_array_init(&metrics->exporters, metrics->pool,
array_count(&set->exporters));
array_foreach_elem(&set->exporters, exporter_set)
stats_exporters_add_set(metrics, exporter_set);
}
/* then add all the metrics */
if (!array_is_created(&set->metrics)) {
p_array_init(&metrics->metrics, metrics->pool, 0);
} else {
struct stats_metric_settings *metric_set;
p_array_init(&metrics->metrics, metrics->pool,
array_count(&set->metrics));
array_foreach_elem(&set->metrics, metric_set) T_BEGIN {
stats_metrics_add_set(metrics, metric_set);
} T_END;
}
}
struct stats_metrics *stats_metrics_init(const struct stats_settings *set)
{
struct stats_metrics *metrics;
pool_t pool = pool_alloconly_create("stats metrics", 1024);
metrics = p_new(pool, struct stats_metrics, 1);
metrics->pool = pool;
metrics->filter = event_filter_create();
stats_metrics_add_from_settings(metrics, set);
return metrics;
}
static void stats_metric_free(struct metric *metric)
{
struct metric *sub_metric;
stats_dist_deinit(&metric->duration_stats);
for (unsigned int i = 0; i < metric->fields_count; i++)
stats_dist_deinit(&metric->fields[i].stats);
if (!array_is_created(&metric->sub_metrics))
return;
array_foreach_elem(&metric->sub_metrics, sub_metric)
stats_metric_free(sub_metric);
}
static void stats_export_deinit(void)
{
/* no need for event_export_transport_drop_deinit() - no-op */
event_export_transport_http_post_deinit();
/* no need for event_export_transport_log_deinit() - no-op */
}
void stats_metrics_deinit(struct stats_metrics **_metrics)
{
struct stats_metrics *metrics = *_metrics;
struct metric *metric;
*_metrics = NULL;
stats_export_deinit();
array_foreach_elem(&metrics->metrics, metric)
stats_metric_free(metric);
event_filter_unref(&metrics->filter);
pool_unref(&metrics->pool);
}
static void stats_metric_reset(struct metric *metric)
{
struct metric *sub_metric;
stats_dist_reset(metric->duration_stats);
for (unsigned int i = 0; i < metric->fields_count; i++)
stats_dist_reset(metric->fields[i].stats);
if (!array_is_created(&metric->sub_metrics))
return;
array_foreach_elem(&metric->sub_metrics, sub_metric)
stats_metric_reset(sub_metric);
}
void stats_metrics_reset(struct stats_metrics *metrics)
{
struct metric *metric;
array_foreach_elem(&metrics->metrics, metric)
stats_metric_reset(metric);
}
struct event_filter *
stats_metrics_get_event_filter(struct stats_metrics *metrics)
{
return metrics->filter;
}
static struct metric *
stats_metric_find_sub_metric(struct metric *metric,
const struct metric_value *value)
{
struct metric *sub_metrics;
/* lookup sub-metric */
array_foreach_elem(&metric->sub_metrics, sub_metrics) {
switch (sub_metrics->group_value.type) {
case METRIC_VALUE_TYPE_STR:
if (memcmp(sub_metrics->group_value.hash, value->hash,
SHA1_RESULTLEN) == 0)
return sub_metrics;
break;
case METRIC_VALUE_TYPE_INT:
if (sub_metrics->group_value.intmax == value->intmax)
return sub_metrics;
break;
case METRIC_VALUE_TYPE_BUCKET_INDEX:
if (sub_metrics->group_value.intmax == value->intmax)
return sub_metrics;
break;
}
}
return NULL;
}
static struct metric *
stats_metric_sub_metric_alloc(struct metric *metric, const char *name, pool_t pool)
{
struct metric *sub_metric;
ARRAY_TYPE(const_string) fields;
t_array_init(&fields, metric->fields_count);
for (unsigned int i = 0; i < metric->fields_count; i++)
array_append(&fields, &metric->fields[i].field_key, 1);
array_append_zero(&fields);
sub_metric = stats_metric_alloc(pool, metric->name, metric->set,
array_idx(&fields, 0));
sub_metric->sub_name = p_strdup(pool, str_sanitize_utf8(name, 32));
array_append(&metric->sub_metrics, &sub_metric, 1);
return sub_metric;
}
static bool
stats_metric_group_by_discrete(const struct event_field *field,
struct metric_value *value_r)
{
switch (field->value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
value_r->type = METRIC_VALUE_TYPE_STR;
/* use sha1 of value to avoid excessive memory usage in case the
actual value is quite long */
sha1_get_digest(field->value.str, strlen(field->value.str),
value_r->hash);
return TRUE;
case EVENT_FIELD_VALUE_TYPE_INTMAX:
value_r->type = METRIC_VALUE_TYPE_INT;
value_r->intmax = field->value.intmax;
return TRUE;
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
return FALSE;
case EVENT_FIELD_VALUE_TYPE_STRLIST:
return FALSE;
}
i_unreached();
}
/* convert the value to a bucket index */
static bool
stats_metric_group_by_quantized(const struct event_field *field,
struct metric_value *value_r,
const struct stats_metric_settings_group_by *group_by)
{
switch (field->value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
case EVENT_FIELD_VALUE_TYPE_STRLIST:
return FALSE;
case EVENT_FIELD_VALUE_TYPE_INTMAX:
break;
}
value_r->type = METRIC_VALUE_TYPE_BUCKET_INDEX;
for (unsigned int i = 0; i < group_by->num_ranges; i++) {
if ((field->value.intmax <= group_by->ranges[i].min) ||
(field->value.intmax > group_by->ranges[i].max))
continue;
value_r->intmax = i;
return TRUE;
}
i_panic("failed to find a matching bucket for '%s'=%jd",
group_by->field, field->value.intmax);
}
/* convert value to a bucket label */
static const char *
stats_metric_group_by_quantized_label(const struct event_field *field,
const struct stats_metric_settings_group_by *group_by,
const size_t bucket_index)
{
const struct stats_metric_settings_bucket_range *range = &group_by->ranges[bucket_index];
const char *name = group_by->field;
const char *label;
switch (field->value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
case EVENT_FIELD_VALUE_TYPE_STRLIST:
i_unreached();
case EVENT_FIELD_VALUE_TYPE_INTMAX:
break;
}
if (range->min == INTMAX_MIN)
label = t_strdup_printf("%s_ninf_%jd", name, range->max);
else if (range->max == INTMAX_MAX)
label = t_strdup_printf("%s_%jd_inf", name, range->min + 1);
else
label = t_strdup_printf("%s_%jd_%jd", name,
range->min + 1, range->max);
return label;
}
static bool
stats_metric_group_by_get_value(const struct event_field *field,
const struct stats_metric_settings_group_by *group_by,
struct metric_value *value_r)
{
switch (group_by->func) {
case STATS_METRIC_GROUPBY_DISCRETE:
if (!stats_metric_group_by_discrete(field, value_r))
return FALSE;
return TRUE;
case STATS_METRIC_GROUPBY_QUANTIZED:
if (!stats_metric_group_by_quantized(field, value_r, group_by))
return FALSE;
return TRUE;
}
i_panic("unknown group-by function %d", group_by->func);
}
static const char *
stats_metric_group_by_get_label(const struct event_field *field,
const struct stats_metric_settings_group_by *group_by,
const struct metric_value *value)
{
switch (group_by->func) {
case STATS_METRIC_GROUPBY_DISCRETE:
i_unreached();
case STATS_METRIC_GROUPBY_QUANTIZED:
return stats_metric_group_by_quantized_label(field, group_by,
value->intmax);
}
i_panic("unknown group-by function %d", group_by->func);
}
static const char *
stats_metric_group_by_value_label(const struct event_field *field,
const struct stats_metric_settings_group_by *group_by,
const struct metric_value *value)
{
switch (value->type) {
case METRIC_VALUE_TYPE_STR:
return field->value.str;
case METRIC_VALUE_TYPE_INT:
return dec2str(field->value.intmax);
case METRIC_VALUE_TYPE_BUCKET_INDEX:
return stats_metric_group_by_get_label(field, group_by, value);
}
i_unreached();
}
static struct metric *
stats_metric_get_sub_metric(struct metric *metric,
const struct event_field *field,
const struct metric_value *value,
pool_t pool)
{
struct metric *sub_metric;
sub_metric = stats_metric_find_sub_metric(metric, value);
if (sub_metric != NULL)
return sub_metric;
T_BEGIN {
const char *value_label =
stats_metric_group_by_value_label(field,
&metric->group_by[0], value);
sub_metric = stats_metric_sub_metric_alloc(metric, value_label,
pool);
} T_END;
if (metric->group_by_count > 1) {
sub_metric->group_by_count = metric->group_by_count - 1;
sub_metric->group_by = &metric->group_by[1];
}
sub_metric->group_value.type = value->type;
sub_metric->group_value.intmax = value->intmax;
memcpy(sub_metric->group_value.hash, value->hash, SHA1_RESULTLEN);
return sub_metric;
}
static void
stats_metric_group_by_field(struct metric *metric, struct event *event,
const struct event_field *field, pool_t pool)
{
struct metric *sub_metric;
struct metric_value value;
if (!stats_metric_group_by_get_value(field, &metric->group_by[0], &value))
return;
if (!array_is_created(&metric->sub_metrics))
p_array_init(&metric->sub_metrics, pool, 8);
sub_metric = stats_metric_get_sub_metric(metric, field, &value, pool);
/* sub-metrics are recursive, so each sub-metric can have additional
sub-metrics. */
stats_metric_event(sub_metric, event, pool);
}
static void
stats_event_get_strlist(struct event *event, const char *name,
ARRAY_TYPE(const_string) *strings)
{
if (event == NULL)
return;
const struct event_field *field =
event_find_field_nonrecursive(event, name);
if (field != NULL) {
const char *str;
array_foreach_elem(&field->value.strlist, str)
array_push_back(strings, &str);
}
stats_event_get_strlist(event_get_parent(event), name, strings);
}
static void
stats_metric_group_by(struct metric *metric, struct event *event, pool_t pool)
{
const struct event_field *field =
event_find_field_recursive(event, metric->group_by[0].field);
/* ignore missing field */
if (field == NULL)
return;
if (field->value_type != EVENT_FIELD_VALUE_TYPE_STRLIST)
stats_metric_group_by_field(metric, event, field, pool);
else {
/* Handle each string in strlist separately. The strlist needs
to be combined from the event and its parents, as well as
the global event and its parents. */
ARRAY_TYPE(const_string) strings;
t_array_init(&strings, 8);
stats_event_get_strlist(event, metric->group_by[0].field,
&strings);
stats_event_get_strlist(event_get_global(),
metric->group_by[0].field, &strings);
struct event_field str_field = {
.value_type = EVENT_FIELD_VALUE_TYPE_STR,
};
const char *str;
/* sort strings so duplicates can be easily skipped */
array_sort(&strings, i_strcmp_p);
array_foreach_elem(&strings, str) {
if (str_field.value.str == NULL ||
strcmp(str_field.value.str, str) != 0) {
str_field.value.str = str;
stats_metric_group_by_field(metric, event,
&str_field, pool);
}
}
}
}
static void
stats_metric_event_field(struct event *event, const char *fieldname,
struct stats_dist *stats)
{
const struct event_field *field =
event_find_field_recursive(event, fieldname);
intmax_t num = 0;
if (field == NULL)
return;
switch (field->value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
case EVENT_FIELD_VALUE_TYPE_STRLIST:
break;
case EVENT_FIELD_VALUE_TYPE_INTMAX:
num = field->value.intmax;
break;
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
num = field->value.timeval.tv_sec * 1000000ULL +
field->value.timeval.tv_usec;
break;
}
stats_dist_add(stats, num);
}
static void
stats_metric_event(struct metric *metric, struct event *event, pool_t pool)
{
/* duration is special - we always add it */
stats_metric_event_field(event, STATS_EVENT_FIELD_NAME_DURATION,
metric->duration_stats);
for (unsigned int i = 0; i < metric->fields_count; i++)
stats_metric_event_field(event,
metric->fields[i].field_key,
metric->fields[i].stats);
if (metric->group_by != NULL)
stats_metric_group_by(metric, event, pool);
}
static void
stats_export_event(struct metric *metric, struct event *oldevent)
{
const struct metric_export_info *info = &metric->export_info;
const struct exporter *exporter = info->exporter;
struct event *event;
i_assert(exporter != NULL);
event = event_flatten(oldevent);
T_BEGIN {
buffer_t *buf;
buf = t_buffer_create(128);
exporter->format(metric, event, buf);
exporter->transport(exporter, buf);
} T_END;
event_unref(&event);
}
void stats_metrics_event(struct stats_metrics *metrics, struct event *event,
const struct failure_context *ctx)
{
struct event_filter_match_iter *iter;
struct metric *metric;
uintmax_t duration;
/* Note: Adding the field here means that it will get exported
below. This is necessary to allow group-by functions to quantize
based on the event duration. */
event_get_last_duration(event, &duration);
event_add_int(event, STATS_EVENT_FIELD_NAME_DURATION, duration);
/* process stats & exports */
iter = event_filter_match_iter_init(metrics->filter, event, ctx);
while ((metric = event_filter_match_iter_next(iter)) != NULL) T_BEGIN {
/* every metric is fed into stats */
stats_metric_event(metric, event, metrics->pool);
/* some metrics are exported */
if (metric->export_info.exporter != NULL)
stats_export_event(metric, event);
} T_END;
event_filter_match_iter_deinit(&iter);
}
struct stats_metrics_iter {
struct stats_metrics *metrics;
unsigned int idx;
};
struct stats_metrics_iter *
stats_metrics_iterate_init(struct stats_metrics *metrics)
{
struct stats_metrics_iter *iter;
iter = i_new(struct stats_metrics_iter, 1);
iter->metrics = metrics;
return iter;
}
const struct metric *stats_metrics_iterate(struct stats_metrics_iter *iter)
{
struct metric *const *metrics;
unsigned int count;
metrics = array_get(&iter->metrics->metrics, &count);
if (iter->idx >= count)
return NULL;
return metrics[iter->idx++];
}
void stats_metrics_iterate_deinit(struct stats_metrics_iter **_iter)
{
struct stats_metrics_iter *iter = *_iter;
*_iter = NULL;
i_free(iter);
}
dovecot-2.3.21.1/src/stats/event-exporter-transport-http-post.c 0000644 0000000 0000000 00000004160 14656633576 021370 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "str.h"
#include "event-exporter.h"
#include "http-client.h"
#include "iostream-ssl.h"
#include "master-service.h"
#include "master-service-ssl-settings.h"
/* the http client used to export all events with exporter=http-post */
static struct http_client *exporter_http_client;
void event_export_transport_http_post_deinit(void)
{
if (exporter_http_client != NULL)
http_client_deinit(&exporter_http_client);
}
static void response_fxn(const struct http_response *response,
void *context ATTR_UNUSED)
{
static time_t last_log;
static unsigned suppressed;
if (http_response_is_success(response))
return;
if (last_log == ioloop_time) {
suppressed++;
return; /* don't spam the log */
}
if (suppressed == 0)
i_error("Failed to export event via HTTP POST: %d %s",
response->status, response->reason);
else
i_error("Failed to export event via HTTP POST: %d %s (%u more errors suppressed)",
response->status, response->reason, suppressed);
last_log = ioloop_time;
suppressed = 0;
}
void event_export_transport_http_post(const struct exporter *exporter,
const buffer_t *buf)
{
struct http_client_request *req;
if (exporter_http_client == NULL) {
const struct master_service_ssl_settings *master_ssl_set =
master_service_ssl_settings_get(master_service);
struct ssl_iostream_settings ssl_set;
struct http_client_settings set = {
.dns_client_socket_path = "dns-client",
};
if (master_ssl_set != NULL) {
master_service_ssl_client_settings_to_iostream_set(
master_ssl_set, pool_datastack_create(),
&ssl_set);
set.ssl = &ssl_set;
}
exporter_http_client = http_client_init(&set);
}
req = http_client_request_url_str(exporter_http_client, "POST",
exporter->transport_args,
response_fxn, NULL);
http_client_request_add_header(req, "Content-Type", exporter->format_mime_type);
http_client_request_set_payload_data(req, buf->data, buf->used);
http_client_request_set_timeout_msecs(req, exporter->transport_timeout);
http_client_request_submit(req);
}
dovecot-2.3.21.1/src/stats/event-exporter-transport-log.c 0000644 0000000 0000000 00000000500 14656633576 020201 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "str.h"
#include "event-exporter.h"
void event_export_transport_log(const struct exporter *exporter ATTR_UNUSED,
const buffer_t *buf)
{
i_info("%.*s", (int)buf->used, (const char *)buf->data);
}
dovecot-2.3.21.1/src/stats/client-http.h 0000644 0000000 0000000 00000001512 14656633576 014645 0000000 0000000 #ifndef CLIENT_HTTP_H
#define CLIENT_HTTP_H
struct master_service_connection;
struct http_server_request;
typedef void
(stats_http_resource_callback_t)(void *context,
struct http_server_request *req,
const char *sub_path);
void client_http_create(struct master_service_connection *conn);
void stats_http_resource_add(const char *path, const char *title,
stats_http_resource_callback_t *callback,
void *context);
#define stats_http_resource_add(path, title, callback, context) \
stats_http_resource_add(path, title, \
(stats_http_resource_callback_t *)callback, \
(TRUE ? context : \
CALLBACK_TYPECHECK(callback, void (*)( \
typeof(context), struct http_server_request *req, \
const char *sub_path))))
void client_http_init(const struct stats_settings *set);
void client_http_deinit(void);
#endif
dovecot-2.3.21.1/src/stats/client-writer.h 0000644 0000000 0000000 00000000344 14656633576 015204 0000000 0000000 #ifndef CLIENT_WRITER_H
#define CLIENT_WRITER_H
struct stats_metrics;
void client_writer_create(int fd);
void client_writer_update_connections(void);
void client_writers_init(void);
void client_writers_deinit(void);
#endif
dovecot-2.3.21.1/src/stats/stats-service.h 0000644 0000000 0000000 00000000173 14656633576 015210 0000000 0000000 #ifndef STATS_SERVICE_H
#define STATS_SERVICE_H
void stats_services_init(void);
void stats_services_deinit(void);
#endif
dovecot-2.3.21.1/src/stats/stats-settings.c 0000644 0000000 0000000 00000035127 14656633576 015412 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "stats-settings.h"
#include "array.h"
/* */
#include "event-filter.h"
#include
/* */
static bool stats_metric_settings_check(void *_set, pool_t pool, const char **error_r);
static bool stats_exporter_settings_check(void *_set, pool_t pool, const char **error_r);
static bool stats_settings_check(void *_set, pool_t pool, const char **error_r);
/* */
static struct file_listener_settings stats_unix_listeners_array[] = {
{ "stats-reader", 0600, "", "" },
{ "stats-writer", 0660, "", "$default_internal_group" },
{ "login/stats-writer", 0600, "$default_login_user", "" },
};
static struct file_listener_settings *stats_unix_listeners[] = {
&stats_unix_listeners_array[0],
&stats_unix_listeners_array[1],
&stats_unix_listeners_array[2],
};
static buffer_t stats_unix_listeners_buf = {
{ { stats_unix_listeners, sizeof(stats_unix_listeners) } }
};
/* */
struct service_settings stats_service_settings = {
.name = "stats",
.protocol = "",
.type = "",
.executable = "stats",
.user = "$default_internal_user",
.group = "",
.privileged_group = "",
.extra_groups = "",
.chroot = "",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 1,
.client_limit = 0,
.service_count = 0,
.idle_kill = UINT_MAX,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &stats_unix_listeners_buf,
sizeof(stats_unix_listeners[0]) } },
.inet_listeners = ARRAY_INIT,
};
/*
* event_exporter { } block settings
*/
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct stats_exporter_settings)
static const struct setting_define stats_exporter_setting_defines[] = {
DEF(STR, name),
DEF(STR, transport),
DEF(STR, transport_args),
DEF(TIME_MSECS, transport_timeout),
DEF(STR, format),
DEF(STR, format_args),
SETTING_DEFINE_LIST_END
};
static const struct stats_exporter_settings stats_exporter_default_settings = {
.name = "",
.transport = "",
.transport_args = "",
.transport_timeout = 250, /* ms */
.format = "",
.format_args = "",
};
const struct setting_parser_info stats_exporter_setting_parser_info = {
.defines = stats_exporter_setting_defines,
.defaults = &stats_exporter_default_settings,
.type_offset = offsetof(struct stats_exporter_settings, name),
.struct_size = sizeof(struct stats_exporter_settings),
.parent_offset = SIZE_MAX,
.check_func = stats_exporter_settings_check,
};
/*
* metric { } block settings
*/
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct stats_metric_settings)
static const struct setting_define stats_metric_setting_defines[] = {
DEF(STR, metric_name),
DEF(STR, fields),
DEF(STR, group_by),
DEF(STR, filter),
DEF(STR, exporter),
DEF(STR, exporter_include),
DEF(STR, description),
SETTING_DEFINE_LIST_END
};
static const struct stats_metric_settings stats_metric_default_settings = {
.metric_name = "",
.fields = "",
.filter = "",
.exporter = "",
.group_by = "",
.exporter_include = STATS_METRIC_SETTINGS_DEFAULT_EXPORTER_INCLUDE,
.description = "",
};
const struct setting_parser_info stats_metric_setting_parser_info = {
.defines = stats_metric_setting_defines,
.defaults = &stats_metric_default_settings,
.type_offset = offsetof(struct stats_metric_settings, metric_name),
.struct_size = sizeof(struct stats_metric_settings),
.parent_offset = SIZE_MAX,
.check_func = stats_metric_settings_check,
};
/*
* top-level settings
*/
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct stats_settings)
#undef DEFLIST_UNIQUE
#define DEFLIST_UNIQUE(field, name, defines) \
{ .type = SET_DEFLIST_UNIQUE, .key = name, \
.offset = offsetof(struct stats_settings, field), \
.list_info = defines }
static const struct setting_define stats_setting_defines[] = {
DEF(STR, stats_http_rawlog_dir),
DEFLIST_UNIQUE(metrics, "metric", &stats_metric_setting_parser_info),
DEFLIST_UNIQUE(exporters, "event_exporter", &stats_exporter_setting_parser_info),
SETTING_DEFINE_LIST_END
};
const struct stats_settings stats_default_settings = {
.stats_http_rawlog_dir = "",
.metrics = ARRAY_INIT,
.exporters = ARRAY_INIT,
};
const struct setting_parser_info stats_setting_parser_info = {
.module_name = "stats",
.defines = stats_setting_defines,
.defaults = &stats_default_settings,
.type_offset = SIZE_MAX,
.struct_size = sizeof(struct stats_settings),
.parent_offset = SIZE_MAX,
.check_func = stats_settings_check,
};
/* */
static bool parse_format_args_set_time(struct stats_exporter_settings *set,
enum event_exporter_time_fmt fmt,
const char **error_r)
{
if ((set->parsed_time_format != EVENT_EXPORTER_TIME_FMT_NATIVE) &&
(set->parsed_time_format != fmt)) {
*error_r = t_strdup_printf("Exporter '%s' specifies multiple "
"time format args", set->name);
return FALSE;
}
set->parsed_time_format = fmt;
return TRUE;
}
static bool parse_format_args(struct stats_exporter_settings *set,
const char **error_r)
{
const char *const *tmp;
/* Defaults */
set->parsed_time_format = EVENT_EXPORTER_TIME_FMT_NATIVE;
tmp = t_strsplit_spaces(set->format_args, " ");
/*
* If the config contains multiple types of the same type (e.g.,
* both time-rfc3339 and time-unix) we fail the config check.
*
* Note: At the moment, we have only time-* tokens. In the future
* when we have other tokens, they should be parsed here.
*/
for (; *tmp != NULL; tmp++) {
enum event_exporter_time_fmt fmt;
if (strcmp(*tmp, "time-rfc3339") == 0) {
fmt = EVENT_EXPORTER_TIME_FMT_RFC3339;
} else if (strcmp(*tmp, "time-unix") == 0) {
fmt = EVENT_EXPORTER_TIME_FMT_UNIX;
} else {
*error_r = t_strdup_printf("Unknown exporter format "
"arg: %s", *tmp);
return FALSE;
}
if (!parse_format_args_set_time(set, fmt, error_r))
return FALSE;
}
return TRUE;
}
static bool stats_exporter_settings_check(void *_set, pool_t pool ATTR_UNUSED,
const char **error_r)
{
struct stats_exporter_settings *set = _set;
bool time_fmt_required;
if (set->name[0] == '\0') {
*error_r = "Exporter name can't be empty";
return FALSE;
}
/* TODO: The following should be plugable.
*
* Note: Make sure to mirror any changes to the below code in
* stats_exporters_add_set().
*/
if (set->format[0] == '\0') {
*error_r = "Exporter format name can't be empty";
return FALSE;
} else if (strcmp(set->format, "none") == 0) {
time_fmt_required = FALSE;
} else if (strcmp(set->format, "json") == 0) {
time_fmt_required = TRUE;
} else if (strcmp(set->format, "tab-text") == 0) {
time_fmt_required = TRUE;
} else {
*error_r = t_strdup_printf("Unknown exporter format '%s'",
set->format);
return FALSE;
}
/* TODO: The following should be plugable.
*
* Note: Make sure to mirror any changes to the below code in
* stats_exporters_add_set().
*/
if (set->transport[0] == '\0') {
*error_r = "Exporter transport name can't be empty";
return FALSE;
} else if (strcmp(set->transport, "drop") == 0 ||
strcmp(set->transport, "http-post") == 0 ||
strcmp(set->transport, "log") == 0) {
/* no-op */
} else {
*error_r = t_strdup_printf("Unknown transport type '%s'",
set->transport);
return FALSE;
}
if (!parse_format_args(set, error_r))
return FALSE;
/* Some formats don't have a native way of serializing time stamps */
if (time_fmt_required &&
set->parsed_time_format == EVENT_EXPORTER_TIME_FMT_NATIVE) {
*error_r = t_strdup_printf("%s exporter format requires a "
"time-* argument", set->format);
return FALSE;
}
return TRUE;
}
static bool parse_metric_group_by_common(const char *func,
const char *const *params,
intmax_t *min_r,
intmax_t *max_r,
intmax_t *other_r,
const char **error_r)
{
intmax_t min, max, other;
if ((str_array_length(params) != 3) ||
(str_to_intmax(params[0], &min) < 0) ||
(str_to_intmax(params[1], &max) < 0) ||
(str_to_intmax(params[2], &other) < 0)) {
*error_r = t_strdup_printf("group_by '%s' aggregate function takes "
"3 int args", func);
return FALSE;
}
if ((min < 0) || (max < 0) || (other < 0)) {
*error_r = t_strdup_printf("group_by '%s' aggregate function "
"arguments must be >= 0", func);
return FALSE;
}
if (min >= max) {
*error_r = t_strdup_printf("group_by '%s' aggregate function "
"min must be < max (%ju must be < %ju)",
func, min, max);
return FALSE;
}
*min_r = min;
*max_r = max;
*other_r = other;
return TRUE;
}
static bool parse_metric_group_by_exp(pool_t pool, struct stats_metric_settings_group_by *group_by,
const char *const *params, const char **error_r)
{
intmax_t min, max, base;
if (!parse_metric_group_by_common("exponential", params, &min, &max, &base, error_r))
return FALSE;
if ((base != 2) && (base != 10)) {
*error_r = t_strdup_printf("group_by 'exponential' aggregate function "
"base must be one of: 2, 10 (base=%ju)",
base);
return FALSE;
}
group_by->func = STATS_METRIC_GROUPBY_QUANTIZED;
/*
* Allocate the bucket range array and fill it in
*
* The first bucket is special - it contains everything less than or
* equal to 'base^min'. The last bucket is also special - it
* contains everything greater than 'base^max'.
*
* The second bucket begins at 'base^min + 1', the third bucket
* begins at 'base^(min + 1) + 1', and so on.
*/
group_by->num_ranges = max - min + 2;
group_by->ranges = p_new(pool, struct stats_metric_settings_bucket_range,
group_by->num_ranges);
/* set up min & max buckets */
group_by->ranges[0].min = INTMAX_MIN;
group_by->ranges[0].max = pow(base, min);
group_by->ranges[group_by->num_ranges - 1].min = pow(base, max);
group_by->ranges[group_by->num_ranges - 1].max = INTMAX_MAX;
/* remaining buckets */
for (unsigned int i = 1; i < group_by->num_ranges - 1; i++) {
group_by->ranges[i].min = pow(base, min + (i - 1));
group_by->ranges[i].max = pow(base, min + i);
}
return TRUE;
}
static bool parse_metric_group_by_lin(pool_t pool, struct stats_metric_settings_group_by *group_by,
const char *const *params, const char **error_r)
{
intmax_t min, max, step;
if (!parse_metric_group_by_common("linear", params, &min, &max, &step, error_r))
return FALSE;
if ((min + step) > max) {
*error_r = t_strdup_printf("group_by 'linear' aggregate function "
"min+step must be <= max (%ju must be <= %ju)",
min + step, max);
return FALSE;
}
group_by->func = STATS_METRIC_GROUPBY_QUANTIZED;
/*
* Allocate the bucket range array and fill it in
*
* The first bucket is special - it contains everything less than or
* equal to 'min'. The last bucket is also special - it contains
* everything greater than 'max'.
*
* The second bucket begins at 'min + 1', the third bucket begins at
* 'min + 1 * step + 1', the fourth at 'min + 2 * step + 1', and so on.
*/
group_by->num_ranges = (max - min) / step + 2;
group_by->ranges = p_new(pool, struct stats_metric_settings_bucket_range,
group_by->num_ranges);
/* set up min & max buckets */
group_by->ranges[0].min = INTMAX_MIN;
group_by->ranges[0].max = min;
group_by->ranges[group_by->num_ranges - 1].min = max;
group_by->ranges[group_by->num_ranges - 1].max = INTMAX_MAX;
/* remaining buckets */
for (unsigned int i = 1; i < group_by->num_ranges - 1; i++) {
group_by->ranges[i].min = min + (i - 1) * step;
group_by->ranges[i].max = min + i * step;
}
return TRUE;
}
static bool parse_metric_group_by(struct stats_metric_settings *set,
pool_t pool, const char **error_r)
{
const char *const *tmp = t_strsplit_spaces(set->group_by, " ");
if (tmp[0] == NULL)
return TRUE;
p_array_init(&set->parsed_group_by, pool, str_array_length(tmp));
/* For each group_by field */
for (; *tmp != NULL; tmp++) {
struct stats_metric_settings_group_by group_by;
const char *const *params;
i_zero(&group_by);
/* :... */
params = t_strsplit(*tmp, ":");
if (params[1] == NULL) {
/* - alias for :discrete */
group_by.func = STATS_METRIC_GROUPBY_DISCRETE;
} else if (strcmp(params[1], "discrete") == 0) {
/* :discrete */
group_by.func = STATS_METRIC_GROUPBY_DISCRETE;
if (params[2] != NULL) {
*error_r = "group_by 'discrete' aggregate function "
"does not take any args";
return FALSE;
}
} else if (strcmp(params[1], "exponential") == 0) {
/* :exponential::: */
if (!parse_metric_group_by_exp(pool, &group_by, ¶ms[2], error_r))
return FALSE;
} else if (strcmp(params[1], "linear") == 0) {
/* :linear::: */
if (!parse_metric_group_by_lin(pool, &group_by, ¶ms[2], error_r))
return FALSE;
} else {
*error_r = t_strdup_printf("unknown aggregation function "
"'%s' on field '%s'", params[1], params[0]);
return FALSE;
}
group_by.field = p_strdup(pool, params[0]);
array_push_back(&set->parsed_group_by, &group_by);
}
return TRUE;
}
static bool stats_metric_settings_check(void *_set, pool_t pool, const char **error_r)
{
struct stats_metric_settings *set = _set;
if (set->metric_name[0] == '\0') {
*error_r = "Metric name can't be empty";
return FALSE;
}
if (set->filter[0] == '\0') {
*error_r = t_strdup_printf("metric %s { filter } is empty - "
"will not match anything", set->metric_name);
return FALSE;
}
set->parsed_filter = event_filter_create_fragment(pool);
if (event_filter_parse(set->filter, set->parsed_filter, error_r) < 0)
return FALSE;
if (!parse_metric_group_by(set, pool, error_r))
return FALSE;
return TRUE;
}
static bool stats_settings_check(void *_set, pool_t pool ATTR_UNUSED,
const char **error_r)
{
struct stats_settings *set = _set;
struct stats_exporter_settings *exporter;
struct stats_metric_settings *metric;
if (!array_is_created(&set->metrics) || !array_is_created(&set->exporters))
return TRUE;
/* check that all metrics refer to exporters that exist */
array_foreach_elem(&set->metrics, metric) {
bool found = FALSE;
if (metric->exporter[0] == '\0')
continue; /* metric not exported */
array_foreach_elem(&set->exporters, exporter) {
if (strcmp(metric->exporter, exporter->name) == 0) {
found = TRUE;
break;
}
}
if (!found) {
*error_r = t_strdup_printf("metric %s refers to "
"non-existent exporter '%s'",
metric->metric_name,
metric->exporter);
return FALSE;
}
}
return TRUE;
}
/* */
dovecot-2.3.21.1/src/stats/stats-service.c 0000644 0000000 0000000 00000000440 14656633576 015200 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "http-server.h"
#include "stats-service-private.h"
void stats_services_init(void)
{
stats_service_openmetrics_init();
}
void stats_services_deinit(void)
{
/* Nothing yet */
}
dovecot-2.3.21.1/src/stats/stats-common.h 0000644 0000000 0000000 00000000263 14656633576 015040 0000000 0000000 #ifndef STATS_COMMON_H
#define STATS_COMMON_H
#include "lib.h"
#include "stats-settings.h"
extern struct stats_metrics *stats_metrics;
extern time_t stats_startup_time;
#endif
dovecot-2.3.21.1/src/stats/event-exporter.h 0000644 0000000 0000000 00000002731 14656633576 015405 0000000 0000000 #ifndef EVENT_EXPORTER_H
#define EVENT_EXPORTER_H
#include "stats-metrics.h"
/* fmt functions */
void event_export_fmt_json(const struct metric *metric, struct event *event, buffer_t *dest);
void event_export_fmt_none(const struct metric *metric, struct event *event, buffer_t *dest);
void event_export_fmt_tabescaped_text(const struct metric *metric, struct event *event, buffer_t *dest);
/* transport functions */
void event_export_transport_drop(const struct exporter *exporter, const buffer_t *buf);
void event_export_transport_http_post(const struct exporter *exporter, const buffer_t *buf);
void event_export_transport_http_post_deinit(void);
void event_export_transport_log(const struct exporter *exporter, const buffer_t *buf);
/* append a microsecond resolution RFC3339 UTC timestamp */
void event_export_helper_fmt_rfc3339_time(string_t *dest, const struct timeval *time);
/* append a microsecond resolution unix timestamp in seconds (i.e., %u.%06u) */
void event_export_helper_fmt_unix_time(string_t *dest, const struct timeval *time);
/* append category names using 'append' function pointer, separated by 'separator' arg
The result has no duplicates regardless of if the array has any or if any
of the categories' ancestors are implictly or explicitly duplicated. */
void event_export_helper_fmt_categories(string_t *dest,
struct event_category *const *cats,
unsigned int count,
void (*append)(string_t *, const char *),
const char *separator);
#endif
dovecot-2.3.21.1/src/stats/client-writer.c 0000644 0000000 0000000 00000023403 14656633576 015200 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "array.h"
#include "llist.h"
#include "hash.h"
#include "str.h"
#include "strescape.h"
#include "lib-event-private.h"
#include "event-filter.h"
#include "ostream.h"
#include "connection.h"
#include "master-service.h"
#include "stats-event-category.h"
#include "stats-metrics.h"
#include "stats-settings.h"
#include "client-writer.h"
#define STATS_UPDATE_CLIENTS_DELAY_MSECS 1000
struct stats_event {
struct stats_event *prev, *next;
uint64_t id;
struct event *event;
};
struct writer_client {
struct connection conn;
struct stats_event *events;
HASH_TABLE(struct stats_event *, struct stats_event *) events_hash;
};
static struct timeout *to_update_clients;
static struct connection_list *writer_clients = NULL;
static void client_writer_send_handshake(struct writer_client *client)
{
string_t *filter = t_str_new(128);
string_t *str = t_str_new(128);
event_filter_export(stats_metrics_get_event_filter(stats_metrics), filter);
str_append(str, "FILTER\t");
str_append_tabescaped(str, str_c(filter));
str_append_c(str, '\n');
o_stream_nsend(client->conn.output, str_data(str), str_len(str));
}
static unsigned int stats_event_hash(const struct stats_event *event)
{
return (unsigned int)event->id;
}
static int stats_event_cmp(const struct stats_event *event1,
const struct stats_event *event2)
{
return event1->id == event2->id ? 0 : 1;
}
void client_writer_create(int fd)
{
struct writer_client *client;
client = i_new(struct writer_client, 1);
hash_table_create(&client->events_hash, default_pool, 0,
stats_event_hash, stats_event_cmp);
connection_init_server(writer_clients, &client->conn,
"stats", fd, fd);
client_writer_send_handshake(client);
}
static void writer_client_destroy(struct connection *conn)
{
struct writer_client *client = (struct writer_client *)conn;
struct stats_event *event, *next;
for (event = client->events; event != NULL; event = next) {
next = event->next;
event_unref(&event->event);
i_free(event);
}
hash_table_destroy(&client->events_hash);
connection_deinit(conn);
i_free(conn);
master_service_client_connection_destroyed(master_service);
}
static struct stats_event *
writer_client_find_event(struct writer_client *client, uint64_t event_id)
{
struct stats_event lookup_event = { .id = event_id };
return hash_table_lookup(client->events_hash, &lookup_event);
}
static bool
writer_client_run_event(struct writer_client *client,
uint64_t parent_event_id, const char *const *args,
struct event **event_r, const char **error_r)
{
struct event *parent_event;
unsigned int log_type;
if (parent_event_id == 0)
parent_event = NULL;
else {
struct stats_event *stats_parent_event =
writer_client_find_event(client, parent_event_id);
if (stats_parent_event == NULL) {
*error_r = "Unknown parent event ID";
return FALSE;
}
parent_event = stats_parent_event->event;
}
if (args[0] == NULL || str_to_uint(args[0], &log_type) < 0 ||
log_type >= LOG_TYPE_COUNT) {
*error_r = "Invalid log type";
return FALSE;
}
const struct failure_context ctx = {
.type = (enum log_type)log_type
};
args++;
struct event *event = event_create(parent_event);
if (!event_import_unescaped(event, args, error_r)) {
event_unref(&event);
return FALSE;
}
stats_metrics_event(stats_metrics, event, &ctx);
*event_r = event;
return TRUE;
}
static bool
writer_client_input_event(struct writer_client *client,
const char *const *args, const char **error_r)
{
struct event *event, *global_event = NULL;
uint64_t parent_event_id, global_event_id;
bool ret;
if (args[1] == NULL || str_to_uint64(args[0], &global_event_id) < 0) {
*error_r = "Invalid global event ID";
return FALSE;
}
if (args[1] == NULL || str_to_uint64(args[1], &parent_event_id) < 0) {
*error_r = "Invalid parent ID";
return FALSE;
}
if (global_event_id != 0) {
struct stats_event *stats_global_event =
writer_client_find_event(client, global_event_id);
if (stats_global_event == NULL) {
*error_r = "Unknown global event ID";
return FALSE;
}
global_event = stats_global_event->event;
event_push_global(global_event);
}
ret = writer_client_run_event(client, parent_event_id, args+2,
&event, error_r);
if (global_event != NULL)
event_pop_global(global_event);
if (!ret)
return FALSE;
event_unref(&event);
return TRUE;
}
static bool
writer_client_input_event_begin(struct writer_client *client,
const char *const *args, const char **error_r)
{
struct event *event;
struct stats_event *stats_event;
uint64_t event_id, parent_event_id;
if (args[0] == NULL || args[1] == NULL ||
str_to_uint64(args[0], &event_id) < 0 ||
str_to_uint64(args[1], &parent_event_id) < 0) {
*error_r = "Invalid event IDs";
return FALSE;
}
if (writer_client_find_event(client, event_id) != NULL) {
*error_r = "Duplicate event ID";
return FALSE;
}
if (!writer_client_run_event(client, parent_event_id, args+2, &event, error_r))
return FALSE;
stats_event = i_new(struct stats_event, 1);
stats_event->id = event_id;
stats_event->event = event;
DLLIST_PREPEND(&client->events, stats_event);
hash_table_insert(client->events_hash, stats_event, stats_event);
return TRUE;
}
static bool
writer_client_input_event_update(struct writer_client *client,
const char *const *args, const char **error_r)
{
struct stats_event *stats_event, *parent_stats_event;
struct event *parent_event;
uint64_t event_id, parent_event_id;
if (args[0] == NULL || args[1] == NULL ||
str_to_uint64(args[0], &event_id) < 0 ||
str_to_uint64(args[1], &parent_event_id) < 0) {
*error_r = "Invalid event IDs";
return FALSE;
}
stats_event = writer_client_find_event(client, event_id);
if (stats_event == NULL) {
*error_r = "Unknown event ID";
return FALSE;
}
parent_stats_event = parent_event_id == 0 ? NULL :
writer_client_find_event(client, parent_event_id);
parent_event = parent_stats_event == NULL ? NULL :
parent_stats_event->event;
if (stats_event->event->parent != parent_event) {
*error_r = "Event unexpectedly changed parent";
return FALSE;
}
return event_import_unescaped(stats_event->event, args+2, error_r);
}
static bool
writer_client_input_event_end(struct writer_client *client,
const char *const *args, const char **error_r)
{
struct stats_event *stats_event;
uint64_t event_id;
if (args[0] == NULL || str_to_uint64(args[0], &event_id) < 0) {
*error_r = "Invalid event ID";
return FALSE;
}
stats_event = writer_client_find_event(client, event_id);
if (stats_event == NULL) {
*error_r = "Unknown event ID";
return FALSE;
}
DLLIST_REMOVE(&client->events, stats_event);
hash_table_remove(client->events_hash, stats_event);
event_unref(&stats_event->event);
i_free(stats_event);
return TRUE;
}
static bool
writer_client_input_category(struct writer_client *client ATTR_UNUSED,
const char *const *args, const char **error_r)
{
struct event_category *category, *parent;
if (args[0] == NULL) {
*error_r = "Missing category name";
return FALSE;
}
if (args[1] == NULL)
parent = NULL;
else if ((parent = event_category_find_registered(args[1])) == NULL) {
*error_r = "Unknown parent category";
return FALSE;
}
category = event_category_find_registered(args[0]);
if (category == NULL) {
/* new category - create */
stats_event_category_register(args[0], parent);
} else if (category->parent != parent) {
*error_r = t_strdup_printf(
"Category parent '%s' changed to '%s'",
category->parent == NULL ? "" : category->parent->name,
parent == NULL ? "" : parent->name);
return FALSE;
} else {
/* duplicate - ignore */
return TRUE;
}
return TRUE;
}
static int
writer_client_input_args(struct connection *conn, const char *const *args)
{
struct writer_client *client = (struct writer_client *)conn;
const char *error, *cmd = args[0];
bool ret;
if (cmd == NULL) {
i_error("Client sent empty line");
return 1;
}
if (strcmp(cmd, "EVENT") == 0)
ret = writer_client_input_event(client, args+1, &error);
else if (strcmp(cmd, "BEGIN") == 0)
ret = writer_client_input_event_begin(client, args+1, &error);
else if (strcmp(cmd, "UPDATE") == 0)
ret = writer_client_input_event_update(client, args+1, &error);
else if (strcmp(cmd, "END") == 0)
ret = writer_client_input_event_end(client, args+1, &error);
else if (strcmp(cmd, "CATEGORY") == 0)
ret = writer_client_input_category(client, args+1, &error);
else {
error = "Unknown command";
ret = FALSE;
}
if (!ret) {
i_error("Client sent invalid input for %s: %s (input: %s)",
cmd, error, t_strarray_join(args, "\t"));
return -1;
}
return 1;
}
static struct connection_settings client_set = {
.service_name_in = "stats-client",
.service_name_out = "stats-server",
.major_version = 4,
.minor_version = 0,
.input_max_size = 1024*128, /* "big enough" */
.output_max_size = SIZE_MAX,
.client = FALSE,
};
static const struct connection_vfuncs client_vfuncs = {
.destroy = writer_client_destroy,
.input_args = writer_client_input_args,
};
static void
client_writer_update_connections_internal(void *context ATTR_UNUSED)
{
struct connection *conn;
for (conn = writer_clients->connections; conn != NULL; conn = conn->next) {
struct writer_client *client =
container_of(conn, struct writer_client, conn);
client_writer_send_handshake(client);
}
timeout_remove(&to_update_clients);
}
void client_writer_update_connections(void)
{
if (to_update_clients != NULL)
return;
to_update_clients = timeout_add(STATS_UPDATE_CLIENTS_DELAY_MSECS,
client_writer_update_connections_internal,
NULL);
}
void client_writers_init(void)
{
writer_clients = connection_list_init(&client_set, &client_vfuncs);
}
void client_writers_deinit(void)
{
timeout_remove(&to_update_clients);
connection_list_deinit(&writer_clients);
}
dovecot-2.3.21.1/src/stats/test-stats-common.c 0000644 0000000 0000000 00000005220 14656633576 016006 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "test-stats-common.h"
#include
#include
struct event_category test_category = {
.name = "test",
};
struct event_category child_test_category = {
.name = "child",
.parent = &test_category,
};
pool_t test_pool;
struct stats_metrics *stats_metrics = NULL;
time_t stats_startup_time;
static bool callback_added = FALSE;
static struct stats_settings *read_settings(const char *settings)
{
struct istream *is = test_istream_create(settings);
const char *error;
struct setting_parser_context *ctx =
settings_parser_init(test_pool, &stats_setting_parser_info, 0);
if (settings_parse_stream_read(ctx, is) < 0)
i_fatal("Failed to parse settings: %s",
settings_parser_get_error(ctx));
if (!settings_parser_check(ctx, test_pool, &error))
i_fatal("Failed to parse settings: %s",
error);
struct stats_settings *set = settings_parser_get(ctx);
settings_parser_deinit(&ctx);
i_stream_unref(&is);
return set;
}
void test_init(const char *settings_blob)
{
if (!callback_added) {
event_register_callback(test_stats_callback);
callback_added = TRUE;
}
stats_event_categories_init();
test_pool = pool_alloconly_create(MEMPOOL_GROWING"test pool", 2048);
stats_startup_time = time(NULL);
/* register test categories */
stats_event_category_register(test_category.name, NULL);
stats_event_category_register(child_test_category.name,
&test_category);
struct stats_settings *set = read_settings(settings_blob);
stats_metrics = stats_metrics_init(set);
}
void test_deinit(void)
{
stats_metrics_deinit(&stats_metrics);
stats_event_categories_deinit();
pool_unref(&test_pool);
}
void test_event_send(struct event *event)
{
struct failure_context ctx = {
.type = LOG_TYPE_DEBUG,
};
usleep(1); /* make sure duration>0 always */
event_send(event, &ctx, "hello");
}
uint64_t get_stats_dist_field(const char *metric_name, enum stats_dist_field field)
{
struct stats_metrics_iter *iter =
stats_metrics_iterate_init(stats_metrics);
const struct metric *metric;
while((metric = stats_metrics_iterate(iter)) != NULL)
if (strcmp(metric->name, metric_name) == 0)
break;
/* bug in test if not found */
i_assert(metric != NULL);
stats_metrics_iterate_deinit(&iter);
switch(field) {
case STATS_DIST_COUNT:
return stats_dist_get_count(metric->duration_stats);
case STATS_DIST_SUM:
return stats_dist_get_sum(metric->duration_stats);
default:
i_unreached();
}
}
dovecot-2.3.21.1/src/stats/main.c 0000644 0000000 0000000 00000005500 14656633576 013332 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "restrict-access.h"
#include "ioloop.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "stats-settings.h"
#include "stats-event-category.h"
#include "stats-metrics.h"
#include "stats-service.h"
#include "client-writer.h"
#include "client-reader.h"
#include "client-http.h"
struct stats_metrics *stats_metrics;
time_t stats_startup_time;
static const struct stats_settings *stats_settings;
static bool client_is_writer(const char *path)
{
const char *name, *suffix;
name = strrchr(path, '/');
if (name == NULL)
name = path;
else
name++;
suffix = strrchr(name, '-');
if (suffix == NULL)
suffix = name;
else
suffix++;
return strcmp(suffix, "writer") == 0;
}
static void client_connected(struct master_service_connection *conn)
{
if (strcmp(conn->name, "http") == 0)
client_http_create(conn);
else if (client_is_writer(conn->name))
client_writer_create(conn->fd);
else
client_reader_create(conn->fd);
master_service_client_connection_accept(conn);
}
static void stats_die(void)
{
/* just wait for existing stats clients to disconnect from us */
}
static void main_preinit(void)
{
restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
restrict_access_allow_coredumps(TRUE);
}
static void main_init(void)
{
void **sets = master_service_settings_get_others(master_service);
stats_settings = sets[0];
stats_startup_time = ioloop_time;
stats_metrics = stats_metrics_init(stats_settings);
stats_event_categories_init();
client_readers_init();
client_writers_init();
client_http_init(stats_settings);
stats_services_init();
}
static void main_deinit(void)
{
stats_services_deinit();
client_readers_deinit();
client_writers_deinit();
client_http_deinit();
stats_event_categories_deinit();
stats_metrics_deinit(&stats_metrics);
}
int main(int argc, char *argv[])
{
const struct setting_parser_info *set_roots[] = {
&stats_setting_parser_info,
NULL
};
const enum master_service_flags service_flags =
MASTER_SERVICE_FLAG_NO_SSL_INIT |
MASTER_SERVICE_FLAG_DONT_SEND_STATS |
MASTER_SERVICE_FLAG_NO_IDLE_DIE |
MASTER_SERVICE_FLAG_UPDATE_PROCTITLE;
const char *error;
master_service = master_service_init("stats", service_flags,
&argc, &argv, "");
if (master_getopt(master_service) > 0)
return FATAL_DEFAULT;
if (master_service_settings_read_simple(master_service, set_roots,
&error) < 0)
i_fatal("Error reading configuration: %s", error);
master_service_init_log(master_service);
master_service_set_die_callback(master_service, stats_die);
main_preinit();
main_init();
master_service_init_finish(master_service);
master_service_run(master_service, client_connected);
main_deinit();
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/stats/Makefile.am 0000644 0000000 0000000 00000004426 14656633576 014304 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = stats
noinst_LTLIBRARIES = libstats_local.la
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-http \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-test \
$(BINARY_CFLAGS)
stats_LDADD = \
$(noinst_LTLIBRARIES) \
$(LIBDOVECOT) \
$(DOVECOT_SSL_LIBS) \
$(BINARY_LDFLAGS) \
-lm
stats_DEPENDENCIES = \
$(noinst_LTLIBRARIES) \
$(DOVECOT_SSL_LIBS) \
$(LIBDOVECOT_DEPS)
stats_services = \
stats-service-openmetrics.c
stats_SOURCES = \
main.c
libstats_local_la_SOURCES = \
client-reader.c \
client-writer.c \
client-http.c \
event-exporter-fmt.c \
event-exporter-fmt-json.c \
event-exporter-fmt-none.c \
event-exporter-fmt-tab-text.c \
event-exporter-transport-drop.c \
event-exporter-transport-http-post.c \
event-exporter-transport-log.c \
$(stats_services) \
stats-service.c \
stats-event-category.c \
stats-metrics.c \
stats-settings.c
noinst_HEADERS = \
stats-common.h \
client-reader.h \
client-writer.h \
client-http.h\
event-exporter.h \
stats-service.h \
stats-service-private.h \
stats-event-category.h \
stats-metrics.h \
stats-settings.h \
test-stats-common.h
test_libs = \
$(noinst_LTLIBRARIES) \
$(DOVECOT_SSL_LIBS) \
$(LIBDOVECOT) \
$(BINARY_LDFLAGS) \
-lm
test_deps = \
$(noinst_LTLIBRARIES) \
$(DOVECOT_SSL_LIBS) \
$(LIBDOVECOT_DEPS)
test_stats_metrics_SOURCES = test-stats-metrics.c test-stats-common.c
test_stats_metrics_LDADD = $(test_libs)
test_stats_metrics_DEPENDENCIES = $(test_deps)
test_client_writer_SOURCES = test-client-writer.c test-stats-common.c
test_client_writer_LDADD = $(test_libs)
test_client_writer_DEPENDENCIES = $(test_deps)
test_client_reader_SOURCES = test-client-reader.c test-stats-common.c
test_client_reader_LDADD = $(test_libs)
test_client_reader_DEPENDENCIES = $(test_deps)
test_programs = test-stats-metrics test-client-writer test-client-reader
noinst_PROGRAMS = $(test_programs)
check-local:
for bin in $(test_programs); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
LIBDOVECOT_TEST_DEPS = \
../lib-ssl-iostream/libssl_iostream.la \
../lib-test/libtest.la \
../lib/liblib.la
LIBDOVECOT_TEST = \
$(LIBDOVECOT_TEST_DEPS) \
$(MODULE_LIBS)
dovecot-2.3.21.1/src/stats/stats-event-category.c 0000644 0000000 0000000 00000001605 14656633576 016500 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "stats-event-category.h"
static pool_t categories_pool;
void stats_event_category_register(const char *name,
struct event_category *parent)
{
struct event_category *category =
p_new(categories_pool, struct event_category, 1);
category->parent = parent;
category->name = p_strdup(categories_pool, name);
/* Create a temporary event to register the category. A bit slower
than necessary, but this code won't be called often. */
struct event *event = event_create(NULL);
struct event_category *categories[] = { category, NULL };
event_add_categories(event, categories);
event_unref(&event);
}
void stats_event_categories_init(void)
{
categories_pool = pool_alloconly_create("categories", 1024);
}
void stats_event_categories_deinit(void)
{
pool_unref(&categories_pool);
}
dovecot-2.3.21.1/src/stats/client-http.c 0000644 0000000 0000000 00000012744 14656633576 014651 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "str.h"
#include "array.h"
#include "strescape.h"
#include "connection.h"
#include "ostream.h"
#include "master-service.h"
#include "http-server.h"
#include "http-url.h"
#include "stats-metrics.h"
#include "stats-service.h"
#include "client-http.h"
struct stats_http_client;
struct stats_http_client {
struct http_server_connection *http_conn;
};
struct stats_http_resource {
pool_t pool;
const char *title;
struct http_server_resource *resource;
stats_http_resource_callback_t *callback;
void *context;
};
static struct http_server *stats_http_server;
static ARRAY(struct stats_http_resource *) stats_http_resources;
/*
* Request
*/
static void
stats_http_server_handle_request(void *context ATTR_UNUSED,
struct http_server_request *http_sreq)
{
http_server_request_fail(http_sreq, 404, "Path Not Found");
}
/*
* Connection
*/
static void
stats_http_server_connection_destroy(void *context, const char *reason);
static const struct http_server_callbacks stats_http_callbacks = {
.connection_destroy = stats_http_server_connection_destroy,
.handle_request = stats_http_server_handle_request
};
void client_http_create(struct master_service_connection *conn)
{
struct stats_http_client *client;
client = i_new(struct stats_http_client, 1);
client->http_conn = http_server_connection_create(
stats_http_server, conn->fd, conn->fd, conn->ssl,
&stats_http_callbacks, client);
}
static void stats_http_client_destroy(struct stats_http_client *client)
{
i_free(client);
master_service_client_connection_destroyed(master_service);
}
static void
stats_http_server_connection_destroy(void *context,
const char *reason ATTR_UNUSED)
{
struct stats_http_client *client = context;
if (client->http_conn == NULL) {
/* Already destroying client directly */
return;
}
/* HTTP connection is destroyed already now */
client->http_conn = NULL;
/* Destroy the connection itself */
stats_http_client_destroy(client);
}
/*
* Resources
*/
/* Registry */
static void
stats_http_resource_callback(struct stats_http_resource *res,
struct http_server_request *req,
const char *sub_path)
{
res->callback(res->context, req, sub_path);
}
#undef stats_http_resource_add
void stats_http_resource_add(const char *path, const char *title,
stats_http_resource_callback_t *callback,
void *context)
{
struct stats_http_resource *res;
pool_t pool;
pool = pool_alloconly_create("stats http resource", 2048);
res = p_new(pool, struct stats_http_resource, 1);
res->pool = pool;
res->title = p_strdup(pool, title);
res->callback = callback;
res->context = context;
res->resource = http_server_resource_create(
stats_http_server, pool, stats_http_resource_callback, res);
http_server_resource_add_location(res->resource, path);
pool_unref(&pool);
array_append(&stats_http_resources, &res, 1);
}
/* Root */
static void
stats_http_resource_root_make_response(struct http_server_response *resp,
const struct http_request *hreq)
{
struct stats_http_resource *res;
struct http_url url;
string_t *msg;
http_url_init_authority_from(&url, hreq->target.url);
msg = t_str_new(1024);
str_append(msg, "\n");
str_append(msg, "\n");
str_append(msg, "\n");
str_append(msg, "\n");
str_append(msg, "\n");
str_append(msg, "Dovecot Stats\n");
str_append(msg, "\n");
str_append(msg, "\n");
str_append(msg, "\n");
str_append(msg, "Dovecot Stats:
\n");
str_append(msg, "\n");
array_foreach_elem(&stats_http_resources, res) {
if (res->title == NULL)
continue;
/* List the resource at its primary location. */
url.path = http_server_resource_get_path(res->resource);
str_append(msg, "- ");
str_append(msg, res->title);
str_append(msg, "
\n");
}
str_append(msg, "
\n");
str_append(msg, "\n");
str_append(msg, "\n");
str_append(msg, "\n");
http_server_response_set_payload_data(
resp, str_data(msg), str_len(msg));
}
static void
stats_http_resource_root_request(void *context ATTR_UNUSED,
struct http_server_request *req,
const char *sub_path)
{
const struct http_request *hreq = http_server_request_get(req);
struct http_server_response *resp;
if (strcmp(hreq->method, "OPTIONS") == 0) {
resp = http_server_response_create(req, 200, "OK");
http_server_response_add_header(resp, "Allow", "GET");
http_server_response_submit(resp);
return;
}
if (strcmp(hreq->method, "GET") != 0) {
http_server_request_fail_bad_method(req, "GET");
return;
}
if (*sub_path != '\0') {
http_server_request_fail(req, 404, "Not Found");
return;
}
resp = http_server_response_create(req, 200, "OK");
http_server_response_add_header(resp, "Content-Type",
"text/html; charset=utf-8");
stats_http_resource_root_make_response(resp, hreq);
http_server_response_submit(resp);
}
/*
* Server
*/
void client_http_init(const struct stats_settings *set)
{
struct http_server_settings http_set = {
.rawlog_dir = set->stats_http_rawlog_dir,
};
i_array_init(&stats_http_resources, 8);
stats_http_server = http_server_init(&http_set);
stats_http_resource_add("/", NULL,
stats_http_resource_root_request, NULL);
}
void client_http_deinit(void)
{
http_server_deinit(&stats_http_server);
array_free(&stats_http_resources);
}
dovecot-2.3.21.1/src/stats/event-exporter-fmt-none.c 0000644 0000000 0000000 00000000461 14656633576 017117 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "event-exporter.h"
void event_export_fmt_none(const struct metric *metric ATTR_UNUSED,
struct event *event ATTR_UNUSED,
buffer_t *dest ATTR_UNUSED)
{
/* nothing to do */
}
dovecot-2.3.21.1/src/stats/stats-service-openmetrics.c 0000644 0000000 0000000 00000055254 14656633576 017543 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "stats-common.h"
#include "dovecot-version.h"
#include "str.h"
#include "array.h"
#include "json-parser.h"
#include "ioloop.h"
#include "ostream.h"
#include "stats-dist.h"
#include "http-server.h"
#include "client-http.h"
#include "stats-settings.h"
#include "stats-metrics.h"
#include "stats-service-private.h"
#define OPENMETRICS_CONTENT_VERSION "0.0.1"
#ifdef DOVECOT_REVISION
#define OPENMETRICS_BUILD_INFO \
"version=\""DOVECOT_VERSION"\"," \
"revision=\""DOVECOT_REVISION"\""
#else
#define OPENMETRICS_BUILD_INFO \
"version=\""DOVECOT_VERSION"\""
#endif
enum openmetrics_metric_type {
OPENMETRICS_METRIC_TYPE_COUNT,
OPENMETRICS_METRIC_TYPE_DURATION,
OPENMETRICS_METRIC_TYPE_FIELD,
OPENMETRICS_METRIC_TYPE_HISTOGRAM,
};
enum openmetrics_request_state {
OPENMETRICS_REQUEST_STATE_INIT = 0,
OPENMETRICS_REQUEST_STATE_METRIC,
OPENMETRICS_REQUEST_STATE_METRIC_HEADER,
OPENMETRICS_REQUEST_STATE_SUB_METRICS,
OPENMETRICS_REQUEST_STATE_METRIC_BODY,
OPENMETRICS_REQUEST_STATE_FINISHED,
};
struct openmetrics_request_sub_metric {
size_t labels_pos;
const struct metric *metric;
unsigned int sub_index;
};
struct openmetrics_request {
struct ostream *output;
enum openmetrics_request_state state;
struct stats_metrics_iter *stats_iter;
const struct metric *metric;
enum openmetrics_metric_type metric_type;
string_t *labels;
size_t labels_pos;
unsigned int field_pos;
ARRAY(struct openmetrics_request_sub_metric) sub_metric_stack;
bool has_submetric:1;
};
/* https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels:
Every time series is uniquely identified by its metric name and optional
key-value pairs called labels.
The metric name specifies the general feature of a system that is measured
(e.g. http_requests_total - the total number of HTTP requests received). It
may contain ASCII letters and digits, as well as underscores and colons. It
must match the regex [a-zA-Z_:][a-zA-Z0-9_:]*.
*/
static bool openmetrics_check_name(const char *name)
{
const unsigned char *p, *pend;
p = (const unsigned char *)name;
pend = p + strlen(name);
if (p == pend)
return FALSE;
if (!(*p >= 'a' && *p <= 'z') && !(*p >= 'A' && *p <= 'Z') &&
*p != '_' && *p != ':')
return FALSE;
p++;
while (p < pend) {
if (!(*p >= 'a' && *p <= 'z') && !(*p >= 'A' && *p <= 'Z') &&
!(*p >= '0' && *p <= '9') && *p != '_' && *p != ':')
return FALSE;
p++;
}
return TRUE;
}
static void openmetrics_export_dovecot(string_t *out)
{
i_assert(stats_startup_time <= ioloop_time);
str_append(out, "# HELP process_start_time_seconds "
"Timestamp of service start\n");
str_append(out, "# TYPE process_start_time_seconds gauge\n");
str_printfa(out, "process_start_time_seconds %"PRIdTIME_T"\n",
stats_startup_time);
str_append(out, "# HELP dovecot_build "
"Dovecot build information\n");
str_append(out, "# TYPE dovecot_build info\n");
str_append(out, "dovecot_build_info{"OPENMETRICS_BUILD_INFO"} 1\n");
}
static void openmetrics_export_eof(string_t *out)
{
str_append(out, "# EOF\n");
}
static void
openmetrics_export_metric_value(struct openmetrics_request *req, string_t *out,
const struct metric *metric)
{
const struct metric_field *field;
/* Metric name */
str_append(out, "dovecot_");
str_append(out, req->metric->name);
switch (req->metric_type) {
case OPENMETRICS_METRIC_TYPE_COUNT:
if (req->metric->group_by != NULL && str_len(req->labels) == 0)
str_append(out, "_count");
else
str_append(out, "_total");
break;
case OPENMETRICS_METRIC_TYPE_DURATION:
if (req->metric->group_by != NULL && str_len(req->labels) == 0)
str_append(out, "_duration_seconds_sum");
else
str_append(out, "_duration_seconds_total");
break;
case OPENMETRICS_METRIC_TYPE_FIELD:
field = &metric->fields[req->field_pos];
if (req->metric->group_by != NULL && str_len(req->labels) == 0)
str_printfa(out, "_%s_sum", field->field_key);
else
str_printfa(out, "_%s_total", field->field_key);
break;
case OPENMETRICS_METRIC_TYPE_HISTOGRAM:
i_unreached();
}
/* Labels */
if (str_len(req->labels) > 0) {
str_append_c(out, '{');
str_append_str(out, req->labels);
str_append_c(out, '}');
}
/* Value */
switch (req->metric_type) {
case OPENMETRICS_METRIC_TYPE_COUNT:
str_printfa(out, " %u\n",
stats_dist_get_count(metric->duration_stats));
break;
case OPENMETRICS_METRIC_TYPE_DURATION:
/* Convert from microseconds to seconds */
str_printfa(out, " %.6f\n",
stats_dist_get_sum(metric->duration_stats)/1e6F);
break;
case OPENMETRICS_METRIC_TYPE_FIELD:
field = &metric->fields[req->field_pos];
str_printfa(out, " %"PRIu64"\n",
stats_dist_get_sum(field->stats));
break;
case OPENMETRICS_METRIC_TYPE_HISTOGRAM:
i_unreached();
}
}
static const struct metric *
openmetrics_find_histogram_bucket(const struct metric *metric,
unsigned int index)
{
struct metric *sub_metric;
if (!array_is_created(&metric->sub_metrics))
return NULL;
array_foreach_elem(&metric->sub_metrics, sub_metric) {
if (sub_metric->group_value.type !=
METRIC_VALUE_TYPE_BUCKET_INDEX)
continue;
if (sub_metric->group_value.intmax == index)
return sub_metric;
}
return NULL;
}
static void
openmetrics_export_histogram_bucket(struct openmetrics_request *req,
string_t *out, const struct metric *metric,
intmax_t bucket_limit, int64_t count)
{
/* Metric name */
str_append(out, "dovecot_");
str_append(out, metric->name);
str_append(out, "_bucket");
/* Labels */
str_append_c(out, '{');
if (str_len(req->labels) > 0) {
str_append_str(out, req->labels);
str_append_c(out, ',');
}
if (bucket_limit == INTMAX_MAX)
str_append(out, "le=\"+Inf\"");
else if (strcmp(metric->group_by->field,
STATS_EVENT_FIELD_NAME_DURATION) == 0) {
/* Convert from microseconds to seconds */
str_printfa(out, "le=\"%.6f\"", bucket_limit/1e6F);
} else {
str_printfa(out, "le=\"%jd\"", bucket_limit);
}
str_printfa(out, "} %"PRIu64"\n", count);
}
static void
openmetrics_export_histogram(struct openmetrics_request *req, string_t *out,
const struct metric *metric)
{
const struct stats_metric_settings_group_by *group_by =
metric->group_by;
float sum = 0;
uint64_t count = 0;
/* Buckets */
for (unsigned int i = 0; i < group_by->num_ranges; i++) {
const struct metric *sub_metric =
openmetrics_find_histogram_bucket(metric, i);
if (sub_metric != NULL) {
sum += stats_dist_get_sum(sub_metric->duration_stats);
count += stats_dist_get_count(sub_metric->duration_stats);
}
openmetrics_export_histogram_bucket(req, out, metric,
group_by->ranges[i].max,
count);
}
/* There is either no data in histogram, which adding the optional
sum and count metrics doesn't add any new information or
these have already been exported for submetrics. */
if (count == 0)
return;
/* Sum */
str_append(out, "dovecot_");
str_append(out, metric->name);
str_append(out, "_sum");
/* Labels */
if (str_len(req->labels) > 0) {
str_append_c(out, '{');
str_append_str(out, req->labels);
str_append_c(out, '}');
}
if (strcmp(metric->group_by->field,
STATS_EVENT_FIELD_NAME_DURATION) == 0) {
/* Convert from microseconds to seconds */
sum /= 1e6F;
}
str_printfa(out, " %.6f\n", sum);
/* Count */
str_append(out, "dovecot_");
str_append(out, metric->name);
str_append(out, "_count");
/* Labels */
if (str_len(req->labels) > 0) {
str_append_c(out, '{');
str_append_str(out, req->labels);
str_append_c(out, '}');
}
str_printfa(out, " %"PRIu64"\n", count);
}
static void
openmetrics_export_metric_header(struct openmetrics_request *req, string_t *out)
{
const struct metric *metric = req->metric;
const struct metric_field *field;
/* Description */
str_append(out, "# HELP dovecot_");
str_append(out, metric->name);
switch (req->metric_type) {
case OPENMETRICS_METRIC_TYPE_COUNT:
str_append(out, " Total number of all events of this kind");
break;
case OPENMETRICS_METRIC_TYPE_DURATION:
str_append(out, "_duration_seconds Total duration of all events of this kind");
break;
case OPENMETRICS_METRIC_TYPE_FIELD:
field = &metric->fields[req->field_pos];
str_printfa(out, "_%s Total of field value for events of this kind",
field->field_key);
break;
case OPENMETRICS_METRIC_TYPE_HISTOGRAM:
str_append(out, " Histogram");
break;
}
if (*metric->set->description != '\0') {
str_append(out, " of ");
str_append(out, metric->set->description);
}
str_append_c(out, '\n');
/* Type */
str_append(out, "# TYPE dovecot_");
str_append(out, metric->name);
switch (req->metric_type) {
case OPENMETRICS_METRIC_TYPE_COUNT:
str_append(out, " counter\n");
break;
case OPENMETRICS_METRIC_TYPE_DURATION:
str_append(out, "_duration_seconds counter\n");
break;
case OPENMETRICS_METRIC_TYPE_FIELD:
field = &metric->fields[req->field_pos];
str_printfa(out, "_%s counter\n", field->field_key);
break;
case OPENMETRICS_METRIC_TYPE_HISTOGRAM:
str_append(out, " histogram\n");
break;
}
}
static void
openmetrics_export_submetric(struct openmetrics_request *req, string_t *out,
const struct metric *metric)
{
/* This metric may be a submetric and therefore have a label
associated with it. */
if (metric->sub_name != NULL) {
str_append_c(req->labels, '"');
json_append_escaped(req->labels, metric->sub_name);
str_append_c(req->labels, '"');
}
if (req->metric_type == OPENMETRICS_METRIC_TYPE_HISTOGRAM) {
if (metric->group_by == NULL ||
metric->group_by[0].func != STATS_METRIC_GROUPBY_QUANTIZED)
return;
openmetrics_export_histogram(req, out, metric);
return;
}
openmetrics_export_metric_value(req, out, metric);
req->has_submetric = TRUE;
}
static const struct metric *
openmetrics_export_sub_metric_get(struct openmetrics_request_sub_metric *reqsm)
{
if (reqsm->sub_index >= array_count(&reqsm->metric->sub_metrics))
return NULL;
return array_idx_elem(&reqsm->metric->sub_metrics, reqsm->sub_index);
}
static const struct metric *
openmetrics_export_sub_metric_get_next(
struct openmetrics_request_sub_metric *reqsm)
{
/* Get the next valid sub-metric */
reqsm->sub_index++;
return openmetrics_export_sub_metric_get(reqsm);
}
static struct openmetrics_request_sub_metric *
openmetrics_export_sub_metric_down(struct openmetrics_request *req)
{
struct openmetrics_request_sub_metric *reqsm =
array_back_modifiable(&req->sub_metric_stack);
const struct metric *sub_metric;
/* Descend further into sub-metric tree */
if (reqsm->metric->group_by == NULL ||
!openmetrics_check_name(reqsm->metric->group_by->field) ||
!array_is_created(&reqsm->metric->sub_metrics) ||
array_count(&reqsm->metric->sub_metrics) == 0)
return NULL;
if (reqsm->metric->group_by[0].func == STATS_METRIC_GROUPBY_QUANTIZED) {
/* Never descend into quantized group_by sub-metrics.
Histograms are exported as a single blob. */
return NULL;
}
/* Find sub-metric to descend into */
sub_metric = openmetrics_export_sub_metric_get(reqsm);
if (sub_metric == NULL) {
/* None valid */
return NULL;
}
if (str_len(req->labels) > 0)
str_append_c(req->labels, ',');
str_append(req->labels, reqsm->metric->group_by->field);
str_append_c(req->labels, '=');
reqsm->labels_pos = str_len(req->labels);
/* Descend */
reqsm = array_append_space(&req->sub_metric_stack);
reqsm->metric = sub_metric;
return reqsm;
}
static struct openmetrics_request_sub_metric *
openmetrics_export_sub_metric_up_next(struct openmetrics_request *req)
{
struct openmetrics_request_sub_metric *reqsm;
const struct metric *sub_metric = NULL;
/* Ascend to next sub-metric of an ancestor */
while (array_count(&req->sub_metric_stack) > 1) {
/* Ascend */
array_pop_back(&req->sub_metric_stack);
reqsm = array_back_modifiable(&req->sub_metric_stack);
str_truncate(req->labels, reqsm->labels_pos);
/* Find next sub-metric */
sub_metric = openmetrics_export_sub_metric_get_next(reqsm);
if (sub_metric != NULL) {
/* None valid */
break;
}
}
if (sub_metric == NULL) {
/* End of sub-metric tree */
return NULL;
}
/* Descend */
reqsm = array_append_space(&req->sub_metric_stack);
reqsm->metric = sub_metric;
return reqsm;
}
static struct openmetrics_request_sub_metric *
openmetrics_export_sub_metric_current(struct openmetrics_request *req)
{
struct openmetrics_request_sub_metric *reqsm;
/* Get state for current sub-metric */
if (!array_is_created(&req->sub_metric_stack))
i_array_init(&req->sub_metric_stack, 8);
if (array_count(&req->sub_metric_stack) >= 2) {
/* Already walking the sub-metric tree */
return array_back_modifiable(&req->sub_metric_stack);
}
/* Start tree walking */
reqsm = array_append_space(&req->sub_metric_stack);
reqsm->metric = req->metric;
reqsm->labels_pos = str_len(req->labels);
return openmetrics_export_sub_metric_down(req);
}
static bool
openmetrics_export_sub_metrics(struct openmetrics_request *req, string_t *out)
{
struct openmetrics_request_sub_metric *reqsm = NULL;
if (!array_is_created(&req->metric->sub_metrics))
return TRUE;
reqsm = openmetrics_export_sub_metric_current(req);
if (reqsm == NULL) {
/* No valid sub-metrics to export */
return TRUE;
}
openmetrics_export_submetric(req, out, reqsm->metric);
/* Try do descend into sub-metrics tree for next sub-metric to export.
*/
reqsm = openmetrics_export_sub_metric_down(req);
if (reqsm == NULL) {
/* Sub-metrics of this metric exhausted; ascend to the next
parent sub-metric.
*/
reqsm = openmetrics_export_sub_metric_up_next(req);
}
if (reqsm == NULL) {
/* Finished */
array_clear(&req->sub_metric_stack);
return TRUE;
}
return FALSE;
}
static void
openmetrics_export_metric_body(struct openmetrics_request *req, string_t *out)
{
openmetrics_export_metric_value(req, out, req->metric);
}
static int
openmetrics_send_buffer(struct openmetrics_request *req, buffer_t *buffer)
{
ssize_t sent;
if (buffer->used == 0)
return 1;
sent = o_stream_send(req->output, buffer->data, buffer->used);
if (sent < 0)
return -1;
/* Max buffer size is enormous */
i_assert((size_t)sent == buffer->used);
if (o_stream_get_buffer_used_size(req->output) >= IO_BLOCK_SIZE)
return 0;
return 1;
}
static bool openmetrics_export_has_histogram(struct openmetrics_request *req)
{
const struct metric *metric = req->metric;
unsigned int i;
if (metric->group_by_count == 0) {
/* No group_by */
return FALSE;
}
/* We can only support quantized group_by when it is the last group
item. */
for (i = 0; i < (metric->group_by_count - 1); i++) {
if (metric->group_by[i].func ==
STATS_METRIC_GROUPBY_QUANTIZED)
return FALSE;
}
return (metric->group_by[metric->group_by_count - 1].func ==
STATS_METRIC_GROUPBY_QUANTIZED);
}
static void openmetrics_export_next(struct openmetrics_request *req)
{
/* Determine what to export next. */
switch (req->metric_type) {
case OPENMETRICS_METRIC_TYPE_COUNT:
/* Continue with duration output for this metric. */
req->metric_type = OPENMETRICS_METRIC_TYPE_DURATION;
req->state = OPENMETRICS_REQUEST_STATE_METRIC_HEADER;
break;
case OPENMETRICS_METRIC_TYPE_DURATION:
if (openmetrics_export_has_histogram(req)) {
/* Continue with histogram output for this metric. */
req->metric_type = OPENMETRICS_METRIC_TYPE_HISTOGRAM;
req->state = OPENMETRICS_REQUEST_STATE_METRIC_HEADER;
} else if (req->metric->fields_count > 0) {
req->field_pos = 0;
req->metric_type = OPENMETRICS_METRIC_TYPE_FIELD;
req->state = OPENMETRICS_REQUEST_STATE_METRIC_HEADER;
} else {
/* No histogram; continue with next metric */
req->state = OPENMETRICS_REQUEST_STATE_METRIC;
}
break;
case OPENMETRICS_METRIC_TYPE_FIELD:
req->field_pos++;
if (req->field_pos < req->metric->fields_count) {
req->metric_type = OPENMETRICS_METRIC_TYPE_FIELD;
req->state = OPENMETRICS_REQUEST_STATE_METRIC_HEADER;
} else {
/* all fields consumed */
req->state = OPENMETRICS_REQUEST_STATE_METRIC;
}
break;
case OPENMETRICS_METRIC_TYPE_HISTOGRAM:
if (req->metric->fields_count > 0) {
/* Continue with fields */
req->field_pos = 0;
req->metric_type = OPENMETRICS_METRIC_TYPE_FIELD;
req->state = OPENMETRICS_REQUEST_STATE_METRIC_HEADER;
} else {
/* Continue with next metric */
req->state = OPENMETRICS_REQUEST_STATE_METRIC;
}
break;
}
}
static void
openmetrics_export_continue(struct openmetrics_request *req, string_t *out)
{
switch (req->state) {
case OPENMETRICS_REQUEST_STATE_INIT:
/* Export the Dovecot base metrics. */
i_assert(req->stats_iter == NULL);
req->stats_iter = stats_metrics_iterate_init(stats_metrics);
openmetrics_export_dovecot(out);
req->state = OPENMETRICS_REQUEST_STATE_METRIC;
break;
case OPENMETRICS_REQUEST_STATE_METRIC:
/* Export the next metric. */
i_assert(req->stats_iter != NULL);
do {
req->metric = stats_metrics_iterate(req->stats_iter);
} while (req->metric != NULL &&
!openmetrics_check_name(req->metric->name));
if (req->metric == NULL) {
/* Finished exporting metrics. */
req->state = OPENMETRICS_REQUEST_STATE_FINISHED;
break;
}
if (req->labels == NULL)
req->labels = str_new(default_pool, 32);
else
str_truncate(req->labels, 0);
req->labels_pos = 0;
/* Start with count output for this metric if the type
is not histogram. If the metric is of type histogram,
start with quantiles. */
if (openmetrics_export_has_histogram(req))
req->metric_type = OPENMETRICS_METRIC_TYPE_HISTOGRAM;
else
req->metric_type = OPENMETRICS_METRIC_TYPE_COUNT;
req->state = OPENMETRICS_REQUEST_STATE_METRIC_HEADER;
/* Fall through */
case OPENMETRICS_REQUEST_STATE_METRIC_HEADER:
/* Export the HELP/TYPE header for the current metric */
str_truncate(req->labels, req->labels_pos);
req->has_submetric = FALSE;
if (array_is_created(&req->sub_metric_stack))
array_clear(&req->sub_metric_stack);
openmetrics_export_metric_header(req, out);
req->state = OPENMETRICS_REQUEST_STATE_SUB_METRICS;
break;
case OPENMETRICS_REQUEST_STATE_SUB_METRICS:
/* Export the sub-metrics for the current metric. This will
return for each sub-metric, so that the out string buffer
stays small. */
if (!openmetrics_export_sub_metrics(req, out))
break;
/* All sub-metrics written. */
req->state = OPENMETRICS_REQUEST_STATE_METRIC_BODY;
break;
case OPENMETRICS_REQUEST_STATE_METRIC_BODY:
/* Export the body of the current metric. */
str_truncate(req->labels, req->labels_pos);
if (req->metric_type == OPENMETRICS_METRIC_TYPE_HISTOGRAM)
openmetrics_export_histogram(req, out, req->metric);
else
openmetrics_export_metric_body(req, out);
openmetrics_export_next(req);
break;
case OPENMETRICS_REQUEST_STATE_FINISHED:
i_unreached();
}
}
static void openmetrics_handle_write_error(struct openmetrics_request *req)
{
i_info("openmetrics: write(%s) failed: %s",
o_stream_get_name(req->output),
o_stream_get_error(req->output));
o_stream_destroy(&req->output);
}
static void openmetrics_request_deinit(struct openmetrics_request *req)
{
stats_metrics_iterate_deinit(&req->stats_iter);
str_free(&req->labels);
array_free(&req->sub_metric_stack);
}
static int openmetrics_export(struct openmetrics_request *req)
{
string_t *out;
int ret;
ret = o_stream_flush(req->output);
if (ret < 0) {
openmetrics_handle_write_error(req);
return -1;
}
if (ret == 0) {
/* Output stream buffer needs to be flushed further */
return 0;
}
if (req->state == OPENMETRICS_REQUEST_STATE_FINISHED) {
/* All metrics were exported already, so we can finish the
HTTP request now. */
o_stream_destroy(&req->output);
return 1;
}
/* Export metrics into a string buffer and write that buffer to the
output stream after each (sub-)metric, so that the string buffer
stays small. The output stream buffer can grow bigger, but writing is
stopped for later resumption when the output stream buffer has grown
beyond an optimal size. */
out = t_str_new(1024);
for (;;) {
str_truncate(out, 0);
openmetrics_export_continue(req, out);
ret = openmetrics_send_buffer(req, out);
if (ret < 0) {
openmetrics_handle_write_error(req);
return -1;
}
if (req->state == OPENMETRICS_REQUEST_STATE_FINISHED) {
/* Finished export of metrics, but the output stream
buffer may still contain data. */
break;
}
if (ret == 0) {
/* Output stream buffer is filled up beyond the optimal
size; wait until we can write more. */
return ret;
}
}
/* Send EOF */
str_truncate(out, 0);
openmetrics_export_eof(out);
ret = openmetrics_send_buffer(req, out);
if (ret < 0) {
openmetrics_handle_write_error(req);
return -1;
}
/* Cleanup everything except the output stream */
openmetrics_request_deinit(req);
/* Finished; flush output */
ret = o_stream_finish(req->output);
if (ret < 0) {
openmetrics_handle_write_error(req);
return -1;
}
return ret;
}
static void openmetrics_request_destroy(struct openmetrics_request *req)
{
o_stream_destroy(&req->output);
openmetrics_request_deinit(req);
}
static void
stats_service_openmetrics_request(void *context ATTR_UNUSED,
struct http_server_request *hsreq,
const char *sub_path)
{
const struct http_request *hreq = http_server_request_get(hsreq);
struct http_server_response *hsresp;
struct openmetrics_request *req;
pool_t pool;
if (strcmp(hreq->method, "OPTIONS") == 0) {
hsresp = http_server_response_create(hsreq, 200, "OK");
http_server_response_add_header(hsresp, "Allow", "GET");
http_server_response_submit(hsresp);
return;
}
if (strcmp(hreq->method, "GET") != 0) {
http_server_request_fail_bad_method(hsreq, "GET");
return;
}
if (*sub_path != '\0') {
http_server_request_fail(hsreq, 404, "Not Found");
return;
}
pool = http_server_request_get_pool(hsreq);
req = p_new(pool, struct openmetrics_request, 1);
http_server_request_set_destroy_callback(
hsreq, openmetrics_request_destroy, req);
hsresp = http_server_response_create(hsreq, 200, "OK");
http_server_response_add_header(
hsresp, "Content-Type",
"application/openmetrics-text; version="OPENMETRICS_CONTENT_VERSION"; "
"charset=utf-8");
req->output = http_server_response_get_payload_output(
hsresp, SIZE_MAX, FALSE);
o_stream_set_flush_callback(req->output, openmetrics_export, req);
o_stream_set_flush_pending(req->output, TRUE);
}
void stats_service_openmetrics_init(void)
{
struct stats_metrics_iter *iter;
const struct metric *metric;
iter = stats_metrics_iterate_init(stats_metrics);
while ((metric = stats_metrics_iterate(iter)) != NULL) {
if (!openmetrics_check_name(metric->name)) {
i_warning(
"stats: openmetrics: "
"Metric `%s' is not valid for OpenMetrics"
"(invalid metric name; skipped)",
metric->name);
}
}
stats_metrics_iterate_deinit(&iter);
stats_http_resource_add("/metrics", "OpenMetrics",
stats_service_openmetrics_request, NULL);
}
dovecot-2.3.21.1/src/stats/event-exporter-fmt-tab-text.c 0000644 0000000 0000000 00000013376 14656633576 017721 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "lib-event-private.h"
#include "event-exporter.h"
#include "str.h"
#include "strescape.h"
#include "hostpid.h"
static void append_strlist(string_t *dest, const ARRAY_TYPE(const_string) *strlist)
{
string_t *str = t_str_new(64);
const char *value;
bool first = TRUE;
/* append the strings first escaped into a temporary string */
array_foreach_elem(strlist, value) {
if (first)
first = FALSE;
else
str_append_c(str, '\t');
str_append_tabescaped(str, value);
}
/* append the temporary string (double-)escaped as the value */
str_append_tabescaped(dest, str_c(str));
}
static void append_int(string_t *dest, intmax_t val)
{
str_printfa(dest, "%jd", val);
}
static void append_time(string_t *dest, const struct timeval *time,
enum event_exporter_time_fmt fmt)
{
switch (fmt) {
case EVENT_EXPORTER_TIME_FMT_NATIVE:
i_panic("tab-text format does not have a native date/time type");
case EVENT_EXPORTER_TIME_FMT_UNIX:
event_export_helper_fmt_unix_time(dest, time);
break;
case EVENT_EXPORTER_TIME_FMT_RFC3339:
event_export_helper_fmt_rfc3339_time(dest, time);
break;
}
}
static void append_field_str(string_t *dest, const char *str,
const struct metric_export_info *info)
{
if (info->exporter->format_max_field_len == 0)
str_append_tabescaped(dest, str);
else {
size_t len = strlen(str);
str_append_tabescaped_n(dest, (const unsigned char *)str,
I_MIN(len, info->exporter->format_max_field_len));
if (len > info->exporter->format_max_field_len)
str_append(dest, "...");
}
}
static void append_field_value(string_t *dest, const struct event_field *field,
const struct metric_export_info *info)
{
switch (field->value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
append_field_str(dest, field->value.str, info);
break;
case EVENT_FIELD_VALUE_TYPE_INTMAX:
append_int(dest, field->value.intmax);
break;
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
append_time(dest, &field->value.timeval,
info->exporter->time_format);
break;
case EVENT_FIELD_VALUE_TYPE_STRLIST:
append_strlist(dest, &field->value.strlist);
break;
}
}
static void tabtext_export_name(string_t *dest, struct event *event,
const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_NAME) == 0)
return;
str_append(dest, "event:");
str_append_tabescaped(dest, event->sending_name);
str_append_c(dest, '\t');
}
static void tabtext_export_hostname(string_t *dest,
const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_HOSTNAME) == 0)
return;
str_append(dest, "hostname:");
str_append_tabescaped(dest, my_hostname);
str_append_c(dest, '\t');
}
static void tabtext_export_timestamps(string_t *dest, struct event *event,
const struct metric_export_info *info)
{
if ((info->include & EVENT_EXPORTER_INCL_TIMESTAMPS) == 0)
return;
str_append(dest, "start_time:");
append_time(dest, &event->tv_created, info->exporter->time_format);
str_append(dest, "\tend_time:");
append_time(dest, &ioloop_timeval, info->exporter->time_format);
str_append_c(dest, '\t');
}
static void append_category(string_t *dest, const char *cat)
{
str_append(dest, "category:");
str_append_tabescaped(dest, cat);
}
static void tabtext_export_categories(string_t *dest, struct event *event,
const struct metric_export_info *info)
{
struct event_category *const *cats;
unsigned int count;
if ((info->include & EVENT_EXPORTER_INCL_CATEGORIES) == 0)
return;
cats = event_get_categories(event, &count);
event_export_helper_fmt_categories(dest, cats, count,
append_category, "\t");
str_append_c(dest, '\t'); /* extra \t to have something to remove later */
}
static void tabtext_export_fields(string_t *dest, struct event *event,
const struct metric_export_info *info,
const unsigned int fields_count,
const struct metric_field *fields)
{
if ((info->include & EVENT_EXPORTER_INCL_FIELDS) == 0)
return;
if (fields_count == 0) {
/* include all fields */
const struct event_field *fields;
unsigned int count;
fields = event_get_fields(event, &count);
for (unsigned int i = 0; i < count; i++) {
const struct event_field *field = &fields[i];
str_append(dest, "field:");
str_append_tabescaped(dest, field->key);
str_append_c(dest, '=');
append_field_value(dest, field, info);
str_append_c(dest, '\t');
}
} else {
for (unsigned int i = 0; i < fields_count; i++) {
const char *name = fields[i].field_key;
const struct event_field *field;
field = event_find_field_recursive(event, name);
if (field == NULL)
continue; /* doesn't exist, skip it */
str_append(dest, "field:");
str_append_tabescaped(dest, name);
str_append_c(dest, '=');
append_field_value(dest, field, info);
str_append_c(dest, '\t');
}
}
}
/*
* Serialize the event as tab delimited collection of the following:
*
* event:
* hostname:
* start_time:
* end_time:
* category:
* field:=
*
* Note: cat and field can occur multiple times.
*/
void event_export_fmt_tabescaped_text(const struct metric *metric,
struct event *event, buffer_t *dest)
{
const struct metric_export_info *info = &metric->export_info;
if (info->include == EVENT_EXPORTER_INCL_NONE)
return;
tabtext_export_name(dest, event, info);
tabtext_export_hostname(dest, info);
tabtext_export_timestamps(dest, event, info);
tabtext_export_categories(dest, event, info);
tabtext_export_fields(dest, event, info, metric->fields_count,
metric->fields);
/* remove trailing tab */
str_truncate(dest, str_len(dest) - 1);
}
dovecot-2.3.21.1/src/stats/stats-event-category.h 0000644 0000000 0000000 00000000516 14656633576 016505 0000000 0000000 #ifndef STATS_EVENT_CATEGORY_H
#define STATS_EVENT_CATEGORY_H
/* Register a new event category if it doesn't already exist.
parent may be NULL. */
void stats_event_category_register(const char *name,
struct event_category *parent);
void stats_event_categories_init(void);
void stats_event_categories_deinit(void);
#endif
dovecot-2.3.21.1/src/stats/test-client-reader.c 0000644 0000000 0000000 00000012473 14656633576 016110 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "test-stats-common.h"
#include "master-service-private.h"
#include "client-reader.h"
#include "connection.h"
#include "ostream.h"
static struct connection_list *conn_list;
struct test_connection {
struct connection conn;
unsigned int row_count;
};
static void test_reader_server_destroy(struct connection *conn)
{
io_loop_stop(conn->ioloop);
}
static struct connection_settings client_set = {
.service_name_in = "stats-reader-server",
.service_name_out = "stats-reader-client",
.major_version = 2,
.minor_version = 0,
.allow_empty_args_input = TRUE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
.client = TRUE,
};
bool test_stats_callback(struct event *event,
enum event_callback_type type ATTR_UNUSED,
struct failure_context *ctx, const char *fmt ATTR_UNUSED,
va_list args ATTR_UNUSED)
{
if (stats_metrics != NULL) {
stats_metrics_event(stats_metrics, event, ctx);
struct event_filter *filter =
stats_metrics_get_event_filter(stats_metrics);
return !event_filter_match(filter, event, ctx);
}
return TRUE;
}
static const char *settings_blob_1 =
"metric=test\n"
"metric/test/metric_name=test\n"
"metric/test/filter=event=test\n"
"\n";
static int test_reader_server_input_args(struct connection *conn ATTR_UNUSED,
const char *const *args)
{
if (args[0] == NULL)
return -1;
test_assert_strcmp(args[0], "test");
test_assert_strcmp(args[1], "1");
return 1;
}
static void test_dump_metrics(void)
{
int fds[2];
test_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
struct connection *conn = i_new(struct connection, 1);
struct ioloop *loop = io_loop_create();
client_reader_create(fds[1]);
connection_init_client_fd(conn_list, conn, "stats", fds[0], fds[0]);
o_stream_nsend_str(conn->output, "DUMP\tcount\n");
io_loop_run(loop);
connection_deinit(conn);
i_free(conn);
/* allow client-reader to finish up */
io_loop_set_running(loop);
io_loop_handler_run(loop);
io_loop_destroy(&loop);
}
static void test_client_reader(void)
{
const struct connection_vfuncs client_vfuncs = {
.input_args = test_reader_server_input_args,
.destroy = test_reader_server_destroy,
};
test_begin("client reader");
/* register some stats */
test_init(settings_blob_1);
client_readers_init();
conn_list = connection_list_init(&client_set, &client_vfuncs);
/* push event in */
struct event *event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
test_event_send(event);
event_unref(&event);
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
/* check output from reader */
test_dump_metrics();
test_deinit();
client_readers_deinit();
connection_list_deinit(&conn_list);
test_end();
}
static const char *settings_blob_2 =
"metric=test\n"
"metric/test/metric_name=test\n"
"metric/test/filter=event=test\n"
"metric/test/group_by=test_name\n"
"\n";
static int
test_reader_server_input_args_group_by(struct connection *conn,
const char *const *args)
{
struct test_connection *tconn =
container_of(conn, struct test_connection, conn);
if (args[0] == NULL)
return -1;
tconn->row_count++;
if (tconn->row_count == 1) {
test_assert_strcmp(args[0], "test");
test_assert_strcmp(args[1], "1");
} else if (tconn->row_count == 2) {
test_assert_strcmp(args[0], "test_alpha");
test_assert_strcmp(args[1], "1");
}
return 1;
}
static void test_dump_metrics_group_by(void)
{
int fds[2];
test_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
struct test_connection *conn = i_new(struct test_connection, 1);
struct ioloop *loop = io_loop_create();
client_reader_create(fds[1]);
connection_init_client_fd(conn_list, &conn->conn, "stats", fds[0], fds[0]);
o_stream_nsend_str(conn->conn.output, "DUMP\tcount\n");
io_loop_run(loop);
connection_deinit(&conn->conn);
i_free(conn);
io_loop_set_running(loop);
io_loop_handler_run(loop);
io_loop_destroy(&loop);
}
static void test_client_reader_group_by(void)
{
const struct connection_vfuncs client_vfuncs = {
.input_args = test_reader_server_input_args_group_by,
.destroy = test_reader_server_destroy,
};
test_begin("client reader (group by)");
/* register some stats */
test_init(settings_blob_2);
client_readers_init();
conn_list = connection_list_init(&client_set, &client_vfuncs);
/* push event in */
struct event *event = event_create(NULL);
event_add_category(event, &test_category);
event_set_name(event, "test");
event_add_str(event, "event_name", "alpha");
test_event_send(event);
event_unref(&event);
test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
/* check output from reader */
test_dump_metrics_group_by();
test_deinit();
client_readers_deinit();
connection_list_deinit(&conn_list);
test_end();
}
int main(void) {
/* fake master service to pretend destroying
connections. */
struct master_service local_master_service = {
.stopping = TRUE,
.total_available_count = 100,
.service_count_left = 100,
};
void (*const test_functions[])(void) = {
test_client_reader,
test_client_reader_group_by,
NULL
};
master_service = &local_master_service;
int ret = test_run(test_functions);
return ret;
}
dovecot-2.3.21.1/src/stats/stats-settings.h 0000644 0000000 0000000 00000010015 14656633576 015404 0000000 0000000 #ifndef STATS_SETTINGS_H
#define STATS_SETTINGS_H
#define STATS_METRIC_SETTINGS_DEFAULT_EXPORTER_INCLUDE \
"name hostname timestamps categories fields"
/* */
/*
* We allow a selection of a timestamp format.
*
* The 'time-unix' format generates a number with the number of seconds
* since 1970-01-01 00:00 UTC.
*
* The 'time-rfc3339' format uses the YYYY-MM-DDTHH:MM:SS.uuuuuuZ format as
* defined by RFC 3339.
*
* The special native format (not explicitly selectable in the config, but
* default if no time-* token is used) uses the format's native timestamp
* format. Note that not all formats have a timestamp data format.
*
* The native format and the rules below try to address the question: can a
* parser that doesn't have any knowledge of fields' values' types losslessly
* reconstruct the fields?
*
* For example, JSON only has strings and numbers, so it cannot represent a
* timestamp in a "context-free lossless" way. Therefore, when making a
* JSON blob, we need to decide which way to serialize timestamps. No
* matter how we do it, we incur some loss. If a decoder sees 1557232304 in
* a field, it cannot be certain if the field is an integer that just
* happens to be a reasonable timestamp, or if it actually is a timestamp.
* Same goes with RFC3339 - it could just be that the user supplied a string
* that looks like a timestamp, and that string made it into an event field.
*
* Other common serialization formats, such as CBOR, have a lossless way of
* encoding timestamps.
*
* Note that there are two concepts at play: native and default.
*
* The rules for how the format's timestamp formats are used:
*
* 1. The default time format is the native format.
* 2. The native time format may or may not exist for a given format (e.g.,
* in JSON)
* 3. If the native format doesn't exist and no time format was specified in
* the config, it is a config error.
*
* We went with these rules because:
*
* 1. It prevents type information loss by default.
* 2. It completely isolates the policy from the algorithm.
* 3. It defers the decision whether each format without a native timestamp
* type should have a default acting as native until after we've had some
* operational experience.
* 4. A future decision to add a default (via 3. point) will be 100% compatible.
*/
enum event_exporter_time_fmt {
EVENT_EXPORTER_TIME_FMT_NATIVE = 0,
EVENT_EXPORTER_TIME_FMT_UNIX,
EVENT_EXPORTER_TIME_FMT_RFC3339,
};
/* */
struct stats_exporter_settings {
const char *name;
const char *transport;
const char *transport_args;
unsigned int transport_timeout;
const char *format;
const char *format_args;
/* parsed values */
enum event_exporter_time_fmt parsed_time_format;
};
/* */
enum stats_metric_group_by_func {
STATS_METRIC_GROUPBY_DISCRETE = 0,
STATS_METRIC_GROUPBY_QUANTIZED,
};
/*
* A range covering a stats bucket. The the interval is half closed - the
* minimum is excluded and the maximum is included. In other words: (min, max].
* Because we don't have a +Inf and -Inf, we use INTMAX_MIN and INTMAX_MAX
* respectively.
*/
struct stats_metric_settings_bucket_range {
intmax_t min;
intmax_t max;
};
struct stats_metric_settings_group_by {
const char *field;
enum stats_metric_group_by_func func;
unsigned int num_ranges;
struct stats_metric_settings_bucket_range *ranges;
};
/* */
struct stats_metric_settings {
const char *metric_name;
const char *description;
const char *fields;
const char *group_by;
const char *filter;
ARRAY(struct stats_metric_settings_group_by) parsed_group_by;
struct event_filter *parsed_filter;
/* exporter related fields */
const char *exporter;
const char *exporter_include;
};
struct stats_settings {
const char *stats_http_rawlog_dir;
ARRAY(struct stats_exporter_settings *) exporters;
ARRAY(struct stats_metric_settings *) metrics;
};
extern const struct setting_parser_info stats_setting_parser_info;
extern const struct setting_parser_info stats_metric_setting_parser_info;
#endif
dovecot-2.3.21.1/src/dns/ 0000755 0000000 0000000 00000000000 14656633640 011740 5 0000000 0000000 dovecot-2.3.21.1/src/dns/Makefile.in 0000644 0000000 0000000 00000062441 14656633607 013737 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = dns-client$(EXEEXT)
subdir = src/dns
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_dns_client_OBJECTS = dns-client.$(OBJEXT) \
dns-client-settings.$(OBJEXT)
dns_client_OBJECTS = $(am_dns_client_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/dns-client-settings.Po \
./$(DEPDIR)/dns-client.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(dns_client_SOURCES)
DIST_SOURCES = $(dns_client_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-settings \
$(BINARY_CFLAGS)
dns_client_LDADD = $(LIBDOVECOT) \
$(BINARY_LDFLAGS)
dns_client_DEPENDENCIES = $(LIBDOVECOT_DEPS)
dns_client_SOURCES = \
dns-client.c \
dns-client-settings.c
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/dns/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/dns/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
dns-client$(EXEEXT): $(dns_client_OBJECTS) $(dns_client_DEPENDENCIES) $(EXTRA_dns_client_DEPENDENCIES)
@rm -f dns-client$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(dns_client_OBJECTS) $(dns_client_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns-client-settings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns-client.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/dns-client-settings.Po
-rm -f ./$(DEPDIR)/dns-client.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/dns-client-settings.Po
-rm -f ./$(DEPDIR)/dns-client.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-pkglibexecPROGRAMS install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/dns/dns-client.c 0000644 0000000 0000000 00000011227 14656633576 014077 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "ostream.h"
#include "array.h"
#include "strfuncs.h"
#include "connection.h"
#include "restrict-access.h"
#include "master-service.h"
#include
static struct event_category event_category_dns = {
.name = "dns-worker"
};
static struct connection_list *dns_clients = NULL;
static int dns_client_input_args(struct connection *client, const char *const *args)
{
struct ip_addr *ips, ip;
const char *name;
struct event *event;
unsigned int i, ips_count;
int ret;
struct event_passthrough *e;
if (strcmp(args[0], "QUIT") == 0) {
return -1;
} else if (args[1] == NULL) {
e_error(client->event, "Got empty request");
return -1;
}
event = event_create(client->event);
event_set_append_log_prefix(event, t_strconcat(args[1], ": ", NULL));
e = event_create_passthrough(event)->
set_name("dns_worker_request_started")->
add_str("name", args[1]);
e_debug(e->event(), "Resolving");
e = event_create_passthrough(event)->
set_name("dns_worker_request_finished")->
add_str("name", args[1]);
if (strcmp(args[0], "IP") == 0) {
ret = net_gethostbyname(args[1], &ips, &ips_count);
if (ret == 0 && ips_count == 0) {
/* shouldn't happen, but fix it anyway.. */
ret = EAI_NONAME;
}
/* update timestamp after hostname lookup so the event duration
field gets set correctly */
io_loop_time_refresh();
if (ret != 0) {
const char *err = net_gethosterror(ret);
e->add_int("error_code", ret);
e->add_str("error", err);
e_debug(e->event(), "Resolve failed: %s", err);
o_stream_nsend_str(client->output,
t_strdup_printf("%d\t%s\n", ret, err));
} else {
ARRAY_TYPE(const_string) tmp;
t_array_init(&tmp, ips_count);
o_stream_nsend_str(client->output, "0\t");
for (i = 0; i < ips_count; i++) {
const char *ip = net_ip2addr(&ips[i]);
array_push_back(&tmp, &ip);
}
array_append_zero(&tmp);
e_debug(e->event(), "Resolve success: %s",
t_strarray_join(array_front(&tmp), ", "));
o_stream_nsend_str(client->output,
t_strarray_join(array_front(&tmp), "\t"));
o_stream_nsend_str(client->output, "\n");
}
} else if (strcmp(args[0], "NAME") == 0) {
if (net_addr2ip(args[1], &ip) < 0) {
e->add_int("error_code", EAI_FAIL);
e->add_str("error", "Not an IP");
e_debug(e->event(), "Resolve failed: Not an IP");
o_stream_nsend_str(client->output, "-1\tNot an IP\n");
} else if ((ret = net_gethostbyaddr(&ip, &name)) != 0) {
const char *err = net_gethosterror(ret);
e->add_int("error_code", ret);
e->add_str("error", err);
e_debug(e->event(), "Resolve failed: %s", err);
o_stream_nsend_str(client->output,
t_strdup_printf("%d\t%s\n", ret, err));
} else {
e_debug(e->event(), "Resolve success: %s", name);
o_stream_nsend_str(client->output,
t_strdup_printf("0\t%s\n", name));
}
} else {
e->add_str("error", "Unknown command");
e_error(e->event(), "Unknown command '%s'", args[0]);
o_stream_nsend_str(client->output, "-1\tUnknown command\n");
}
event_unref(&event);
return 1;
}
static void dns_client_destroy(struct connection *client)
{
connection_deinit(client);
event_unref(&client->event);
i_free(client);
master_service_client_connection_destroyed(master_service);
}
static const struct connection_vfuncs dns_client_vfuncs = {
.input_args = dns_client_input_args,
.destroy = dns_client_destroy
};
static const struct connection_settings dns_client_set = {
.service_name_in = "dns-client",
.service_name_out = "dns",
.major_version = 1,
.minor_version = 0,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX
};
static void client_connected(struct master_service_connection *master_conn)
{
struct connection *conn = i_new(struct connection, 1);
master_service_client_connection_accept(master_conn);
connection_init_server(dns_clients, conn, master_conn->name,
master_conn->fd, master_conn->fd);
event_add_category(conn->event, &event_category_dns);
}
int main(int argc, char *argv[])
{
master_service = master_service_init("dns-client", 0,
&argc, &argv, "");
if (master_getopt(master_service) > 0)
return FATAL_DEFAULT;
master_service_init_log(master_service);
restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
restrict_access_allow_coredumps(TRUE);
/* setup connection list */
dns_clients = connection_list_init(&dns_client_set, &dns_client_vfuncs);
master_service_init_finish(master_service);
master_service_run(master_service, client_connected);
/* disconnect all clients */
connection_list_deinit(&dns_clients);
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/dns/Makefile.am 0000644 0000000 0000000 00000000557 14656633576 013733 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = dns-client
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-settings \
$(BINARY_CFLAGS)
dns_client_LDADD = $(LIBDOVECOT) \
$(BINARY_LDFLAGS)
dns_client_DEPENDENCIES = $(LIBDOVECOT_DEPS)
dns_client_SOURCES = \
dns-client.c \
dns-client-settings.c
dovecot-2.3.21.1/src/dns/dns-client-settings.c 0000644 0000000 0000000 00000002353 14656633576 015735 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include
/* */
static struct file_listener_settings dns_client_unix_listeners_array[] = {
{ "dns-client", 0666, "", "" },
{ "login/dns-client", 0666, "", "" },
};
static struct file_listener_settings *dns_client_unix_listeners[] = {
&dns_client_unix_listeners_array[0],
&dns_client_unix_listeners_array[1],
};
static buffer_t dns_client_unix_listeners_buf = {
{ { dns_client_unix_listeners, sizeof(dns_client_unix_listeners) } }
};
/* */
struct service_settings dns_client_service_settings = {
.name = "dns-client",
.protocol = "",
.type = "",
.executable = "dns-client",
.user = "$default_internal_user",
.group = "",
.privileged_group = "",
.extra_groups = "",
.chroot = "",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 0,
.client_limit = 1,
.service_count = 0,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &dns_client_unix_listeners_buf,
sizeof(dns_client_unix_listeners[0]) } },
.fifo_listeners = ARRAY_INIT,
.inet_listeners = ARRAY_INIT
};
dovecot-2.3.21.1/src/lda/ 0000755 0000000 0000000 00000000000 14656633640 011714 5 0000000 0000000 dovecot-2.3.21.1/src/lda/Makefile.in 0000644 0000000 0000000 00000063420 14656633610 013703 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = dovecot-lda$(EXEEXT)
subdir = src/lda
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_dovecot_lda_OBJECTS = main.$(OBJEXT)
dovecot_lda_OBJECTS = $(am_dovecot_lda_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
dovecot_lda_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(dovecot_lda_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/main.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(dovecot_lda_SOURCES)
DIST_SOURCES = $(dovecot_lda_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-smtp \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-smtp \
-I$(top_srcdir)/src/lib-lda \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index \
-I$(top_srcdir)/src/lib-storage/index/raw \
$(BINARY_CFLAGS)
dovecot_lda_LDFLAGS = -export-dynamic
dovecot_lda_LDADD = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT) \
$(BINARY_LDFLAGS)
dovecot_lda_DEPENDENCIES = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
dovecot_lda_SOURCES = \
main.c
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lda/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/lda/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
dovecot-lda$(EXEEXT): $(dovecot_lda_OBJECTS) $(dovecot_lda_DEPENDENCIES) $(EXTRA_dovecot_lda_DEPENDENCIES)
@rm -f dovecot-lda$(EXEEXT)
$(AM_V_CCLD)$(dovecot_lda_LINK) $(dovecot_lda_OBJECTS) $(dovecot_lda_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/main.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-exec-local install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/main.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-exec-local install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-pkglibexecPROGRAMS \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am \
uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
install-exec-local:
rm -f $(DESTDIR)$(pkglibexecdir)/deliver
$(LN_S) dovecot-lda $(DESTDIR)$(pkglibexecdir)/deliver
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/lda/main.c 0000644 0000000 0000000 00000037644 14656633576 012752 0000000 0000000 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "lib-signals.h"
#include "ioloop.h"
#include "env-util.h"
#include "istream.h"
#include "istream-seekable.h"
#include "path-util.h"
#include "safe-mkstemp.h"
#include "eacces-error.h"
#include "ipwd.h"
#include "str.h"
#include "str-sanitize.h"
#include "strescape.h"
#include "unichar.h"
#include "rfc822-parser.h"
#include "message-address.h"
#include "smtp-address.h"
#include "settings-parser.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "mail-storage-service.h"
#include "mail-namespace.h"
#include "raw-storage.h"
#include "mail-deliver.h"
#include "mail-send.h"
#include "mbox-from.h"
#include "smtp-submit-settings.h"
#include "lda-settings.h"
#include
#include
const struct smtp_address default_envelope_sender = {
.localpart = "MAILER-DAEMON",
};
/* After buffer grows larger than this, create a temporary file to /tmp
where to read the mail. */
#define MAIL_MAX_MEMORY_BUFFER (1024*128)
struct event_category event_category_lda = {
.name = "lda",
};
static const char *wanted_headers[] = {
"From", "To", "Message-ID", "Subject", "Return-Path",
NULL
};
static int seekable_fd_callback(const char **path_r, void *context)
{
struct mail_deliver_input *dinput = context;
string_t *path;
int fd;
path = t_str_new(128);
mail_user_set_get_temp_prefix(path, dinput->rcpt_user->set);
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
if (fd == -1) {
i_error("safe_mkstemp(%s) failed: %m", str_c(path));
return -1;
}
/* we just want the fd, unlink it */
if (i_unlink(str_c(path)) < 0) {
/* shouldn't happen.. */
i_close_fd(&fd);
return -1;
}
*path_r = str_c(path);
return fd;
}
static struct istream *
create_raw_stream(struct mail_deliver_input *dinput,
int fd, time_t *mtime_r)
{
struct istream *input, *input2, *input_list[2];
const unsigned char *data;
const char *error;
char *sender = NULL;
size_t i, size;
int ret, tz;
*mtime_r = (time_t)-1;
fd_set_nonblock(fd, FALSE);
input = i_stream_create_fd(fd, 4096);
input->blocking = TRUE;
/* If input begins with a From-line, drop it */
ret = i_stream_read_bytes(input, &data, &size, 5);
if (ret > 0 && memcmp(data, "From ", 5) == 0) {
/* skip until the first LF */
i_stream_skip(input, 5);
while (i_stream_read_more(input, &data, &size) > 0) {
for (i = 0; i < size; i++) {
if (data[i] == '\n')
break;
}
if (i != size) {
(void)mbox_from_parse(data, i, mtime_r, &tz,
&sender);
i_stream_skip(input, i + 1);
break;
}
i_stream_skip(input, size);
}
}
if (sender != NULL && dinput->mail_from == NULL) {
struct smtp_address *mail_from = NULL;
/* use the envelope sender from From_-line, but only if it
hasn't been specified with -f already. */
if (smtp_address_parse_mailbox(pool_datastack_create(),
sender, 0, &mail_from,
&error) < 0) {
i_warning("Failed to parse address from `From_'-line: %s",
error);
}
dinput->mail_from = mail_from;
}
i_free(sender);
if (input->v_offset == 0) {
input2 = input;
i_stream_ref(input2);
} else {
input2 = i_stream_create_limit(input, UOFF_T_MAX);
}
i_stream_unref(&input);
input_list[0] = input2; input_list[1] = NULL;
input = i_stream_create_seekable(input_list, MAIL_MAX_MEMORY_BUFFER,
seekable_fd_callback, dinput);
i_stream_unref(&input2);
return input;
}
static struct mail *
lda_raw_mail_open(struct mail_deliver_input *dinput, const char *path)
{
struct mail_user *raw_mail_user;
struct mailbox *box;
struct mailbox_transaction_context *t;
struct mail *mail;
struct mailbox_header_lookup_ctx *headers_ctx;
const struct smtp_address *mail_from;
struct istream *input;
void **sets;
time_t mtime;
int ret;
sets = master_service_settings_get_others(master_service);
raw_mail_user = raw_storage_create_from_set(dinput->rcpt_user->set_info,
sets[0]);
mail_from = (dinput->mail_from != NULL ?
dinput->mail_from : &default_envelope_sender);
if (path == NULL) {
input = create_raw_stream(dinput, 0, &mtime);
i_stream_set_name(input, "stdin");
ret = raw_mailbox_alloc_stream(raw_mail_user, input, mtime,
smtp_address_encode(mail_from), &box);
i_stream_unref(&input);
} else {
ret = raw_mailbox_alloc_path(raw_mail_user, path, (time_t)-1,
smtp_address_encode(mail_from), &box);
}
if (ret < 0) {
i_fatal("Can't open delivery mail as raw: %s",
mailbox_get_last_internal_error(box, NULL));
}
mail_user_unref(&raw_mail_user);
t = mailbox_transaction_begin(box, 0, __func__);
headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
mail = mail_alloc(t, 0, headers_ctx);
mailbox_header_lookup_unref(&headers_ctx);
mail_set_seq(mail, 1);
return mail;
}
static void
lda_set_rcpt_to(struct mail_deliver_input *dinput,
const struct smtp_address *rcpt_to, const char *user,
const char *rcpt_to_source)
{
const char *error;
if (rcpt_to == NULL &&
*dinput->set->lda_original_recipient_header != '\0') {
rcpt_to = mail_deliver_get_address(
dinput->src_mail,
dinput->set->lda_original_recipient_header);
rcpt_to_source = t_strconcat(
dinput->set->lda_original_recipient_header,
" header", NULL);
}
if (rcpt_to == NULL) {
struct smtp_address *user_addr;
if (smtp_address_parse_username(pool_datastack_create(), user,
&user_addr, &error) < 0) {
i_fatal_status(EX_USAGE,
"Cannot obtain SMTP address from username `%s': %s",
user, error);
}
if (user_addr->domain == NULL)
user_addr->domain = dinput->set->hostname;
rcpt_to = user_addr;
rcpt_to_source = "user@hostname";
}
dinput->rcpt_params.orcpt.addr = rcpt_to;
if (dinput->rcpt_to == NULL)
dinput->rcpt_to = rcpt_to;
e_debug(dinput->rcpt_user->event,
"Destination address: %s (source: %s)",
smtp_address_encode_path(rcpt_to), rcpt_to_source);
}
static int
lda_do_deliver(struct mail_deliver_context *ctx, bool stderr_rejection)
{
enum mail_deliver_error error_code;
const char *error;
int ret;
if (mail_deliver(ctx, &error_code, &error) >= 0)
return EX_OK;
if (error_code == MAIL_DELIVER_ERROR_INTERNAL) {
/* This shouldn't happen */
return EX_TEMPFAIL;
}
if (stderr_rejection) {
/* write to stderr also for tempfails so that MTA
can log the reason if it wants to. */
fprintf(stderr, "%s\n", error);
}
switch (error_code) {
case MAIL_DELIVER_ERROR_NONE:
i_unreached();
case MAIL_DELIVER_ERROR_TEMPORARY:
return EX_TEMPFAIL;
case MAIL_DELIVER_ERROR_REJECTED:
break;
case MAIL_DELIVER_ERROR_NOQUOTA:
if (ctx->set->quota_full_tempfail)
return EX_TEMPFAIL;
ctx->mailbox_full = TRUE;
break;
case MAIL_DELIVER_ERROR_INTERNAL:
i_unreached();
}
/* Rejected */
ctx->dsn = TRUE;
/* we'll have to reply with permanent failure */
mail_deliver_log(ctx, "rejected: %s",
str_sanitize(error, 512));
if (stderr_rejection)
return EX_NOPERM;
ret = mail_send_rejection(ctx, ctx->rcpt_to, error);
if (ret != 0)
return ret < 0 ? EX_TEMPFAIL : ret;
/* ok, rejection sent */
return EX_OK;
}
static int
lda_deliver(struct mail_deliver_input *dinput,
struct mail_storage_service_user *service_user,
const char *user, const char *path,
struct smtp_address *rcpt_to, const char *rcpt_to_source,
bool stderr_rejection)
{
struct mail_deliver_context ctx;
const struct var_expand_table *var_table;
struct lda_settings *lda_set;
struct smtp_submit_settings *smtp_set;
const char *errstr;
int ret;
var_table = mail_user_var_expand_table(dinput->rcpt_user);
smtp_set = mail_storage_service_user_get_set(service_user)[1];
lda_set = mail_storage_service_user_get_set(service_user)[2];
ret = settings_var_expand(
&lda_setting_parser_info,
lda_set, dinput->rcpt_user->pool, var_table,
&errstr);
if (ret > 0) {
ret = settings_var_expand(
&smtp_submit_setting_parser_info,
smtp_set, dinput->rcpt_user->pool, var_table,
&errstr);
}
if (ret <= 0)
i_fatal("Failed to expand settings: %s", errstr);
dinput->set = lda_set;
dinput->smtp_set = smtp_set;
dinput->src_mail = lda_raw_mail_open(dinput, path);
lda_set_rcpt_to(dinput, rcpt_to, user, rcpt_to_source);
mail_deliver_init(&ctx, dinput);
ret = lda_do_deliver(&ctx, stderr_rejection);
mail_deliver_deinit(&ctx);
return ret;
}
static void failure_exit_callback(int *status)
{
/* we want all our exit codes to be sysexits.h compatible.
if we failed because of a logging related error, we most likely
aren't writing to stderr, so try writing there to give some kind of
a clue what's wrong. FATAL_LOGOPEN failure already wrote to
stderr, so don't duplicate it. */
switch (*status) {
case FATAL_LOGWRITE:
fputs("Failed to write to log file", stderr);
break;
case FATAL_LOGERROR:
fputs("Internal logging error", stderr);
break;
case FATAL_LOGOPEN:
case FATAL_OUTOFMEM:
case FATAL_EXEC:
case FATAL_DEFAULT:
break;
default:
return;
}
*status = EX_TEMPFAIL;
}
static void print_help(void)
{
printf(
"Usage: dovecot-lda [-c ] [-d ] [-p ]\n"
" [-m ] [-e] [-k] [-f ]\n"
" [-a ]\n"
" [-r ] \n");
}
int main(int argc, char *argv[])
{
const struct setting_parser_info *set_roots[] = {
&smtp_submit_setting_parser_info,
&lda_setting_parser_info,
NULL
};
struct mail_deliver_input dinput;
enum mail_storage_service_flags service_flags = 0;
const char *user, *errstr, *path;
struct smtp_address *rcpt_to, *final_rcpt_to, *mail_from;
struct mail_storage_service_ctx *storage_service;
struct mail_storage_service_user *service_user;
struct mail_storage_service_input service_input;
struct event *event;
const char *user_source = "", *rcpt_to_source = "", *mail_from_error;
uid_t process_euid;
bool stderr_rejection = FALSE;
int ret, c;
if (getuid() != geteuid() && geteuid() == 0) {
/* running setuid - don't allow this if the binary is
executable by anyone */
struct stat st;
if (stat(argv[0], &st) < 0) {
fprintf(stderr, "stat(%s) failed: %s\n",
argv[0], strerror(errno));
return EX_TEMPFAIL;
} else if ((st.st_mode & 1) != 0 && (st.st_mode & 04000) != 0) {
fprintf(stderr, "%s must not be both world-executable "
"and setuid-root. This allows root exploits. "
"See http://wiki2.dovecot.org/LDA#multipleuids\n",
argv[0]);
return EX_TEMPFAIL;
}
}
i_set_failure_exit_callback(failure_exit_callback);
master_service = master_service_init("lda",
MASTER_SERVICE_FLAG_STANDALONE |
MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR |
MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME,
&argc, &argv, "a:d:ef:m:p:r:");
event = event_create(NULL);
event_add_category(event, &event_category_lda);
i_zero(&dinput);
dinput.session = mail_deliver_session_init();
dinput.rcpt_default_mailbox = "INBOX";
path = NULL;
user = getenv("USER");
mail_from = final_rcpt_to = rcpt_to = NULL;
mail_from_error = NULL;
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'a':
/* original recipient address */
if (smtp_address_parse_path(
pool_datastack_create(), optarg,
SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART |
SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL,
&rcpt_to, &errstr) < 0) {
i_fatal_status(EX_USAGE,
"Invalid -a parameter: %s", errstr);
}
rcpt_to_source = "-a parameter";
break;
case 'd':
/* destination user */
user = optarg;
service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
break;
case 'e':
stderr_rejection = TRUE;
break;
case 'f':
/* envelope sender address */
ret = smtp_address_parse_path(
pool_datastack_create(), optarg,
SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL |
SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART |
SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY |
SMTP_ADDRESS_PARSE_FLAG_IGNORE_BROKEN |
SMTP_ADDRESS_PARSE_FLAG_PRESERVE_RAW,
&mail_from, &errstr);
if (ret < 0 && !smtp_address_is_broken(mail_from)) {
i_fatal_status(EX_USAGE,
"Invalid -f parameter: %s", errstr);
}
if (ret < 0)
mail_from_error = errstr;
break;
case 'm':
/* destination mailbox.
Ignore -m "". This allows doing -m ${extension}
in Postfix to handle user+mailbox */
if (*optarg != '\0') T_BEGIN {
if (!uni_utf8_str_is_valid(optarg)) {
i_fatal("Mailbox name not UTF-8: %s",
optarg);
}
dinput.rcpt_default_mailbox = optarg;
} T_END;
break;
case 'p':
/* input path */
if (t_abspath(optarg, &path, &errstr) < 0) {
i_fatal("t_abspath(%s) failed: %s",
optarg, errstr);
}
break;
case 'r':
/* final recipient address */
if (smtp_address_parse_path(
pool_datastack_create(), optarg,
SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART |
SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL,
&final_rcpt_to, &errstr) < 0) {
i_fatal_status(EX_USAGE,
"Invalid -r parameter: %s", errstr);
}
break;
default:
print_help();
return EX_USAGE;
}
}
if (optind != argc) {
print_help();
i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
}
process_euid = geteuid();
if ((service_flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0)
;
else if (process_euid != 0) {
/* we're non-root. get our username and possibly our home. */
struct passwd pw;
const char *home;
home = getenv("HOME");
if (user != NULL && home != NULL) {
/* no need for a pw lookup */
user_source = "USER environment";
} else if ((ret = i_getpwuid(process_euid, &pw)) > 0) {
user = t_strdup(pw.pw_name);
if (home == NULL)
env_put("HOME", pw.pw_dir);
user_source = "passwd lookup for process euid";
} else if (ret < 0) {
/* temporary failure */
i_fatal("getpwuid() failed: %m");
} else if (user == NULL) {
i_fatal_status(EX_USAGE,
"Couldn't lookup our username (uid=%s)",
dec2str(process_euid));
}
} else {
i_fatal_status(EX_USAGE,
"destination user parameter (-d user) not given");
}
master_service_init_finish(master_service);
dinput.mail_from = mail_from;
dinput.rcpt_to = final_rcpt_to;
event_add_str(event, "protocol", "lda");
event_add_str(event, "user", user);
if (mail_from != NULL) {
event_add_str(event, "mail_from",
smtp_address_encode(mail_from));
}
if (final_rcpt_to != NULL) {
event_add_str(event, "rcpt_to",
smtp_address_encode(final_rcpt_to));
}
dinput.event_parent = event;
i_zero(&service_input);
service_input.module = "lda";
service_input.service = "lda";
service_input.username = user;
service_input.event_parent = event;
service_flags |= MAIL_STORAGE_SERVICE_FLAG_USE_SYSEXITS;
storage_service = mail_storage_service_init(master_service, set_roots,
service_flags);
mail_deliver_hooks_init();
/* set before looking up the user (or ideally we'd do this between
_lookup() and _next(), but don't bother) */
dinput.delivery_time_started = ioloop_timeval;
ret = mail_storage_service_lookup_next(storage_service,
&service_input, &service_user,
&dinput.rcpt_user,
&errstr);
if (ret <= 0) {
if (ret < 0)
i_fatal("%s", errstr);
ret = EX_NOUSER;
} else {
#ifdef SIGXFSZ
lib_signals_ignore(SIGXFSZ, TRUE);
#endif
if (*user_source != '\0') {
e_debug(dinput.rcpt_user->event,
"userdb lookup skipped, username taken from %s",
user_source);
}
if (mail_from_error != NULL) {
e_debug(event, "Broken -f parameter: %s "
"(proceeding with <> as sender)",
mail_from_error);
}
ret = lda_deliver(&dinput, service_user, user, path,
rcpt_to, rcpt_to_source, stderr_rejection);
struct mailbox_transaction_context *t =
dinput.src_mail->transaction;
struct mailbox *box = dinput.src_mail->box;
mail_free(&dinput.src_mail);
mailbox_transaction_rollback(&t);
mailbox_free(&box);
mail_user_deinit(&dinput.rcpt_user);
mail_storage_service_user_unref(&service_user);
}
mail_deliver_session_deinit(&dinput.session);
mail_storage_service_deinit(&storage_service);
event_unref(&event);
master_service_deinit(&master_service);
return ret;
}
dovecot-2.3.21.1/src/lda/Makefile.am 0000644 0000000 0000000 00000001623 14656633576 013702 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = dovecot-lda
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-smtp \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-smtp \
-I$(top_srcdir)/src/lib-lda \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index \
-I$(top_srcdir)/src/lib-storage/index/raw \
$(BINARY_CFLAGS)
dovecot_lda_LDFLAGS = -export-dynamic
dovecot_lda_LDADD = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT) \
$(BINARY_LDFLAGS)
dovecot_lda_DEPENDENCIES = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
dovecot_lda_SOURCES = \
main.c
install-exec-local:
rm -f $(DESTDIR)$(pkglibexecdir)/deliver
$(LN_S) dovecot-lda $(DESTDIR)$(pkglibexecdir)/deliver
dovecot-2.3.21.1/src/lib-sql/ 0000755 0000000 0000000 00000000000 14656633637 012525 5 0000000 0000000 dovecot-2.3.21.1/src/lib-sql/sql-api.c 0000644 0000000 0000000 00000047431 14656633576 014172 0000000 0000000 /* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "hash.h"
#include "str.h"
#include "time-util.h"
#include "sql-api-private.h"
#include
struct event_category event_category_sql = {
.name = "sql",
};
struct sql_db_module_register sql_db_module_register = { 0 };
ARRAY_TYPE(sql_drivers) sql_drivers;
void sql_drivers_init(void)
{
i_array_init(&sql_drivers, 8);
}
void sql_drivers_deinit(void)
{
array_free(&sql_drivers);
}
static const struct sql_db *sql_driver_lookup(const char *name)
{
const struct sql_db *const *drivers;
unsigned int i, count;
drivers = array_get(&sql_drivers, &count);
for (i = 0; i < count; i++) {
if (strcmp(drivers[i]->name, name) == 0)
return drivers[i];
}
return NULL;
}
void sql_driver_register(const struct sql_db *driver)
{
if (sql_driver_lookup(driver->name) != NULL) {
i_fatal("sql_driver_register(%s): Already registered",
driver->name);
}
array_push_back(&sql_drivers, &driver);
}
void sql_driver_unregister(const struct sql_db *driver)
{
const struct sql_db *const *drivers;
unsigned int i, count;
drivers = array_get(&sql_drivers, &count);
for (i = 0; i < count; i++) {
if (drivers[i] == driver) {
array_delete(&sql_drivers, i, 1);
break;
}
}
}
struct sql_db *sql_init(const char *db_driver, const char *connect_string)
{
const char *error;
struct sql_db *db;
struct sql_settings set = {
.driver = db_driver,
.connect_string = connect_string,
};
if (sql_init_full(&set, &db, &error) < 0)
i_fatal("%s", error);
return db;
}
int sql_init_full(const struct sql_settings *set, struct sql_db **db_r,
const char **error_r)
{
const struct sql_db *driver;
struct sql_db *db;
int ret = 0;
i_assert(set->connect_string != NULL);
driver = sql_driver_lookup(set->driver);
if (driver == NULL) {
*error_r = t_strdup_printf("Unknown database driver '%s'", set->driver);
return -1;
}
if ((driver->flags & SQL_DB_FLAG_POOLED) == 0) {
if (driver->v.init_full == NULL) {
db = driver->v.init(set->connect_string);
} else
ret = driver->v.init_full(set, &db, error_r);
} else
ret = driver_sqlpool_init_full(set, driver, &db, error_r);
if (ret < 0)
return -1;
sql_init_common(db);
*db_r = db;
return 0;
}
void sql_init_common(struct sql_db *db)
{
db->refcount = 1;
i_array_init(&db->module_contexts, 5);
hash_table_create(&db->prepared_stmt_hash, default_pool, 0,
str_hash, strcmp);
}
void sql_ref(struct sql_db *db)
{
i_assert(db->refcount > 0);
db->refcount++;
}
static void
default_sql_prepared_statement_deinit(struct sql_prepared_statement *prep_stmt)
{
i_free(prep_stmt->query_template);
i_free(prep_stmt);
}
static void sql_prepared_statements_free(struct sql_db *db)
{
struct hash_iterate_context *iter;
struct sql_prepared_statement *prep_stmt;
char *query;
iter = hash_table_iterate_init(db->prepared_stmt_hash);
while (hash_table_iterate(iter, db->prepared_stmt_hash, &query, &prep_stmt)) {
i_assert(prep_stmt->refcount == 0);
if (prep_stmt->db->v.prepared_statement_deinit != NULL)
prep_stmt->db->v.prepared_statement_deinit(prep_stmt);
else
default_sql_prepared_statement_deinit(prep_stmt);
}
hash_table_iterate_deinit(&iter);
hash_table_clear(db->prepared_stmt_hash, TRUE);
}
void sql_unref(struct sql_db **_db)
{
struct sql_db *db = *_db;
*_db = NULL;
i_assert(db->refcount > 0);
if (db->v.unref != NULL)
db->v.unref(db);
if (--db->refcount > 0)
return;
timeout_remove(&db->to_reconnect);
sql_prepared_statements_free(db);
hash_table_destroy(&db->prepared_stmt_hash);
db->v.deinit(db);
}
enum sql_db_flags sql_get_flags(struct sql_db *db)
{
if (db->v.get_flags != NULL)
return db->v.get_flags(db);
else
return db->flags;
}
int sql_connect(struct sql_db *db)
{
time_t now;
switch (db->state) {
case SQL_DB_STATE_DISCONNECTED:
break;
case SQL_DB_STATE_CONNECTING:
return 0;
default:
return 1;
}
/* don't try reconnecting more than once a second */
now = time(NULL);
if (db->last_connect_try + (time_t)db->connect_delay > now)
return -1;
db->last_connect_try = now;
return db->v.connect(db);
}
void sql_disconnect(struct sql_db *db)
{
timeout_remove(&db->to_reconnect);
db->v.disconnect(db);
}
const char *sql_escape_string(struct sql_db *db, const char *string)
{
return db->v.escape_string(db, string);
}
const char *sql_escape_blob(struct sql_db *db,
const unsigned char *data, size_t size)
{
return db->v.escape_blob(db, data, size);
}
void sql_exec(struct sql_db *db, const char *query)
{
db->v.exec(db, query);
}
#undef sql_query
void sql_query(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context)
{
db->v.query(db, query, callback, context);
}
struct sql_result *sql_query_s(struct sql_db *db, const char *query)
{
return db->v.query_s(db, query);
}
static struct sql_prepared_statement *
default_sql_prepared_statement_init(struct sql_db *db,
const char *query_template)
{
struct sql_prepared_statement *prep_stmt;
prep_stmt = i_new(struct sql_prepared_statement, 1);
prep_stmt->db = db;
prep_stmt->refcount = 1;
prep_stmt->query_template = i_strdup(query_template);
return prep_stmt;
}
static struct sql_statement *
default_sql_statement_init_prepared(struct sql_prepared_statement *stmt)
{
return sql_statement_init(stmt->db, stmt->query_template);
}
const char *sql_statement_get_log_query(struct sql_statement *stmt)
{
if (stmt->no_log_expanded_values)
return stmt->query_template;
return sql_statement_get_query(stmt);
}
const char *sql_statement_get_query(struct sql_statement *stmt)
{
string_t *query = t_str_new(128);
const char *const *args;
unsigned int i, args_count, arg_pos = 0;
args = array_get(&stmt->args, &args_count);
for (i = 0; stmt->query_template[i] != '\0'; i++) {
if (stmt->query_template[i] == '?') {
if (arg_pos >= args_count ||
args[arg_pos] == NULL) {
i_panic("lib-sql: Missing bind for arg #%u in statement: %s",
arg_pos, stmt->query_template);
}
str_append(query, args[arg_pos++]);
} else {
str_append_c(query, stmt->query_template[i]);
}
}
if (arg_pos != args_count) {
i_panic("lib-sql: Too many bind args (%u) for statement: %s",
args_count, stmt->query_template);
}
return str_c(query);
}
static void
default_sql_statement_query(struct sql_statement *stmt,
sql_query_callback_t *callback, void *context)
{
sql_query(stmt->db, sql_statement_get_query(stmt),
callback, context);
pool_unref(&stmt->pool);
}
static struct sql_result *
default_sql_statement_query_s(struct sql_statement *stmt)
{
struct sql_result *result =
sql_query_s(stmt->db, sql_statement_get_query(stmt));
pool_unref(&stmt->pool);
return result;
}
static void default_sql_update_stmt(struct sql_transaction_context *ctx,
struct sql_statement *stmt,
unsigned int *affected_rows)
{
ctx->db->v.update(ctx, sql_statement_get_query(stmt),
affected_rows);
pool_unref(&stmt->pool);
}
struct sql_prepared_statement *
sql_prepared_statement_init(struct sql_db *db, const char *query_template)
{
struct sql_prepared_statement *stmt;
stmt = hash_table_lookup(db->prepared_stmt_hash, query_template);
if (stmt != NULL) {
stmt->refcount++;
return stmt;
}
if (db->v.prepared_statement_init != NULL)
stmt = db->v.prepared_statement_init(db, query_template);
else
stmt = default_sql_prepared_statement_init(db, query_template);
hash_table_insert(db->prepared_stmt_hash, stmt->query_template, stmt);
return stmt;
}
void sql_prepared_statement_unref(struct sql_prepared_statement **_prep_stmt)
{
struct sql_prepared_statement *prep_stmt = *_prep_stmt;
*_prep_stmt = NULL;
i_assert(prep_stmt->refcount > 0);
prep_stmt->refcount--;
}
static void
sql_statement_init_fields(struct sql_statement *stmt, struct sql_db *db)
{
stmt->db = db;
p_array_init(&stmt->args, stmt->pool, 8);
}
struct sql_statement *
sql_statement_init(struct sql_db *db, const char *query_template)
{
struct sql_statement *stmt;
if (db->v.statement_init != NULL)
stmt = db->v.statement_init(db, query_template);
else {
pool_t pool = pool_alloconly_create("sql statement", 1024);
stmt = p_new(pool, struct sql_statement, 1);
stmt->pool = pool;
}
stmt->query_template = p_strdup(stmt->pool, query_template);
sql_statement_init_fields(stmt, db);
return stmt;
}
struct sql_statement *
sql_statement_init_prepared(struct sql_prepared_statement *prep_stmt)
{
struct sql_statement *stmt;
if (prep_stmt->db->v.statement_init_prepared == NULL)
return default_sql_statement_init_prepared(prep_stmt);
stmt = prep_stmt->db->v.statement_init_prepared(prep_stmt);
sql_statement_init_fields(stmt, prep_stmt->db);
return stmt;
}
void sql_statement_abort(struct sql_statement **_stmt)
{
struct sql_statement *stmt = *_stmt;
*_stmt = NULL;
if (stmt->db->v.statement_abort != NULL)
stmt->db->v.statement_abort(stmt);
pool_unref(&stmt->pool);
}
void sql_statement_set_timestamp(struct sql_statement *stmt,
const struct timespec *ts)
{
if (stmt->db->v.statement_set_timestamp != NULL)
stmt->db->v.statement_set_timestamp(stmt, ts);
}
void sql_statement_set_no_log_expanded_values(struct sql_statement *stmt,
bool no_expand)
{
stmt->no_log_expanded_values = no_expand;
}
void sql_statement_bind_str(struct sql_statement *stmt,
unsigned int column_idx, const char *value)
{
const char *escaped_value =
p_strdup_printf(stmt->pool, "'%s'",
sql_escape_string(stmt->db, value));
array_idx_set(&stmt->args, column_idx, &escaped_value);
if (stmt->db->v.statement_bind_str != NULL)
stmt->db->v.statement_bind_str(stmt, column_idx, value);
}
void sql_statement_bind_binary(struct sql_statement *stmt,
unsigned int column_idx, const void *value,
size_t value_size)
{
const char *value_str =
p_strdup_printf(stmt->pool, "%s",
sql_escape_blob(stmt->db, value, value_size));
array_idx_set(&stmt->args, column_idx, &value_str);
if (stmt->db->v.statement_bind_binary != NULL) {
stmt->db->v.statement_bind_binary(stmt, column_idx,
value, value_size);
}
}
void sql_statement_bind_int64(struct sql_statement *stmt,
unsigned int column_idx, int64_t value)
{
const char *value_str = p_strdup_printf(stmt->pool, "%"PRId64, value);
array_idx_set(&stmt->args, column_idx, &value_str);
if (stmt->db->v.statement_bind_int64 != NULL)
stmt->db->v.statement_bind_int64(stmt, column_idx, value);
}
#undef sql_statement_query
void sql_statement_query(struct sql_statement **_stmt,
sql_query_callback_t *callback, void *context)
{
struct sql_statement *stmt = *_stmt;
*_stmt = NULL;
if (stmt->db->v.statement_query != NULL)
stmt->db->v.statement_query(stmt, callback, context);
else
default_sql_statement_query(stmt, callback, context);
}
struct sql_result *sql_statement_query_s(struct sql_statement **_stmt)
{
struct sql_statement *stmt = *_stmt;
*_stmt = NULL;
if (stmt->db->v.statement_query_s != NULL)
return stmt->db->v.statement_query_s(stmt);
else
return default_sql_statement_query_s(stmt);
}
void sql_result_ref(struct sql_result *result)
{
result->refcount++;
}
void sql_result_unref(struct sql_result *result)
{
i_assert(result->refcount > 0);
if (--result->refcount > 0)
return;
i_free(result->map);
result->v.free(result);
}
static const struct sql_field_def *
sql_field_def_find(const struct sql_field_def *fields, const char *name)
{
unsigned int i;
for (i = 0; fields[i].name != NULL; i++) {
if (strcasecmp(fields[i].name, name) == 0)
return &fields[i];
}
return NULL;
}
static void
sql_result_build_map(struct sql_result *result,
const struct sql_field_def *fields, size_t dest_size)
{
const struct sql_field_def *def;
const char *name;
unsigned int i, count, field_size = 0;
count = sql_result_get_fields_count(result);
result->map_size = count;
result->map = i_new(struct sql_field_map, result->map_size);
for (i = 0; i < count; i++) {
name = sql_result_get_field_name(result, i);
def = sql_field_def_find(fields, name);
if (def != NULL) {
result->map[i].type = def->type;
result->map[i].offset = def->offset;
switch (def->type) {
case SQL_TYPE_STR:
field_size = sizeof(const char *);
break;
case SQL_TYPE_UINT:
field_size = sizeof(unsigned int);
break;
case SQL_TYPE_ULLONG:
field_size = sizeof(unsigned long long);
break;
case SQL_TYPE_BOOL:
field_size = sizeof(bool);
break;
}
i_assert(def->offset + field_size <= dest_size);
} else {
result->map[i].offset = SIZE_MAX;
}
}
}
void sql_result_setup_fetch(struct sql_result *result,
const struct sql_field_def *fields,
void *dest, size_t dest_size)
{
if (result->map == NULL)
sql_result_build_map(result, fields, dest_size);
result->fetch_dest = dest;
result->fetch_dest_size = dest_size;
}
static void sql_result_fetch(struct sql_result *result)
{
unsigned int i, count;
const char *value;
void *ptr;
memset(result->fetch_dest, 0, result->fetch_dest_size);
count = result->map_size;
for (i = 0; i < count; i++) {
if (result->map[i].offset == SIZE_MAX)
continue;
value = sql_result_get_field_value(result, i);
ptr = STRUCT_MEMBER_P(result->fetch_dest,
result->map[i].offset);
switch (result->map[i].type) {
case SQL_TYPE_STR: {
*((const char **)ptr) = value;
break;
}
case SQL_TYPE_UINT: {
if (value != NULL &&
str_to_uint(value, (unsigned int *)ptr) < 0)
i_error("sql: Value not uint: %s", value);
break;
}
case SQL_TYPE_ULLONG: {
if (value != NULL &&
str_to_ullong(value, (unsigned long long *)ptr) < 0)
i_error("sql: Value not ullong: %s", value);
break;
}
case SQL_TYPE_BOOL: {
if (value != NULL && (*value == 't' || *value == '1'))
*((bool *)ptr) = TRUE;
break;
}
}
}
}
int sql_result_next_row(struct sql_result *result)
{
int ret;
if ((ret = result->v.next_row(result)) <= 0)
return ret;
if (result->fetch_dest != NULL)
sql_result_fetch(result);
return 1;
}
#undef sql_result_more
void sql_result_more(struct sql_result **result,
sql_query_callback_t *callback, void *context)
{
i_assert((*result)->v.more != NULL);
(*result)->v.more(result, TRUE, callback, context);
}
static void
sql_result_more_sync_callback(struct sql_result *result, void *context)
{
struct sql_result **dest_result = context;
*dest_result = result;
}
void sql_result_more_s(struct sql_result **result)
{
i_assert((*result)->v.more != NULL);
(*result)->v.more(result, FALSE, sql_result_more_sync_callback, result);
/* the callback must have been called */
i_assert(*result != NULL);
}
unsigned int sql_result_get_fields_count(struct sql_result *result)
{
return result->v.get_fields_count(result);
}
const char *sql_result_get_field_name(struct sql_result *result,
unsigned int idx)
{
return result->v.get_field_name(result, idx);
}
int sql_result_find_field(struct sql_result *result, const char *field_name)
{
return result->v.find_field(result, field_name);
}
const char *sql_result_get_field_value(struct sql_result *result,
unsigned int idx)
{
return result->v.get_field_value(result, idx);
}
const unsigned char *
sql_result_get_field_value_binary(struct sql_result *result,
unsigned int idx, size_t *size_r)
{
return result->v.get_field_value_binary(result, idx, size_r);
}
const char *sql_result_find_field_value(struct sql_result *result,
const char *field_name)
{
return result->v.find_field_value(result, field_name);
}
const char *const *sql_result_get_values(struct sql_result *result)
{
return result->v.get_values(result);
}
const char *sql_result_get_error(struct sql_result *result)
{
return result->v.get_error(result);
}
enum sql_result_error_type sql_result_get_error_type(struct sql_result *result)
{
return result->error_type;
}
static void
sql_result_not_connected_free(struct sql_result *result ATTR_UNUSED)
{
}
static int
sql_result_not_connected_next_row(struct sql_result *result ATTR_UNUSED)
{
return -1;
}
static const char *
sql_result_not_connected_get_error(struct sql_result *result ATTR_UNUSED)
{
return SQL_ERRSTR_NOT_CONNECTED;
}
struct sql_transaction_context *sql_transaction_begin(struct sql_db *db)
{
return db->v.transaction_begin(db);
}
#undef sql_transaction_commit
void sql_transaction_commit(struct sql_transaction_context **_ctx,
sql_commit_callback_t *callback, void *context)
{
struct sql_transaction_context *ctx = *_ctx;
*_ctx = NULL;
ctx->db->v.transaction_commit(ctx, callback, context);
}
int sql_transaction_commit_s(struct sql_transaction_context **_ctx,
const char **error_r)
{
struct sql_transaction_context *ctx = *_ctx;
*_ctx = NULL;
return ctx->db->v.transaction_commit_s(ctx, error_r);
}
void sql_transaction_rollback(struct sql_transaction_context **_ctx)
{
struct sql_transaction_context *ctx = *_ctx;
*_ctx = NULL;
ctx->db->v.transaction_rollback(ctx);
}
void sql_update(struct sql_transaction_context *ctx, const char *query)
{
ctx->db->v.update(ctx, query, NULL);
}
void sql_update_stmt(struct sql_transaction_context *ctx,
struct sql_statement **_stmt)
{
struct sql_statement *stmt = *_stmt;
*_stmt = NULL;
if (ctx->db->v.update_stmt != NULL)
ctx->db->v.update_stmt(ctx, stmt, NULL);
else
default_sql_update_stmt(ctx, stmt, NULL);
}
void sql_update_get_rows(struct sql_transaction_context *ctx, const char *query,
unsigned int *affected_rows)
{
ctx->db->v.update(ctx, query, affected_rows);
}
void sql_update_stmt_get_rows(struct sql_transaction_context *ctx,
struct sql_statement **_stmt,
unsigned int *affected_rows)
{
struct sql_statement *stmt = *_stmt;
*_stmt = NULL;
if (ctx->db->v.update_stmt != NULL)
ctx->db->v.update_stmt(ctx, stmt, affected_rows);
else
default_sql_update_stmt(ctx, stmt, affected_rows);
}
void sql_db_set_state(struct sql_db *db, enum sql_db_state state)
{
enum sql_db_state old_state = db->state;
if (db->state == state)
return;
db->state = state;
if (db->state_change_callback != NULL) {
db->state_change_callback(db, old_state,
db->state_change_context);
}
}
void sql_transaction_add_query(struct sql_transaction_context *ctx, pool_t pool,
const char *query, unsigned int *affected_rows)
{
struct sql_transaction_query *tquery;
tquery = p_new(pool, struct sql_transaction_query, 1);
tquery->trans = ctx;
tquery->query = p_strdup(pool, query);
tquery->affected_rows = affected_rows;
if (ctx->head == NULL)
ctx->head = tquery;
else
ctx->tail->next = tquery;
ctx->tail = tquery;
}
void sql_connection_log_finished(struct sql_db *db)
{
struct event_passthrough *e = event_create_passthrough(db->event)->
set_name(SQL_CONNECTION_FINISHED);
e_debug(e->event(),
"Connection finished (queries=%"PRIu64", slow queries=%"PRIu64")",
db->succeeded_queries + db->failed_queries,
db->slow_queries);
}
struct event_passthrough *
sql_query_finished_event(struct sql_db *db, struct event *event, const char *query,
bool success, int *duration_r)
{
int diff;
struct timeval tv;
event_get_create_time(event, &tv);
struct event_passthrough *e = event_create_passthrough(event)->
set_name(SQL_QUERY_FINISHED)->
add_str("query_first_word", t_strcut(query, ' '));
diff = timeval_diff_msecs(&ioloop_timeval, &tv);
if (!success) {
db->failed_queries++;
} else {
db->succeeded_queries++;
}
if (diff >= SQL_SLOW_QUERY_MSEC) {
e->add_str("slow_query", "y");
db->slow_queries++;
}
if (duration_r != NULL)
*duration_r = diff;
return e;
}
struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx)
{
return event_create_passthrough(ctx->event)->
set_name(SQL_TRANSACTION_FINISHED);
}
void sql_wait(struct sql_db *db)
{
if (db->v.wait != NULL)
db->v.wait(db);
}
struct sql_result sql_not_connected_result = {
.v = {
sql_result_not_connected_free,
sql_result_not_connected_next_row,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
sql_result_not_connected_get_error,
NULL,
},
.failed_try_retry = TRUE
};
dovecot-2.3.21.1/src/lib-sql/driver-test.c 0000644 0000000 0000000 00000034666 14656633576 015102 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "test-lib.h"
#include "str.h"
#include "buffer.h"
#include "sql-api-private.h"
#include "driver-test.h"
#include "array.h"
#include "hex-binary.h"
struct test_sql_db {
struct sql_db api;
pool_t pool;
ARRAY(struct test_driver_result) expected;
const char *error;
bool failed:1;
};
struct test_sql_result {
struct sql_result api;
struct test_driver_result *result;
const char *error;
};
static struct sql_db *driver_test_mysql_init(const char *connect_string);
static struct sql_db *driver_test_cassandra_init(const char *connect_string);
static struct sql_db *driver_test_sqlite_init(const char *connect_string);
static void driver_test_deinit(struct sql_db *_db);
static int driver_test_connect(struct sql_db *_db);
static void driver_test_disconnect(struct sql_db *_db);
static const char *
driver_test_mysql_escape_string(struct sql_db *_db, const char *string);
static const char *
driver_test_escape_string(struct sql_db *_db, const char *string);
static void driver_test_exec(struct sql_db *_db, const char *query);
static void driver_test_query(struct sql_db *_db, const char *query,
sql_query_callback_t *callback, void *context);
static struct sql_result *
driver_test_query_s(struct sql_db *_db, const char *query);
static struct sql_transaction_context *
driver_test_transaction_begin(struct sql_db *_db);
static void driver_test_transaction_commit(struct sql_transaction_context *ctx,
sql_commit_callback_t *callback,
void *context);
static int
driver_test_transaction_commit_s(struct sql_transaction_context *ctx,
const char **error_r);
static void
driver_test_transaction_rollback(struct sql_transaction_context *ctx);
static void
driver_test_update(struct sql_transaction_context *ctx, const char *query,
unsigned int *affected_rows);
static const char *
driver_test_mysql_escape_blob(struct sql_db *_db, const unsigned char *data,
size_t size);
static const char *
driver_test_escape_blob(struct sql_db *_db, const unsigned char *data,
size_t size);
static void driver_test_result_free(struct sql_result *result);
static int driver_test_result_next_row(struct sql_result *result);
static unsigned int
driver_test_result_get_fields_count(struct sql_result *result);
static const char *
driver_test_result_get_field_name(struct sql_result *result, unsigned int idx);
static int
driver_test_result_find_field(struct sql_result *result, const char *field_name);
static const char *
driver_test_result_get_field_value(struct sql_result *result, unsigned int idx);
static const unsigned char *
driver_test_result_get_field_value_binary(struct sql_result *result,
unsigned int idx, size_t *size_r);
static const char *
driver_test_result_find_field_value(struct sql_result *result,
const char *field_name);
static const char *const *
driver_test_result_get_values(struct sql_result *result);
const char *driver_test_result_get_error(struct sql_result *result);
const struct sql_db driver_test_mysql_db = {
.name = "mysql",
.flags = SQL_DB_FLAG_BLOCKING | SQL_DB_FLAG_ON_DUPLICATE_KEY,
.v = {
.init = driver_test_mysql_init,
.deinit = driver_test_deinit,
.connect = driver_test_connect,
.disconnect = driver_test_disconnect,
.escape_string = driver_test_mysql_escape_string,
.exec = driver_test_exec,
.query = driver_test_query,
.query_s = driver_test_query_s,
.transaction_begin = driver_test_transaction_begin,
.transaction_commit = driver_test_transaction_commit,
.transaction_commit_s = driver_test_transaction_commit_s,
.transaction_rollback = driver_test_transaction_rollback,
.update = driver_test_update,
.escape_blob = driver_test_mysql_escape_blob,
}
};
const struct sql_db driver_test_cassandra_db = {
.name = "cassandra",
.v = {
.init = driver_test_cassandra_init,
.deinit = driver_test_deinit,
.connect = driver_test_connect,
.disconnect = driver_test_disconnect,
.escape_string = driver_test_escape_string,
.exec = driver_test_exec,
.query = driver_test_query,
.query_s = driver_test_query_s,
.transaction_begin = driver_test_transaction_begin,
.transaction_commit = driver_test_transaction_commit,
.transaction_commit_s = driver_test_transaction_commit_s,
.transaction_rollback = driver_test_transaction_rollback,
.update = driver_test_update,
.escape_blob = driver_test_escape_blob,
}
};
const struct sql_db driver_test_sqlite_db = {
.name = "sqlite",
.flags = SQL_DB_FLAG_ON_CONFLICT_DO | SQL_DB_FLAG_BLOCKING,
.v = {
.init = driver_test_sqlite_init,
.deinit = driver_test_deinit,
.connect = driver_test_connect,
.disconnect = driver_test_disconnect,
.escape_string = driver_test_escape_string,
.exec = driver_test_exec,
.query = driver_test_query,
.query_s = driver_test_query_s,
.transaction_begin = driver_test_transaction_begin,
.transaction_commit = driver_test_transaction_commit,
.transaction_commit_s = driver_test_transaction_commit_s,
.transaction_rollback = driver_test_transaction_rollback,
.update = driver_test_update,
.escape_blob = driver_test_escape_blob,
}
};
const struct sql_result driver_test_result = {
.v = {
.free = driver_test_result_free,
.next_row = driver_test_result_next_row,
.get_fields_count = driver_test_result_get_fields_count,
.get_field_name = driver_test_result_get_field_name,
.find_field = driver_test_result_find_field,
.get_field_value = driver_test_result_get_field_value,
.get_field_value_binary = driver_test_result_get_field_value_binary,
.find_field_value = driver_test_result_find_field_value,
.get_values = driver_test_result_get_values,
.get_error = driver_test_result_get_error,
}
};
void sql_driver_test_register(void)
{
sql_driver_register(&driver_test_mysql_db);
sql_driver_register(&driver_test_cassandra_db);
sql_driver_register(&driver_test_sqlite_db);
}
void sql_driver_test_unregister(void)
{
sql_driver_unregister(&driver_test_mysql_db);
sql_driver_unregister(&driver_test_cassandra_db);
sql_driver_unregister(&driver_test_sqlite_db);
}
static struct sql_db *driver_test_init(const struct sql_db *driver,
const char *connect_string ATTR_UNUSED)
{
pool_t pool = pool_alloconly_create(MEMPOOL_GROWING" test sql driver", 2048);
struct test_sql_db *ret = p_new(pool, struct test_sql_db, 1);
ret->pool = pool;
ret->api = *driver;
p_array_init(&ret->expected, pool, 8);
return &ret->api;
}
static struct sql_db *driver_test_mysql_init(const char *connect_string)
{
return driver_test_init(&driver_test_mysql_db, connect_string);
}
static struct sql_db *driver_test_cassandra_init(const char *connect_string)
{
return driver_test_init(&driver_test_cassandra_db, connect_string);
}
static struct sql_db *driver_test_sqlite_init(const char *connect_string)
{
return driver_test_init(&driver_test_sqlite_db, connect_string);
}
static void driver_test_deinit(struct sql_db *_db ATTR_UNUSED)
{
struct test_sql_db *db = (struct test_sql_db*)_db;
array_free(&_db->module_contexts);
pool_unref(&db->pool);
}
static int driver_test_connect(struct sql_db *_db ATTR_UNUSED)
{
/* nix */
return 0;
}
static void driver_test_disconnect(struct sql_db *_db ATTR_UNUSED)
{ }
static const char *
driver_test_mysql_escape_string(struct sql_db *_db ATTR_UNUSED,
const char *string)
{
string_t *esc = t_str_new(strlen(string));
for(const char *ptr = string; *ptr != '\0'; ptr++) {
if (*ptr == '\n' || *ptr == '\r' || *ptr == '\\' ||
*ptr == '\'' || *ptr == '\"' || *ptr == '\x1a')
str_append_c(esc, '\\');
str_append_c(esc, *ptr);
}
return str_c(esc);
}
static const char *
driver_test_escape_string(struct sql_db *_db ATTR_UNUSED, const char *string)
{
return string;
}
static void driver_test_exec(struct sql_db *_db, const char *query)
{
struct test_sql_db *db = (struct test_sql_db*)_db;
struct test_driver_result *result =
array_front_modifiable(&db->expected);
i_assert(result->cur < result->nqueries);
/* i_debug("DUMMY EXECUTE: %s", query);
i_debug("DUMMY EXPECT : %s", result->queries[result->cur]); */
test_assert_strcmp(result->queries[result->cur], query);
if (strcmp(result->queries[result->cur], query) != 0) {
db->error = "Invalid query";
db->failed = TRUE;
}
result->cur++;
}
static void
driver_test_query(struct sql_db *_db, const char *query,
sql_query_callback_t *callback, void *context)
{
struct sql_result *result = driver_test_query_s(_db, query);
if (callback != NULL)
callback(result, context);
}
static struct sql_result *
driver_test_query_s(struct sql_db *_db, const char *query)
{
struct test_sql_db *db = (struct test_sql_db*)_db;
struct test_driver_result *result =
array_front_modifiable(&db->expected);
struct test_sql_result *res = i_new(struct test_sql_result, 1);
driver_test_exec(_db, query);
if (db->failed) {
res->api.failed = TRUE;
}
res->api.v = driver_test_result.v;
res->api.db = _db;
if (result->result != NULL) {
res->result = i_new(struct test_driver_result, 1);
memcpy(res->result, result, sizeof(*result));
}
res->api.refcount = 1;
/* drop it from array if it's used up */
if (result->cur == result->nqueries)
array_pop_front(&db->expected);
return &res->api;
}
static struct sql_transaction_context *
driver_test_transaction_begin(struct sql_db *_db)
{
struct sql_transaction_context *ctx =
i_new(struct sql_transaction_context, 1);
ctx->db = _db;
return ctx;
}
static void
driver_test_transaction_commit(struct sql_transaction_context *ctx,
sql_commit_callback_t *callback, void *context)
{
struct sql_commit_result res;
res.error_type = driver_test_transaction_commit_s(ctx, &res.error);
callback(&res, context);
}
static int
driver_test_transaction_commit_s(struct sql_transaction_context *ctx,
const char **error_r)
{
struct test_sql_db *db = (struct test_sql_db*)ctx->db;
int ret = 0;
if (db->error != NULL) {
*error_r = db->error;
ret = -1;
}
i_free(ctx);
db->error = NULL;
db->failed = FALSE;
return ret;
}
static void
driver_test_transaction_rollback(struct sql_transaction_context *ctx)
{
struct test_sql_db *db = (struct test_sql_db*)ctx->db;
i_free(ctx);
db->error = NULL;
db->failed = FALSE;
}
static void
driver_test_update(struct sql_transaction_context *ctx, const char *query,
unsigned int *affected_rows)
{
struct test_sql_db *db= (struct test_sql_db*)ctx->db;
struct test_driver_result *result =
array_front_modifiable(&db->expected);
driver_test_exec(ctx->db, query);
if (affected_rows != NULL)
*affected_rows = result->affected_rows;
/* drop it from array if it's used up */
if (result->cur == result->nqueries)
array_pop_front(&db->expected);
}
static const char *
driver_test_mysql_escape_blob(struct sql_db *_db ATTR_UNUSED,
const unsigned char *data, size_t size)
{
return t_strdup_printf("X'%s'", binary_to_hex(data,size));
}
static const char *
driver_test_escape_blob(struct sql_db *_db ATTR_UNUSED,
const unsigned char *data, size_t size)
{
return t_strdup_printf("X'%s'", binary_to_hex(data,size));
}
static void driver_test_result_free(struct sql_result *result)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
if (tsr->result != NULL)
i_free(tsr->result);
i_free(result);
}
static int driver_test_result_next_row(struct sql_result *result)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
struct test_driver_result *r = tsr->result;
if (r == NULL) return 0;
struct test_driver_result_set *rs =
&(r->result[r->cur-1]);
if (rs->cur <= rs->rows) {
rs->cur++;
}
return rs->cur <= rs->rows ? 1 : 0;
}
static unsigned int
driver_test_result_get_fields_count(struct sql_result *result)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
struct test_driver_result *r = tsr->result;
struct test_driver_result_set *rs =
&(r->result[r->cur-1]);
return rs->cols;
}
static const char *
driver_test_result_get_field_name(struct sql_result *result, unsigned int idx)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
struct test_driver_result *r = tsr->result;
struct test_driver_result_set *rs =
&(r->result[r->cur-1]);
i_assert(idx < rs->cols);
return rs->col_names[idx];
}
static int
driver_test_result_find_field(struct sql_result *result, const char *field_name)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
struct test_driver_result *r = tsr->result;
struct test_driver_result_set *rs =
&(r->result[r->cur-1]);
for(size_t i = 0; i < rs->cols; i++) {
if (strcmp(field_name, rs->col_names[i])==0)
return i;
}
return -1;
}
static const char *
driver_test_result_get_field_value(struct sql_result *result, unsigned int idx)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
struct test_driver_result *r = tsr->result;
struct test_driver_result_set *rs =
&(r->result[r->cur-1]);
i_assert(idx < rs->cols);
i_assert(rs->cur <= rs->rows);
return rs->row_data[rs->cur-1][idx];
}
static const unsigned char *
driver_test_result_get_field_value_binary(struct sql_result *result,
unsigned int idx, size_t *size_r)
{
buffer_t *buf = t_buffer_create(64);
const char *value = driver_test_result_get_field_value(result, idx);
/* expect it hex encoded */
if (hex_to_binary(value, buf) < 0) {
*size_r = 0;
return NULL;
}
*size_r = buf->used;
return buf->data;
}
static const char *
driver_test_result_find_field_value(struct sql_result *result,
const char *field_name)
{
int idx = driver_test_result_find_field(result, field_name);
if (idx < 0) return NULL;
return driver_test_result_get_field_value(result, idx);
}
static const char *const *
driver_test_result_get_values(struct sql_result *result)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
struct test_driver_result *r = tsr->result;
struct test_driver_result_set *rs =
&(r->result[r->cur-1]);
i_assert(rs->cur <= rs->rows);
return rs->row_data[rs->cur-1];
}
const char *driver_test_result_get_error(struct sql_result *result)
{
struct test_sql_result *tsr =
(struct test_sql_result *)result;
return tsr->error;
}
void sql_driver_test_add_expected_result(struct sql_db *_db,
const struct test_driver_result *result)
{
struct test_sql_db *db = (struct test_sql_db*)_db;
array_push_back(&db->expected, result);
}
void sql_driver_test_clear_expected_results(struct sql_db *_db)
{
struct test_sql_db *db = (struct test_sql_db*)_db;
array_clear(&db->expected);
}
dovecot-2.3.21.1/src/lib-sql/driver-sqlite.c 0000644 0000000 0000000 00000033546 14656633576 015420 0000000 0000000 /* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "str.h"
#include "hex-binary.h"
#include "sql-api-private.h"
#ifdef BUILD_SQLITE
#include
/* retry time if db is busy (in ms) */
static const int sqlite_busy_timeout = 1000;
struct sqlite_db {
struct sql_db api;
pool_t pool;
const char *dbfile;
sqlite3 *sqlite;
bool connected:1;
int rc;
};
struct sqlite_result {
struct sql_result api;
sqlite3_stmt *stmt;
unsigned int cols;
const char **row;
};
struct sqlite_transaction_context {
struct sql_transaction_context ctx;
bool failed:1;
};
extern const struct sql_db driver_sqlite_db;
extern const struct sql_result driver_sqlite_result;
extern const struct sql_result driver_sqlite_error_result;
static struct event_category event_category_sqlite = {
.parent = &event_category_sql,
.name = "sqlite"
};
static int driver_sqlite_connect(struct sql_db *_db)
{
struct sqlite_db *db = (struct sqlite_db *)_db;
if (db->connected)
return 1;
db->rc = sqlite3_open(db->dbfile, &db->sqlite);
if (db->rc == SQLITE_OK) {
db->connected = TRUE;
sqlite3_busy_timeout(db->sqlite, sqlite_busy_timeout);
return 1;
} else {
e_error(_db->event, "open(%s) failed: %s", db->dbfile,
sqlite3_errmsg(db->sqlite));
sqlite3_close(db->sqlite);
db->sqlite = NULL;
return -1;
}
}
static void driver_sqlite_disconnect(struct sql_db *_db)
{
struct sqlite_db *db = (struct sqlite_db *)_db;
sqlite3_close(db->sqlite);
db->sqlite = NULL;
}
static int driver_sqlite_init_full_v(const struct sql_settings *set, struct sql_db **db_r,
const char **error_r ATTR_UNUSED)
{
struct sqlite_db *db;
pool_t pool;
pool = pool_alloconly_create("sqlite driver", 512);
db = p_new(pool, struct sqlite_db, 1);
db->pool = pool;
db->api = driver_sqlite_db;
db->dbfile = p_strdup(db->pool, set->connect_string);
db->connected = FALSE;
db->api.event = event_create(set->event_parent);
event_add_category(db->api.event, &event_category_sqlite);
event_set_append_log_prefix(db->api.event, "sqlite: ");
*db_r = &db->api;
return 0;
}
static void driver_sqlite_deinit_v(struct sql_db *_db)
{
struct sqlite_db *db = (struct sqlite_db *)_db;
_db->no_reconnect = TRUE;
sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
sqlite3_close(db->sqlite);
sql_connection_log_finished(_db);
event_unref(&_db->event);
array_free(&_db->module_contexts);
pool_unref(&db->pool);
}
static const char *
driver_sqlite_escape_string(struct sql_db *_db ATTR_UNUSED,
const char *string)
{
const char *p;
char *dest, *destbegin;
/* find the first ' */
for (p = string; *p != '\''; p++) {
if (*p == '\0')
return t_strdup_noconst(string);
}
/* @UNSAFE: escape ' with '' */
dest = destbegin = t_buffer_get((p - string) + strlen(string) * 2 + 1);
memcpy(dest, string, p - string);
dest += p - string;
for (; *p != '\0'; p++) {
*dest++ = *p;
if (*p == '\'')
*dest++ = *p;
}
*dest++ = '\0';
t_buffer_alloc(dest - destbegin);
return destbegin;
}
static void driver_sqlite_result_log(const struct sql_result *result, const char *query)
{
struct sqlite_db *db = (struct sqlite_db *)result->db;
bool success = db->connected && db->rc == SQLITE_OK;
int duration;
const char *suffix = "";
struct event_passthrough *e =
sql_query_finished_event(&db->api, result->event, query, success,
&duration);
io_loop_time_refresh();
if (!db->connected) {
suffix = ": Cannot connect to database";
e->add_str("error", "Cannot connect to database");
} else if (db->rc != SQLITE_OK) {
suffix = t_strdup_printf(": %s (%d)", sqlite3_errmsg(db->sqlite),
db->rc);
e->add_str("error", sqlite3_errmsg(db->sqlite));
e->add_int("error_code", db->rc);
}
e_debug(e->event(), SQL_QUERY_FINISHED_FMT"%s", query, duration, suffix);
}
static void driver_sqlite_exec(struct sql_db *_db, const char *query)
{
struct sqlite_db *db = (struct sqlite_db *)_db;
struct sql_result result;
i_zero(&result);
result.db = _db;
result.event = event_create(_db->event);
/* Other drivers do not include time spent connecting
but this simplifies error logging, so we include
it here. */
if (driver_sqlite_connect(_db) < 0) {
driver_sqlite_result_log(&result, query);
} else {
db->rc = sqlite3_exec(db->sqlite, query, NULL, NULL, NULL);
driver_sqlite_result_log(&result, query);
}
event_unref(&result.event);
}
static void driver_sqlite_query(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context)
{
struct sql_result *result;
result = sql_query_s(db, query);
result->callback = TRUE;
callback(result, context);
result->callback = FALSE;
sql_result_unref(result);
}
static struct sql_result *
driver_sqlite_query_s(struct sql_db *_db, const char *query)
{
struct sqlite_db *db = (struct sqlite_db *)_db;
struct sqlite_result *result;
struct event *event;
result = i_new(struct sqlite_result, 1);
result->api.db = _db;
/* Temporarily store the event since result->api gets
* overwritten later here and we need to reset it. */
event = event_create(_db->event);
result->api.event = event;
if (driver_sqlite_connect(_db) < 0) {
driver_sqlite_result_log(&result->api, query);
result->api = driver_sqlite_error_result;
result->stmt = NULL;
result->cols = 0;
} else {
db->rc = sqlite3_prepare(db->sqlite, query, -1, &result->stmt, NULL);
driver_sqlite_result_log(&result->api, query);
if (db->rc == SQLITE_OK) {
result->api = driver_sqlite_result;
result->cols = sqlite3_column_count(result->stmt);
result->row = i_new(const char *, result->cols);
} else {
result->api = driver_sqlite_error_result;
result->stmt = NULL;
result->cols = 0;
}
}
result->api.db = _db;
result->api.refcount = 1;
result->api.event = event;
return &result->api;
}
static void driver_sqlite_result_free(struct sql_result *_result)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
struct sqlite_db *db = (struct sqlite_db *) result->api.db;
int rc;
if (_result->callback)
return;
if (result->stmt != NULL) {
if ((rc = sqlite3_finalize(result->stmt)) != SQLITE_OK) {
e_warning(_result->event, "finalize failed: %s (%d)",
sqlite3_errmsg(db->sqlite), rc);
}
i_free(result->row);
}
event_unref(&result->api.event);
i_free(result);
}
static int driver_sqlite_result_next_row(struct sql_result *_result)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
switch (sqlite3_step(result->stmt)) {
case SQLITE_ROW:
return 1;
case SQLITE_DONE:
return 0;
default:
return -1;
}
}
static unsigned int
driver_sqlite_result_get_fields_count(struct sql_result *_result)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
return result->cols;
}
static const char *
driver_sqlite_result_get_field_name(struct sql_result *_result,
unsigned int idx)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
return sqlite3_column_name(result->stmt, idx);
}
static int driver_sqlite_result_find_field(struct sql_result *_result,
const char *field_name)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
unsigned int i;
for (i = 0; i < result->cols; ++i) {
const char *col = sqlite3_column_name(result->stmt, i);
if (strcmp(col, field_name) == 0)
return i;
}
return -1;
}
static const char *
driver_sqlite_result_get_field_value(struct sql_result *_result,
unsigned int idx)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
return (const char*)sqlite3_column_text(result->stmt, idx);
}
static const unsigned char *
driver_sqlite_result_get_field_value_binary(struct sql_result *_result,
unsigned int idx, size_t *size_r)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
*size_r = sqlite3_column_bytes(result->stmt, idx);
return sqlite3_column_blob(result->stmt, idx);
}
static const char *
driver_sqlite_result_find_field_value(struct sql_result *result,
const char *field_name)
{
int idx;
idx = driver_sqlite_result_find_field(result, field_name);
if (idx < 0)
return NULL;
return driver_sqlite_result_get_field_value(result, idx);
}
static const char *const *
driver_sqlite_result_get_values(struct sql_result *_result)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
unsigned int i;
for (i = 0; i < result->cols; ++i) {
result->row[i] =
driver_sqlite_result_get_field_value(_result, i);
}
return (const char *const *)result->row;
}
static const char *driver_sqlite_result_get_error(struct sql_result *_result)
{
struct sqlite_result *result = (struct sqlite_result *)_result;
struct sqlite_db *db = (struct sqlite_db *)result->api.db;
if (db->connected)
return sqlite3_errmsg(db->sqlite);
else
return "Cannot connect to database";
}
static struct sql_transaction_context *
driver_sqlite_transaction_begin(struct sql_db *_db)
{
struct sqlite_transaction_context *ctx;
struct sqlite_db *db = (struct sqlite_db *)_db;
ctx = i_new(struct sqlite_transaction_context, 1);
ctx->ctx.db = _db;
ctx->ctx.event = event_create(_db->event);
sql_exec(_db, "BEGIN TRANSACTION");
if (db->rc != SQLITE_OK)
ctx->failed = TRUE;
return &ctx->ctx;
}
static void
driver_sqlite_transaction_rollback(struct sql_transaction_context *_ctx)
{
struct sqlite_transaction_context *ctx =
(struct sqlite_transaction_context *)_ctx;
if (!ctx->failed) {
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", "Rolled back")->event(),
"Transaction rolled back");
}
sql_exec(_ctx->db, "ROLLBACK");
event_unref(&_ctx->event);
i_free(ctx);
}
static void
driver_sqlite_transaction_commit(struct sql_transaction_context *_ctx,
sql_commit_callback_t *callback, void *context)
{
struct sqlite_transaction_context *ctx =
(struct sqlite_transaction_context *)_ctx;
struct sqlite_db *db = (struct sqlite_db *)ctx->ctx.db;
struct sql_commit_result commit_result;
if (!ctx->failed) {
sql_exec(_ctx->db, "COMMIT");
if (db->rc != SQLITE_OK)
ctx->failed = TRUE;
}
i_zero(&commit_result);
if (ctx->failed) {
commit_result.error = sqlite3_errmsg(db->sqlite);
callback(&commit_result, context);
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", commit_result.error)->event(),
"Transaction failed");
/* From SQLite manual: It is recommended that applications
respond to the errors listed above by explicitly issuing a
ROLLBACK command. If the transaction has already been rolled
back automatically by the error response, then the ROLLBACK
command will fail with an error, but no harm is caused by
this. */
driver_sqlite_transaction_rollback(_ctx);
} else {
e_debug(sql_transaction_finished_event(_ctx)->event(),
"Transaction committed");
callback(&commit_result, context);
event_unref(&_ctx->event);
i_free(ctx);
}
}
static int
driver_sqlite_transaction_commit_s(struct sql_transaction_context *_ctx,
const char **error_r)
{
struct sqlite_transaction_context *ctx =
(struct sqlite_transaction_context *)_ctx;
struct sqlite_db *db = (struct sqlite_db *) ctx->ctx.db;
if (ctx->failed) {
/* also does i_free(ctx) */
driver_sqlite_transaction_rollback(_ctx);
return -1;
}
sql_exec(_ctx->db, "COMMIT");
*error_r = sqlite3_errmsg(db->sqlite);
i_free(ctx);
return 0;
}
static void
driver_sqlite_update(struct sql_transaction_context *_ctx, const char *query,
unsigned int *affected_rows)
{
struct sqlite_transaction_context *ctx =
(struct sqlite_transaction_context *)_ctx;
struct sqlite_db *db = (struct sqlite_db *)ctx->ctx.db;
if (ctx->failed)
return;
sql_exec(_ctx->db, query);
if (db->rc != SQLITE_OK)
ctx->failed = TRUE;
else if (affected_rows != NULL)
*affected_rows = sqlite3_changes(db->sqlite);
}
static const char *
driver_sqlite_escape_blob(struct sql_db *_db ATTR_UNUSED,
const unsigned char *data, size_t size)
{
string_t *str = t_str_new(128);
str_append(str, "x'");
binary_to_hex_append(str, data, size);
str_append_c(str, '\'');
return str_c(str);
}
const struct sql_db driver_sqlite_db = {
.name = "sqlite",
.flags =
#if SQLITE_VERSION_NUMBER >= 3024000
SQL_DB_FLAG_ON_CONFLICT_DO |
#endif
SQL_DB_FLAG_BLOCKING,
.v = {
.init_full = driver_sqlite_init_full_v,
.deinit = driver_sqlite_deinit_v,
.connect = driver_sqlite_connect,
.disconnect = driver_sqlite_disconnect,
.escape_string = driver_sqlite_escape_string,
.exec = driver_sqlite_exec,
.query = driver_sqlite_query,
.query_s = driver_sqlite_query_s,
.transaction_begin = driver_sqlite_transaction_begin,
.transaction_commit = driver_sqlite_transaction_commit,
.transaction_commit_s = driver_sqlite_transaction_commit_s,
.transaction_rollback = driver_sqlite_transaction_rollback,
.update = driver_sqlite_update,
.escape_blob = driver_sqlite_escape_blob,
}
};
const struct sql_result driver_sqlite_result = {
.v = {
.free = driver_sqlite_result_free,
.next_row = driver_sqlite_result_next_row,
.get_fields_count = driver_sqlite_result_get_fields_count,
.get_field_name = driver_sqlite_result_get_field_name,
.find_field = driver_sqlite_result_find_field,
.get_field_value = driver_sqlite_result_get_field_value,
.get_field_value_binary = driver_sqlite_result_get_field_value_binary,
.find_field_value = driver_sqlite_result_find_field_value,
.get_values = driver_sqlite_result_get_values,
.get_error = driver_sqlite_result_get_error,
}
};
static int
driver_sqlite_result_error_next_row(struct sql_result *result ATTR_UNUSED)
{
return -1;
}
const struct sql_result driver_sqlite_error_result = {
.v = {
.free = driver_sqlite_result_free,
.next_row = driver_sqlite_result_error_next_row,
.get_error = driver_sqlite_result_get_error,
}
};
const char *driver_sqlite_version = DOVECOT_ABI_VERSION;
void driver_sqlite_init(void);
void driver_sqlite_deinit(void);
void driver_sqlite_init(void)
{
sql_driver_register(&driver_sqlite_db);
}
void driver_sqlite_deinit(void)
{
sql_driver_unregister(&driver_sqlite_db);
}
#endif
dovecot-2.3.21.1/src/lib-sql/sql-db-cache.h 0000644 0000000 0000000 00000000612 14656633576 015042 0000000 0000000 #ifndef SQL_DB_CACHE_H
#define SQL_DB_CACHE_H
struct sql_db_cache;
/* Like sql_init(), but use a connection pool. */
int sql_db_cache_new(struct sql_db_cache *cache, const struct sql_settings *set,
struct sql_db **db_r, const char **error_r);
struct sql_db_cache *sql_db_cache_init(unsigned int max_unused_connections);
void sql_db_cache_deinit(struct sql_db_cache **cache);
#endif
dovecot-2.3.21.1/src/lib-sql/driver-pgsql.c 0000644 0000000 0000000 00000101754 14656633576 015242 0000000 0000000 /* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "hex-binary.h"
#include "str.h"
#include "time-util.h"
#include "sql-api-private.h"
#include "llist.h"
#ifdef BUILD_PGSQL
#include
#define PGSQL_DNS_WARN_MSECS 500
struct pgsql_db {
struct sql_db api;
pool_t pool;
char *connect_string;
char *host;
PGconn *pg;
struct io *io;
struct timeout *to_connect;
enum io_condition io_dir;
struct pgsql_result *pending_results;
struct pgsql_result *cur_result;
struct ioloop *ioloop, *orig_ioloop;
struct sql_result *sync_result;
bool (*next_callback)(void *);
void *next_context;
char *error;
const char *connect_state;
bool fatal_error:1;
};
struct pgsql_binary_value {
unsigned char *value;
size_t size;
};
struct pgsql_result {
struct sql_result api;
struct pgsql_result *prev, *next;
PGresult *pgres;
struct timeout *to;
unsigned int rownum, rows;
unsigned int fields_count;
const char **fields;
const char **values;
char *query;
ARRAY(struct pgsql_binary_value) binary_values;
sql_query_callback_t *callback;
void *context;
bool timeout:1;
};
struct pgsql_transaction_context {
struct sql_transaction_context ctx;
int refcount;
sql_commit_callback_t *callback;
void *context;
pool_t query_pool;
const char *error;
bool failed:1;
};
extern const struct sql_db driver_pgsql_db;
extern const struct sql_result driver_pgsql_result;
static void result_finish(struct pgsql_result *result);
static void
transaction_update_callback(struct sql_result *result,
struct sql_transaction_query *query);
static struct event_category event_category_pgsql = {
.parent = &event_category_sql,
.name = "pgsql"
};
static void driver_pgsql_set_state(struct pgsql_db *db, enum sql_db_state state)
{
i_assert(state == SQL_DB_STATE_BUSY || db->cur_result == NULL);
/* switch back to original ioloop in case the caller wants to
add/remove timeouts */
if (db->ioloop != NULL)
io_loop_set_current(db->orig_ioloop);
sql_db_set_state(&db->api, state);
if (db->ioloop != NULL)
io_loop_set_current(db->ioloop);
}
static bool driver_pgsql_next_callback(struct pgsql_db *db)
{
bool (*next_callback)(void *) = db->next_callback;
void *next_context = db->next_context;
if (next_callback == NULL)
return FALSE;
db->next_callback = NULL;
db->next_context = NULL;
return next_callback(next_context);
}
static void driver_pgsql_stop_io(struct pgsql_db *db)
{
if (db->io != NULL) {
io_remove(&db->io);
db->io_dir = 0;
}
}
static void driver_pgsql_close(struct pgsql_db *db)
{
db->io_dir = 0;
db->fatal_error = FALSE;
driver_pgsql_stop_io(db);
PQfinish(db->pg);
db->pg = NULL;
timeout_remove(&db->to_connect);
driver_pgsql_set_state(db, SQL_DB_STATE_DISCONNECTED);
if (db->ioloop != NULL) {
/* running a sync query, stop it */
io_loop_stop(db->ioloop);
}
driver_pgsql_next_callback(db);
}
static const char *last_error(struct pgsql_db *db)
{
const char *msg;
size_t len;
msg = PQerrorMessage(db->pg);
if (msg == NULL)
return "(no error set)";
/* Error message should contain trailing \n, we don't want it */
len = strlen(msg);
return len == 0 || msg[len-1] != '\n' ? msg :
t_strndup(msg, len-1);
}
static void connect_callback(struct pgsql_db *db)
{
enum io_condition io_dir = 0;
int ret;
driver_pgsql_stop_io(db);
while ((ret = PQconnectPoll(db->pg)) == PGRES_POLLING_ACTIVE)
;
switch (ret) {
case PGRES_POLLING_READING:
db->connect_state = "wait for input";
io_dir = IO_READ;
break;
case PGRES_POLLING_WRITING:
db->connect_state = "wait for output";
io_dir = IO_WRITE;
break;
case PGRES_POLLING_OK:
break;
case PGRES_POLLING_FAILED:
e_error(db->api.event, "Connect failed to database %s: %s (state: %s)",
PQdb(db->pg), last_error(db), db->connect_state);
driver_pgsql_close(db);
return;
}
if (io_dir != 0) {
db->io = io_add(PQsocket(db->pg), io_dir, connect_callback, db);
db->io_dir = io_dir;
}
if (io_dir == 0) {
db->connect_state = "connected";
timeout_remove(&db->to_connect);
if (PQserverVersion(db->pg) >= 90500) {
/* v9.5+ */
db->api.flags |= SQL_DB_FLAG_ON_CONFLICT_DO;
}
driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
if (db->ioloop != NULL) {
/* driver_pgsql_sync_init() waiting for connection to
finish */
io_loop_stop(db->ioloop);
}
}
}
static void driver_pgsql_connect_timeout(struct pgsql_db *db)
{
unsigned int secs = ioloop_time - db->api.last_connect_try;
e_error(db->api.event, "Connect failed: Timeout after %u seconds (state: %s)",
secs, db->connect_state);
driver_pgsql_close(db);
}
static int driver_pgsql_connect(struct sql_db *_db)
{
struct pgsql_db *db = (struct pgsql_db *)_db;
struct timeval tv_start;
int msecs;
i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
io_loop_time_refresh();
tv_start = ioloop_timeval;
db->pg = PQconnectStart(db->connect_string);
if (db->pg == NULL) {
i_fatal("pgsql: PQconnectStart() failed (out of memory)");
}
if (PQstatus(db->pg) == CONNECTION_BAD) {
e_error(_db->event, "Connect failed to database %s: %s",
PQdb(db->pg), last_error(db));
driver_pgsql_close(db);
return -1;
}
/* PQconnectStart() blocks on host name resolving. Log a warning if
it takes too long. Also don't include time spent on that in the
connect timeout (by refreshing ioloop time). */
io_loop_time_refresh();
msecs = timeval_diff_msecs(&ioloop_timeval, &tv_start);
if (msecs > PGSQL_DNS_WARN_MSECS) {
e_warning(_db->event, "DNS lookup took %d.%03d s",
msecs/1000, msecs % 1000);
}
/* nonblocking connecting begins. */
if (PQsetnonblocking(db->pg, 1) < 0)
e_error(_db->event, "PQsetnonblocking() failed");
i_assert(db->to_connect == NULL);
db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
driver_pgsql_connect_timeout, db);
db->connect_state = "connecting";
db->io = io_add(PQsocket(db->pg), IO_WRITE, connect_callback, db);
db->io_dir = IO_WRITE;
driver_pgsql_set_state(db, SQL_DB_STATE_CONNECTING);
return 0;
}
static void driver_pgsql_disconnect(struct sql_db *_db)
{
struct pgsql_db *db = (struct pgsql_db *)_db;
if (db->cur_result != NULL && db->cur_result->to != NULL) {
driver_pgsql_stop_io(db);
result_finish(db->cur_result);
}
_db->no_reconnect = TRUE;
driver_pgsql_close(db);
_db->no_reconnect = FALSE;
}
static void driver_pgsql_free(struct pgsql_db **_db)
{
struct pgsql_db *db = *_db;
*_db = NULL;
event_unref(&db->api.event);
i_free(db->connect_string);
i_free(db->host);
i_free(db->error);
array_free(&db->api.module_contexts);
i_free(db);
}
static enum sql_db_flags driver_pgsql_get_flags(struct sql_db *db)
{
switch (db->state) {
case SQL_DB_STATE_DISCONNECTED:
if (sql_connect(db) < 0)
break;
/* fall through */
case SQL_DB_STATE_CONNECTING:
/* Wait for connection to finish, so we can get the flags
reliably. */
sql_wait(db);
break;
case SQL_DB_STATE_IDLE:
case SQL_DB_STATE_BUSY:
break;
}
return db->flags;
}
static int driver_pgsql_init_full_v(const struct sql_settings *set,
struct sql_db **db_r, const char **error_r ATTR_UNUSED)
{
struct pgsql_db *db;
db = i_new(struct pgsql_db, 1);
db->connect_string = i_strdup(set->connect_string);
db->api = driver_pgsql_db;
db->api.event = event_create(set->event_parent);
event_add_category(db->api.event, &event_category_pgsql);
/* NOTE: Connection string will be parsed by pgsql itself
We only pick the host part here */
T_BEGIN {
const char *const *arg = t_strsplit(db->connect_string, " ");
for (; *arg != NULL; arg++) {
if (str_begins(*arg, "host="))
db->host = i_strdup(*arg + 5);
}
} T_END;
event_set_append_log_prefix(db->api.event, t_strdup_printf("pgsql(%s): ", db->host));
*db_r = &db->api;
return 0;
}
static void driver_pgsql_deinit_v(struct sql_db *_db)
{
struct pgsql_db *db = (struct pgsql_db *)_db;
driver_pgsql_disconnect(_db);
driver_pgsql_free(&db);
}
static void driver_pgsql_set_idle(struct pgsql_db *db)
{
i_assert(db->api.state == SQL_DB_STATE_BUSY);
if (db->fatal_error)
driver_pgsql_close(db);
else if (!driver_pgsql_next_callback(db))
driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
}
static void consume_results(struct pgsql_db *db)
{
PGresult *pgres;
driver_pgsql_stop_io(db);
while (PQconsumeInput(db->pg) != 0) {
if (PQisBusy(db->pg) != 0) {
db->io = io_add(PQsocket(db->pg), IO_READ,
consume_results, db);
db->io_dir = IO_READ;
return;
}
pgres = PQgetResult(db->pg);
if (pgres == NULL)
break;
PQclear(pgres);
}
if (PQstatus(db->pg) == CONNECTION_BAD)
driver_pgsql_close(db);
else
driver_pgsql_set_idle(db);
}
static void driver_pgsql_result_free(struct sql_result *_result)
{
struct pgsql_db *db = (struct pgsql_db *)_result->db;
struct pgsql_result *result = (struct pgsql_result *)_result;
bool success;
i_assert(!result->api.callback);
i_assert(db->cur_result == result);
i_assert(result->callback == NULL);
if (_result == db->sync_result)
db->sync_result = NULL;
db->cur_result = NULL;
success = result->pgres != NULL && !db->fatal_error;
if (result->pgres != NULL) {
PQclear(result->pgres);
result->pgres = NULL;
}
if (success) {
/* we'll have to read the rest of the results as well */
i_assert(db->io == NULL);
consume_results(db);
} else {
driver_pgsql_set_idle(db);
}
if (array_is_created(&result->binary_values)) {
struct pgsql_binary_value *value;
array_foreach_modifiable(&result->binary_values, value)
PQfreemem(value->value);
array_free(&result->binary_values);
}
event_unref(&result->api.event);
i_free(result->query);
i_free(result->fields);
i_free(result->values);
i_free(result);
}
static void result_finish(struct pgsql_result *result)
{
struct pgsql_db *db = (struct pgsql_db *)result->api.db;
bool free_result = TRUE;
int duration;
i_assert(db->io == NULL);
timeout_remove(&result->to);
DLLIST_REMOVE(&db->pending_results, result);
/* if connection to server was lost, we don't yet see that the
connection is bad. we only see the fatal error, so assume it also
means disconnection. */
if (PQstatus(db->pg) == CONNECTION_BAD || result->pgres == NULL ||
PQresultStatus(result->pgres) == PGRES_FATAL_ERROR)
db->fatal_error = TRUE;
if (db->fatal_error) {
result->api.failed = TRUE;
result->api.failed_try_retry = TRUE;
}
/* emit event */
if (result->api.failed) {
const char *error = result->timeout ? "Timed out" : last_error(db);
struct event_passthrough *e =
sql_query_finished_event(&db->api, result->api.event,
result->query, TRUE, &duration);
e->add_str("error", error);
e_debug(e->event(), SQL_QUERY_FINISHED_FMT": %s", result->query,
duration, error);
} else {
e_debug(sql_query_finished_event(&db->api, result->api.event,
result->query, FALSE, &duration)->
event(),
SQL_QUERY_FINISHED_FMT, result->query, duration);
}
result->api.callback = TRUE;
T_BEGIN {
if (result->callback != NULL)
result->callback(&result->api, result->context);
} T_END;
result->api.callback = FALSE;
free_result = db->sync_result != &result->api;
if (db->ioloop != NULL)
io_loop_stop(db->ioloop);
i_assert(!free_result || result->api.refcount > 0);
result->callback = NULL;
if (free_result)
sql_result_unref(&result->api);
}
static void get_result(struct pgsql_result *result)
{
struct pgsql_db *db = (struct pgsql_db *)result->api.db;
driver_pgsql_stop_io(db);
if (PQconsumeInput(db->pg) == 0) {
result_finish(result);
return;
}
if (PQisBusy(db->pg) != 0) {
db->io = io_add(PQsocket(db->pg), IO_READ,
get_result, result);
db->io_dir = IO_READ;
return;
}
result->pgres = PQgetResult(db->pg);
result_finish(result);
}
static void flush_callback(struct pgsql_result *result)
{
struct pgsql_db *db = (struct pgsql_db *)result->api.db;
int ret;
driver_pgsql_stop_io(db);
ret = PQflush(db->pg);
if (ret > 0) {
db->io = io_add(PQsocket(db->pg), IO_WRITE,
flush_callback, result);
db->io_dir = IO_WRITE;
return;
}
if (ret < 0) {
result_finish(result);
} else {
/* all flushed */
get_result(result);
}
}
static void query_timeout(struct pgsql_result *result)
{
struct pgsql_db *db = (struct pgsql_db *)result->api.db;
driver_pgsql_stop_io(db);
result->timeout = TRUE;
result_finish(result);
}
static void do_query(struct pgsql_result *result, const char *query)
{
struct pgsql_db *db = (struct pgsql_db *)result->api.db;
int ret;
i_assert(SQL_DB_IS_READY(&db->api));
i_assert(db->cur_result == NULL);
i_assert(db->io == NULL);
driver_pgsql_set_state(db, SQL_DB_STATE_BUSY);
db->cur_result = result;
DLLIST_PREPEND(&db->pending_results, result);
result->to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
query_timeout, result);
result->query = i_strdup(query);
if (PQsendQuery(db->pg, query) == 0 ||
(ret = PQflush(db->pg)) < 0) {
/* failed to send query */
result_finish(result);
return;
}
if (ret > 0) {
/* write blocks */
db->io = io_add(PQsocket(db->pg), IO_WRITE,
flush_callback, result);
db->io_dir = IO_WRITE;
} else {
get_result(result);
}
}
static const char *
driver_pgsql_escape_string(struct sql_db *_db, const char *string)
{
struct pgsql_db *db = (struct pgsql_db *)_db;
size_t len = strlen(string);
char *to;
#ifdef HAVE_PQESCAPE_STRING_CONN
if (db->api.state == SQL_DB_STATE_DISCONNECTED) {
/* try connecting again */
(void)sql_connect(&db->api);
}
if (db->api.state != SQL_DB_STATE_DISCONNECTED) {
int error;
to = t_buffer_get(len * 2 + 1);
len = PQescapeStringConn(db->pg, to, string, len, &error);
} else
#endif
{
to = t_buffer_get(len * 2 + 1);
len = PQescapeString(to, string, len);
}
t_buffer_alloc(len + 1);
return to;
}
static void exec_callback(struct sql_result *_result,
void *context ATTR_UNUSED)
{
struct pgsql_result *result = (struct pgsql_result*)_result;
result_finish(result);
}
static void driver_pgsql_exec(struct sql_db *db, const char *query)
{
struct pgsql_result *result;
result = i_new(struct pgsql_result, 1);
result->api = driver_pgsql_result;
result->api.db = db;
result->api.refcount = 1;
result->api.event = event_create(db->event);
result->callback = exec_callback;
do_query(result, query);
}
static void driver_pgsql_query(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context)
{
struct pgsql_result *result;
result = i_new(struct pgsql_result, 1);
result->api = driver_pgsql_result;
result->api.db = db;
result->api.refcount = 1;
result->api.event = event_create(db->event);
result->callback = callback;
result->context = context;
do_query(result, query);
}
static void pgsql_query_s_callback(struct sql_result *result, void *context)
{
struct pgsql_db *db = context;
db->sync_result = result;
}
static void driver_pgsql_sync_init(struct pgsql_db *db)
{
bool add_to_connect;
db->orig_ioloop = current_ioloop;
if (db->io == NULL) {
db->ioloop = io_loop_create();
return;
}
i_assert(db->api.state == SQL_DB_STATE_CONNECTING);
/* have to move our existing I/O and timeout handlers to new I/O loop */
io_remove(&db->io);
add_to_connect = (db->to_connect != NULL);
timeout_remove(&db->to_connect);
db->ioloop = io_loop_create();
if (add_to_connect) {
db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
driver_pgsql_connect_timeout, db);
}
db->io = io_add(PQsocket(db->pg), db->io_dir, connect_callback, db);
/* wait for connecting to finish */
io_loop_run(db->ioloop);
}
static void driver_pgsql_sync_deinit(struct pgsql_db *db)
{
io_loop_destroy(&db->ioloop);
}
static struct sql_result *
driver_pgsql_sync_query(struct pgsql_db *db, const char *query)
{
struct sql_result *result;
i_assert(db->sync_result == NULL);
switch (db->api.state) {
case SQL_DB_STATE_CONNECTING:
case SQL_DB_STATE_BUSY:
i_unreached();
case SQL_DB_STATE_DISCONNECTED:
sql_not_connected_result.refcount++;
return &sql_not_connected_result;
case SQL_DB_STATE_IDLE:
break;
}
driver_pgsql_query(&db->api, query, pgsql_query_s_callback, db);
if (db->sync_result == NULL)
io_loop_run(db->ioloop);
i_assert(db->io == NULL);
result = db->sync_result;
if (result == &sql_not_connected_result) {
/* we don't end up in pgsql's free function, so sync_result
won't be set to NULL if we don't do it here. */
db->sync_result = NULL;
} else if (result == NULL) {
result = &sql_not_connected_result;
result->refcount++;
}
i_assert(db->io == NULL);
return result;
}
static struct sql_result *
driver_pgsql_query_s(struct sql_db *_db, const char *query)
{
struct pgsql_db *db = (struct pgsql_db *)_db;
struct sql_result *result;
driver_pgsql_sync_init(db);
result = driver_pgsql_sync_query(db, query);
driver_pgsql_sync_deinit(db);
return result;
}
static int driver_pgsql_result_next_row(struct sql_result *_result)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
struct pgsql_db *db = (struct pgsql_db *)_result->db;
if (result->rows != 0) {
/* second time we're here */
if (++result->rownum < result->rows)
return 1;
/* end of this packet. see if there's more. FIXME: this may
block, but the current API doesn't provide a non-blocking
way to do this.. */
PQclear(result->pgres);
result->pgres = PQgetResult(db->pg);
if (result->pgres == NULL)
return 0;
}
if (result->pgres == NULL) {
_result->failed = TRUE;
return -1;
}
switch (PQresultStatus(result->pgres)) {
case PGRES_COMMAND_OK:
/* no rows returned */
return 0;
case PGRES_TUPLES_OK:
result->rows = PQntuples(result->pgres);
return result->rows > 0 ? 1 : 0;
case PGRES_EMPTY_QUERY:
case PGRES_NONFATAL_ERROR:
/* nonfatal error */
_result->failed = TRUE;
return -1;
default:
/* treat as fatal error */
_result->failed = TRUE;
db->fatal_error = TRUE;
return -1;
}
}
static void driver_pgsql_result_fetch_fields(struct pgsql_result *result)
{
unsigned int i;
if (result->fields != NULL)
return;
/* @UNSAFE */
result->fields_count = PQnfields(result->pgres);
result->fields = i_new(const char *, result->fields_count);
for (i = 0; i < result->fields_count; i++)
result->fields[i] = PQfname(result->pgres, i);
}
static unsigned int
driver_pgsql_result_get_fields_count(struct sql_result *_result)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
driver_pgsql_result_fetch_fields(result);
return result->fields_count;
}
static const char *
driver_pgsql_result_get_field_name(struct sql_result *_result, unsigned int idx)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
driver_pgsql_result_fetch_fields(result);
i_assert(idx < result->fields_count);
return result->fields[idx];
}
static int driver_pgsql_result_find_field(struct sql_result *_result,
const char *field_name)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
unsigned int i;
driver_pgsql_result_fetch_fields(result);
for (i = 0; i < result->fields_count; i++) {
if (strcmp(result->fields[i], field_name) == 0)
return i;
}
return -1;
}
static const char *
driver_pgsql_result_get_field_value(struct sql_result *_result,
unsigned int idx)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
if (PQgetisnull(result->pgres, result->rownum, idx) != 0)
return NULL;
return PQgetvalue(result->pgres, result->rownum, idx);
}
static const unsigned char *
driver_pgsql_result_get_field_value_binary(struct sql_result *_result,
unsigned int idx, size_t *size_r)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
const char *value;
struct pgsql_binary_value *binary_value;
if (PQgetisnull(result->pgres, result->rownum, idx) != 0) {
*size_r = 0;
return NULL;
}
value = PQgetvalue(result->pgres, result->rownum, idx);
if (!array_is_created(&result->binary_values))
i_array_init(&result->binary_values, idx + 1);
binary_value = array_idx_get_space(&result->binary_values, idx);
if (binary_value->value == NULL) {
binary_value->value =
PQunescapeBytea((const unsigned char *)value,
&binary_value->size);
}
*size_r = binary_value->size;
return binary_value->value;
}
static const char *
driver_pgsql_result_find_field_value(struct sql_result *result,
const char *field_name)
{
int idx;
idx = driver_pgsql_result_find_field(result, field_name);
if (idx < 0)
return NULL;
return driver_pgsql_result_get_field_value(result, idx);
}
static const char *const *
driver_pgsql_result_get_values(struct sql_result *_result)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
unsigned int i;
if (result->values == NULL) {
driver_pgsql_result_fetch_fields(result);
result->values = i_new(const char *, result->fields_count);
}
/* @UNSAFE */
for (i = 0; i < result->fields_count; i++) {
result->values[i] =
driver_pgsql_result_get_field_value(_result, i);
}
return result->values;
}
static const char *driver_pgsql_result_get_error(struct sql_result *_result)
{
struct pgsql_result *result = (struct pgsql_result *)_result;
struct pgsql_db *db = (struct pgsql_db *)_result->db;
const char *msg;
size_t len;
i_free_and_null(db->error);
if (result->timeout) {
db->error = i_strdup("Query timed out");
} else if (result->pgres == NULL) {
/* connection error */
db->error = i_strdup(last_error(db));
} else {
msg = PQresultErrorMessage(result->pgres);
if (msg == NULL)
return "(no error set)";
/* Error message should contain trailing \n, we don't want it */
len = strlen(msg);
db->error = len == 0 || msg[len-1] != '\n' ?
i_strdup(msg) : i_strndup(msg, len-1);
}
return db->error;
}
static struct sql_transaction_context *
driver_pgsql_transaction_begin(struct sql_db *db)
{
struct pgsql_transaction_context *ctx;
ctx = i_new(struct pgsql_transaction_context, 1);
ctx->ctx.db = db;
ctx->ctx.event = event_create(db->event);
/* we need to be able to handle multiple open transactions, so at least
for now just keep them in memory until commit time. */
ctx->query_pool = pool_alloconly_create("pgsql transaction", 1024);
return &ctx->ctx;
}
static void
driver_pgsql_transaction_free(struct pgsql_transaction_context *ctx)
{
pool_unref(&ctx->query_pool);
event_unref(&ctx->ctx.event);
i_free(ctx);
}
static void
transaction_commit_callback(struct sql_result *result,
struct pgsql_transaction_context *ctx)
{
struct sql_commit_result commit_result;
i_zero(&commit_result);
if (sql_result_next_row(result) < 0) {
commit_result.error = sql_result_get_error(result);
commit_result.error_type = sql_result_get_error_type(result);
}
ctx->callback(&commit_result, ctx->context);
driver_pgsql_transaction_free(ctx);
}
static bool transaction_send_next(void *context)
{
struct pgsql_transaction_context *ctx = context;
i_assert(!ctx->failed);
if (ctx->ctx.db->state == SQL_DB_STATE_BUSY) {
/* kludgy.. */
ctx->ctx.db->state = SQL_DB_STATE_IDLE;
} else if (!SQL_DB_IS_READY(ctx->ctx.db)) {
struct sql_commit_result commit_result = {
.error = "Not connected"
};
ctx->callback(&commit_result, ctx->context);
return FALSE;
}
if (ctx->ctx.head != NULL) {
struct sql_transaction_query *query = ctx->ctx.head;
ctx->ctx.head = ctx->ctx.head->next;
sql_query(ctx->ctx.db, query->query,
transaction_update_callback, query);
} else {
sql_query(ctx->ctx.db, "COMMIT",
transaction_commit_callback, ctx);
}
return TRUE;
}
static void
transaction_commit_error_callback(struct pgsql_transaction_context *ctx,
struct sql_result *result)
{
struct sql_commit_result commit_result;
i_zero(&commit_result);
commit_result.error = sql_result_get_error(result);
commit_result.error_type = sql_result_get_error_type(result);
e_debug(sql_transaction_finished_event(&ctx->ctx)->
add_str("error", commit_result.error)->event(),
"Transaction failed: %s", commit_result.error);
ctx->callback(&commit_result, ctx->context);
}
static void
transaction_begin_callback(struct sql_result *result,
struct pgsql_transaction_context *ctx)
{
struct pgsql_db *db = (struct pgsql_db *)result->db;
i_assert(result->db == ctx->ctx.db);
if (sql_result_next_row(result) < 0) {
transaction_commit_error_callback(ctx, result);
driver_pgsql_transaction_free(ctx);
return;
}
i_assert(db->next_callback == NULL);
db->next_callback = transaction_send_next;
db->next_context = ctx;
}
static void
transaction_update_callback(struct sql_result *result,
struct sql_transaction_query *query)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)query->trans;
struct pgsql_db *db = (struct pgsql_db *)result->db;
if (sql_result_next_row(result) < 0) {
transaction_commit_error_callback(ctx, result);
driver_pgsql_transaction_free(ctx);
return;
}
if (query->affected_rows != NULL) {
struct pgsql_result *pg_result = (struct pgsql_result *)result;
if (str_to_uint(PQcmdTuples(pg_result->pgres),
query->affected_rows) < 0)
i_unreached();
}
i_assert(db->next_callback == NULL);
db->next_callback = transaction_send_next;
db->next_context = ctx;
}
static void
transaction_trans_query_callback(struct sql_result *result,
struct sql_transaction_query *query)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)query->trans;
struct sql_commit_result commit_result;
if (sql_result_next_row(result) < 0) {
transaction_commit_error_callback(ctx, result);
driver_pgsql_transaction_free(ctx);
return;
}
if (query->affected_rows != NULL) {
struct pgsql_result *pg_result = (struct pgsql_result *)result;
if (str_to_uint(PQcmdTuples(pg_result->pgres),
query->affected_rows) < 0)
i_unreached();
}
e_debug(sql_transaction_finished_event(&ctx->ctx)->event(),
"Transaction committed");
i_zero(&commit_result);
ctx->callback(&commit_result, ctx->context);
driver_pgsql_transaction_free(ctx);
}
static void
driver_pgsql_transaction_commit(struct sql_transaction_context *_ctx,
sql_commit_callback_t *callback, void *context)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)_ctx;
struct sql_commit_result result;
i_zero(&result);
ctx->callback = callback;
ctx->context = context;
if (ctx->failed || _ctx->head == NULL) {
if (ctx->failed) {
result.error = ctx->error;
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", ctx->error)->event(),
"Transaction failed: %s", ctx->error);
} else {
e_debug(sql_transaction_finished_event(_ctx)->event(),
"Transaction committed");
}
callback(&result, context);
driver_pgsql_transaction_free(ctx);
} else if (_ctx->head->next == NULL) {
/* just a single query, send it */
sql_query(_ctx->db, _ctx->head->query,
transaction_trans_query_callback, _ctx->head);
} else {
/* multiple queries, use a transaction */
i_assert(_ctx->db->v.query == driver_pgsql_query);
sql_query(_ctx->db, "BEGIN", transaction_begin_callback, ctx);
}
}
static void
commit_multi_fail(struct pgsql_transaction_context *ctx,
struct sql_result *result, const char *query)
{
ctx->failed = TRUE;
ctx->error = t_strdup_printf("%s (query: %s)",
sql_result_get_error(result), query);
sql_result_unref(result);
}
static struct sql_result *
driver_pgsql_transaction_commit_multi(struct pgsql_transaction_context *ctx)
{
struct pgsql_db *db = (struct pgsql_db *)ctx->ctx.db;
struct sql_result *result;
struct sql_transaction_query *query;
result = driver_pgsql_sync_query(db, "BEGIN");
if (sql_result_next_row(result) < 0) {
commit_multi_fail(ctx, result, "BEGIN");
return NULL;
}
sql_result_unref(result);
/* send queries */
for (query = ctx->ctx.head; query != NULL; query = query->next) {
result = driver_pgsql_sync_query(db, query->query);
if (sql_result_next_row(result) < 0) {
commit_multi_fail(ctx, result, query->query);
break;
}
if (query->affected_rows != NULL) {
struct pgsql_result *pg_result =
(struct pgsql_result *)result;
if (str_to_uint(PQcmdTuples(pg_result->pgres),
query->affected_rows) < 0)
i_unreached();
}
sql_result_unref(result);
}
return driver_pgsql_sync_query(db, ctx->failed ?
"ROLLBACK" : "COMMIT");
}
static void
driver_pgsql_try_commit_s(struct pgsql_transaction_context *ctx,
const char **error_r)
{
struct sql_transaction_context *_ctx = &ctx->ctx;
struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
struct sql_transaction_query *single_query = NULL;
struct sql_result *result;
if (_ctx->head->next == NULL) {
/* just a single query, send it */
single_query = _ctx->head;
result = sql_query_s(_ctx->db, single_query->query);
} else {
/* multiple queries, use a transaction */
driver_pgsql_sync_init(db);
result = driver_pgsql_transaction_commit_multi(ctx);
driver_pgsql_sync_deinit(db);
}
if (ctx->failed) {
i_assert(ctx->error != NULL);
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", ctx->error)->event(),
"Transaction failed: %s", ctx->error);
*error_r = ctx->error;
} else if (result != NULL) {
if (sql_result_next_row(result) < 0)
*error_r = sql_result_get_error(result);
else if (single_query != NULL &&
single_query->affected_rows != NULL) {
struct pgsql_result *pg_result =
(struct pgsql_result *)result;
if (str_to_uint(PQcmdTuples(pg_result->pgres),
single_query->affected_rows) < 0)
i_unreached();
}
}
if (!ctx->failed) {
e_debug(sql_transaction_finished_event(_ctx)->event(),
"Transaction committed");
}
if (result != NULL)
sql_result_unref(result);
}
static int
driver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
const char **error_r)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)_ctx;
struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
*error_r = NULL;
if (_ctx->head != NULL) {
driver_pgsql_try_commit_s(ctx, error_r);
if (_ctx->db->state == SQL_DB_STATE_DISCONNECTED) {
*error_r = t_strdup(*error_r);
e_info(db->api.event, "Disconnected from database, "
"retrying commit");
if (sql_connect(_ctx->db) >= 0) {
ctx->failed = FALSE;
*error_r = NULL;
driver_pgsql_try_commit_s(ctx, error_r);
}
}
}
driver_pgsql_transaction_free(ctx);
return *error_r == NULL ? 0 : -1;
}
static void
driver_pgsql_transaction_rollback(struct sql_transaction_context *_ctx)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)_ctx;
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", "Rolled back")->event(),
"Transaction rolled back");
driver_pgsql_transaction_free(ctx);
}
static void
driver_pgsql_update(struct sql_transaction_context *_ctx, const char *query,
unsigned int *affected_rows)
{
struct pgsql_transaction_context *ctx =
(struct pgsql_transaction_context *)_ctx;
sql_transaction_add_query(_ctx, ctx->query_pool, query, affected_rows);
}
static const char *
driver_pgsql_escape_blob(struct sql_db *_db ATTR_UNUSED,
const unsigned char *data, size_t size)
{
string_t *str = t_str_new(128);
str_append(str, "E'\\\\x");
binary_to_hex_append(str, data, size);
str_append_c(str, '\'');
return str_c(str);
}
static bool driver_pgsql_have_work(struct pgsql_db *db)
{
return db->next_callback != NULL || db->pending_results != NULL ||
db->api.state == SQL_DB_STATE_CONNECTING;
}
static void driver_pgsql_wait(struct sql_db *_db)
{
struct pgsql_db *db = (struct pgsql_db *)_db;
if (!driver_pgsql_have_work(db))
return;
db->orig_ioloop = current_ioloop;
db->ioloop = io_loop_create();
db->io = io_loop_move_io(&db->io);
while (driver_pgsql_have_work(db))
io_loop_run(db->ioloop);
io_loop_set_current(db->orig_ioloop);
db->io = io_loop_move_io(&db->io);
io_loop_set_current(db->ioloop);
io_loop_destroy(&db->ioloop);
}
const struct sql_db driver_pgsql_db = {
.name = "pgsql",
.flags = SQL_DB_FLAG_POOLED,
.v = {
.get_flags = driver_pgsql_get_flags,
.init_full = driver_pgsql_init_full_v,
.deinit = driver_pgsql_deinit_v,
.connect = driver_pgsql_connect,
.disconnect = driver_pgsql_disconnect,
.escape_string = driver_pgsql_escape_string,
.exec = driver_pgsql_exec,
.query = driver_pgsql_query,
.query_s = driver_pgsql_query_s,
.wait = driver_pgsql_wait,
.transaction_begin = driver_pgsql_transaction_begin,
.transaction_commit = driver_pgsql_transaction_commit,
.transaction_commit_s = driver_pgsql_transaction_commit_s,
.transaction_rollback = driver_pgsql_transaction_rollback,
.update = driver_pgsql_update,
.escape_blob = driver_pgsql_escape_blob,
}
};
const struct sql_result driver_pgsql_result = {
.v = {
.free = driver_pgsql_result_free,
.next_row = driver_pgsql_result_next_row,
.get_fields_count = driver_pgsql_result_get_fields_count,
.get_field_name = driver_pgsql_result_get_field_name,
.find_field = driver_pgsql_result_find_field,
.get_field_value = driver_pgsql_result_get_field_value,
.get_field_value_binary = driver_pgsql_result_get_field_value_binary,
.find_field_value = driver_pgsql_result_find_field_value,
.get_values = driver_pgsql_result_get_values,
.get_error = driver_pgsql_result_get_error,
}
};
const char *driver_pgsql_version = DOVECOT_ABI_VERSION;
void driver_pgsql_init(void);
void driver_pgsql_deinit(void);
void driver_pgsql_init(void)
{
sql_driver_register(&driver_pgsql_db);
}
void driver_pgsql_deinit(void)
{
sql_driver_unregister(&driver_pgsql_db);
}
#endif
dovecot-2.3.21.1/src/lib-sql/driver-cassandra.c 0000644 0000000 0000000 00000225673 14656633576 016062 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "array.h"
#include "hostpid.h"
#include "hex-binary.h"
#include "str.h"
#include "ioloop.h"
#include "net.h"
#include "write-full.h"
#include "time-util.h"
#include "var-expand.h"
#include "safe-memset.h"
#include "settings-parser.h"
#include "sql-api-private.h"
#ifdef BUILD_CASSANDRA
#include
#include
#include
#include
#include
#define IS_CONNECTED(db) \
((db)->api.state != SQL_DB_STATE_DISCONNECTED && \
(db)->api.state != SQL_DB_STATE_CONNECTING)
#define CASSANDRA_FALLBACK_WARN_INTERVAL_SECS 60
#define CASSANDRA_FALLBACK_FIRST_RETRY_MSECS 50
#define CASSANDRA_FALLBACK_MAX_RETRY_MSECS (1000*60)
#define CASS_QUERY_DEFAULT_WARN_TIMEOUT_MSECS (5*1000)
typedef void driver_cassandra_callback_t(CassFuture *future, void *context);
enum cassandra_counter_type {
CASSANDRA_COUNTER_TYPE_QUERY_SENT,
CASSANDRA_COUNTER_TYPE_QUERY_RECV_OK,
CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_NO_HOSTS,
CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_QUEUE_FULL,
CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_CLIENT_TIMEOUT,
CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_SERVER_TIMEOUT,
CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_SERVER_UNAVAILABLE,
CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_OTHER,
CASSANDRA_COUNTER_TYPE_QUERY_SLOW,
CASSANDRA_COUNTER_COUNT
};
static const char *counter_names[CASSANDRA_COUNTER_COUNT] = {
"sent",
"recv_ok",
"recv_err_no_hosts",
"recv_err_queue_full",
"recv_err_client_timeout",
"recv_err_server_timeout",
"recv_err_server_unavailable",
"recv_err_other",
"slow",
};
enum cassandra_query_type {
CASSANDRA_QUERY_TYPE_READ,
CASSANDRA_QUERY_TYPE_READ_MORE,
CASSANDRA_QUERY_TYPE_WRITE,
CASSANDRA_QUERY_TYPE_DELETE,
CASSANDRA_QUERY_TYPE_COUNT
};
static const char *cassandra_query_type_names[CASSANDRA_QUERY_TYPE_COUNT] = {
"read", "read-more", "write", "delete"
};
struct cassandra_callback {
unsigned int id;
struct timeout *to;
CassFuture *future;
struct cassandra_db *db;
driver_cassandra_callback_t *callback;
void *context;
};
struct cassandra_db {
struct sql_db api;
char *hosts, *keyspace, *user, *password;
CassConsistency read_consistency, write_consistency, delete_consistency;
CassConsistency read_fallback_consistency, write_fallback_consistency;
CassConsistency delete_fallback_consistency;
CassLogLevel log_level;
bool debug_queries;
bool latency_aware_routing;
bool init_ssl;
unsigned int protocol_version;
unsigned int num_threads;
unsigned int connect_timeout_msecs, request_timeout_msecs;
unsigned int warn_timeout_msecs;
unsigned int heartbeat_interval_secs, idle_timeout_secs;
unsigned int execution_retry_interval_msecs, execution_retry_times;
unsigned int page_size;
in_port_t port;
CassCluster *cluster;
CassSession *session;
CassTimestampGen *timestamp_gen;
CassSsl *ssl;
int fd_pipe[2];
struct io *io_pipe;
ARRAY(struct cassandra_sql_prepared_statement *) pending_prepares;
ARRAY(struct cassandra_callback *) callbacks;
ARRAY(struct cassandra_result *) results;
unsigned int callback_ids;
char *metrics_path;
char *ssl_ca_file;
char *ssl_cert_file;
char *ssl_private_key_file;
char *ssl_private_key_password;
CassSslVerifyFlags ssl_verify_flags;
struct timeout *to_metrics;
uint64_t counters[CASSANDRA_COUNTER_COUNT];
struct timeval primary_query_last_sent[CASSANDRA_QUERY_TYPE_COUNT];
time_t last_fallback_warning[CASSANDRA_QUERY_TYPE_COUNT];
unsigned int fallback_failures[CASSANDRA_QUERY_TYPE_COUNT];
/* for synchronous queries: */
struct ioloop *ioloop, *orig_ioloop;
struct sql_result *sync_result;
char *error;
};
struct cassandra_result {
struct sql_result api;
CassStatement *statement;
const CassResult *result;
CassIterator *iterator;
char *log_query;
char *error;
CassConsistency consistency, fallback_consistency;
enum cassandra_query_type query_type;
struct timeval page0_start_time, start_time, finish_time;
unsigned int row_count, total_row_count, page_num;
cass_int64_t timestamp;
pool_t row_pool;
ARRAY_TYPE(const_string) fields;
ARRAY(size_t) field_sizes;
sql_query_callback_t *callback;
void *context;
bool is_prepared:1;
bool query_sent:1;
bool finished:1;
bool paging_continues:1;
};
struct cassandra_transaction_context {
struct sql_transaction_context ctx;
int refcount;
sql_commit_callback_t *callback;
void *context;
struct cassandra_sql_statement *stmt;
char *query;
char *log_query;
cass_int64_t query_timestamp;
char *error;
bool begin_succeeded:1;
bool begin_failed:1;
bool failed:1;
};
struct cassandra_sql_arg {
unsigned int column_idx;
char *value_str;
const unsigned char *value_binary;
size_t value_binary_size;
int64_t value_int64;
};
struct cassandra_sql_statement {
struct sql_statement stmt;
struct cassandra_sql_prepared_statement *prep;
CassStatement *cass_stmt;
ARRAY(struct cassandra_sql_arg) pending_args;
cass_int64_t timestamp;
struct cassandra_result *result;
};
struct cassandra_sql_prepared_statement {
struct sql_prepared_statement prep_stmt;
/* NULL, until the prepare is asynchronously finished */
const CassPrepared *prepared;
/* statements waiting for prepare to finish */
ARRAY(struct cassandra_sql_statement *) pending_statements;
/* an error here will cause the prepare to be retried on the next
execution attempt. */
char *error;
bool pending;
};
extern const struct sql_db driver_cassandra_db;
extern const struct sql_result driver_cassandra_result;
static struct {
CassConsistency consistency;
const char *name;
} cass_consistency_names[] = {
{ CASS_CONSISTENCY_ANY, "any" },
{ CASS_CONSISTENCY_ONE, "one" },
{ CASS_CONSISTENCY_TWO, "two" },
{ CASS_CONSISTENCY_THREE, "three" },
{ CASS_CONSISTENCY_QUORUM, "quorum" },
{ CASS_CONSISTENCY_ALL, "all" },
{ CASS_CONSISTENCY_LOCAL_QUORUM, "local-quorum" },
{ CASS_CONSISTENCY_EACH_QUORUM, "each-quorum" },
{ CASS_CONSISTENCY_SERIAL, "serial" },
{ CASS_CONSISTENCY_LOCAL_SERIAL, "local-serial" },
{ CASS_CONSISTENCY_LOCAL_ONE, "local-one" }
};
static struct {
CassLogLevel log_level;
const char *name;
} cass_log_level_names[] = {
{ CASS_LOG_CRITICAL, "critical" },
{ CASS_LOG_ERROR, "error" },
{ CASS_LOG_WARN, "warn" },
{ CASS_LOG_INFO, "info" },
{ CASS_LOG_DEBUG, "debug" },
{ CASS_LOG_TRACE, "trace" }
};
static struct event_category event_category_cassandra = {
.parent = &event_category_sql,
.name = "cassandra"
};
static pthread_t main_thread_id;
static bool main_thread_id_set;
static void driver_cassandra_prepare_pending(struct cassandra_db *db);
static void
prepare_finish_pending_statements(struct cassandra_sql_prepared_statement *prep_stmt);
static void driver_cassandra_result_send_query(struct cassandra_result *result);
static void driver_cassandra_send_queries(struct cassandra_db *db);
static void result_finish(struct cassandra_result *result);
static void log_one_line(const CassLogMessage *message,
enum log_type log_type, const char *log_level_str,
const char *text, size_t text_len)
{
/* NOTE: We may not be in the main thread. We can't use the
standard Dovecot functions that may use data stack. That's why
we can't use i_log_type() in here, but have to re-implement the
internal logging protocol. Otherwise preserve Cassandra's own
logging format. */
fprintf(stderr, "\001%c%s %u.%03u %s(%s:%d:%s): %.*s\n",
log_type+1, my_pid,
(unsigned int)(message->time_ms / 1000),
(unsigned int)(message->time_ms % 1000),
log_level_str,
message->file, message->line, message->function,
(int)text_len, text);
}
static void
driver_cassandra_log_handler(const CassLogMessage* message,
void *data ATTR_UNUSED)
{
enum log_type log_type = LOG_TYPE_ERROR;
const char *log_level_str = "";
switch (message->severity) {
case CASS_LOG_DISABLED:
case CASS_LOG_LAST_ENTRY:
i_unreached();
case CASS_LOG_CRITICAL:
log_type = LOG_TYPE_PANIC;
break;
case CASS_LOG_ERROR:
log_type = LOG_TYPE_ERROR;
break;
case CASS_LOG_WARN:
log_type = LOG_TYPE_WARNING;
break;
case CASS_LOG_INFO:
log_type = LOG_TYPE_INFO;
break;
case CASS_LOG_TRACE:
log_level_str = "[TRACE] ";
/* fall through */
case CASS_LOG_DEBUG:
log_type = LOG_TYPE_DEBUG;
break;
}
/* Log message may contain LFs, so log each line separately. */
const char *p, *line = message->message;
while ((p = strchr(line, '\n')) != NULL) {
log_one_line(message, log_type, log_level_str, line, p - line);
line = p+1;
}
log_one_line(message, log_type, log_level_str, line, strlen(line));
}
static void driver_cassandra_init_log(void)
{
failure_callback_t *fatal_callback, *error_callback;
failure_callback_t *info_callback, *debug_callback;
i_get_failure_handlers(&fatal_callback, &error_callback,
&info_callback, &debug_callback);
if (i_failure_handler_is_internal(debug_callback)) {
/* Using internal logging protocol. Use it ourself to set log
levels correctly. */
cass_log_set_callback(driver_cassandra_log_handler, NULL);
}
}
static int consistency_parse(const char *str, CassConsistency *consistency_r)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(cass_consistency_names); i++) {
if (strcmp(cass_consistency_names[i].name, str) == 0) {
*consistency_r = cass_consistency_names[i].consistency;
return 0;
}
}
return -1;
}
static int log_level_parse(const char *str, CassLogLevel *log_level_r)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(cass_log_level_names); i++) {
if (strcmp(cass_log_level_names[i].name, str) == 0) {
*log_level_r = cass_log_level_names[i].log_level;
return 0;
}
}
return -1;
}
static void driver_cassandra_set_state(struct cassandra_db *db,
enum sql_db_state state)
{
/* switch back to original ioloop in case the caller wants to
add/remove timeouts */
if (db->ioloop != NULL)
io_loop_set_current(db->orig_ioloop);
sql_db_set_state(&db->api, state);
if (db->ioloop != NULL)
io_loop_set_current(db->ioloop);
}
static void driver_cassandra_close(struct cassandra_db *db, const char *error)
{
struct cassandra_sql_prepared_statement *prep_stmt;
struct cassandra_result *const *resultp;
io_remove(&db->io_pipe);
if (db->fd_pipe[0] != -1) {
i_close_fd(&db->fd_pipe[0]);
i_close_fd(&db->fd_pipe[1]);
}
driver_cassandra_set_state(db, SQL_DB_STATE_DISCONNECTED);
array_foreach_elem(&db->pending_prepares, prep_stmt) {
prep_stmt->pending = FALSE;
prep_stmt->error = i_strdup(error);
prepare_finish_pending_statements(prep_stmt);
}
array_clear(&db->pending_prepares);
while (array_count(&db->results) > 0) {
resultp = array_front(&db->results);
if ((*resultp)->error == NULL)
(*resultp)->error = i_strdup(error);
result_finish(*resultp);
}
if (db->ioloop != NULL) {
/* running a sync query, stop it */
io_loop_stop(db->ioloop);
}
}
static void driver_cassandra_log_error(struct cassandra_db *db,
CassFuture *future, const char *str)
{
const char *message;
size_t size;
cass_future_error_message(future, &message, &size);
e_error(db->api.event, "%s: %.*s", str, (int)size, message);
}
static struct cassandra_callback *
cassandra_callback_detach(struct cassandra_db *db, unsigned int id)
{
struct cassandra_callback *cb, *const *cbp;
/* usually there are only a few callbacks, so don't bother with using
a hash table */
array_foreach(&db->callbacks, cbp) {
cb = *cbp;
if (cb->id == id) {
array_delete(&db->callbacks,
array_foreach_idx(&db->callbacks, cbp), 1);
return cb;
}
}
return NULL;
}
static void cassandra_callback_run(struct cassandra_callback *cb)
{
timeout_remove(&cb->to);
cb->callback(cb->future, cb->context);
cass_future_free(cb->future);
i_free(cb);
}
static void driver_cassandra_future_callback(CassFuture *future ATTR_UNUSED,
void *context)
{
struct cassandra_callback *cb = context;
if (pthread_equal(pthread_self(), main_thread_id) != 0) {
/* called immediately from the main thread. */
cassandra_callback_detach(cb->db, cb->id);
cb->to = timeout_add_short(0, cassandra_callback_run, cb);
return;
}
/* this isn't the main thread - communicate with main thread by
writing the callback id to the pipe. note that we must not use
almost any dovecot functions here because most of them are using
data-stack, which isn't thread-safe. especially don't use
i_error() here. */
if (write_full(cb->db->fd_pipe[1], &cb->id, sizeof(cb->id)) < 0) {
const char *str = t_strdup_printf(
"cassandra: write(pipe) failed: %s\n",
strerror(errno));
(void)write_full(STDERR_FILENO, str, strlen(str));
}
}
static void driver_cassandra_input_id(struct cassandra_db *db, unsigned int id)
{
struct cassandra_callback *cb;
cb = cassandra_callback_detach(db, id);
if (cb == NULL)
i_panic("cassandra: Received unknown ID %u", id);
cassandra_callback_run(cb);
}
static void driver_cassandra_input(struct cassandra_db *db)
{
unsigned int ids[1024];
ssize_t ret;
ret = read(db->fd_pipe[0], ids, sizeof(ids));
if (ret < 0)
e_error(db->api.event, "read(pipe) failed: %m");
else if (ret == 0)
e_error(db->api.event, "read(pipe) failed: EOF");
else if (ret % sizeof(ids[0]) != 0)
e_error(db->api.event, "read(pipe) returned wrong amount of data");
else {
/* success */
unsigned int i, count = ret / sizeof(ids[0]);
for (i = 0; i < count &&
db->api.state != SQL_DB_STATE_DISCONNECTED; i++)
driver_cassandra_input_id(db, ids[i]);
return;
}
driver_cassandra_close(db, "IPC pipe closed");
}
static void
driver_cassandra_set_callback(CassFuture *future, struct cassandra_db *db,
driver_cassandra_callback_t *callback,
void *context)
{
struct cassandra_callback *cb;
i_assert(callback != NULL);
cb = i_new(struct cassandra_callback, 1);
cb->future = future;
cb->callback = callback;
cb->context = context;
cb->db = db;
array_push_back(&db->callbacks, &cb);
cb->id = ++db->callback_ids;
if (cb->id == 0)
cb->id = ++db->callback_ids;
/* NOTE: The callback may be called immediately by this same thread.
This is checked within the callback. It may also be called at any
time after this call by another thread. So we must not access "cb"
again after this call. */
cass_future_set_callback(future, driver_cassandra_future_callback, cb);
}
static void connect_callback(CassFuture *future, void *context)
{
struct cassandra_db *db = context;
if (cass_future_error_code(future) != CASS_OK) {
driver_cassandra_log_error(db, future,
"Couldn't connect to Cassandra");
driver_cassandra_close(db, "Couldn't connect to Cassandra");
return;
}
driver_cassandra_set_state(db, SQL_DB_STATE_IDLE);
if (db->ioloop != NULL) {
/* driver_cassandra_sync_init() waiting for connection to
finish */
io_loop_stop(db->ioloop);
}
driver_cassandra_prepare_pending(db);
driver_cassandra_send_queries(db);
}
static int driver_cassandra_connect(struct sql_db *_db)
{
struct cassandra_db *db = (struct cassandra_db *)_db;
CassFuture *future;
i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
if (pipe(db->fd_pipe) < 0) {
e_error(_db->event, "pipe() failed: %m");
return -1;
}
db->io_pipe = io_add(db->fd_pipe[0], IO_READ,
driver_cassandra_input, db);
driver_cassandra_set_state(db, SQL_DB_STATE_CONNECTING);
future = cass_session_connect_keyspace(db->session, db->cluster,
db->keyspace);
driver_cassandra_set_callback(future, db, connect_callback, db);
return 0;
}
static void driver_cassandra_disconnect(struct sql_db *_db)
{
struct cassandra_db *db = (struct cassandra_db *)_db;
driver_cassandra_close(db, "Disconnected");
}
static const char *
driver_cassandra_escape_string(struct sql_db *db ATTR_UNUSED,
const char *string)
{
string_t *escaped;
unsigned int i;
if (strchr(string, '\'') == NULL)
return string;
escaped = t_str_new(strlen(string)+10);
for (i = 0; string[i] != '\0'; i++) {
if (string[i] == '\'')
str_append_c(escaped, '\'');
str_append_c(escaped, string[i]);
}
return str_c(escaped);
}
static int driver_cassandra_parse_connect_string(struct cassandra_db *db,
const char *connect_string,
const char **error_r)
{
const char *const *args, *key, *value, *error;
string_t *hosts = t_str_new(64);
bool read_fallback_set = FALSE, write_fallback_set = FALSE;
bool delete_fallback_set = FALSE;
db->log_level = CASS_LOG_WARN;
db->read_consistency = CASS_CONSISTENCY_LOCAL_QUORUM;
db->write_consistency = CASS_CONSISTENCY_LOCAL_QUORUM;
db->delete_consistency = CASS_CONSISTENCY_LOCAL_QUORUM;
db->connect_timeout_msecs = SQL_CONNECT_TIMEOUT_SECS*1000;
db->request_timeout_msecs = SQL_QUERY_TIMEOUT_SECS*1000;
db->warn_timeout_msecs = CASS_QUERY_DEFAULT_WARN_TIMEOUT_MSECS;
args = t_strsplit_spaces(connect_string, " ");
for (; *args != NULL; args++) {
value = strchr(*args, '=');
if (value == NULL) {
*error_r = t_strdup_printf(
"Missing value in connect string: %s", *args);
return -1;
}
key = t_strdup_until(*args, value++);
if (str_begins(key, "ssl_"))
db->init_ssl = TRUE;
if (strcmp(key, "host") == 0) {
if (str_len(hosts) > 0)
str_append_c(hosts, ',');
str_append(hosts, value);
} else if (strcmp(key, "port") == 0) {
if (net_str2port(value, &db->port) < 0) {
*error_r = t_strdup_printf(
"Invalid port: %s", value);
return -1;
}
} else if (strcmp(key, "dbname") == 0 ||
strcmp(key, "keyspace") == 0) {
i_free(db->keyspace);
db->keyspace = i_strdup(value);
} else if (strcmp(key, "user") == 0) {
i_free(db->user);
db->user = i_strdup(value);
} else if (strcmp(key, "password") == 0) {
i_free(db->password);
db->password = i_strdup(value);
} else if (strcmp(key, "read_consistency") == 0) {
if (consistency_parse(value, &db->read_consistency) < 0) {
*error_r = t_strdup_printf(
"Unknown read_consistency: %s", value);
return -1;
}
} else if (strcmp(key, "read_fallback_consistency") == 0) {
if (consistency_parse(value, &db->read_fallback_consistency) < 0) {
*error_r = t_strdup_printf(
"Unknown read_fallback_consistency: %s", value);
return -1;
}
read_fallback_set = TRUE;
} else if (strcmp(key, "write_consistency") == 0) {
if (consistency_parse(value,
&db->write_consistency) < 0) {
*error_r = t_strdup_printf(
"Unknown write_consistency: %s", value);
return -1;
}
} else if (strcmp(key, "write_fallback_consistency") == 0) {
if (consistency_parse(value,
&db->write_fallback_consistency) < 0) {
*error_r = t_strdup_printf(
"Unknown write_fallback_consistency: %s",
value);
return -1;
}
write_fallback_set = TRUE;
} else if (strcmp(key, "delete_consistency") == 0) {
if (consistency_parse(value,
&db->delete_consistency) < 0) {
*error_r = t_strdup_printf(
"Unknown delete_consistency: %s", value);
return -1;
}
} else if (strcmp(key, "delete_fallback_consistency") == 0) {
if (consistency_parse(value,
&db->delete_fallback_consistency) < 0) {
*error_r = t_strdup_printf(
"Unknown delete_fallback_consistency: %s",
value);
return -1;
}
delete_fallback_set = TRUE;
} else if (strcmp(key, "log_level") == 0) {
if (log_level_parse(value, &db->log_level) < 0) {
*error_r = t_strdup_printf(
"Unknown log_level: %s", value);
return -1;
}
} else if (strcmp(key, "debug_queries") == 0) {
db->debug_queries = TRUE;
} else if (strcmp(key, "latency_aware_routing") == 0) {
db->latency_aware_routing = TRUE;
} else if (strcmp(key, "version") == 0) {
if (str_to_uint(value, &db->protocol_version) < 0) {
*error_r = t_strdup_printf(
"Invalid version: %s", value);
return -1;
}
} else if (strcmp(key, "num_threads") == 0) {
if (str_to_uint(value, &db->num_threads) < 0) {
*error_r = t_strdup_printf(
"Invalid num_threads: %s", value);
return -1;
}
} else if (strcmp(key, "heartbeat_interval") == 0) {
if (settings_get_time(value, &db->heartbeat_interval_secs,
&error) < 0) {
*error_r = t_strdup_printf(
"Invalid heartbeat_interval '%s': %s",
value, error);
return -1;
}
} else if (strcmp(key, "idle_timeout") == 0) {
if (settings_get_time(value, &db->idle_timeout_secs,
&error) < 0) {
*error_r = t_strdup_printf(
"Invalid idle_timeout '%s': %s",
value, error);
return -1;
}
} else if (strcmp(key, "connect_timeout") == 0) {
if (settings_get_time_msecs(value,
&db->connect_timeout_msecs,
&error) < 0) {
*error_r = t_strdup_printf(
"Invalid connect_timeout '%s': %s",
value, error);
return -1;
}
} else if (strcmp(key, "request_timeout") == 0) {
if (settings_get_time_msecs(value,
&db->request_timeout_msecs,
&error) < 0) {
*error_r = t_strdup_printf(
"Invalid request_timeout '%s': %s",
value, error);
return -1;
}
} else if (strcmp(key, "warn_timeout") == 0) {
if (settings_get_time_msecs(value,
&db->warn_timeout_msecs,
&error) < 0) {
*error_r = t_strdup_printf(
"Invalid warn_timeout '%s': %s",
value, error);
return -1;
}
} else if (strcmp(key, "metrics") == 0) {
i_free(db->metrics_path);
db->metrics_path = i_strdup(value);
} else if (strcmp(key, "execution_retry_interval") == 0) {
if (settings_get_time_msecs(value,
&db->execution_retry_interval_msecs,
&error) < 0) {
*error_r = t_strdup_printf(
"Invalid execution_retry_interval '%s': %s",
value, error);
return -1;
}
#ifndef HAVE_CASSANDRA_SPECULATIVE_POLICY
*error_r = t_strdup_printf(
"This cassandra version does not support execution_retry_interval");
return -1;
#endif
} else if (strcmp(key, "execution_retry_times") == 0) {
if (str_to_uint(value, &db->execution_retry_times) < 0) {
*error_r = t_strdup_printf(
"Invalid execution_retry_times %s",
value);
return -1;
}
#ifndef HAVE_CASSANDRA_SPECULATIVE_POLICY
*error_r = t_strdup_printf(
"This cassandra version does not support execution_retry_times");
return -1;
#endif
} else if (strcmp(key, "page_size") == 0) {
if (str_to_uint(value, &db->page_size) < 0) {
*error_r = t_strdup_printf(
"Invalid page_size: %s",
value);
return -1;
}
} else if (strcmp(key, "ssl_ca") == 0) {
db->ssl_ca_file = i_strdup(value);
} else if (strcmp(key, "ssl_cert_file") == 0) {
db->ssl_cert_file = i_strdup(value);
} else if (strcmp(key, "ssl_private_key_file") == 0) {
db->ssl_private_key_file = i_strdup(value);
} else if (strcmp(key, "ssl_private_key_password") == 0) {
db->ssl_private_key_password = i_strdup(value);
} else if (strcmp(key, "ssl_verify") == 0) {
if (strcmp(value, "none") == 0) {
db->ssl_verify_flags = CASS_SSL_VERIFY_NONE;
} else if (strcmp(value, "cert") == 0) {
db->ssl_verify_flags = CASS_SSL_VERIFY_PEER_CERT;
} else if (strcmp(value, "cert-ip") == 0) {
db->ssl_verify_flags =
CASS_SSL_VERIFY_PEER_CERT |
CASS_SSL_VERIFY_PEER_IDENTITY;
#if HAVE_DECL_CASS_SSL_VERIFY_PEER_IDENTITY_DNS == 1
} else if (strcmp(value, "cert-dns") == 0) {
db->ssl_verify_flags =
CASS_SSL_VERIFY_PEER_CERT |
CASS_SSL_VERIFY_PEER_IDENTITY_DNS;
#endif
} else {
*error_r = t_strdup_printf(
"Unsupported ssl_verify flags: '%s'",
value);
return -1;
}
} else {
*error_r = t_strdup_printf(
"Unknown connect string: %s", key);
return -1;
}
}
if (!read_fallback_set)
db->read_fallback_consistency = db->read_consistency;
if (!write_fallback_set)
db->write_fallback_consistency = db->write_consistency;
if (!delete_fallback_set)
db->delete_fallback_consistency = db->delete_consistency;
if (str_len(hosts) == 0) {
*error_r = t_strdup_printf("No hosts given in connect string");
return -1;
}
if (db->keyspace == NULL) {
*error_r = t_strdup_printf("No dbname given in connect string");
return -1;
}
if ((db->ssl_cert_file != NULL && db->ssl_private_key_file == NULL) ||
(db->ssl_cert_file == NULL && db->ssl_private_key_file != NULL)) {
*error_r = "ssl_cert_file and ssl_private_key_file need to be both set";
return -1;
}
db->hosts = i_strdup(str_c(hosts));
return 0;
}
static void
driver_cassandra_get_metrics_json(struct cassandra_db *db, string_t *dest)
{
#define ADD_UINT64(_struct, _field) \
str_printfa(dest, "\""#_field"\": %llu,", \
(unsigned long long)metrics._struct._field);
#define ADD_DOUBLE(_struct, _field) \
str_printfa(dest, "\""#_field"\": %02lf,", metrics._struct._field);
CassMetrics metrics;
cass_session_get_metrics(db->session, &metrics);
str_append(dest, "{ \"requests\": {");
ADD_UINT64(requests, min);
ADD_UINT64(requests, max);
ADD_UINT64(requests, mean);
ADD_UINT64(requests, stddev);
ADD_UINT64(requests, median);
ADD_UINT64(requests, percentile_75th);
ADD_UINT64(requests, percentile_95th);
ADD_UINT64(requests, percentile_98th);
ADD_UINT64(requests, percentile_99th);
ADD_UINT64(requests, percentile_999th);
ADD_DOUBLE(requests, mean_rate);
ADD_DOUBLE(requests, one_minute_rate);
ADD_DOUBLE(requests, five_minute_rate);
ADD_DOUBLE(requests, fifteen_minute_rate);
str_truncate(dest, str_len(dest)-1);
str_append(dest, "}, \"stats\": {");
ADD_UINT64(stats, total_connections);
ADD_UINT64(stats, available_connections);
ADD_UINT64(stats, exceeded_pending_requests_water_mark);
ADD_UINT64(stats, exceeded_write_bytes_water_mark);
str_truncate(dest, str_len(dest)-1);
str_append(dest, "}, \"errors\": {");
ADD_UINT64(errors, connection_timeouts);
ADD_UINT64(errors, pending_request_timeouts);
ADD_UINT64(errors, request_timeouts);
str_truncate(dest, str_len(dest)-1);
str_append(dest, "}, \"queries\": {");
for (unsigned int i = 0; i < CASSANDRA_COUNTER_COUNT; i++) {
str_printfa(dest, "\"%s\": %"PRIu64",", counter_names[i],
db->counters[i]);
}
str_truncate(dest, str_len(dest)-1);
str_append(dest, "}}");
}
static void driver_cassandra_metrics_write(struct cassandra_db *db)
{
struct var_expand_table tab[] = {
{ '\0', NULL, NULL }
};
string_t *path = t_str_new(64);
string_t *data;
const char *error;
int fd;
if (var_expand(path, db->metrics_path, tab, &error) <= 0) {
e_error(db->api.event, "Failed to expand metrics_path=%s: %s",
db->metrics_path, error);
return;
}
fd = open(str_c(path), O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, 0600);
if (fd == -1) {
e_error(db->api.event, "creat(%s) failed: %m", str_c(path));
return;
}
data = t_str_new(1024);
driver_cassandra_get_metrics_json(db, data);
if (write_full(fd, str_data(data), str_len(data)) < 0)
e_error(db->api.event, "write(%s) failed: %m", str_c(path));
i_close_fd(&fd);
}
static void driver_cassandra_free(struct cassandra_db **_db)
{
struct cassandra_db *db = *_db;
*_db = NULL;
event_unref(&db->api.event);
i_free(db->metrics_path);
i_free(db->hosts);
i_free(db->error);
i_free(db->keyspace);
i_free(db->user);
i_free(db->password);
i_free(db->ssl_ca_file);
i_free(db->ssl_cert_file);
i_free(db->ssl_private_key_file);
i_free_and_null(db->ssl_private_key_password);
array_free(&db->api.module_contexts);
if (db->ssl != NULL)
cass_ssl_free(db->ssl);
i_free(db);
}
static int driver_cassandra_init_ssl(struct cassandra_db *db, const char **error_r)
{
buffer_t *buf = t_buffer_create(512);
CassError c_err;
db->ssl = cass_ssl_new();
i_assert(db->ssl != NULL);
if (db->ssl_ca_file != NULL) {
if (buffer_append_full_file(buf, db->ssl_ca_file, SIZE_MAX,
error_r) < 0)
return -1;
if ((c_err = cass_ssl_add_trusted_cert(db->ssl, str_c(buf))) != CASS_OK) {
*error_r = cass_error_desc(c_err);
return -1;
}
}
if (db->ssl_private_key_file != NULL && db->ssl_cert_file != NULL) {
buffer_set_used_size(buf, 0);
if (buffer_append_full_file(buf, db->ssl_private_key_file,
SIZE_MAX, error_r) < 0)
return -1;
c_err = cass_ssl_set_private_key(db->ssl, str_c(buf),
db->ssl_private_key_password);
safe_memset(buffer_get_modifiable_data(buf, NULL), 0, buf->used);
if (c_err != CASS_OK) {
*error_r = cass_error_desc(c_err);
return -1;
}
buffer_set_used_size(buf, 0);
if (buffer_append_full_file(buf, db->ssl_cert_file, SIZE_MAX, error_r) < 0)
return -1;
if ((c_err = cass_ssl_set_cert(db->ssl, str_c(buf))) != CASS_OK) {
*error_r = cass_error_desc(c_err);
return -1;
}
}
cass_ssl_set_verify_flags(db->ssl, db->ssl_verify_flags);
return 0;
}
static int driver_cassandra_init_full_v(const struct sql_settings *set,
struct sql_db **db_r,
const char **error_r)
{
struct cassandra_db *db;
int ret;
db = i_new(struct cassandra_db, 1);
db->api = driver_cassandra_db;
db->fd_pipe[0] = db->fd_pipe[1] = -1;
db->api.event = event_create(set->event_parent);
event_add_category(db->api.event, &event_category_cassandra);
event_set_append_log_prefix(db->api.event, "cassandra: ");
T_BEGIN {
ret = driver_cassandra_parse_connect_string(db,
set->connect_string, error_r);
} T_END_PASS_STR_IF(ret < 0, error_r);
if (ret < 0) {
driver_cassandra_free(&db);
return -1;
}
if (db->init_ssl && driver_cassandra_init_ssl(db, error_r) < 0) {
driver_cassandra_free(&db);
return -1;
}
driver_cassandra_init_log();
cass_log_set_level(db->log_level);
if (db->log_level >= CASS_LOG_DEBUG)
event_set_forced_debug(db->api.event, TRUE);
if (db->protocol_version > 0 && db->protocol_version < 4) {
/* binding with column indexes requires v4 */
db->api.v.prepared_statement_init = NULL;
db->api.v.prepared_statement_deinit = NULL;
db->api.v.statement_init_prepared = NULL;
}
db->timestamp_gen = cass_timestamp_gen_monotonic_new();
db->cluster = cass_cluster_new();
#ifdef HAVE_CASS_CLUSTER_SET_USE_HOSTNAME_RESOLUTION
if ((db->ssl_verify_flags & CASS_SSL_VERIFY_PEER_IDENTITY_DNS) != 0) {
CassError c_err;
if ((c_err = cass_cluster_set_use_hostname_resolution(
db->cluster, cass_true)) != CASS_OK) {
*error_r = cass_error_desc(c_err);
driver_cassandra_free(&db);
return -1;
}
}
#endif
cass_cluster_set_ssl(db->cluster, db->ssl);
cass_cluster_set_timestamp_gen(db->cluster, db->timestamp_gen);
cass_cluster_set_connect_timeout(db->cluster, db->connect_timeout_msecs);
cass_cluster_set_request_timeout(db->cluster, db->request_timeout_msecs);
cass_cluster_set_contact_points(db->cluster, db->hosts);
if (db->user != NULL && db->password != NULL)
cass_cluster_set_credentials(db->cluster, db->user, db->password);
if (db->port != 0)
cass_cluster_set_port(db->cluster, db->port);
if (db->protocol_version != 0)
cass_cluster_set_protocol_version(db->cluster, db->protocol_version);
if (db->num_threads != 0)
cass_cluster_set_num_threads_io(db->cluster, db->num_threads);
if (db->latency_aware_routing)
cass_cluster_set_latency_aware_routing(db->cluster, cass_true);
if (db->heartbeat_interval_secs != 0)
cass_cluster_set_connection_heartbeat_interval(db->cluster,
db->heartbeat_interval_secs);
if (db->idle_timeout_secs != 0)
cass_cluster_set_connection_idle_timeout(db->cluster,
db->idle_timeout_secs);
#ifdef HAVE_CASSANDRA_SPECULATIVE_POLICY
if (db->execution_retry_times > 0 && db->execution_retry_interval_msecs > 0)
cass_cluster_set_constant_speculative_execution_policy(
db->cluster, db->execution_retry_interval_msecs,
db->execution_retry_times);
#endif
if (db->ssl != NULL) {
e_debug(db->api.event, "Enabling TLS for cluster");
cass_cluster_set_ssl(db->cluster, db->ssl);
}
db->session = cass_session_new();
if (db->metrics_path != NULL)
db->to_metrics = timeout_add(1000, driver_cassandra_metrics_write,
db);
i_array_init(&db->results, 16);
i_array_init(&db->callbacks, 16);
i_array_init(&db->pending_prepares, 16);
if (!main_thread_id_set) {
main_thread_id = pthread_self();
main_thread_id_set = TRUE;
}
*db_r = &db->api;
return 0;
}
static void driver_cassandra_deinit_v(struct sql_db *_db)
{
struct cassandra_db *db = (struct cassandra_db *)_db;
driver_cassandra_close(db, "Deinitialized");
i_assert(array_count(&db->callbacks) == 0);
array_free(&db->callbacks);
i_assert(array_count(&db->results) == 0);
array_free(&db->results);
i_assert(array_count(&db->pending_prepares) == 0);
array_free(&db->pending_prepares);
cass_session_free(db->session);
cass_cluster_free(db->cluster);
cass_timestamp_gen_free(db->timestamp_gen);
timeout_remove(&db->to_metrics);
sql_connection_log_finished(_db);
driver_cassandra_free(&db);
}
static void driver_cassandra_result_unlink(struct cassandra_db *db,
struct cassandra_result *result)
{
struct cassandra_result *const *results;
unsigned int i, count;
results = array_get(&db->results, &count);
for (i = 0; i < count; i++) {
if (results[i] == result) {
array_delete(&db->results, i, 1);
return;
}
}
i_unreached();
}
static void driver_cassandra_log_result(struct cassandra_result *result,
bool all_pages, long long reply_usecs)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
struct timeval now;
unsigned int row_count;
i_gettimeofday(&now);
string_t *str = t_str_new(128);
str_printfa(str, "Finished %squery '%s' (",
result->is_prepared ? "prepared " : "", result->log_query);
if (result->timestamp != 0)
str_printfa(str, "timestamp=%"PRId64", ", result->timestamp);
if (all_pages) {
str_printfa(str, "%u pages in total, ", result->page_num);
row_count = result->total_row_count;
} else {
if (result->page_num > 0 || result->paging_continues)
str_printfa(str, "page %u, ", result->page_num);
row_count = result->row_count;
}
str_printfa(str, "%u rows, %lld+%lld us): %s", row_count, reply_usecs,
timeval_diff_usecs(&now, &result->finish_time),
result->error != NULL ? result->error : "success");
struct event_passthrough *e =
sql_query_finished_event(&db->api, result->api.event,
result->log_query, result->error == NULL,
NULL);
if (result->error != NULL)
e->add_str("error", result->error);
struct event *event = e->event();
if (db->debug_queries)
event_set_forced_debug(event, TRUE);
if (reply_usecs/1000 >= db->warn_timeout_msecs) {
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_SLOW]++;
e_warning(event, "%s", str_c(str));
} else {
e_debug(event, "%s", str_c(str));
}
}
static void driver_cassandra_result_free(struct sql_result *_result)
{
struct cassandra_db *db = (struct cassandra_db *)_result->db;
struct cassandra_result *result = (struct cassandra_result *)_result;
long long reply_usecs;
i_assert(!result->api.callback);
i_assert(result->callback == NULL);
if (_result == db->sync_result)
db->sync_result = NULL;
reply_usecs = timeval_diff_usecs(&result->finish_time,
&result->start_time);
driver_cassandra_log_result(result, FALSE, reply_usecs);
if (result->page_num > 0 && !result->paging_continues) {
/* Multi-page query finishes now. Log a debug/warning summary
message about it separate from the per-page messages. */
reply_usecs = timeval_diff_usecs(&result->finish_time,
&result->page0_start_time);
driver_cassandra_log_result(result, TRUE, reply_usecs);
}
if (result->result != NULL)
cass_result_free(result->result);
if (result->iterator != NULL)
cass_iterator_free(result->iterator);
if (result->statement != NULL)
cass_statement_free(result->statement);
pool_unref(&result->row_pool);
event_unref(&result->api.event);
i_free(result->log_query);
i_free(result->error);
i_free(result);
}
static void result_finish(struct cassandra_result *result)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
bool free_result = TRUE;
result->finished = TRUE;
result->finish_time = ioloop_timeval;
driver_cassandra_result_unlink(db, result);
i_assert((result->error != NULL) == (result->iterator == NULL));
result->api.callback = TRUE;
T_BEGIN {
result->callback(&result->api, result->context);
} T_END;
result->api.callback = FALSE;
free_result = db->sync_result != &result->api;
if (db->ioloop != NULL)
io_loop_stop(db->ioloop);
i_assert(!free_result || result->api.refcount > 0);
result->callback = NULL;
if (free_result)
sql_result_unref(&result->api);
}
static void query_resend_with_fallback(struct cassandra_result *result)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
time_t last_warning =
ioloop_time - db->last_fallback_warning[result->query_type];
if (last_warning >= CASSANDRA_FALLBACK_WARN_INTERVAL_SECS) {
e_warning(db->api.event,
"%s - retrying future %s queries with consistency %s (instead of %s)",
result->error, cassandra_query_type_names[result->query_type],
cass_consistency_string(result->fallback_consistency),
cass_consistency_string(result->consistency));
db->last_fallback_warning[result->query_type] = ioloop_time;
}
i_free_and_null(result->error);
db->fallback_failures[result->query_type]++;
result->consistency = result->fallback_consistency;
driver_cassandra_result_send_query(result);
}
static void counters_inc_error(struct cassandra_db *db, CassError error)
{
switch (error) {
case CASS_ERROR_LIB_NO_HOSTS_AVAILABLE:
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_NO_HOSTS]++;
break;
case CASS_ERROR_LIB_REQUEST_QUEUE_FULL:
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_QUEUE_FULL]++;
break;
case CASS_ERROR_LIB_REQUEST_TIMED_OUT:
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_CLIENT_TIMEOUT]++;
break;
case CASS_ERROR_SERVER_WRITE_TIMEOUT:
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_SERVER_TIMEOUT]++;
break;
case CASS_ERROR_SERVER_UNAVAILABLE:
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_SERVER_UNAVAILABLE]++;
break;
default:
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_RECV_ERR_OTHER]++;
break;
}
}
static bool query_error_want_fallback(CassError error)
{
switch (error) {
case CASS_ERROR_LIB_WRITE_ERROR:
case CASS_ERROR_LIB_REQUEST_TIMED_OUT:
/* Communication problems on client side. Maybe it will work
with fallback consistency? */
return TRUE;
case CASS_ERROR_LIB_NO_HOSTS_AVAILABLE:
/* The client library couldn't connect to enough Cassandra
nodes. The error message text is the same as for
CASS_ERROR_SERVER_UNAVAILABLE. */
return TRUE;
case CASS_ERROR_SERVER_SERVER_ERROR:
case CASS_ERROR_SERVER_OVERLOADED:
case CASS_ERROR_SERVER_IS_BOOTSTRAPPING:
case CASS_ERROR_SERVER_READ_TIMEOUT:
case CASS_ERROR_SERVER_READ_FAILURE:
case CASS_ERROR_SERVER_WRITE_FAILURE:
/* Servers are having trouble. Maybe with fallback consistency
we can reach non-troubled servers? */
return TRUE;
case CASS_ERROR_SERVER_UNAVAILABLE:
/* Cassandra server knows that there aren't enough nodes
available. "All hosts in current policy attempted and were
either unavailable or failed". */
return TRUE;
case CASS_ERROR_SERVER_WRITE_TIMEOUT:
/* Cassandra server couldn't reach all the needed nodes.
This may be because it hasn't yet detected that the servers
are down, or because the servers are just too busy. We'll
try the fallback consistency to avoid unnecessary temporary
errors. */
return TRUE;
default:
return FALSE;
}
}
static enum sql_result_error_type
driver_cassandra_error_is_uncertain(CassError error)
{
switch (error) {
case CASS_ERROR_SERVER_WRITE_FAILURE:
/* This happens when some of the replicas that were contacted
* by the coordinator replied with an error. */
case CASS_ERROR_SERVER_WRITE_TIMEOUT:
/* A Cassandra timeout during a write query. */
case CASS_ERROR_SERVER_UNAVAILABLE:
/* The coordinator knows there are not enough replicas alive
* to perform a query with the requested consistency level. */
case CASS_ERROR_LIB_REQUEST_TIMED_OUT:
/* A request sent from the driver has timed out. */
case CASS_ERROR_LIB_WRITE_ERROR:
/* A write error occured. */
return SQL_RESULT_ERROR_TYPE_WRITE_UNCERTAIN;
default:
return SQL_RESULT_ERROR_TYPE_UNKNOWN;
}
}
static void query_callback(CassFuture *future, void *context)
{
struct cassandra_result *result = context;
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
CassError error = cass_future_error_code(future);
if (error != CASS_OK) {
const char *errmsg;
size_t errsize;
int msecs;
cass_future_error_message(future, &errmsg, &errsize);
i_free(result->error);
msecs = timeval_diff_msecs(&ioloop_timeval, &result->start_time);
counters_inc_error(db, error);
/* Timeouts bring uncertainty whether the query succeeded or
not. Also _SERVER_UNAVAILABLE could have actually written
enough copies of the data for the query to succeed. */
result->api.error_type = driver_cassandra_error_is_uncertain(error);
result->error = i_strdup_printf(
"Query '%s' failed: %.*s (in %u.%03u secs%s)",
result->log_query, (int)errsize, errmsg, msecs/1000, msecs%1000,
result->page_num == 0 ?
"" :
t_strdup_printf(", page %u", result->page_num));
if (query_error_want_fallback(error) &&
result->fallback_consistency != result->consistency) {
/* retry with fallback consistency */
query_resend_with_fallback(result);
return;
}
result_finish(result);
return;
}
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_RECV_OK]++;
if (result->fallback_consistency != result->consistency) {
/* non-fallback query finished successfully. if there had been
any fallbacks, reset them. */
db->fallback_failures[result->query_type] = 0;
}
result->result = cass_future_get_result(future);
result->iterator = cass_iterator_from_result(result->result);
result_finish(result);
}
static void driver_cassandra_init_statement(struct cassandra_result *result)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
cass_statement_set_consistency(result->statement, result->consistency);
#ifdef HAVE_CASSANDRA_SPECULATIVE_POLICY
cass_statement_set_is_idempotent(result->statement, cass_true);
#endif
if (db->page_size > 0)
cass_statement_set_paging_size(result->statement, db->page_size);
}
static void driver_cassandra_result_send_query(struct cassandra_result *result)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
CassFuture *future;
i_assert(result->statement != NULL);
db->counters[CASSANDRA_COUNTER_TYPE_QUERY_SENT]++;
if (result->query_type != CASSANDRA_QUERY_TYPE_READ_MORE)
driver_cassandra_init_statement(result);
future = cass_session_execute(db->session, result->statement);
driver_cassandra_set_callback(future, db, query_callback, result);
}
static bool
driver_cassandra_want_fallback_query(struct cassandra_result *result)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
unsigned int failure_count = db->fallback_failures[result->query_type];
unsigned int i, msecs = CASSANDRA_FALLBACK_FIRST_RETRY_MSECS;
struct timeval tv;
if (failure_count == 0)
return FALSE;
/* double the retries every time. */
for (i = 1; i < failure_count; i++) {
msecs *= 2;
if (msecs >= CASSANDRA_FALLBACK_MAX_RETRY_MSECS) {
msecs = CASSANDRA_FALLBACK_MAX_RETRY_MSECS;
break;
}
}
/* If last primary query sent timestamp + msecs is older than current
time, we need to retry the primary query. Note that this practically
prevents multiple primary queries from being attempted
simultaneously, because the caller updates primary_query_last_sent
immediately when returning.
The only time when multiple primary queries can be running in
parallel is when the earlier query is being slow and hasn't finished
early enough. This could even be a wanted feature, since while the
first query might have to wait for a timeout, Cassandra could have
been fixed in the meantime and the second query finishes
successfully. */
tv = db->primary_query_last_sent[result->query_type];
timeval_add_msecs(&tv, msecs);
return timeval_cmp(&ioloop_timeval, &tv) < 0;
}
static int driver_cassandra_send_query(struct cassandra_result *result)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
int ret;
if (!SQL_DB_IS_READY(&db->api)) {
if ((ret = sql_connect(&db->api)) <= 0) {
if (ret < 0)
driver_cassandra_close(db,
"Couldn't connect to Cassandra");
return ret;
}
}
if (result->page0_start_time.tv_sec == 0)
result->page0_start_time = ioloop_timeval;
result->start_time = ioloop_timeval;
result->row_pool = pool_alloconly_create("cassandra result", 512);
switch (result->query_type) {
case CASSANDRA_QUERY_TYPE_READ:
result->consistency = db->read_consistency;
result->fallback_consistency = db->read_fallback_consistency;
break;
case CASSANDRA_QUERY_TYPE_READ_MORE:
/* consistency is already set and we don't want to fallback
at this point anymore. */
result->fallback_consistency = result->consistency;
break;
case CASSANDRA_QUERY_TYPE_WRITE:
result->consistency = db->write_consistency;
result->fallback_consistency = db->write_fallback_consistency;
break;
case CASSANDRA_QUERY_TYPE_DELETE:
result->consistency = db->delete_consistency;
result->fallback_consistency = db->delete_fallback_consistency;
break;
case CASSANDRA_QUERY_TYPE_COUNT:
i_unreached();
}
if (driver_cassandra_want_fallback_query(result))
result->consistency = result->fallback_consistency;
else
db->primary_query_last_sent[result->query_type] = ioloop_timeval;
driver_cassandra_result_send_query(result);
result->query_sent = TRUE;
return 1;
}
static void driver_cassandra_send_queries(struct cassandra_db *db)
{
struct cassandra_result *const *results;
unsigned int i, count;
results = array_get(&db->results, &count);
for (i = 0; i < count; i++) {
if (!results[i]->query_sent && results[i]->statement != NULL) {
if (driver_cassandra_send_query(results[i]) <= 0)
break;
}
}
}
static void exec_callback(struct sql_result *_result ATTR_UNUSED,
void *context ATTR_UNUSED)
{
}
static struct cassandra_result *
driver_cassandra_query_init(struct cassandra_db *db, const char *log_query,
enum cassandra_query_type query_type,
bool is_prepared,
sql_query_callback_t *callback, void *context)
{
struct cassandra_result *result;
result = i_new(struct cassandra_result, 1);
result->api = driver_cassandra_result;
result->api.db = &db->api;
result->api.refcount = 1;
result->callback = callback;
result->context = context;
result->query_type = query_type;
result->log_query = i_strdup(log_query);
result->is_prepared = is_prepared;
result->api.event = event_create(db->api.event);
array_push_back(&db->results, &result);
return result;
}
static void
driver_cassandra_query_full(struct sql_db *_db, const char *query,
enum cassandra_query_type query_type,
sql_query_callback_t *callback, void *context)
{
struct cassandra_db *db = (struct cassandra_db *)_db;
struct cassandra_result *result;
result = driver_cassandra_query_init(db, query, query_type, FALSE,
callback, context);
result->statement = cass_statement_new(query, 0);
(void)driver_cassandra_send_query(result);
}
static void driver_cassandra_exec(struct sql_db *db, const char *query)
{
driver_cassandra_query_full(db, query, CASSANDRA_QUERY_TYPE_WRITE,
exec_callback, NULL);
}
static void driver_cassandra_query(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context)
{
driver_cassandra_query_full(db, query, CASSANDRA_QUERY_TYPE_READ,
callback, context);
}
static void cassandra_query_s_callback(struct sql_result *result, void *context)
{
struct cassandra_db *db = context;
db->sync_result = result;
}
static void driver_cassandra_sync_init(struct cassandra_db *db)
{
if (sql_connect(&db->api) < 0)
return;
db->orig_ioloop = current_ioloop;
db->ioloop = io_loop_create();
if (IS_CONNECTED(db))
return;
i_assert(db->api.state == SQL_DB_STATE_CONNECTING);
db->io_pipe = io_loop_move_io(&db->io_pipe);
/* wait for connecting to finish */
io_loop_run(db->ioloop);
}
static void driver_cassandra_sync_deinit(struct cassandra_db *db)
{
if (db->orig_ioloop == NULL)
return;
if (db->io_pipe != NULL) {
io_loop_set_current(db->orig_ioloop);
db->io_pipe = io_loop_move_io(&db->io_pipe);
io_loop_set_current(db->ioloop);
}
io_loop_destroy(&db->ioloop);
}
static struct sql_result *
driver_cassandra_sync_query(struct cassandra_db *db, const char *query,
enum cassandra_query_type query_type)
{
struct sql_result *result;
i_assert(db->sync_result == NULL);
switch (db->api.state) {
case SQL_DB_STATE_CONNECTING:
case SQL_DB_STATE_BUSY:
i_unreached();
case SQL_DB_STATE_DISCONNECTED:
sql_not_connected_result.refcount++;
return &sql_not_connected_result;
case SQL_DB_STATE_IDLE:
break;
}
driver_cassandra_query_full(&db->api, query, query_type,
cassandra_query_s_callback, db);
if (db->sync_result == NULL) {
db->io_pipe = io_loop_move_io(&db->io_pipe);
io_loop_run(db->ioloop);
}
result = db->sync_result;
if (result == &sql_not_connected_result) {
/* we don't end up in cassandra's free function, so sync_result
won't be set to NULL if we don't do it here. */
db->sync_result = NULL;
} else if (result == NULL) {
result = &sql_not_connected_result;
result->refcount++;
}
return result;
}
static struct sql_result *
driver_cassandra_query_s(struct sql_db *_db, const char *query)
{
struct cassandra_db *db = (struct cassandra_db *)_db;
struct sql_result *result;
driver_cassandra_sync_init(db);
result = driver_cassandra_sync_query(db, query,
CASSANDRA_QUERY_TYPE_READ);
driver_cassandra_sync_deinit(db);
return result;
}
static int
driver_cassandra_get_value(struct cassandra_result *result,
const CassValue *value, const char **str_r,
size_t *len_r)
{
const unsigned char *output;
void *output_dup;
size_t output_size;
CassError rc;
const char *type;
if (cass_value_is_null(value) != 0) {
*str_r = NULL;
*len_r = 0;
return 0;
}
switch (cass_data_type_type(cass_value_data_type(value))) {
case CASS_VALUE_TYPE_INT: {
cass_int32_t num;
rc = cass_value_get_int32(value, &num);
if (rc == CASS_OK) {
const char *str = t_strdup_printf("%d", num);
output_size = strlen(str);
output = (const void *)str;
}
type = "int32";
break;
}
case CASS_VALUE_TYPE_TIMESTAMP:
case CASS_VALUE_TYPE_BIGINT: {
cass_int64_t num;
rc = cass_value_get_int64(value, &num);
if (rc == CASS_OK) {
const char *str = t_strdup_printf("%lld", (long long)num);
output_size = strlen(str);
output = (const void *)str;
}
type = "int64";
break;
}
default:
rc = cass_value_get_bytes(value, &output, &output_size);
type = "bytes";
break;
}
if (rc != CASS_OK) {
i_free(result->error);
result->error = i_strdup_printf("Couldn't get value as %s: %s",
type, cass_error_desc(rc));
return -1;
}
output_dup = p_malloc(result->row_pool, output_size + 1);
memcpy(output_dup, output, output_size);
*str_r = output_dup;
*len_r = output_size;
return 0;
}
static int driver_cassandra_result_next_page(struct cassandra_result *result)
{
struct cassandra_db *db = (struct cassandra_db *)result->api.db;
if (db->page_size == 0) {
/* no paging */
return 0;
}
if (cass_result_has_more_pages(result->result) == cass_false)
return 0;
/* callers that don't support sql_query_more() will still get a useful
error message. */
i_free(result->error);
result->error = i_strdup(
"Paged query has more results, but not supported by the caller");
return SQL_RESULT_NEXT_MORE;
}
static int driver_cassandra_result_next_row(struct sql_result *_result)
{
struct cassandra_result *result = (struct cassandra_result *)_result;
const CassRow *row;
const CassValue *value;
const char *str;
size_t size;
unsigned int i;
int ret = 1;
if (result->iterator == NULL)
return -1;
if (cass_iterator_next(result->iterator) == 0)
return driver_cassandra_result_next_page(result);
result->row_count++;
result->total_row_count++;
p_clear(result->row_pool);
p_array_init(&result->fields, result->row_pool, 8);
p_array_init(&result->field_sizes, result->row_pool, 8);
row = cass_iterator_get_row(result->iterator);
for (i = 0; (value = cass_row_get_column(row, i)) != NULL; i++) {
if (driver_cassandra_get_value(result, value, &str, &size) < 0) {
ret = -1;
break;
}
array_push_back(&result->fields, &str);
array_push_back(&result->field_sizes, &size);
}
return ret;
}
static void
driver_cassandra_result_more(struct sql_result **_result, bool async,
sql_query_callback_t *callback, void *context)
{
struct cassandra_db *db = (struct cassandra_db *)(*_result)->db;
struct cassandra_result *new_result;
struct cassandra_result *old_result =
(struct cassandra_result *)*_result;
/* Initialize the next page as a new sql_result */
new_result = driver_cassandra_query_init(db, old_result->log_query,
CASSANDRA_QUERY_TYPE_READ_MORE,
old_result->is_prepared,
callback, context);
/* Preserve the statement and update its paging state */
new_result->statement = old_result->statement;
old_result->statement = NULL;
cass_statement_set_paging_state(new_result->statement,
old_result->result);
old_result->paging_continues = TRUE;
/* The caller did support paging. Clear out the "...not supported by
the caller" error text, so it won't be in the debug log output. */
i_free_and_null(old_result->error);
new_result->timestamp = old_result->timestamp;
new_result->consistency = old_result->consistency;
new_result->page_num = old_result->page_num + 1;
new_result->page0_start_time = old_result->page0_start_time;
new_result->total_row_count = old_result->total_row_count;
sql_result_unref(*_result);
*_result = NULL;
if (async)
(void)driver_cassandra_send_query(new_result);
else {
i_assert(db->api.state == SQL_DB_STATE_IDLE);
driver_cassandra_sync_init(db);
(void)driver_cassandra_send_query(new_result);
if (new_result->result == NULL) {
db->io_pipe = io_loop_move_io(&db->io_pipe);
io_loop_run(db->ioloop);
}
driver_cassandra_sync_deinit(db);
callback(&new_result->api, context);
}
}
static unsigned int
driver_cassandra_result_get_fields_count(struct sql_result *_result)
{
struct cassandra_result *result = (struct cassandra_result *)_result;
return array_count(&result->fields);
}
static const char *
driver_cassandra_result_get_field_name(struct sql_result *_result ATTR_UNUSED,
unsigned int idx ATTR_UNUSED)
{
i_unreached();
}
static int
driver_cassandra_result_find_field(struct sql_result *_result ATTR_UNUSED,
const char *field_name ATTR_UNUSED)
{
i_unreached();
}
static const char *
driver_cassandra_result_get_field_value(struct sql_result *_result,
unsigned int idx)
{
struct cassandra_result *result = (struct cassandra_result *)_result;
return array_idx_elem(&result->fields, idx);
}
static const unsigned char *
driver_cassandra_result_get_field_value_binary(struct sql_result *_result ATTR_UNUSED,
unsigned int idx ATTR_UNUSED,
size_t *size_r ATTR_UNUSED)
{
struct cassandra_result *result = (struct cassandra_result *)_result;
const char *str;
const size_t *sizep;
str = array_idx_elem(&result->fields, idx);
sizep = array_idx(&result->field_sizes, idx);
*size_r = *sizep;
return (const void *)str;
}
static const char *
driver_cassandra_result_find_field_value(struct sql_result *result ATTR_UNUSED,
const char *field_name ATTR_UNUSED)
{
i_unreached();
}
static const char *const *
driver_cassandra_result_get_values(struct sql_result *_result)
{
struct cassandra_result *result = (struct cassandra_result *)_result;
return array_front(&result->fields);
}
static const char *driver_cassandra_result_get_error(struct sql_result *_result)
{
struct cassandra_result *result = (struct cassandra_result *)_result;
if (result->error != NULL)
return result->error;
return "FIXME";
}
static struct sql_transaction_context *
driver_cassandra_transaction_begin(struct sql_db *db)
{
struct cassandra_transaction_context *ctx;
ctx = i_new(struct cassandra_transaction_context, 1);
ctx->ctx.db = db;
ctx->ctx.event = event_create(db->event);
ctx->refcount = 1;
return &ctx->ctx;
}
static void
driver_cassandra_transaction_unref(struct cassandra_transaction_context **_ctx)
{
struct cassandra_transaction_context *ctx = *_ctx;
*_ctx = NULL;
i_assert(ctx->refcount > 0);
if (--ctx->refcount > 0)
return;
event_unref(&ctx->ctx.event);
i_free(ctx->log_query);
i_free(ctx->query);
i_free(ctx->error);
i_free(ctx);
}
static void
transaction_set_failed(struct cassandra_transaction_context *ctx,
const char *error)
{
if (ctx->failed) {
i_assert(ctx->error != NULL);
} else {
i_assert(ctx->error == NULL);
ctx->failed = TRUE;
ctx->error = i_strdup(error);
}
}
static void
transaction_commit_callback(struct sql_result *result, void *context)
{
struct cassandra_transaction_context *ctx = context;
struct sql_commit_result commit_result;
i_zero(&commit_result);
if (sql_result_next_row(result) < 0) {
commit_result.error = sql_result_get_error(result);
commit_result.error_type = sql_result_get_error_type(result);
e_debug(sql_transaction_finished_event(&ctx->ctx)->
add_str("error", commit_result.error)->event(),
"Transaction failed");
} else {
e_debug(sql_transaction_finished_event(&ctx->ctx)->event(),
"Transaction committed");
}
ctx->callback(&commit_result, ctx->context);
driver_cassandra_transaction_unref(&ctx);
}
static void
driver_cassandra_transaction_commit(struct sql_transaction_context *_ctx,
sql_commit_callback_t *callback, void *context)
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
struct cassandra_db *db = (struct cassandra_db *)_ctx->db;
enum cassandra_query_type query_type;
struct sql_commit_result result;
i_zero(&result);
ctx->callback = callback;
ctx->context = context;
if (ctx->failed || (ctx->query == NULL && ctx->stmt == NULL)) {
if (ctx->failed)
result.error = ctx->error;
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", "Rolled back")->event(),
"Transaction rolled back");
callback(&result, context);
driver_cassandra_transaction_unref(&ctx);
return;
}
/* just a single query, send it */
const char *query = ctx->query != NULL ?
ctx->query : sql_statement_get_query(&ctx->stmt->stmt);
if (strncasecmp(query, "DELETE ", 7) == 0)
query_type = CASSANDRA_QUERY_TYPE_DELETE;
else
query_type = CASSANDRA_QUERY_TYPE_WRITE;
if (ctx->query != NULL) {
struct cassandra_result *cass_result;
cass_result = driver_cassandra_query_init(db, ctx->log_query,
query_type, FALSE, transaction_commit_callback, ctx);
cass_result->statement = cass_statement_new(query, 0);
if (ctx->query_timestamp != 0) {
cass_result->timestamp = ctx->query_timestamp;
cass_statement_set_timestamp(cass_result->statement,
ctx->query_timestamp);
}
(void)driver_cassandra_send_query(cass_result);
} else {
ctx->stmt->result =
driver_cassandra_query_init(db,
sql_statement_get_log_query(&ctx->stmt->stmt),
query_type, TRUE, transaction_commit_callback,
ctx);
if (ctx->stmt->cass_stmt == NULL) {
/* wait for prepare to finish */
} else {
ctx->stmt->result->statement = ctx->stmt->cass_stmt;
ctx->stmt->result->timestamp = ctx->stmt->timestamp;
(void)driver_cassandra_send_query(ctx->stmt->result);
pool_unref(&ctx->stmt->stmt.pool);
}
}
}
static void
driver_cassandra_try_commit_s(struct cassandra_transaction_context *ctx)
{
struct sql_transaction_context *_ctx = &ctx->ctx;
struct cassandra_db *db = (struct cassandra_db *)_ctx->db;
struct sql_result *result = NULL;
enum cassandra_query_type query_type;
/* just a single query, send it */
if (strncasecmp(ctx->query, "DELETE ", 7) == 0)
query_type = CASSANDRA_QUERY_TYPE_DELETE;
else
query_type = CASSANDRA_QUERY_TYPE_WRITE;
driver_cassandra_sync_init(db);
result = driver_cassandra_sync_query(db, ctx->query, query_type);
driver_cassandra_sync_deinit(db);
if (sql_result_next_row(result) < 0)
transaction_set_failed(ctx, sql_result_get_error(result));
sql_result_unref(result);
}
static int
driver_cassandra_transaction_commit_s(struct sql_transaction_context *_ctx,
const char **error_r)
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
if (ctx->stmt != NULL) {
/* nothing should be using this - don't bother implementing */
i_panic("cassandra: sql_transaction_commit_s() not supported for prepared statements");
}
if (ctx->query != NULL && !ctx->failed)
driver_cassandra_try_commit_s(ctx);
*error_r = t_strdup(ctx->error);
i_assert(ctx->refcount == 1);
i_assert((*error_r != NULL) == ctx->failed);
driver_cassandra_transaction_unref(&ctx);
return *error_r == NULL ? 0 : -1;
}
static void
driver_cassandra_transaction_rollback(struct sql_transaction_context *_ctx)
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
i_assert(ctx->refcount == 1);
driver_cassandra_transaction_unref(&ctx);
}
static void
driver_cassandra_update(struct sql_transaction_context *_ctx, const char *query,
unsigned int *affected_rows)
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
i_assert(affected_rows == NULL);
if (ctx->query != NULL || ctx->stmt != NULL) {
transaction_set_failed(ctx, "Multiple changes in transaction not supported");
return;
}
ctx->query = i_strdup(query);
/* When log_query is set here it can contain expanded values even
if stmt->no_log_expanded_values is set. */
ctx->log_query = i_strdup(query);
}
static const char *
driver_cassandra_escape_blob(struct sql_db *_db ATTR_UNUSED,
const unsigned char *data, size_t size)
{
string_t *str = t_str_new(128);
str_append(str, "0x");
binary_to_hex_append(str, data, size);
return str_c(str);
}
static CassError
driver_cassandra_bind_int(struct cassandra_sql_statement *stmt,
unsigned int column_idx, int64_t value)
{
const CassDataType *data_type;
CassValueType value_type;
i_assert(stmt->prep != NULL);
/* statements require exactly correct value type */
data_type = cass_prepared_parameter_data_type(stmt->prep->prepared,
column_idx);
value_type = cass_data_type_type(data_type);
switch (value_type) {
case CASS_VALUE_TYPE_INT:
if (value < INT32_MIN || value > INT32_MAX)
return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
return cass_statement_bind_int32(stmt->cass_stmt, column_idx,
value);
case CASS_VALUE_TYPE_TIMESTAMP:
case CASS_VALUE_TYPE_BIGINT:
return cass_statement_bind_int64(stmt->cass_stmt, column_idx,
value);
case CASS_VALUE_TYPE_SMALL_INT:
if (value < INT16_MIN || value > INT16_MAX)
return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
return cass_statement_bind_int16(stmt->cass_stmt, column_idx,
value);
case CASS_VALUE_TYPE_TINY_INT:
if (value < INT8_MIN || value > INT8_MAX)
return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
return cass_statement_bind_int8(stmt->cass_stmt, column_idx,
value);
default:
return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
}
}
static void prepare_finish_arg(struct cassandra_sql_statement *stmt,
const struct cassandra_sql_arg *arg)
{
CassError rc;
if (arg->value_str != NULL) {
rc = cass_statement_bind_string(stmt->cass_stmt, arg->column_idx,
arg->value_str);
} else if (arg->value_binary != NULL) {
rc = cass_statement_bind_bytes(stmt->cass_stmt, arg->column_idx,
arg->value_binary,
arg->value_binary_size);
} else {
rc = driver_cassandra_bind_int(stmt, arg->column_idx,
arg->value_int64);
}
if (rc != CASS_OK) {
e_error(stmt->stmt.db->event,
"Statement '%s': Failed to bind column %u: %s",
stmt->stmt.query_template, arg->column_idx,
cass_error_desc(rc));
}
}
static void prepare_finish_statement(struct cassandra_sql_statement *stmt)
{
const struct cassandra_sql_arg *arg;
if (stmt->prep->prepared == NULL) {
i_assert(stmt->prep->error != NULL);
if (stmt->result != NULL) {
stmt->result->error = i_strdup(stmt->prep->error);
result_finish(stmt->result);
}
pool_unref(&stmt->stmt.pool);
return;
}
stmt->cass_stmt = cass_prepared_bind(stmt->prep->prepared);
if (stmt->timestamp != 0)
cass_statement_set_timestamp(stmt->cass_stmt, stmt->timestamp);
if (array_is_created(&stmt->pending_args)) {
array_foreach(&stmt->pending_args, arg)
prepare_finish_arg(stmt, arg);
}
if (stmt->result != NULL) {
stmt->result->statement = stmt->cass_stmt;
stmt->result->timestamp = stmt->timestamp;
(void)driver_cassandra_send_query(stmt->result);
pool_unref(&stmt->stmt.pool);
}
}
static void
prepare_finish_pending_statements(struct cassandra_sql_prepared_statement *prep_stmt)
{
struct cassandra_sql_statement *stmt;
array_foreach_elem(&prep_stmt->pending_statements, stmt)
prepare_finish_statement(stmt);
array_clear(&prep_stmt->pending_statements);
}
static void prepare_callback(CassFuture *future, void *context)
{
struct cassandra_sql_prepared_statement *prep_stmt = context;
CassError error = cass_future_error_code(future);
if (error != CASS_OK) {
const char *errmsg;
size_t errsize;
cass_future_error_message(future, &errmsg, &errsize);
i_free(prep_stmt->error);
prep_stmt->error = i_strndup(errmsg, errsize);
} else {
prep_stmt->prepared = cass_future_get_prepared(future);
}
prepare_finish_pending_statements(prep_stmt);
}
static void prepare_start(struct cassandra_sql_prepared_statement *prep_stmt)
{
struct cassandra_db *db = (struct cassandra_db *)prep_stmt->prep_stmt.db;
CassFuture *future;
if (!SQL_DB_IS_READY(&db->api)) {
if (!prep_stmt->pending) {
prep_stmt->pending = TRUE;
array_push_back(&db->pending_prepares, &prep_stmt);
if (sql_connect(&db->api) < 0)
i_unreached();
}
return;
}
/* clear the current error in case we're retrying */
i_free_and_null(prep_stmt->error);
future = cass_session_prepare(db->session,
prep_stmt->prep_stmt.query_template);
driver_cassandra_set_callback(future, db, prepare_callback, prep_stmt);
}
static void driver_cassandra_prepare_pending(struct cassandra_db *db)
{
struct cassandra_sql_prepared_statement *prep_stmt;
i_assert(SQL_DB_IS_READY(&db->api));
array_foreach_elem(&db->pending_prepares, prep_stmt) {
prep_stmt->pending = FALSE;
prepare_start(prep_stmt);
}
array_clear(&db->pending_prepares);
}
static struct sql_prepared_statement *
driver_cassandra_prepared_statement_init(struct sql_db *db,
const char *query_template)
{
struct cassandra_sql_prepared_statement *prep_stmt =
i_new(struct cassandra_sql_prepared_statement, 1);
prep_stmt->prep_stmt.db = db;
prep_stmt->prep_stmt.refcount = 1;
prep_stmt->prep_stmt.query_template = i_strdup(query_template);
i_array_init(&prep_stmt->pending_statements, 4);
prepare_start(prep_stmt);
return &prep_stmt->prep_stmt;
}
static void
driver_cassandra_prepared_statement_deinit(struct sql_prepared_statement *_prep_stmt)
{
struct cassandra_sql_prepared_statement *prep_stmt =
(struct cassandra_sql_prepared_statement *)_prep_stmt;
i_assert(array_count(&prep_stmt->pending_statements) == 0);
if (prep_stmt->prepared != NULL)
cass_prepared_free(prep_stmt->prepared);
array_free(&prep_stmt->pending_statements);
i_free(prep_stmt->error);
i_free(prep_stmt->prep_stmt.query_template);
i_free(prep_stmt);
}
static struct sql_statement *
driver_cassandra_statement_init(struct sql_db *db ATTR_UNUSED,
const char *query_template ATTR_UNUSED)
{
pool_t pool = pool_alloconly_create("cassandra sql statement", 1024);
struct cassandra_sql_statement *stmt =
p_new(pool, struct cassandra_sql_statement, 1);
stmt->stmt.pool = pool;
return &stmt->stmt;
}
static struct sql_statement *
driver_cassandra_statement_init_prepared(struct sql_prepared_statement *_prep_stmt)
{
struct cassandra_sql_prepared_statement *prep_stmt =
(struct cassandra_sql_prepared_statement *)_prep_stmt;
pool_t pool = pool_alloconly_create("cassandra prepared sql statement", 1024);
struct cassandra_sql_statement *stmt =
p_new(pool, struct cassandra_sql_statement, 1);
stmt->stmt.pool = pool;
stmt->stmt.query_template =
p_strdup(stmt->stmt.pool, prep_stmt->prep_stmt.query_template);
stmt->prep = prep_stmt;
if (prep_stmt->prepared != NULL) {
/* statement is already prepared. we can use it immediately. */
stmt->cass_stmt = cass_prepared_bind(prep_stmt->prepared);
} else {
if (prep_stmt->error != NULL)
prepare_start(prep_stmt);
/* need to wait until prepare is finished */
array_push_back(&prep_stmt->pending_statements, &stmt);
}
return &stmt->stmt;
}
static void
driver_cassandra_statement_abort(struct sql_statement *_stmt)
{
struct cassandra_sql_statement *stmt =
(struct cassandra_sql_statement *)_stmt;
if (stmt->cass_stmt != NULL)
cass_statement_free(stmt->cass_stmt);
}
static void
driver_cassandra_statement_set_timestamp(struct sql_statement *_stmt,
const struct timespec *ts)
{
struct cassandra_sql_statement *stmt =
(struct cassandra_sql_statement *)_stmt;
cass_int64_t ts_usecs =
(cass_int64_t)ts->tv_sec * 1000000ULL +
ts->tv_nsec / 1000;
i_assert(stmt->result == NULL);
if (stmt->cass_stmt != NULL)
cass_statement_set_timestamp(stmt->cass_stmt, ts_usecs);
stmt->timestamp = ts_usecs;
}
static struct cassandra_sql_arg *
driver_cassandra_add_pending_arg(struct cassandra_sql_statement *stmt,
unsigned int column_idx)
{
struct cassandra_sql_arg *arg;
if (!array_is_created(&stmt->pending_args))
p_array_init(&stmt->pending_args, stmt->stmt.pool, 8);
arg = array_append_space(&stmt->pending_args);
arg->column_idx = column_idx;
return arg;
}
static void
driver_cassandra_statement_bind_str(struct sql_statement *_stmt,
unsigned int column_idx,
const char *value)
{
struct cassandra_sql_statement *stmt =
(struct cassandra_sql_statement *)_stmt;
if (stmt->cass_stmt != NULL)
cass_statement_bind_string(stmt->cass_stmt, column_idx, value);
else if (stmt->prep != NULL) {
struct cassandra_sql_arg *arg =
driver_cassandra_add_pending_arg(stmt, column_idx);
arg->value_str = p_strdup(_stmt->pool, value);
}
}
static void
driver_cassandra_statement_bind_binary(struct sql_statement *_stmt,
unsigned int column_idx,
const void *value, size_t value_size)
{
struct cassandra_sql_statement *stmt =
(struct cassandra_sql_statement *)_stmt;
if (stmt->cass_stmt != NULL) {
cass_statement_bind_bytes(stmt->cass_stmt, column_idx,
value, value_size);
} else if (stmt->prep != NULL) {
struct cassandra_sql_arg *arg =
driver_cassandra_add_pending_arg(stmt, column_idx);
arg->value_binary = value_size == 0 ? &uchar_nul :
p_memdup(_stmt->pool, value, value_size);
arg->value_binary_size = value_size;
}
}
static void
driver_cassandra_statement_bind_int64(struct sql_statement *_stmt,
unsigned int column_idx, int64_t value)
{
struct cassandra_sql_statement *stmt =
(struct cassandra_sql_statement *)_stmt;
if (stmt->cass_stmt != NULL)
driver_cassandra_bind_int(stmt, column_idx, value);
else if (stmt->prep != NULL) {
struct cassandra_sql_arg *arg =
driver_cassandra_add_pending_arg(stmt, column_idx);
arg->value_int64 = value;
}
}
static void
driver_cassandra_statement_query(struct sql_statement *_stmt,
sql_query_callback_t *callback, void *context)
{
struct cassandra_sql_statement *stmt =
(struct cassandra_sql_statement *)_stmt;
struct cassandra_db *db = (struct cassandra_db *)_stmt->db;
const char *query = sql_statement_get_query(_stmt);
bool is_prepared = stmt->cass_stmt != NULL || stmt->prep != NULL;
stmt->result = driver_cassandra_query_init(db,
sql_statement_get_log_query(_stmt),
CASSANDRA_QUERY_TYPE_READ,
is_prepared,
callback, context);
if (stmt->cass_stmt != NULL) {
stmt->result->statement = stmt->cass_stmt;
stmt->result->timestamp = stmt->timestamp;
} else if (stmt->prep != NULL) {
/* wait for prepare to finish */
return;
} else {
stmt->result->statement = cass_statement_new(query, 0);
stmt->result->timestamp = stmt->timestamp;
if (stmt->timestamp != 0) {
cass_statement_set_timestamp(stmt->result->statement,
stmt->timestamp);
}
}
(void)driver_cassandra_send_query(stmt->result);
pool_unref(&_stmt->pool);
}
static struct sql_result *
driver_cassandra_statement_query_s(struct sql_statement *_stmt ATTR_UNUSED)
{
i_panic("cassandra: sql_statement_query_s() not supported");
}
static void
driver_cassandra_update_stmt(struct sql_transaction_context *_ctx,
struct sql_statement *_stmt,
unsigned int *affected_rows)
{
struct cassandra_transaction_context *ctx =
(struct cassandra_transaction_context *)_ctx;
struct cassandra_sql_statement *stmt =
(struct cassandra_sql_statement *)_stmt;
i_assert(affected_rows == NULL);
if (ctx->query != NULL || ctx->stmt != NULL) {
transaction_set_failed(ctx,
"Multiple changes in transaction not supported");
return;
}
if (stmt->prep != NULL)
ctx->stmt = stmt;
else {
ctx->query = i_strdup(sql_statement_get_query(_stmt));
ctx->log_query = i_strdup(sql_statement_get_log_query(_stmt));
ctx->query_timestamp = stmt->timestamp;
pool_unref(&_stmt->pool);
}
}
static bool driver_cassandra_have_work(struct cassandra_db *db)
{
return array_not_empty(&db->pending_prepares) ||
array_not_empty(&db->callbacks) ||
array_not_empty(&db->results);
}
static void driver_cassandra_wait(struct sql_db *_db)
{
struct cassandra_db *db = (struct cassandra_db *)_db;
if (!driver_cassandra_have_work(db))
return;
struct ioloop *prev_ioloop = current_ioloop;
db->ioloop = io_loop_create();
db->io_pipe = io_loop_move_io(&db->io_pipe);
while (driver_cassandra_have_work(db))
io_loop_run(db->ioloop);
io_loop_set_current(prev_ioloop);
db->io_pipe = io_loop_move_io(&db->io_pipe);
io_loop_set_current(db->ioloop);
io_loop_destroy(&db->ioloop);
}
const struct sql_db driver_cassandra_db = {
.name = "cassandra",
.flags = SQL_DB_FLAG_PREP_STATEMENTS,
.v = {
.init_full = driver_cassandra_init_full_v,
.deinit = driver_cassandra_deinit_v,
.connect = driver_cassandra_connect,
.disconnect = driver_cassandra_disconnect,
.escape_string = driver_cassandra_escape_string,
.exec = driver_cassandra_exec,
.query = driver_cassandra_query,
.query_s = driver_cassandra_query_s,
.wait = driver_cassandra_wait,
.transaction_begin = driver_cassandra_transaction_begin,
.transaction_commit = driver_cassandra_transaction_commit,
.transaction_commit_s = driver_cassandra_transaction_commit_s,
.transaction_rollback = driver_cassandra_transaction_rollback,
.update = driver_cassandra_update,
.escape_blob = driver_cassandra_escape_blob,
.prepared_statement_init = driver_cassandra_prepared_statement_init,
.prepared_statement_deinit = driver_cassandra_prepared_statement_deinit,
.statement_init = driver_cassandra_statement_init,
.statement_init_prepared = driver_cassandra_statement_init_prepared,
.statement_abort = driver_cassandra_statement_abort,
.statement_set_timestamp = driver_cassandra_statement_set_timestamp,
.statement_bind_str = driver_cassandra_statement_bind_str,
.statement_bind_binary = driver_cassandra_statement_bind_binary,
.statement_bind_int64 = driver_cassandra_statement_bind_int64,
.statement_query = driver_cassandra_statement_query,
.statement_query_s = driver_cassandra_statement_query_s,
.update_stmt = driver_cassandra_update_stmt,
}
};
const struct sql_result driver_cassandra_result = {
.v = {
driver_cassandra_result_free,
driver_cassandra_result_next_row,
driver_cassandra_result_get_fields_count,
driver_cassandra_result_get_field_name,
driver_cassandra_result_find_field,
driver_cassandra_result_get_field_value,
driver_cassandra_result_get_field_value_binary,
driver_cassandra_result_find_field_value,
driver_cassandra_result_get_values,
driver_cassandra_result_get_error,
driver_cassandra_result_more,
}
};
const char *driver_cassandra_version = DOVECOT_ABI_VERSION;
void driver_cassandra_init(void);
void driver_cassandra_deinit(void);
void driver_cassandra_init(void)
{
sql_driver_register(&driver_cassandra_db);
}
void driver_cassandra_deinit(void)
{
sql_driver_unregister(&driver_cassandra_db);
}
#endif
dovecot-2.3.21.1/src/lib-sql/driver-sqlpool.c 0000644 0000000 0000000 00000061173 14656633576 015605 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "llist.h"
#include "ioloop.h"
#include "sql-api-private.h"
#include
#define QUERY_TIMEOUT_SECS 6
/* sqlpool events are separate from category:sql, because
they are usually not very interesting, and would only
make logging too noisy. They can be enabled explicitly.
*/
static struct event_category event_category_sqlpool = {
.name = "sqlpool",
};
struct sqlpool_host {
char *connect_string;
unsigned int connection_count;
};
struct sqlpool_connection {
struct sql_db *db;
unsigned int host_idx;
};
struct sqlpool_db {
struct sql_db api;
pool_t pool;
const struct sql_db *driver;
unsigned int connection_limit;
ARRAY(struct sqlpool_host) hosts;
/* all connections from all hosts */
ARRAY(struct sqlpool_connection) all_connections;
/* index of last connection in all_connections that was used to
send a query. */
unsigned int last_query_conn_idx;
/* queued requests */
struct sqlpool_request *requests_head, *requests_tail;
struct timeout *request_to;
};
struct sqlpool_request {
struct sqlpool_request *prev, *next;
struct sqlpool_db *db;
time_t created;
unsigned int host_idx;
unsigned int retry_count;
struct event *event;
/* requests are a) queries */
char *query;
sql_query_callback_t *callback;
void *context;
/* b) transaction waiters */
struct sqlpool_transaction_context *trans;
};
struct sqlpool_transaction_context {
struct sql_transaction_context ctx;
sql_commit_callback_t *callback;
void *context;
pool_t query_pool;
struct sqlpool_request *commit_request;
};
extern struct sql_db driver_sqlpool_db;
static struct sqlpool_connection *
sqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host,
unsigned int host_idx);
static void
driver_sqlpool_query_callback(struct sql_result *result,
struct sqlpool_request *request);
static void
driver_sqlpool_commit_callback(const struct sql_commit_result *result,
struct sqlpool_transaction_context *ctx);
static void driver_sqlpool_deinit(struct sql_db *_db);
static struct sqlpool_request * ATTR_NULL(2)
sqlpool_request_new(struct sqlpool_db *db, const char *query)
{
struct sqlpool_request *request;
request = i_new(struct sqlpool_request, 1);
request->db = db;
request->created = time(NULL);
request->query = i_strdup(query);
request->event = event_create(db->api.event);
return request;
}
static void
sqlpool_request_free(struct sqlpool_request **_request)
{
struct sqlpool_request *request = *_request;
*_request = NULL;
i_assert(request->prev == NULL && request->next == NULL);
event_unref(&request->event);
i_free(request->query);
i_free(request);
}
static void
sqlpool_request_abort(struct sqlpool_request **_request)
{
struct sqlpool_request *request = *_request;
*_request = NULL;
if (request->callback != NULL)
request->callback(&sql_not_connected_result, request->context);
i_assert(request->prev != NULL ||
request->db->requests_head == request);
DLLIST2_REMOVE(&request->db->requests_head,
&request->db->requests_tail, request);
sqlpool_request_free(&request);
}
static struct sql_transaction_context *
driver_sqlpool_new_conn_trans(struct sqlpool_transaction_context *trans,
struct sql_db *conndb)
{
struct sql_transaction_context *conn_trans;
struct sql_transaction_query *query;
conn_trans = sql_transaction_begin(conndb);
/* backend will use our queries list (we might still append more
queries to the list) */
conn_trans->head = trans->ctx.head;
conn_trans->tail = trans->ctx.tail;
for (query = conn_trans->head; query != NULL; query = query->next)
query->trans = conn_trans;
return conn_trans;
}
static void
sqlpool_request_handle_transaction(struct sql_db *conndb,
struct sqlpool_transaction_context *trans)
{
struct sql_transaction_context *conn_trans;
sqlpool_request_free(&trans->commit_request);
conn_trans = driver_sqlpool_new_conn_trans(trans, conndb);
sql_transaction_commit(&conn_trans,
driver_sqlpool_commit_callback, trans);
}
static void
sqlpool_request_send_next(struct sqlpool_db *db, struct sql_db *conndb)
{
struct sqlpool_request *request;
if (db->requests_head == NULL || !SQL_DB_IS_READY(conndb))
return;
request = db->requests_head;
DLLIST2_REMOVE(&db->requests_head, &db->requests_tail, request);
timeout_reset(db->request_to);
if (request->query != NULL) {
sql_query(conndb, request->query,
driver_sqlpool_query_callback, request);
} else if (request->trans != NULL) {
sqlpool_request_handle_transaction(conndb, request->trans);
} else {
i_unreached();
}
}
static void sqlpool_reconnect(struct sql_db *conndb)
{
timeout_remove(&conndb->to_reconnect);
(void)sql_connect(conndb);
}
static struct sqlpool_host *
sqlpool_find_host_with_least_connections(struct sqlpool_db *db,
unsigned int *host_idx_r)
{
struct sqlpool_host *hosts, *min = NULL;
unsigned int i, count;
hosts = array_get_modifiable(&db->hosts, &count);
i_assert(count > 0);
min = &hosts[0];
*host_idx_r = 0;
for (i = 1; i < count; i++) {
if (min->connection_count > hosts[i].connection_count) {
min = &hosts[i];
*host_idx_r = i;
}
}
return min;
}
static bool sqlpool_have_successful_connections(struct sqlpool_db *db)
{
const struct sqlpool_connection *conn;
array_foreach(&db->all_connections, conn) {
if (conn->db->state >= SQL_DB_STATE_IDLE)
return TRUE;
}
return FALSE;
}
static void
sqlpool_handle_connect_failed(struct sqlpool_db *db, struct sql_db *conndb)
{
struct sqlpool_host *host;
unsigned int host_idx;
if (conndb->connect_failure_count > 0) {
/* increase delay between reconnections to this
server */
conndb->connect_delay *= 5;
if (conndb->connect_delay > SQL_CONNECT_MAX_DELAY)
conndb->connect_delay = SQL_CONNECT_MAX_DELAY;
}
conndb->connect_failure_count++;
/* reconnect after the delay */
timeout_remove(&conndb->to_reconnect);
conndb->to_reconnect = timeout_add(conndb->connect_delay * 1000,
sqlpool_reconnect, conndb);
/* if we have zero successful hosts and there still are hosts
without connections, connect to one of them. */
if (!sqlpool_have_successful_connections(db)) {
host = sqlpool_find_host_with_least_connections(db, &host_idx);
if (host->connection_count == 0)
(void)sqlpool_add_connection(db, host, host_idx);
}
}
static void
sqlpool_state_changed(struct sql_db *conndb, enum sql_db_state prev_state,
void *context)
{
struct sqlpool_db *db = context;
if (conndb->state == SQL_DB_STATE_IDLE) {
conndb->connect_failure_count = 0;
conndb->connect_delay = SQL_CONNECT_MIN_DELAY;
sqlpool_request_send_next(db, conndb);
}
if (prev_state == SQL_DB_STATE_CONNECTING &&
conndb->state == SQL_DB_STATE_DISCONNECTED &&
!conndb->no_reconnect)
sqlpool_handle_connect_failed(db, conndb);
}
static struct sqlpool_connection *
sqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host,
unsigned int host_idx)
{
struct sql_db *conndb;
struct sqlpool_connection *conn;
const char *error;
int ret = 0;
host->connection_count++;
e_debug(db->api.event, "Creating new connection");
if (db->driver->v.init_full == NULL) {
conndb = db->driver->v.init(host->connect_string);
} else {
struct sql_settings set = {
.connect_string = host->connect_string,
.event_parent = event_get_parent(db->api.event),
};
ret = db->driver->v.init_full(&set, &conndb, &error);
}
if (ret < 0)
i_fatal("sqlpool: %s", error);
sql_init_common(conndb);
conndb->state_change_callback = sqlpool_state_changed;
conndb->state_change_context = db;
conndb->connect_delay = SQL_CONNECT_MIN_DELAY;
conn = array_append_space(&db->all_connections);
conn->host_idx = host_idx;
conn->db = conndb;
return conn;
}
static struct sqlpool_connection *
sqlpool_add_new_connection(struct sqlpool_db *db)
{
struct sqlpool_host *host;
unsigned int host_idx;
host = sqlpool_find_host_with_least_connections(db, &host_idx);
if (host->connection_count >= db->connection_limit)
return NULL;
else
return sqlpool_add_connection(db, host, host_idx);
}
static const struct sqlpool_connection *
sqlpool_find_available_connection(struct sqlpool_db *db,
unsigned int unwanted_host_idx,
bool *all_disconnected_r)
{
const struct sqlpool_connection *conns;
unsigned int i, count;
*all_disconnected_r = TRUE;
conns = array_get(&db->all_connections, &count);
for (i = 0; i < count; i++) {
unsigned int idx = (i + db->last_query_conn_idx + 1) % count;
struct sql_db *conndb = conns[idx].db;
if (conns[idx].host_idx == unwanted_host_idx)
continue;
if (!SQL_DB_IS_READY(conndb) && conndb->to_reconnect == NULL) {
/* see if we could reconnect to it immediately */
(void)sql_connect(conndb);
}
if (SQL_DB_IS_READY(conndb)) {
db->last_query_conn_idx = idx;
*all_disconnected_r = FALSE;
return &conns[idx];
}
if (conndb->state != SQL_DB_STATE_DISCONNECTED)
*all_disconnected_r = FALSE;
}
return NULL;
}
static bool
driver_sqlpool_get_connection(struct sqlpool_db *db,
unsigned int unwanted_host_idx,
const struct sqlpool_connection **conn_r)
{
const struct sqlpool_connection *conn, *conns;
unsigned int i, count;
bool all_disconnected;
conn = sqlpool_find_available_connection(db, unwanted_host_idx,
&all_disconnected);
if (conn == NULL && unwanted_host_idx != UINT_MAX) {
/* maybe there are no wanted hosts. use any of them. */
conn = sqlpool_find_available_connection(db, UINT_MAX,
&all_disconnected);
}
if (conn == NULL && all_disconnected) {
/* no connected connections. connect_delays may have gotten too
high, reset all of them to see if some are still alive. */
conns = array_get(&db->all_connections, &count);
for (i = 0; i < count; i++) {
struct sql_db *conndb = conns[i].db;
if (conndb->connect_delay > SQL_CONNECT_RESET_DELAY)
conndb->connect_delay = SQL_CONNECT_RESET_DELAY;
}
conn = sqlpool_find_available_connection(db, UINT_MAX,
&all_disconnected);
}
if (conn == NULL) {
/* still nothing. try creating new connections */
conn = sqlpool_add_new_connection(db);
if (conn != NULL)
(void)sql_connect(conn->db);
if (conn == NULL || !SQL_DB_IS_READY(conn->db))
return FALSE;
}
*conn_r = conn;
return TRUE;
}
static bool
driver_sqlpool_get_sync_connection(struct sqlpool_db *db,
const struct sqlpool_connection **conn_r)
{
const struct sqlpool_connection *conns;
unsigned int i, count;
if (driver_sqlpool_get_connection(db, UINT_MAX, conn_r))
return TRUE;
/* no idling connections, but maybe we can find one that's trying to
connect to server, and we can use it once it's finished */
conns = array_get(&db->all_connections, &count);
for (i = 0; i < count; i++) {
if (conns[i].db->state == SQL_DB_STATE_CONNECTING) {
*conn_r = &conns[i];
return TRUE;
}
}
return FALSE;
}
static bool
driver_sqlpool_get_connected_flags(struct sqlpool_db *db,
enum sql_db_flags *flags_r)
{
const struct sqlpool_connection *conn;
array_foreach(&db->all_connections, conn) {
if (conn->db->state > SQL_DB_STATE_CONNECTING) {
*flags_r = sql_get_flags(conn->db);
return TRUE;
}
}
return FALSE;
}
static enum sql_db_flags driver_sqlpool_get_flags(struct sql_db *_db)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
const struct sqlpool_connection *conn;
enum sql_db_flags flags;
/* try to use a connected db */
if (driver_sqlpool_get_connected_flags(db, &flags))
return flags;
if (!driver_sqlpool_get_sync_connection(db, &conn)) {
/* Failed to connect to database. Just use the first
connection. */
conn = array_idx(&db->all_connections, 0);
}
return sql_get_flags(conn->db);
}
static int
driver_sqlpool_parse_hosts(struct sqlpool_db *db, const char *connect_string,
const char **error_r)
{
const char *const *args, *key, *value, *hostname;
struct sqlpool_host *host;
ARRAY_TYPE(const_string) hostnames, connect_args;
t_array_init(&hostnames, 8);
t_array_init(&connect_args, 32);
/* connect string is a space separated list. it may contain
backend-specific strings which we'll pass as-is. we'll only care
about our own settings, plus the host settings. */
args = t_strsplit_spaces(connect_string, " ");
for (; *args != NULL; args++) {
value = strchr(*args, '=');
if (value == NULL) {
key = *args;
value = "";
} else {
key = t_strdup_until(*args, value);
value++;
}
if (strcmp(key, "maxconns") == 0) {
if (str_to_uint(value, &db->connection_limit) < 0) {
*error_r = t_strdup_printf("Invalid value for maxconns: %s",
value);
return -1;
}
} else if (strcmp(key, "host") == 0) {
array_push_back(&hostnames, &value);
} else {
array_push_back(&connect_args, args);
}
}
/* build a new connect string without our settings or hosts */
array_append_zero(&connect_args);
connect_string = t_strarray_join(array_front(&connect_args), " ");
if (array_count(&hostnames) == 0) {
/* no hosts specified. create a default one. */
host = array_append_space(&db->hosts);
host->connect_string = i_strdup(connect_string);
} else {
if (*connect_string == '\0')
connect_string = NULL;
array_foreach_elem(&hostnames, hostname) {
host = array_append_space(&db->hosts);
host->connect_string =
i_strconcat("host=", hostname, " ",
connect_string, NULL);
}
}
if (db->connection_limit == 0)
db->connection_limit = SQL_DEFAULT_CONNECTION_LIMIT;
return 0;
}
static void sqlpool_add_all_once(struct sqlpool_db *db)
{
struct sqlpool_host *host;
unsigned int host_idx;
for (;;) {
host = sqlpool_find_host_with_least_connections(db, &host_idx);
if (host->connection_count > 0)
break;
(void)sqlpool_add_connection(db, host, host_idx);
}
}
int driver_sqlpool_init_full(const struct sql_settings *set, const struct sql_db *driver,
struct sql_db **db_r, const char **error_r)
{
struct sqlpool_db *db;
int ret;
db = i_new(struct sqlpool_db, 1);
db->driver = driver;
db->api = driver_sqlpool_db;
db->api.flags = driver->flags;
db->api.event = event_create(set->event_parent);
event_add_category(db->api.event, &event_category_sqlpool);
event_set_append_log_prefix(db->api.event,
t_strdup_printf("sqlpool(%s): ", driver->name));
i_array_init(&db->hosts, 8);
T_BEGIN {
ret = driver_sqlpool_parse_hosts(db, set->connect_string,
error_r);
} T_END_PASS_STR_IF(ret < 0, error_r);
if (ret < 0) {
driver_sqlpool_deinit(&db->api);
return ret;
}
i_array_init(&db->all_connections, 16);
/* connect to all databases so we can do load balancing immediately */
sqlpool_add_all_once(db);
*db_r = &db->api;
return 0;
}
static void driver_sqlpool_abort_requests(struct sqlpool_db *db)
{
while (db->requests_head != NULL) {
struct sqlpool_request *request = db->requests_head;
sqlpool_request_abort(&request);
}
timeout_remove(&db->request_to);
}
static void driver_sqlpool_deinit(struct sql_db *_db)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
struct sqlpool_host *host;
struct sqlpool_connection *conn;
array_foreach_modifiable(&db->all_connections, conn)
sql_unref(&conn->db);
array_clear(&db->all_connections);
driver_sqlpool_abort_requests(db);
array_foreach_modifiable(&db->hosts, host)
i_free(host->connect_string);
i_assert(array_count(&db->all_connections) == 0);
array_free(&db->hosts);
array_free(&db->all_connections);
array_free(&_db->module_contexts);
event_unref(&_db->event);
i_free(db);
}
static int driver_sqlpool_connect(struct sql_db *_db)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
const struct sqlpool_connection *conn;
int ret = -1, ret2;
array_foreach(&db->all_connections, conn) {
ret2 = conn->db->to_reconnect != NULL ? -1 :
sql_connect(conn->db);
if (ret2 > 0)
ret = 1;
else if (ret2 == 0 && ret < 0)
ret = 0;
}
return ret;
}
static void driver_sqlpool_disconnect(struct sql_db *_db)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
const struct sqlpool_connection *conn;
array_foreach(&db->all_connections, conn)
sql_disconnect(conn->db);
driver_sqlpool_abort_requests(db);
}
static const char *
driver_sqlpool_escape_string(struct sql_db *_db, const char *string)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
const struct sqlpool_connection *conns;
unsigned int i, count;
/* use the first ready connection */
conns = array_get(&db->all_connections, &count);
for (i = 0; i < count; i++) {
if (SQL_DB_IS_READY(conns[i].db))
return sql_escape_string(conns[i].db, string);
}
/* no ready connections. just use the first one (we're guaranteed
to always have one) */
return sql_escape_string(conns[0].db, string);
}
static void driver_sqlpool_timeout(struct sqlpool_db *db)
{
int duration;
while (db->requests_head != NULL) {
struct sqlpool_request *request = db->requests_head;
if (request->created + SQL_QUERY_TIMEOUT_SECS > ioloop_time)
break;
if (request->query != NULL) {
e_error(sql_query_finished_event(&db->api, request->event,
request->query, FALSE,
&duration)->
add_str("error", "Query timed out")->
event(),
SQL_QUERY_FINISHED_FMT": Query timed out "
"(no free connections for %u secs)",
request->query, duration,
(unsigned int)(ioloop_time - request->created));
} else {
e_error(event_create_passthrough(request->event)->
add_str("error", "Timed out")->
set_name(SQL_TRANSACTION_FINISHED)->event(),
"Transaction timed out "
"(no free connections for %u secs)",
(unsigned int)(ioloop_time - request->created));
}
sqlpool_request_abort(&request);
}
if (db->requests_head == NULL)
timeout_remove(&db->request_to);
}
static void
driver_sqlpool_prepend_request(struct sqlpool_db *db,
struct sqlpool_request *request)
{
DLLIST2_PREPEND(&db->requests_head, &db->requests_tail, request);
if (db->request_to == NULL) {
db->request_to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
driver_sqlpool_timeout, db);
}
}
static void
driver_sqlpool_append_request(struct sqlpool_db *db,
struct sqlpool_request *request)
{
DLLIST2_APPEND(&db->requests_head, &db->requests_tail, request);
if (db->request_to == NULL) {
db->request_to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
driver_sqlpool_timeout, db);
}
}
static void
driver_sqlpool_query_callback(struct sql_result *result,
struct sqlpool_request *request)
{
struct sqlpool_db *db = request->db;
const struct sqlpool_connection *conn = NULL;
struct sql_db *conndb;
if (result->failed_try_retry &&
request->retry_count < array_count(&db->hosts)) {
e_warning(db->api.event, "Query failed, retrying: %s",
sql_result_get_error(result));
request->retry_count++;
driver_sqlpool_prepend_request(db, request);
if (driver_sqlpool_get_connection(request->db,
request->host_idx, &conn)) {
request->host_idx = conn->host_idx;
sqlpool_request_send_next(db, conn->db);
}
} else {
if (result->failed) {
e_error(db->api.event, "Query failed, aborting: %s",
request->query);
}
conndb = result->db;
if (request->callback != NULL)
request->callback(result, request->context);
sqlpool_request_free(&request);
sqlpool_request_send_next(db, conndb);
}
}
static void ATTR_NULL(3, 4)
driver_sqlpool_query(struct sql_db *_db, const char *query,
sql_query_callback_t *callback, void *context)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
struct sqlpool_request *request;
const struct sqlpool_connection *conn;
request = sqlpool_request_new(db, query);
request->callback = callback;
request->context = context;
if (!driver_sqlpool_get_connection(db, UINT_MAX, &conn))
driver_sqlpool_append_request(db, request);
else {
request->host_idx = conn->host_idx;
sql_query(conn->db, query, driver_sqlpool_query_callback,
request);
}
}
static void driver_sqlpool_exec(struct sql_db *_db, const char *query)
{
driver_sqlpool_query(_db, query, NULL, NULL);
}
static struct sql_result *
driver_sqlpool_query_s(struct sql_db *_db, const char *query)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
const struct sqlpool_connection *conn;
struct sql_result *result;
if (!driver_sqlpool_get_sync_connection(db, &conn)) {
sql_not_connected_result.refcount++;
return &sql_not_connected_result;
}
result = sql_query_s(conn->db, query);
if (result->failed_try_retry) {
if (!driver_sqlpool_get_sync_connection(db, &conn))
return result;
sql_result_unref(result);
result = sql_query_s(conn->db, query);
}
return result;
}
static struct sql_transaction_context *
driver_sqlpool_transaction_begin(struct sql_db *_db)
{
struct sqlpool_transaction_context *ctx;
ctx = i_new(struct sqlpool_transaction_context, 1);
ctx->ctx.db = _db;
/* queue changes until commit. even if we did have a free connection
now, don't use it or multiple open transactions could tie up all
connections. */
ctx->query_pool = pool_alloconly_create("sqlpool transaction", 1024);
return &ctx->ctx;
}
static void
driver_sqlpool_transaction_free(struct sqlpool_transaction_context *ctx)
{
if (ctx->commit_request != NULL)
sqlpool_request_abort(&ctx->commit_request);
pool_unref(&ctx->query_pool);
i_free(ctx);
}
static void
driver_sqlpool_commit_callback(const struct sql_commit_result *result,
struct sqlpool_transaction_context *ctx)
{
ctx->callback(result, ctx->context);
driver_sqlpool_transaction_free(ctx);
}
static void
driver_sqlpool_transaction_commit(struct sql_transaction_context *_ctx,
sql_commit_callback_t *callback,
void *context)
{
struct sqlpool_transaction_context *ctx =
(struct sqlpool_transaction_context *)_ctx;
struct sqlpool_db *db = (struct sqlpool_db *)_ctx->db;
const struct sqlpool_connection *conn;
ctx->callback = callback;
ctx->context = context;
ctx->commit_request = sqlpool_request_new(db, NULL);
ctx->commit_request->trans = ctx;
if (driver_sqlpool_get_connection(db, UINT_MAX, &conn))
sqlpool_request_handle_transaction(conn->db, ctx);
else
driver_sqlpool_append_request(db, ctx->commit_request);
}
static int
driver_sqlpool_transaction_commit_s(struct sql_transaction_context *_ctx,
const char **error_r)
{
struct sqlpool_transaction_context *ctx =
(struct sqlpool_transaction_context *)_ctx;
struct sqlpool_db *db = (struct sqlpool_db *)_ctx->db;
const struct sqlpool_connection *conn;
struct sql_transaction_context *conn_trans;
int ret;
*error_r = NULL;
if (!driver_sqlpool_get_sync_connection(db, &conn)) {
*error_r = SQL_ERRSTR_NOT_CONNECTED;
driver_sqlpool_transaction_free(ctx);
return -1;
}
conn_trans = driver_sqlpool_new_conn_trans(ctx, conn->db);
ret = sql_transaction_commit_s(&conn_trans, error_r);
driver_sqlpool_transaction_free(ctx);
return ret;
}
static void
driver_sqlpool_transaction_rollback(struct sql_transaction_context *_ctx)
{
struct sqlpool_transaction_context *ctx =
(struct sqlpool_transaction_context *)_ctx;
driver_sqlpool_transaction_free(ctx);
}
static void
driver_sqlpool_update(struct sql_transaction_context *_ctx, const char *query,
unsigned int *affected_rows)
{
struct sqlpool_transaction_context *ctx =
(struct sqlpool_transaction_context *)_ctx;
/* we didn't get a connection for transaction immediately.
queue updates until commit transfers all of these */
sql_transaction_add_query(&ctx->ctx, ctx->query_pool,
query, affected_rows);
}
static const char *
driver_sqlpool_escape_blob(struct sql_db *_db,
const unsigned char *data, size_t size)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
const struct sqlpool_connection *conns;
unsigned int i, count;
/* use the first ready connection */
conns = array_get(&db->all_connections, &count);
for (i = 0; i < count; i++) {
if (SQL_DB_IS_READY(conns[i].db))
return sql_escape_blob(conns[i].db, data, size);
}
/* no ready connections. just use the first one (we're guaranteed
to always have one) */
return sql_escape_blob(conns[0].db, data, size);
}
static void driver_sqlpool_wait(struct sql_db *_db)
{
struct sqlpool_db *db = (struct sqlpool_db *)_db;
const struct sqlpool_connection *conn;
array_foreach(&db->all_connections, conn)
sql_wait(conn->db);
}
struct sql_db driver_sqlpool_db = {
"",
.v = {
.get_flags = driver_sqlpool_get_flags,
.deinit = driver_sqlpool_deinit,
.connect = driver_sqlpool_connect,
.disconnect = driver_sqlpool_disconnect,
.escape_string = driver_sqlpool_escape_string,
.exec = driver_sqlpool_exec,
.query = driver_sqlpool_query,
.query_s = driver_sqlpool_query_s,
.wait = driver_sqlpool_wait,
.transaction_begin = driver_sqlpool_transaction_begin,
.transaction_commit = driver_sqlpool_transaction_commit,
.transaction_commit_s = driver_sqlpool_transaction_commit_s,
.transaction_rollback = driver_sqlpool_transaction_rollback,
.update = driver_sqlpool_update,
.escape_blob = driver_sqlpool_escape_blob,
}
};
dovecot-2.3.21.1/src/lib-sql/Makefile.in 0000644 0000000 0000000 00000135467 14656633611 014522 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
@BUILD_MYSQL_TRUE@@SQL_PLUGINS_TRUE@am__append_1 = mysql
@BUILD_PGSQL_TRUE@@SQL_PLUGINS_TRUE@am__append_2 = pgsql
@BUILD_SQLITE_TRUE@@SQL_PLUGINS_TRUE@am__append_3 = sqlite
@BUILD_CASSANDRA_TRUE@@SQL_PLUGINS_TRUE@am__append_4 = cassandra
subdir = src/lib-sql
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(pkginc_lib_HEADERS) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(pkglibdir)" \
"$(DESTDIR)$(sql_moduledir)" "$(DESTDIR)$(pkginc_libdir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(pkglib_LTLIBRARIES) \
$(sql_module_LTLIBRARIES)
am_libdovecot_sql_la_OBJECTS =
libdovecot_sql_la_OBJECTS = $(am_libdovecot_sql_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
libdovecot_sql_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libdovecot_sql_la_LDFLAGS) $(LDFLAGS) \
-o $@
am__DEPENDENCIES_1 =
@SQL_PLUGINS_TRUE@libdriver_cassandra_la_DEPENDENCIES = \
@SQL_PLUGINS_TRUE@ $(am__DEPENDENCIES_1)
am__libdriver_cassandra_la_SOURCES_DIST = driver-cassandra.c
@SQL_PLUGINS_TRUE@am_libdriver_cassandra_la_OBJECTS = \
@SQL_PLUGINS_TRUE@ libdriver_cassandra_la-driver-cassandra.lo
libdriver_cassandra_la_OBJECTS = $(am_libdriver_cassandra_la_OBJECTS)
libdriver_cassandra_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libdriver_cassandra_la_LDFLAGS) \
$(LDFLAGS) -o $@
@BUILD_CASSANDRA_TRUE@@SQL_PLUGINS_TRUE@am_libdriver_cassandra_la_rpath = \
@BUILD_CASSANDRA_TRUE@@SQL_PLUGINS_TRUE@ -rpath \
@BUILD_CASSANDRA_TRUE@@SQL_PLUGINS_TRUE@ $(sql_moduledir)
@SQL_PLUGINS_TRUE@libdriver_mysql_la_DEPENDENCIES = \
@SQL_PLUGINS_TRUE@ $(am__DEPENDENCIES_1)
am__libdriver_mysql_la_SOURCES_DIST = driver-mysql.c
@SQL_PLUGINS_TRUE@am_libdriver_mysql_la_OBJECTS = \
@SQL_PLUGINS_TRUE@ libdriver_mysql_la-driver-mysql.lo
libdriver_mysql_la_OBJECTS = $(am_libdriver_mysql_la_OBJECTS)
libdriver_mysql_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libdriver_mysql_la_LDFLAGS) \
$(LDFLAGS) -o $@
@BUILD_MYSQL_TRUE@@SQL_PLUGINS_TRUE@am_libdriver_mysql_la_rpath = \
@BUILD_MYSQL_TRUE@@SQL_PLUGINS_TRUE@ -rpath $(sql_moduledir)
@SQL_PLUGINS_TRUE@libdriver_pgsql_la_DEPENDENCIES = \
@SQL_PLUGINS_TRUE@ $(am__DEPENDENCIES_1)
am__libdriver_pgsql_la_SOURCES_DIST = driver-pgsql.c
@SQL_PLUGINS_TRUE@am_libdriver_pgsql_la_OBJECTS = \
@SQL_PLUGINS_TRUE@ libdriver_pgsql_la-driver-pgsql.lo
libdriver_pgsql_la_OBJECTS = $(am_libdriver_pgsql_la_OBJECTS)
libdriver_pgsql_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libdriver_pgsql_la_LDFLAGS) \
$(LDFLAGS) -o $@
@BUILD_PGSQL_TRUE@@SQL_PLUGINS_TRUE@am_libdriver_pgsql_la_rpath = \
@BUILD_PGSQL_TRUE@@SQL_PLUGINS_TRUE@ -rpath $(sql_moduledir)
@SQL_PLUGINS_TRUE@libdriver_sqlite_la_DEPENDENCIES = \
@SQL_PLUGINS_TRUE@ $(am__DEPENDENCIES_1)
am__libdriver_sqlite_la_SOURCES_DIST = driver-sqlite.c
@SQL_PLUGINS_TRUE@am_libdriver_sqlite_la_OBJECTS = \
@SQL_PLUGINS_TRUE@ libdriver_sqlite_la-driver-sqlite.lo
libdriver_sqlite_la_OBJECTS = $(am_libdriver_sqlite_la_OBJECTS)
libdriver_sqlite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libdriver_sqlite_la_LDFLAGS) \
$(LDFLAGS) -o $@
@BUILD_SQLITE_TRUE@@SQL_PLUGINS_TRUE@am_libdriver_sqlite_la_rpath = \
@BUILD_SQLITE_TRUE@@SQL_PLUGINS_TRUE@ -rpath $(sql_moduledir)
libdriver_test_la_LIBADD =
am_libdriver_test_la_OBJECTS = libdriver_test_la-driver-test.lo
libdriver_test_la_OBJECTS = $(am_libdriver_test_la_OBJECTS)
libdriver_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libdriver_test_la_LDFLAGS) $(LDFLAGS) \
-o $@
libsql_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am__libsql_la_SOURCES_DIST = sql-api.c sql-db-cache.c driver-mysql.c \
driver-pgsql.c driver-sqlite.c driver-cassandra.c \
driver-sqlpool.c
am__objects_1 = sql-api.lo sql-db-cache.lo
@SQL_PLUGINS_FALSE@am__objects_2 = driver-mysql.lo driver-pgsql.lo \
@SQL_PLUGINS_FALSE@ driver-sqlite.lo driver-cassandra.lo
am_libsql_la_OBJECTS = $(am__objects_1) $(am__objects_2) \
driver-sqlpool.lo
nodist_libsql_la_OBJECTS = sql-drivers-register.lo
libsql_la_OBJECTS = $(am_libsql_la_OBJECTS) \
$(nodist_libsql_la_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/driver-cassandra.Plo \
./$(DEPDIR)/driver-mysql.Plo ./$(DEPDIR)/driver-pgsql.Plo \
./$(DEPDIR)/driver-sqlite.Plo ./$(DEPDIR)/driver-sqlpool.Plo \
./$(DEPDIR)/libdriver_cassandra_la-driver-cassandra.Plo \
./$(DEPDIR)/libdriver_mysql_la-driver-mysql.Plo \
./$(DEPDIR)/libdriver_pgsql_la-driver-pgsql.Plo \
./$(DEPDIR)/libdriver_sqlite_la-driver-sqlite.Plo \
./$(DEPDIR)/libdriver_test_la-driver-test.Plo \
./$(DEPDIR)/sql-api.Plo ./$(DEPDIR)/sql-db-cache.Plo \
./$(DEPDIR)/sql-drivers-register.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libdovecot_sql_la_SOURCES) \
$(libdriver_cassandra_la_SOURCES) \
$(libdriver_mysql_la_SOURCES) $(libdriver_pgsql_la_SOURCES) \
$(libdriver_sqlite_la_SOURCES) $(libdriver_test_la_SOURCES) \
$(libsql_la_SOURCES) $(nodist_libsql_la_SOURCES)
DIST_SOURCES = $(libdovecot_sql_la_SOURCES) \
$(am__libdriver_cassandra_la_SOURCES_DIST) \
$(am__libdriver_mysql_la_SOURCES_DIST) \
$(am__libdriver_pgsql_la_SOURCES_DIST) \
$(am__libdriver_sqlite_la_SOURCES_DIST) \
$(libdriver_test_la_SOURCES) $(am__libsql_la_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
# automake seems to force making this unconditional..
NOPLUGIN_LDFLAGS =
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
noinst_LTLIBRARIES = libsql.la libdriver_test.la
SQL_DRIVER_PLUGINS = $(am__append_1) $(am__append_2) $(am__append_3) \
$(am__append_4)
@BUILD_MYSQL_TRUE@@SQL_PLUGINS_TRUE@MYSQL_LIB = libdriver_mysql.la
@BUILD_PGSQL_TRUE@@SQL_PLUGINS_TRUE@PGSQL_LIB = libdriver_pgsql.la
@BUILD_SQLITE_TRUE@@SQL_PLUGINS_TRUE@SQLITE_LIB = libdriver_sqlite.la
@BUILD_CASSANDRA_TRUE@@SQL_PLUGINS_TRUE@CASSANDRA_LIB = libdriver_cassandra.la
@SQL_PLUGINS_TRUE@sql_module_LTLIBRARIES = \
@SQL_PLUGINS_TRUE@ $(MYSQL_LIB) \
@SQL_PLUGINS_TRUE@ $(PGSQL_LIB) \
@SQL_PLUGINS_TRUE@ $(SQLITE_LIB) \
@SQL_PLUGINS_TRUE@ $(CASSANDRA_LIB)
@SQL_PLUGINS_TRUE@sql_moduledir = $(moduledir)
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
$(SQL_CFLAGS)
dist_sources = \
sql-api.c \
sql-db-cache.c
@SQL_PLUGINS_FALSE@driver_sources = \
@SQL_PLUGINS_FALSE@ driver-mysql.c \
@SQL_PLUGINS_FALSE@ driver-pgsql.c \
@SQL_PLUGINS_FALSE@ driver-sqlite.c \
@SQL_PLUGINS_FALSE@ driver-cassandra.c
libsql_la_SOURCES = \
$(dist_sources) \
$(driver_sources) \
driver-sqlpool.c
libsql_la_LIBADD = $(SQL_LIBS)
nodist_libsql_la_SOURCES = sql-drivers-register.c
deplibs = \
../lib-dovecot/libdovecot.la
@SQL_PLUGINS_TRUE@libdriver_mysql_la_LDFLAGS = -module -avoid-version
@SQL_PLUGINS_TRUE@libdriver_mysql_la_LIBADD = $(MYSQL_LIBS)
@SQL_PLUGINS_TRUE@libdriver_mysql_la_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQL_CFLAGS)
@SQL_PLUGINS_TRUE@libdriver_mysql_la_SOURCES = driver-mysql.c
@SQL_PLUGINS_TRUE@libdriver_pgsql_la_LDFLAGS = -module -avoid-version
@SQL_PLUGINS_TRUE@libdriver_pgsql_la_LIBADD = $(PGSQL_LIBS)
@SQL_PLUGINS_TRUE@libdriver_pgsql_la_CPPFLAGS = $(AM_CPPFLAGS) $(PGSQL_CFLAGS)
@SQL_PLUGINS_TRUE@libdriver_pgsql_la_SOURCES = driver-pgsql.c
@SQL_PLUGINS_TRUE@libdriver_sqlite_la_LDFLAGS = -module -avoid-version
@SQL_PLUGINS_TRUE@libdriver_sqlite_la_LIBADD = $(SQLITE_LIBS)
@SQL_PLUGINS_TRUE@libdriver_sqlite_la_CPPFLAGS = $(AM_CPPFLAGS) $(SQLITE_CFLAGS)
@SQL_PLUGINS_TRUE@libdriver_sqlite_la_SOURCES = driver-sqlite.c
@SQL_PLUGINS_TRUE@libdriver_cassandra_la_LDFLAGS = -module -avoid-version
@SQL_PLUGINS_TRUE@libdriver_cassandra_la_LIBADD = $(CASSANDRA_LIBS)
@SQL_PLUGINS_TRUE@libdriver_cassandra_la_CPPFLAGS = $(AM_CPPFLAGS) $(CASSANDRA_CFLAGS)
@SQL_PLUGINS_TRUE@libdriver_cassandra_la_SOURCES = driver-cassandra.c
libdriver_test_la_LDFLAGS = -avoid-version
libdriver_test_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I$(top_srcdir)/src/lib-test
libdriver_test_la_SOURCES = driver-test.c
noinst_HEADERS = driver-test.h
pkglib_LTLIBRARIES = libdovecot-sql.la
libdovecot_sql_la_SOURCES =
libdovecot_sql_la_LIBADD = libsql.la $(deplibs)
libdovecot_sql_la_DEPENDENCIES = libsql.la
libdovecot_sql_la_LDFLAGS = -export-dynamic
headers = \
sql-api.h \
sql-api-private.h \
sql-db-cache.h
pkginc_libdir = $(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sql/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/lib-sql/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
}
uninstall-pkglibLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
done
clean-pkglibLTLIBRARIES:
-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
@list='$(pkglib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
install-sql_moduleLTLIBRARIES: $(sql_module_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(sql_module_LTLIBRARIES)'; test -n "$(sql_moduledir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(sql_moduledir)'"; \
$(MKDIR_P) "$(DESTDIR)$(sql_moduledir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sql_moduledir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sql_moduledir)"; \
}
uninstall-sql_moduleLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(sql_module_LTLIBRARIES)'; test -n "$(sql_moduledir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sql_moduledir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sql_moduledir)/$$f"; \
done
clean-sql_moduleLTLIBRARIES:
-test -z "$(sql_module_LTLIBRARIES)" || rm -f $(sql_module_LTLIBRARIES)
@list='$(sql_module_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libdovecot-sql.la: $(libdovecot_sql_la_OBJECTS) $(libdovecot_sql_la_DEPENDENCIES) $(EXTRA_libdovecot_sql_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdovecot_sql_la_LINK) -rpath $(pkglibdir) $(libdovecot_sql_la_OBJECTS) $(libdovecot_sql_la_LIBADD) $(LIBS)
libdriver_cassandra.la: $(libdriver_cassandra_la_OBJECTS) $(libdriver_cassandra_la_DEPENDENCIES) $(EXTRA_libdriver_cassandra_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdriver_cassandra_la_LINK) $(am_libdriver_cassandra_la_rpath) $(libdriver_cassandra_la_OBJECTS) $(libdriver_cassandra_la_LIBADD) $(LIBS)
libdriver_mysql.la: $(libdriver_mysql_la_OBJECTS) $(libdriver_mysql_la_DEPENDENCIES) $(EXTRA_libdriver_mysql_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdriver_mysql_la_LINK) $(am_libdriver_mysql_la_rpath) $(libdriver_mysql_la_OBJECTS) $(libdriver_mysql_la_LIBADD) $(LIBS)
libdriver_pgsql.la: $(libdriver_pgsql_la_OBJECTS) $(libdriver_pgsql_la_DEPENDENCIES) $(EXTRA_libdriver_pgsql_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdriver_pgsql_la_LINK) $(am_libdriver_pgsql_la_rpath) $(libdriver_pgsql_la_OBJECTS) $(libdriver_pgsql_la_LIBADD) $(LIBS)
libdriver_sqlite.la: $(libdriver_sqlite_la_OBJECTS) $(libdriver_sqlite_la_DEPENDENCIES) $(EXTRA_libdriver_sqlite_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdriver_sqlite_la_LINK) $(am_libdriver_sqlite_la_rpath) $(libdriver_sqlite_la_OBJECTS) $(libdriver_sqlite_la_LIBADD) $(LIBS)
libdriver_test.la: $(libdriver_test_la_OBJECTS) $(libdriver_test_la_DEPENDENCIES) $(EXTRA_libdriver_test_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdriver_test_la_LINK) $(libdriver_test_la_OBJECTS) $(libdriver_test_la_LIBADD) $(LIBS)
libsql.la: $(libsql_la_OBJECTS) $(libsql_la_DEPENDENCIES) $(EXTRA_libsql_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(libsql_la_OBJECTS) $(libsql_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver-cassandra.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver-mysql.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver-pgsql.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver-sqlite.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver-sqlpool.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdriver_cassandra_la-driver-cassandra.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdriver_mysql_la-driver-mysql.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdriver_pgsql_la-driver-pgsql.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdriver_sqlite_la-driver-sqlite.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdriver_test_la-driver-test.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql-api.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql-db-cache.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql-drivers-register.Plo@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
libdriver_cassandra_la-driver-cassandra.lo: driver-cassandra.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_cassandra_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdriver_cassandra_la-driver-cassandra.lo -MD -MP -MF $(DEPDIR)/libdriver_cassandra_la-driver-cassandra.Tpo -c -o libdriver_cassandra_la-driver-cassandra.lo `test -f 'driver-cassandra.c' || echo '$(srcdir)/'`driver-cassandra.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdriver_cassandra_la-driver-cassandra.Tpo $(DEPDIR)/libdriver_cassandra_la-driver-cassandra.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver-cassandra.c' object='libdriver_cassandra_la-driver-cassandra.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_cassandra_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdriver_cassandra_la-driver-cassandra.lo `test -f 'driver-cassandra.c' || echo '$(srcdir)/'`driver-cassandra.c
libdriver_mysql_la-driver-mysql.lo: driver-mysql.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdriver_mysql_la-driver-mysql.lo -MD -MP -MF $(DEPDIR)/libdriver_mysql_la-driver-mysql.Tpo -c -o libdriver_mysql_la-driver-mysql.lo `test -f 'driver-mysql.c' || echo '$(srcdir)/'`driver-mysql.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdriver_mysql_la-driver-mysql.Tpo $(DEPDIR)/libdriver_mysql_la-driver-mysql.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver-mysql.c' object='libdriver_mysql_la-driver-mysql.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_mysql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdriver_mysql_la-driver-mysql.lo `test -f 'driver-mysql.c' || echo '$(srcdir)/'`driver-mysql.c
libdriver_pgsql_la-driver-pgsql.lo: driver-pgsql.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_pgsql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdriver_pgsql_la-driver-pgsql.lo -MD -MP -MF $(DEPDIR)/libdriver_pgsql_la-driver-pgsql.Tpo -c -o libdriver_pgsql_la-driver-pgsql.lo `test -f 'driver-pgsql.c' || echo '$(srcdir)/'`driver-pgsql.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdriver_pgsql_la-driver-pgsql.Tpo $(DEPDIR)/libdriver_pgsql_la-driver-pgsql.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver-pgsql.c' object='libdriver_pgsql_la-driver-pgsql.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_pgsql_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdriver_pgsql_la-driver-pgsql.lo `test -f 'driver-pgsql.c' || echo '$(srcdir)/'`driver-pgsql.c
libdriver_sqlite_la-driver-sqlite.lo: driver-sqlite.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_sqlite_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdriver_sqlite_la-driver-sqlite.lo -MD -MP -MF $(DEPDIR)/libdriver_sqlite_la-driver-sqlite.Tpo -c -o libdriver_sqlite_la-driver-sqlite.lo `test -f 'driver-sqlite.c' || echo '$(srcdir)/'`driver-sqlite.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdriver_sqlite_la-driver-sqlite.Tpo $(DEPDIR)/libdriver_sqlite_la-driver-sqlite.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver-sqlite.c' object='libdriver_sqlite_la-driver-sqlite.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_sqlite_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdriver_sqlite_la-driver-sqlite.lo `test -f 'driver-sqlite.c' || echo '$(srcdir)/'`driver-sqlite.c
libdriver_test_la-driver-test.lo: driver-test.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_test_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdriver_test_la-driver-test.lo -MD -MP -MF $(DEPDIR)/libdriver_test_la-driver-test.Tpo -c -o libdriver_test_la-driver-test.lo `test -f 'driver-test.c' || echo '$(srcdir)/'`driver-test.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdriver_test_la-driver-test.Tpo $(DEPDIR)/libdriver_test_la-driver-test.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='driver-test.c' object='libdriver_test_la-driver-test.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdriver_test_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdriver_test_la-driver-test.lo `test -f 'driver-test.c' || echo '$(srcdir)/'`driver-test.c
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
done
uninstall-pkginc_libHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(sql_moduledir)" "$(DESTDIR)$(pkginc_libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
@SQL_PLUGINS_FALSE@install-exec-local:
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
clean-pkglibLTLIBRARIES clean-sql_moduleLTLIBRARIES \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/driver-cassandra.Plo
-rm -f ./$(DEPDIR)/driver-mysql.Plo
-rm -f ./$(DEPDIR)/driver-pgsql.Plo
-rm -f ./$(DEPDIR)/driver-sqlite.Plo
-rm -f ./$(DEPDIR)/driver-sqlpool.Plo
-rm -f ./$(DEPDIR)/libdriver_cassandra_la-driver-cassandra.Plo
-rm -f ./$(DEPDIR)/libdriver_mysql_la-driver-mysql.Plo
-rm -f ./$(DEPDIR)/libdriver_pgsql_la-driver-pgsql.Plo
-rm -f ./$(DEPDIR)/libdriver_sqlite_la-driver-sqlite.Plo
-rm -f ./$(DEPDIR)/libdriver_test_la-driver-test.Plo
-rm -f ./$(DEPDIR)/sql-api.Plo
-rm -f ./$(DEPDIR)/sql-db-cache.Plo
-rm -f ./$(DEPDIR)/sql-drivers-register.Plo
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkginc_libHEADERS \
install-sql_moduleLTLIBRARIES
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-exec-local install-pkglibLTLIBRARIES
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/driver-cassandra.Plo
-rm -f ./$(DEPDIR)/driver-mysql.Plo
-rm -f ./$(DEPDIR)/driver-pgsql.Plo
-rm -f ./$(DEPDIR)/driver-sqlite.Plo
-rm -f ./$(DEPDIR)/driver-sqlpool.Plo
-rm -f ./$(DEPDIR)/libdriver_cassandra_la-driver-cassandra.Plo
-rm -f ./$(DEPDIR)/libdriver_mysql_la-driver-mysql.Plo
-rm -f ./$(DEPDIR)/libdriver_pgsql_la-driver-pgsql.Plo
-rm -f ./$(DEPDIR)/libdriver_sqlite_la-driver-sqlite.Plo
-rm -f ./$(DEPDIR)/libdriver_test_la-driver-test.Plo
-rm -f ./$(DEPDIR)/sql-api.Plo
-rm -f ./$(DEPDIR)/sql-db-cache.Plo
-rm -f ./$(DEPDIR)/sql-drivers-register.Plo
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkginc_libHEADERS uninstall-pkglibLTLIBRARIES \
uninstall-sql_moduleLTLIBRARIES
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-noinstLTLIBRARIES \
clean-pkglibLTLIBRARIES clean-sql_moduleLTLIBRARIES \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-exec-local install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-pkginc_libHEADERS \
install-pkglibLTLIBRARIES install-ps install-ps-am \
install-sql_moduleLTLIBRARIES install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am \
uninstall-pkginc_libHEADERS uninstall-pkglibLTLIBRARIES \
uninstall-sql_moduleLTLIBRARIES
.PRECIOUS: Makefile
sql-drivers-register.c: Makefile
rm -f $@
echo '/* this file automatically generated by Makefile */' >$@
echo '#include "lib.h"' >>$@
echo '#include "sql-api.h"' >>$@
@SQL_PLUGINS_FALSE@ for i in $(sql_drivers) null; do \
@SQL_PLUGINS_FALSE@ if [ "$${i}" != "null" ]; then \
@SQL_PLUGINS_FALSE@ echo "extern struct sql_db driver_$${i}_db;" >>$@ ; \
@SQL_PLUGINS_FALSE@ fi; \
@SQL_PLUGINS_FALSE@ done
echo 'void sql_drivers_register_all(void) {' >>$@
@SQL_PLUGINS_FALSE@ for i in $(sql_drivers) null; do \
@SQL_PLUGINS_FALSE@ if [ "$${i}" != "null" ]; then \
@SQL_PLUGINS_FALSE@ echo "sql_driver_register(&driver_$${i}_db);" >>$@ ; \
@SQL_PLUGINS_FALSE@ fi; \
@SQL_PLUGINS_FALSE@ done
echo '}' >>$@
@SQL_PLUGINS_TRUE@install-exec-local:
@SQL_PLUGINS_TRUE@ for d in auth dict; do \
@SQL_PLUGINS_TRUE@ $(mkdir_p) $(DESTDIR)$(moduledir)/$$d; \
@SQL_PLUGINS_TRUE@ for driver in $(SQL_DRIVER_PLUGINS); do \
@SQL_PLUGINS_TRUE@ rm -f $(DESTDIR)$(moduledir)/$$d/libdriver_$$driver.so; \
@SQL_PLUGINS_TRUE@ $(LN_S) ../libdriver_$$driver.so $(DESTDIR)$(moduledir)/$$d; \
@SQL_PLUGINS_TRUE@ done; \
@SQL_PLUGINS_TRUE@ done
distclean-generic:
rm -f Makefile sql-drivers-register.c
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/lib-sql/driver-test.h 0000644 0000000 0000000 00000001206 14656633576 015067 0000000 0000000 #ifndef DRIVER_TEST_H
#define DRIVER_TEST_H 1
struct test_driver_result_set {
size_t rows, cols, cur;
const char *const *col_names;
const char ***row_data;
};
struct test_driver_result {
/* expected queries */
size_t nqueries;
size_t cur;
unsigned int affected_rows;
const char *const *queries;
/* test result, rows and columns */
struct test_driver_result_set *result;
};
void sql_driver_test_register(void);
void sql_driver_test_unregister(void);
void sql_driver_test_add_expected_result(struct sql_db *_db,
const struct test_driver_result *result);
void sql_driver_test_clear_expected_results(struct sql_db *_db);
#endif
dovecot-2.3.21.1/src/lib-sql/sql-api-private.h 0000644 0000000 0000000 00000017664 14656633576 015654 0000000 0000000 #ifndef SQL_API_PRIVATE_H
#define SQL_API_PRIVATE_H
#include "sql-api.h"
#include "module-context.h"
enum sql_db_state {
/* not connected to database */
SQL_DB_STATE_DISCONNECTED,
/* waiting for connection attempt to succeed or fail */
SQL_DB_STATE_CONNECTING,
/* connected, allowing more queries */
SQL_DB_STATE_IDLE,
/* connected, no more queries allowed */
SQL_DB_STATE_BUSY
};
/* Minimum delay between reconnecting to same server */
#define SQL_CONNECT_MIN_DELAY 1
/* Maximum time to avoiding reconnecting to same server */
#define SQL_CONNECT_MAX_DELAY (60*30)
/* If no servers are connected but a query is requested, try reconnecting to
next server which has been disconnected longer than this (with a single
server setup this is really the "max delay" and the SQL_CONNECT_MAX_DELAY
is never used). */
#define SQL_CONNECT_RESET_DELAY 15
/* Abort connect() if it can't connect within this time. */
#define SQL_CONNECT_TIMEOUT_SECS 5
/* Abort queries after this many seconds */
#define SQL_QUERY_TIMEOUT_SECS 60
/* Default max. number of connections to create per host */
#define SQL_DEFAULT_CONNECTION_LIMIT 5
#define SQL_DB_IS_READY(db) \
((db)->state == SQL_DB_STATE_IDLE)
#define SQL_ERRSTR_NOT_CONNECTED "Not connected to database"
/* What is considered slow query */
#define SQL_SLOW_QUERY_MSEC 1000
#define SQL_QUERY_FINISHED "sql_query_finished"
#define SQL_CONNECTION_FINISHED "sql_connection_finished"
#define SQL_TRANSACTION_FINISHED "sql_transaction_finished"
#define SQL_QUERY_FINISHED_FMT "Finished query '%s' in %u msecs"
struct sql_db_module_register {
unsigned int id;
};
union sql_db_module_context {
struct sql_db_module_register *reg;
};
extern struct sql_db_module_register sql_db_module_register;
extern struct event_category event_category_sql;
struct sql_transaction_query {
struct sql_transaction_query *next;
struct sql_transaction_context *trans;
const char *query;
unsigned int *affected_rows;
};
struct sql_db_vfuncs {
struct sql_db *(*init)(const char *connect_string);
int (*init_full)(const struct sql_settings *set, struct sql_db **db_r,
const char **error);
void (*deinit)(struct sql_db *db);
void (*unref)(struct sql_db *db);
void (*wait) (struct sql_db *db);
enum sql_db_flags (*get_flags)(struct sql_db *db);
int (*connect)(struct sql_db *db);
void (*disconnect)(struct sql_db *db);
const char *(*escape_string)(struct sql_db *db, const char *string);
void (*exec)(struct sql_db *db, const char *query);
void (*query)(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context);
struct sql_result *(*query_s)(struct sql_db *db, const char *query);
struct sql_transaction_context *(*transaction_begin)(struct sql_db *db);
void (*transaction_commit)(struct sql_transaction_context *ctx,
sql_commit_callback_t *callback,
void *context);
int (*transaction_commit_s)(struct sql_transaction_context *ctx,
const char **error_r);
void (*transaction_rollback)(struct sql_transaction_context *ctx);
void (*update)(struct sql_transaction_context *ctx, const char *query,
unsigned int *affected_rows);
const char *(*escape_blob)(struct sql_db *db,
const unsigned char *data, size_t size);
struct sql_prepared_statement *
(*prepared_statement_init)(struct sql_db *db,
const char *query_template);
void (*prepared_statement_deinit)(struct sql_prepared_statement *prep_stmt);
struct sql_statement *
(*statement_init)(struct sql_db *db, const char *query_template);
struct sql_statement *
(*statement_init_prepared)(struct sql_prepared_statement *prep_stmt);
void (*statement_abort)(struct sql_statement *stmt);
void (*statement_set_timestamp)(struct sql_statement *stmt,
const struct timespec *ts);
void (*statement_bind_str)(struct sql_statement *stmt,
unsigned int column_idx, const char *value);
void (*statement_bind_binary)(struct sql_statement *stmt,
unsigned int column_idx, const void *value,
size_t value_size);
void (*statement_bind_int64)(struct sql_statement *stmt,
unsigned int column_idx, int64_t value);
void (*statement_query)(struct sql_statement *stmt,
sql_query_callback_t *callback, void *context);
struct sql_result *(*statement_query_s)(struct sql_statement *stmt);
void (*update_stmt)(struct sql_transaction_context *ctx,
struct sql_statement *stmt,
unsigned int *affected_rows);
};
struct sql_db {
const char *name;
enum sql_db_flags flags;
int refcount;
struct sql_db_vfuncs v;
ARRAY(union sql_db_module_context *) module_contexts;
void (*state_change_callback)(struct sql_db *db,
enum sql_db_state prev_state,
void *context);
void *state_change_context;
struct event *event;
HASH_TABLE(char *, struct sql_prepared_statement *) prepared_stmt_hash;
enum sql_db_state state;
/* last time we started connecting to this server
(which may or may not have succeeded) */
time_t last_connect_try;
unsigned int connect_delay;
unsigned int connect_failure_count;
struct timeout *to_reconnect;
uint64_t succeeded_queries;
uint64_t failed_queries;
/* includes both succeeded and failed */
uint64_t slow_queries;
bool no_reconnect:1;
};
struct sql_result_vfuncs {
void (*free)(struct sql_result *result);
int (*next_row)(struct sql_result *result);
unsigned int (*get_fields_count)(struct sql_result *result);
const char *(*get_field_name)(struct sql_result *result,
unsigned int idx);
int (*find_field)(struct sql_result *result, const char *field_name);
const char *(*get_field_value)(struct sql_result *result,
unsigned int idx);
const unsigned char *
(*get_field_value_binary)(struct sql_result *result,
unsigned int idx,
size_t *size_r);
const char *(*find_field_value)(struct sql_result *result,
const char *field_name);
const char *const *(*get_values)(struct sql_result *result);
const char *(*get_error)(struct sql_result *result);
void (*more)(struct sql_result **result, bool async,
sql_query_callback_t *callback, void *context);
};
struct sql_prepared_statement {
struct sql_db *db;
int refcount;
char *query_template;
};
struct sql_statement {
struct sql_db *db;
pool_t pool;
const char *query_template;
ARRAY_TYPE(const_string) args;
/* Tell the driver to not log this query with expanded values. */
bool no_log_expanded_values;
};
struct sql_field_map {
enum sql_field_type type;
size_t offset;
};
struct sql_result {
struct sql_result_vfuncs v;
int refcount;
struct sql_db *db;
const struct sql_field_def *fields;
unsigned int map_size;
struct sql_field_map *map;
void *fetch_dest;
struct event *event;
size_t fetch_dest_size;
enum sql_result_error_type error_type;
bool failed:1;
bool failed_try_retry:1;
bool callback:1;
};
struct sql_transaction_context {
struct sql_db *db;
struct event *event;
/* commit() must use this query list if head is non-NULL. */
struct sql_transaction_query *head, *tail;
};
ARRAY_DEFINE_TYPE(sql_drivers, const struct sql_db *);
extern ARRAY_TYPE(sql_drivers) sql_drivers;
extern struct sql_result sql_not_connected_result;
void sql_init_common(struct sql_db *db);
struct sql_db *
driver_sqlpool_init(const char *connect_string, const struct sql_db *driver);
int driver_sqlpool_init_full(const struct sql_settings *set, const struct sql_db *driver,
struct sql_db **db_r, const char **error_r);
void sql_db_set_state(struct sql_db *db, enum sql_db_state state);
void sql_transaction_add_query(struct sql_transaction_context *ctx, pool_t pool,
const char *query, unsigned int *affected_rows);
const char *sql_statement_get_log_query(struct sql_statement *stmt);
const char *sql_statement_get_query(struct sql_statement *stmt);
void sql_connection_log_finished(struct sql_db *db);
struct event_passthrough *
sql_query_finished_event(struct sql_db *db, struct event *event, const char *query,
bool success, int *duration_r);
struct event_passthrough *sql_transaction_finished_event(struct sql_transaction_context *ctx);
#endif
dovecot-2.3.21.1/src/lib-sql/Makefile.am 0000644 0000000 0000000 00000006607 14656633576 014514 0000000 0000000 noinst_LTLIBRARIES = libsql.la libdriver_test.la
SQL_DRIVER_PLUGINS =
# automake seems to force making this unconditional..
NOPLUGIN_LDFLAGS =
if SQL_PLUGINS
if BUILD_MYSQL
MYSQL_LIB = libdriver_mysql.la
SQL_DRIVER_PLUGINS += mysql
endif
if BUILD_PGSQL
PGSQL_LIB = libdriver_pgsql.la
SQL_DRIVER_PLUGINS += pgsql
endif
if BUILD_SQLITE
SQLITE_LIB = libdriver_sqlite.la
SQL_DRIVER_PLUGINS += sqlite
endif
if BUILD_CASSANDRA
CASSANDRA_LIB = libdriver_cassandra.la
SQL_DRIVER_PLUGINS += cassandra
endif
sql_module_LTLIBRARIES = \
$(MYSQL_LIB) \
$(PGSQL_LIB) \
$(SQLITE_LIB) \
$(CASSANDRA_LIB)
sql_moduledir = $(moduledir)
endif
sql_drivers = @sql_drivers@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
$(SQL_CFLAGS)
dist_sources = \
sql-api.c \
sql-db-cache.c
if ! SQL_PLUGINS
driver_sources = \
driver-mysql.c \
driver-pgsql.c \
driver-sqlite.c \
driver-cassandra.c
endif
libsql_la_SOURCES = \
$(dist_sources) \
$(driver_sources) \
driver-sqlpool.c
libsql_la_LIBADD = $(SQL_LIBS)
nodist_libsql_la_SOURCES = sql-drivers-register.c
deplibs = \
../lib-dovecot/libdovecot.la
if SQL_PLUGINS
libdriver_mysql_la_LDFLAGS = -module -avoid-version
libdriver_mysql_la_LIBADD = $(MYSQL_LIBS)
libdriver_mysql_la_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQL_CFLAGS)
libdriver_mysql_la_SOURCES = driver-mysql.c
libdriver_pgsql_la_LDFLAGS = -module -avoid-version
libdriver_pgsql_la_LIBADD = $(PGSQL_LIBS)
libdriver_pgsql_la_CPPFLAGS = $(AM_CPPFLAGS) $(PGSQL_CFLAGS)
libdriver_pgsql_la_SOURCES = driver-pgsql.c
libdriver_sqlite_la_LDFLAGS = -module -avoid-version
libdriver_sqlite_la_LIBADD = $(SQLITE_LIBS)
libdriver_sqlite_la_CPPFLAGS = $(AM_CPPFLAGS) $(SQLITE_CFLAGS)
libdriver_sqlite_la_SOURCES = driver-sqlite.c
libdriver_cassandra_la_LDFLAGS = -module -avoid-version
libdriver_cassandra_la_LIBADD = $(CASSANDRA_LIBS)
libdriver_cassandra_la_CPPFLAGS = $(AM_CPPFLAGS) $(CASSANDRA_CFLAGS)
libdriver_cassandra_la_SOURCES = driver-cassandra.c
else
endif
libdriver_test_la_LDFLAGS = -avoid-version
libdriver_test_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I$(top_srcdir)/src/lib-test
libdriver_test_la_SOURCES = driver-test.c
noinst_HEADERS = driver-test.h
pkglib_LTLIBRARIES = libdovecot-sql.la
libdovecot_sql_la_SOURCES =
libdovecot_sql_la_LIBADD = libsql.la $(deplibs)
libdovecot_sql_la_DEPENDENCIES = libsql.la
libdovecot_sql_la_LDFLAGS = -export-dynamic
headers = \
sql-api.h \
sql-api-private.h \
sql-db-cache.h
pkginc_libdir=$(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
sql-drivers-register.c: Makefile
rm -f $@
echo '/* this file automatically generated by Makefile */' >$@
echo '#include "lib.h"' >>$@
echo '#include "sql-api.h"' >>$@
if ! SQL_PLUGINS
for i in $(sql_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "extern struct sql_db driver_$${i}_db;" >>$@ ; \
fi; \
done
endif
echo 'void sql_drivers_register_all(void) {' >>$@
if ! SQL_PLUGINS
for i in $(sql_drivers) null; do \
if [ "$${i}" != "null" ]; then \
echo "sql_driver_register(&driver_$${i}_db);" >>$@ ; \
fi; \
done
endif
echo '}' >>$@
if SQL_PLUGINS
install-exec-local:
for d in auth dict; do \
$(mkdir_p) $(DESTDIR)$(moduledir)/$$d; \
for driver in $(SQL_DRIVER_PLUGINS); do \
rm -f $(DESTDIR)$(moduledir)/$$d/libdriver_$$driver.so; \
$(LN_S) ../libdriver_$$driver.so $(DESTDIR)$(moduledir)/$$d; \
done; \
done
endif
distclean-generic:
rm -f Makefile sql-drivers-register.c
dovecot-2.3.21.1/src/lib-sql/sql-db-cache.c 0000644 0000000 0000000 00000007172 14656633576 015045 0000000 0000000 /* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "hash.h"
#include "sql-api-private.h"
#include "sql-db-cache.h"
#define SQL_DB_CACHE_CONTEXT(obj) \
MODULE_CONTEXT_REQUIRE(obj, sql_db_cache_module)
struct sql_db_cache_context {
union sql_db_module_context module_ctx;
struct sql_db *prev, *next; /* These are set while refcount=0 */
struct sql_db_cache *cache;
int refcount;
char *key;
void (*orig_deinit)(struct sql_db *db);
};
struct sql_db_cache {
HASH_TABLE(char *, struct sql_db *) dbs;
unsigned int unused_count, max_unused_connections;
struct sql_db *unused_tail, *unused_head;
};
static MODULE_CONTEXT_DEFINE_INIT(sql_db_cache_module, &sql_db_module_register);
static void sql_db_cache_db_unref(struct sql_db *db)
{
struct sql_db_cache_context *ctx = SQL_DB_CACHE_CONTEXT(db);
struct sql_db_cache_context *head_ctx;
if (--ctx->refcount > 0)
return;
i_assert(db->refcount == 2);
ctx->cache->unused_count++;
if (ctx->cache->unused_tail == NULL)
ctx->cache->unused_tail = db;
else {
head_ctx = SQL_DB_CACHE_CONTEXT(ctx->cache->unused_head);
head_ctx->next = db;
}
ctx->prev = ctx->cache->unused_head;
ctx->cache->unused_head = db;
}
static void sql_db_cache_unlink(struct sql_db_cache_context *ctx)
{
struct sql_db_cache_context *prev_ctx, *next_ctx;
i_assert(ctx->refcount == 0);
if (ctx->prev == NULL)
ctx->cache->unused_tail = ctx->next;
else {
prev_ctx = SQL_DB_CACHE_CONTEXT(ctx->prev);
prev_ctx->next = ctx->next;
}
if (ctx->next == NULL)
ctx->cache->unused_head = ctx->prev;
else {
next_ctx = SQL_DB_CACHE_CONTEXT(ctx->next);
next_ctx->prev = ctx->prev;
}
ctx->cache->unused_count--;
}
static void sql_db_cache_free_tail(struct sql_db_cache *cache)
{
struct sql_db *db;
struct sql_db_cache_context *ctx;
db = cache->unused_tail;
i_assert(db->refcount == 1);
ctx = SQL_DB_CACHE_CONTEXT(db);
sql_db_cache_unlink(ctx);
hash_table_remove(cache->dbs, ctx->key);
i_free(ctx->key);
i_free(ctx);
db->v.unref = NULL;
sql_unref(&db);
}
static void sql_db_cache_drop_oldest(struct sql_db_cache *cache)
{
while (cache->unused_count >= cache->max_unused_connections)
sql_db_cache_free_tail(cache);
}
int sql_db_cache_new(struct sql_db_cache *cache, const struct sql_settings *set,
struct sql_db **db_r, const char **error_r)
{
struct sql_db_cache_context *ctx;
struct sql_db *db;
char *key;
key = i_strdup_printf("%s\t%s", set->driver, set->connect_string);
db = hash_table_lookup(cache->dbs, key);
if (db != NULL) {
ctx = SQL_DB_CACHE_CONTEXT(db);
if (ctx->refcount == 0) {
sql_db_cache_unlink(ctx);
ctx->prev = ctx->next = NULL;
}
i_free(key);
} else {
sql_db_cache_drop_oldest(cache);
if (sql_init_full(set, &db, error_r) < 0) {
i_free(key);
return -1;
}
ctx = i_new(struct sql_db_cache_context, 1);
ctx->cache = cache;
ctx->key = key;
ctx->orig_deinit = db->v.deinit;
db->v.unref = sql_db_cache_db_unref;
MODULE_CONTEXT_SET(db, sql_db_cache_module, ctx);
hash_table_insert(cache->dbs, ctx->key, db);
}
ctx->refcount++;
sql_ref(db);
*db_r = db;
return 0;
}
struct sql_db_cache *sql_db_cache_init(unsigned int max_unused_connections)
{
struct sql_db_cache *cache;
cache = i_new(struct sql_db_cache, 1);
hash_table_create(&cache->dbs, default_pool, 0, str_hash, strcmp);
cache->max_unused_connections = max_unused_connections;
return cache;
}
void sql_db_cache_deinit(struct sql_db_cache **_cache)
{
struct sql_db_cache *cache = *_cache;
*_cache = NULL;
while (cache->unused_tail != NULL)
sql_db_cache_free_tail(cache);
hash_table_destroy(&cache->dbs);
i_free(cache);
}
dovecot-2.3.21.1/src/lib-sql/driver-mysql.c 0000644 0000000 0000000 00000054256 14656633576 015265 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "hex-binary.h"
#include "str.h"
#include "net.h"
#include "time-util.h"
#include "sql-api-private.h"
#ifdef BUILD_MYSQL
#include
#include
#ifdef HAVE_ATTR_NULL
/* ugly way to tell clang that mysql.h is a system header and we don't want
to enable nonnull attributes for it by default.. */
# 4 "driver-mysql.c" 3
#endif
#include
#ifdef HAVE_ATTR_NULL
# 4 "driver-mysql.c" 3
# line 20
#endif
#include
#define MYSQL_DEFAULT_READ_TIMEOUT_SECS 30
#define MYSQL_DEFAULT_WRITE_TIMEOUT_SECS 30
struct mysql_db {
struct sql_db api;
pool_t pool;
const char *user, *password, *dbname, *host, *unix_socket;
const char *ssl_cert, *ssl_key, *ssl_ca, *ssl_ca_path, *ssl_cipher;
int ssl_verify_server_cert;
const char *option_file, *option_group;
in_port_t port;
unsigned int client_flags;
unsigned int connect_timeout, read_timeout, write_timeout;
time_t last_success;
MYSQL *mysql;
unsigned int next_query_connection;
bool ssl_set:1;
};
struct mysql_result {
struct sql_result api;
MYSQL_RES *result;
MYSQL_ROW row;
MYSQL_FIELD *fields;
unsigned int fields_count;
my_ulonglong affected_rows;
};
struct mysql_transaction_context {
struct sql_transaction_context ctx;
pool_t query_pool;
const char *error;
bool failed:1;
bool committed:1;
bool commit_started:1;
};
extern const struct sql_db driver_mysql_db;
extern const struct sql_result driver_mysql_result;
extern const struct sql_result driver_mysql_error_result;
static struct event_category event_category_mysql = {
.parent = &event_category_sql,
.name = "mysql"
};
static int driver_mysql_connect(struct sql_db *_db)
{
struct mysql_db *db = container_of(_db, struct mysql_db, api);
const char *unix_socket, *host;
unsigned long client_flags = db->client_flags;
unsigned int secs_used;
time_t start_time;
bool failed;
i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED);
sql_db_set_state(&db->api, SQL_DB_STATE_CONNECTING);
if (db->host == NULL) {
/* assume option_file overrides the host, or if not we'll just
connect to localhost */
unix_socket = NULL;
host = NULL;
} else if (*db->host == '/') {
unix_socket = db->host;
host = NULL;
} else {
unix_socket = NULL;
host = db->host;
}
if (db->option_file != NULL) {
mysql_options(db->mysql, MYSQL_READ_DEFAULT_FILE,
db->option_file);
}
if (db->host != NULL)
event_set_append_log_prefix(_db->event, t_strdup_printf("mysql(%s): ", db->host));
e_debug(_db->event, "Connecting");
mysql_options(db->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &db->connect_timeout);
mysql_options(db->mysql, MYSQL_OPT_READ_TIMEOUT, &db->read_timeout);
mysql_options(db->mysql, MYSQL_OPT_WRITE_TIMEOUT, &db->write_timeout);
mysql_options(db->mysql, MYSQL_READ_DEFAULT_GROUP,
db->option_group != NULL ? db->option_group : "client");
if (!db->ssl_set && (db->ssl_ca != NULL || db->ssl_ca_path != NULL)) {
#ifdef HAVE_MYSQL_SSL
mysql_ssl_set(db->mysql, db->ssl_key, db->ssl_cert,
db->ssl_ca, db->ssl_ca_path
#ifdef HAVE_MYSQL_SSL_CIPHER
, db->ssl_cipher
#endif
);
#ifdef HAVE_MYSQL_SSL_VERIFY_SERVER_CERT
mysql_options(db->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(void *)&db->ssl_verify_server_cert);
#endif
db->ssl_set = TRUE;
#else
i_fatal("mysql: SSL support not compiled in "
"(remove ssl_ca and ssl_ca_path settings)");
#endif
}
#ifdef CLIENT_MULTI_RESULTS
client_flags |= CLIENT_MULTI_RESULTS;
#endif
/* CLIENT_MULTI_RESULTS allows the use of stored procedures */
start_time = time(NULL);
failed = mysql_real_connect(db->mysql, host, db->user, db->password,
db->dbname, db->port, unix_socket,
client_flags) == NULL;
secs_used = time(NULL) - start_time;
if (failed) {
/* connecting could have taken a while. make sure that any
timeouts that get added soon will get a refreshed
timestamp. */
io_loop_time_refresh();
if (db->api.connect_delay < secs_used)
db->api.connect_delay = secs_used;
sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
e_error(_db->event, "Connect failed to database (%s): %s - "
"waiting for %u seconds before retry",
db->dbname, mysql_error(db->mysql), db->api.connect_delay);
sql_disconnect(&db->api);
return -1;
} else {
db->last_success = ioloop_time;
sql_db_set_state(&db->api, SQL_DB_STATE_IDLE);
return 1;
}
}
static void driver_mysql_disconnect(struct sql_db *_db)
{
struct mysql_db *db = container_of(_db, struct mysql_db, api);
if (db->mysql != NULL)
mysql_close(db->mysql);
}
static int driver_mysql_parse_connect_string(struct mysql_db *db,
const char *connect_string,
const char **error_r)
{
const char *const *args, *name, *value;
const char **field;
db->ssl_cipher = "HIGH";
db->ssl_verify_server_cert = 1;
db->connect_timeout = SQL_CONNECT_TIMEOUT_SECS;
db->read_timeout = MYSQL_DEFAULT_READ_TIMEOUT_SECS;
db->write_timeout = MYSQL_DEFAULT_WRITE_TIMEOUT_SECS;
args = t_strsplit_spaces(connect_string, " ");
for (; *args != NULL; args++) {
value = strchr(*args, '=');
if (value == NULL) {
*error_r = t_strdup_printf("Missing value in connect string: %s",
*args);
return -1;
}
name = t_strdup_until(*args, value);
value++;
field = NULL;
if (strcmp(name, "host") == 0 ||
strcmp(name, "hostaddr") == 0)
field = &db->host;
else if (strcmp(name, "user") == 0)
field = &db->user;
else if (strcmp(name, "password") == 0)
field = &db->password;
else if (strcmp(name, "dbname") == 0)
field = &db->dbname;
else if (strcmp(name, "port") == 0) {
if (net_str2port(value, &db->port) < 0) {
*error_r = t_strdup_printf("Invalid port number: %s", value);
return -1;
}
} else if (strcmp(name, "client_flags") == 0) {
if (str_to_uint(value, &db->client_flags) < 0) {
*error_r = t_strdup_printf("Invalid client flags: %s", value);
return -1;
}
} else if (strcmp(name, "connect_timeout") == 0) {
if (str_to_uint(value, &db->connect_timeout) < 0) {
*error_r = t_strdup_printf("Invalid read_timeout: %s", value);
return -1;
}
} else if (strcmp(name, "read_timeout") == 0) {
if (str_to_uint(value, &db->read_timeout) < 0) {
*error_r = t_strdup_printf("Invalid read_timeout: %s", value);
return -1;
}
} else if (strcmp(name, "write_timeout") == 0) {
if (str_to_uint(value, &db->write_timeout) < 0) {
*error_r = t_strdup_printf("Invalid read_timeout: %s", value);
return -1;
}
} else if (strcmp(name, "ssl_cert") == 0)
field = &db->ssl_cert;
else if (strcmp(name, "ssl_key") == 0)
field = &db->ssl_key;
else if (strcmp(name, "ssl_ca") == 0)
field = &db->ssl_ca;
else if (strcmp(name, "ssl_ca_path") == 0)
field = &db->ssl_ca_path;
else if (strcmp(name, "ssl_cipher") == 0)
field = &db->ssl_cipher;
else if (strcmp(name, "ssl_verify_server_cert") == 0) {
if (strcmp(value, "yes") == 0)
db->ssl_verify_server_cert = 1;
else if (strcmp(value, "no") == 0)
db->ssl_verify_server_cert = 0;
else {
*error_r = t_strdup_printf("Invalid boolean: %s", value);
return -1;
}
} else if (strcmp(name, "option_file") == 0)
field = &db->option_file;
else if (strcmp(name, "option_group") == 0)
field = &db->option_group;
else {
*error_r = t_strdup_printf("Unknown connect string: %s", name);
return -1;
}
if (field != NULL)
*field = p_strdup(db->pool, value);
}
if (db->host == NULL && db->option_file == NULL) {
*error_r = "No hosts given in connect string";
return -1;
}
if (db->mysql == NULL) {
db->mysql = p_new(db->pool, MYSQL, 1);
MYSQL *ptr = mysql_init(db->mysql);
if (ptr == NULL)
i_fatal_status(FATAL_OUTOFMEM, "mysql_init() failed");
}
return 0;
}
static int driver_mysql_init_full_v(const struct sql_settings *set,
struct sql_db **db_r, const char **error_r)
{
struct mysql_db *db;
const char *error = NULL;
pool_t pool;
int ret;
pool = pool_alloconly_create("mysql driver", 1024);
db = p_new(pool, struct mysql_db, 1);
db->pool = pool;
db->api = driver_mysql_db;
db->api.event = event_create(set->event_parent);
event_add_category(db->api.event, &event_category_mysql);
event_set_append_log_prefix(db->api.event, "mysql: ");
T_BEGIN {
ret = driver_mysql_parse_connect_string(db, set->connect_string, &error);
error = p_strdup(db->pool, error);
} T_END;
if (ret < 0) {
*error_r = t_strdup(error);
pool_unref(&db->pool);
return ret;
}
*db_r = &db->api;
return 0;
}
static void driver_mysql_deinit_v(struct sql_db *_db)
{
struct mysql_db *db = container_of(_db, struct mysql_db, api);
_db->no_reconnect = TRUE;
sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
driver_mysql_disconnect(_db);
sql_connection_log_finished(_db);
event_unref(&_db->event);
array_free(&_db->module_contexts);
pool_unref(&db->pool);
}
static int driver_mysql_do_query(struct mysql_db *db, const char *query,
struct event *event)
{
int ret, diff;
struct event_passthrough *e;
ret = mysql_query(db->mysql, query);
io_loop_time_refresh();
e = sql_query_finished_event(&db->api, event, query, ret == 0, &diff);
if (ret != 0) {
e->add_int("error_code", mysql_errno(db->mysql));
e->add_str("error", mysql_error(db->mysql));
e_debug(e->event(), SQL_QUERY_FINISHED_FMT": %s", query,
diff, mysql_error(db->mysql));
} else
e_debug(e->event(), SQL_QUERY_FINISHED_FMT, query, diff);
if (ret == 0)
return 0;
/* failed */
switch (mysql_errno(db->mysql)) {
case CR_SERVER_GONE_ERROR:
case CR_SERVER_LOST:
sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
break;
default:
break;
}
return -1;
}
static const char *
driver_mysql_escape_string(struct sql_db *_db, const char *string)
{
struct mysql_db *db = container_of(_db, struct mysql_db, api);
size_t len = strlen(string);
char *to;
if (_db->state == SQL_DB_STATE_DISCONNECTED) {
/* try connecting */
(void)sql_connect(&db->api);
}
if (_db->state == SQL_DB_STATE_DISCONNECTED) {
/* FIXME: we don't have a valid connection, so fallback
to using default escaping. the next query will most
likely fail anyway so it shouldn't matter that much
what we return here.. Anyway, this API needs
changing so that the escaping function could already
fail the query reliably. */
to = t_buffer_get(len * 2 + 1);
len = mysql_escape_string(to, string, len);
t_buffer_alloc(len + 1);
return to;
}
to = t_buffer_get(len * 2 + 1);
len = mysql_real_escape_string(db->mysql, to, string, len);
t_buffer_alloc(len + 1);
return to;
}
static void driver_mysql_exec(struct sql_db *_db, const char *query)
{
struct mysql_db *db = container_of(_db, struct mysql_db, api);
struct event *event = event_create(_db->event);
(void)driver_mysql_do_query(db, query, event);
event_unref(&event);
}
static void driver_mysql_query(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context)
{
struct sql_result *result;
result = sql_query_s(db, query);
result->callback = TRUE;
callback(result, context);
result->callback = FALSE;
sql_result_unref(result);
}
static struct sql_result *
driver_mysql_query_s(struct sql_db *_db, const char *query)
{
struct mysql_db *db = container_of(_db, struct mysql_db, api);
struct mysql_result *result;
struct event *event;
int ret;
result = i_new(struct mysql_result, 1);
result->api = driver_mysql_result;
event = event_create(_db->event);
if (driver_mysql_do_query(db, query, event) < 0)
result->api = driver_mysql_error_result;
else {
/* query ok */
result->affected_rows = mysql_affected_rows(db->mysql);
result->result = mysql_store_result(db->mysql);
#ifdef CLIENT_MULTI_RESULTS
/* Because we've enabled CLIENT_MULTI_RESULTS, we need to read
(ignore) extra results - there should not be any.
ret is: -1 = done, >0 = error, 0 = more results. */
while ((ret = mysql_next_result(db->mysql)) == 0) ;
#else
ret = -1;
#endif
if (ret < 0 &&
(result->result != NULL || mysql_errno(db->mysql) == 0)) {
/* ok */
} else {
/* failed */
if (result->result != NULL)
mysql_free_result(result->result);
result->api = driver_mysql_error_result;
}
}
result->api.db = _db;
result->api.refcount = 1;
result->api.event = event;
return &result->api;
}
static void driver_mysql_result_free(struct sql_result *_result)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
i_assert(_result != &sql_not_connected_result);
if (_result->callback)
return;
if (result->result != NULL)
mysql_free_result(result->result);
event_unref(&_result->event);
i_free(result);
}
static int driver_mysql_result_next_row(struct sql_result *_result)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
struct mysql_db *db = container_of(_result->db, struct mysql_db, api);
int ret;
if (result->result == NULL) {
/* no results */
return 0;
}
result->row = mysql_fetch_row(result->result);
if (result->row != NULL)
ret = 1;
else {
if (mysql_errno(db->mysql) != 0)
return -1;
ret = 0;
}
db->last_success = ioloop_time;
return ret;
}
static void driver_mysql_result_fetch_fields(struct mysql_result *result)
{
if (result->fields != NULL)
return;
result->fields_count = mysql_num_fields(result->result);
result->fields = mysql_fetch_fields(result->result);
}
static unsigned int
driver_mysql_result_get_fields_count(struct sql_result *_result)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
driver_mysql_result_fetch_fields(result);
return result->fields_count;
}
static const char *
driver_mysql_result_get_field_name(struct sql_result *_result, unsigned int idx)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
driver_mysql_result_fetch_fields(result);
i_assert(idx < result->fields_count);
return result->fields[idx].name;
}
static int driver_mysql_result_find_field(struct sql_result *_result,
const char *field_name)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
unsigned int i;
driver_mysql_result_fetch_fields(result);
for (i = 0; i < result->fields_count; i++) {
if (strcmp(result->fields[i].name, field_name) == 0)
return i;
}
return -1;
}
static const char *
driver_mysql_result_get_field_value(struct sql_result *_result,
unsigned int idx)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
return (const char *)result->row[idx];
}
static const unsigned char *
driver_mysql_result_get_field_value_binary(struct sql_result *_result,
unsigned int idx, size_t *size_r)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
unsigned long *lengths;
lengths = mysql_fetch_lengths(result->result);
*size_r = lengths[idx];
return (const void *)result->row[idx];
}
static const char *
driver_mysql_result_find_field_value(struct sql_result *result,
const char *field_name)
{
int idx;
idx = driver_mysql_result_find_field(result, field_name);
if (idx < 0)
return NULL;
return driver_mysql_result_get_field_value(result, idx);
}
static const char *const *
driver_mysql_result_get_values(struct sql_result *_result)
{
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
return (const char *const *)result->row;
}
static const char *driver_mysql_result_get_error(struct sql_result *_result)
{
struct mysql_db *db = container_of(_result->db, struct mysql_db, api);
const char *errstr;
unsigned int idle_time;
int err;
err = mysql_errno(db->mysql);
errstr = mysql_error(db->mysql);
if ((err == CR_SERVER_GONE_ERROR || err == CR_SERVER_LOST) &&
db->last_success != 0) {
idle_time = ioloop_time - db->last_success;
errstr = t_strdup_printf("%s (idled for %u secs)",
errstr, idle_time);
}
return errstr;
}
static struct sql_transaction_context *
driver_mysql_transaction_begin(struct sql_db *db)
{
struct mysql_transaction_context *ctx;
ctx = i_new(struct mysql_transaction_context, 1);
ctx->ctx.db = db;
ctx->query_pool = pool_alloconly_create("mysql transaction", 1024);
ctx->ctx.event = event_create(db->event);
return &ctx->ctx;
}
static void
driver_mysql_transaction_commit(struct sql_transaction_context *ctx,
sql_commit_callback_t *callback, void *context)
{
struct sql_commit_result result;
const char *error;
i_zero(&result);
if (sql_transaction_commit_s(&ctx, &error) < 0)
result.error = error;
callback(&result, context);
}
static int ATTR_NULL(3)
transaction_send_query(struct mysql_transaction_context *ctx, const char *query,
unsigned int *affected_rows_r)
{
struct sql_result *_result;
int ret = 0;
if (ctx->failed)
return -1;
_result = sql_query_s(ctx->ctx.db, query);
if (sql_result_next_row(_result) < 0) {
ctx->error = sql_result_get_error(_result);
ctx->failed = TRUE;
ret = -1;
} else if (affected_rows_r != NULL) {
struct mysql_result *result =
container_of(_result, struct mysql_result, api);
i_assert(result->affected_rows != (my_ulonglong)-1);
*affected_rows_r = result->affected_rows;
}
sql_result_unref(_result);
return ret;
}
static int driver_mysql_try_commit_s(struct mysql_transaction_context *ctx)
{
struct sql_transaction_context *_ctx = &ctx->ctx;
bool multi = _ctx->head != NULL && _ctx->head->next != NULL;
/* wrap in BEGIN/COMMIT only if transaction has mutiple statements. */
if (multi && transaction_send_query(ctx, "BEGIN", NULL) < 0) {
if (_ctx->db->state != SQL_DB_STATE_DISCONNECTED)
return -1;
/* we got disconnected, retry */
return 0;
} else if (multi) {
ctx->commit_started = TRUE;
}
while (_ctx->head != NULL) {
if (transaction_send_query(ctx, _ctx->head->query,
_ctx->head->affected_rows) < 0)
return -1;
_ctx->head = _ctx->head->next;
}
if (multi && transaction_send_query(ctx, "COMMIT", NULL) < 0)
return -1;
return 1;
}
static int
driver_mysql_transaction_commit_s(struct sql_transaction_context *_ctx,
const char **error_r)
{
struct mysql_transaction_context *ctx =
container_of(_ctx, struct mysql_transaction_context, ctx);
struct mysql_db *db = container_of(_ctx->db, struct mysql_db, api);
int ret = 1;
*error_r = NULL;
if (_ctx->head != NULL) {
ret = driver_mysql_try_commit_s(ctx);
*error_r = t_strdup(ctx->error);
if (ret == 0) {
e_info(db->api.event, "Disconnected from database, "
"retrying commit");
if (sql_connect(_ctx->db) >= 0) {
ctx->failed = FALSE;
ret = driver_mysql_try_commit_s(ctx);
}
}
}
if (ret > 0)
ctx->committed = TRUE;
sql_transaction_rollback(&_ctx);
return ret <= 0 ? -1 : 0;
}
static void
driver_mysql_transaction_rollback(struct sql_transaction_context *_ctx)
{
struct mysql_transaction_context *ctx =
container_of(_ctx, struct mysql_transaction_context, ctx);
if (ctx->failed) {
bool rolledback = FALSE;
const char *orig_error = t_strdup(ctx->error);
if (ctx->commit_started) {
/* reset failed flag so ROLLBACK is actually sent.
otherwise, transaction_send_query() will return
without trying to send the query. */
ctx->failed = FALSE;
if (transaction_send_query(ctx, "ROLLBACK", NULL) < 0)
e_debug(event_create_passthrough(_ctx->event)->
add_str("error", ctx->error)->event(),
"Rollback failed: %s", ctx->error);
else
rolledback = TRUE;
}
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", orig_error)->event(),
"Transaction failed: %s%s", orig_error,
rolledback ? " - Rolled back" : "");
} else if (ctx->committed)
e_debug(sql_transaction_finished_event(_ctx)->event(),
"Transaction committed");
else
e_debug(sql_transaction_finished_event(_ctx)->
add_str("error", "Rolled back")->event(),
"Transaction rolled back");
event_unref(&ctx->ctx.event);
pool_unref(&ctx->query_pool);
i_free(ctx);
}
static void
driver_mysql_update(struct sql_transaction_context *_ctx, const char *query,
unsigned int *affected_rows)
{
struct mysql_transaction_context *ctx =
container_of(_ctx, struct mysql_transaction_context, ctx);
sql_transaction_add_query(&ctx->ctx, ctx->query_pool,
query, affected_rows);
}
static const char *
driver_mysql_escape_blob(struct sql_db *_db ATTR_UNUSED,
const unsigned char *data, size_t size)
{
string_t *str = t_str_new(128);
str_append(str, "X'");
binary_to_hex_append(str, data, size);
str_append_c(str, '\'');
return str_c(str);
}
const struct sql_db driver_mysql_db = {
.name = "mysql",
.flags = SQL_DB_FLAG_BLOCKING | SQL_DB_FLAG_POOLED |
SQL_DB_FLAG_ON_DUPLICATE_KEY,
.v = {
.init_full = driver_mysql_init_full_v,
.deinit = driver_mysql_deinit_v,
.connect = driver_mysql_connect,
.disconnect = driver_mysql_disconnect,
.escape_string = driver_mysql_escape_string,
.exec = driver_mysql_exec,
.query = driver_mysql_query,
.query_s = driver_mysql_query_s,
.transaction_begin = driver_mysql_transaction_begin,
.transaction_commit = driver_mysql_transaction_commit,
.transaction_commit_s = driver_mysql_transaction_commit_s,
.transaction_rollback = driver_mysql_transaction_rollback,
.update = driver_mysql_update,
.escape_blob = driver_mysql_escape_blob,
}
};
const struct sql_result driver_mysql_result = {
.v = {
.free = driver_mysql_result_free,
.next_row = driver_mysql_result_next_row,
.get_fields_count = driver_mysql_result_get_fields_count,
.get_field_name = driver_mysql_result_get_field_name,
.find_field = driver_mysql_result_find_field,
.get_field_value = driver_mysql_result_get_field_value,
.get_field_value_binary = driver_mysql_result_get_field_value_binary,
.find_field_value = driver_mysql_result_find_field_value,
.get_values = driver_mysql_result_get_values,
.get_error = driver_mysql_result_get_error,
}
};
static int
driver_mysql_result_error_next_row(struct sql_result *result ATTR_UNUSED)
{
return -1;
}
const struct sql_result driver_mysql_error_result = {
.v = {
.free = driver_mysql_result_free,
.next_row = driver_mysql_result_error_next_row,
.get_error = driver_mysql_result_get_error,
},
.failed_try_retry = TRUE
};
const char *driver_mysql_version = DOVECOT_ABI_VERSION;
void driver_mysql_init(void);
void driver_mysql_deinit(void);
void driver_mysql_init(void)
{
sql_driver_register(&driver_mysql_db);
}
void driver_mysql_deinit(void)
{
sql_driver_unregister(&driver_mysql_db);
}
#endif
dovecot-2.3.21.1/src/lib-sql/sql-api.h 0000644 0000000 0000000 00000023543 14656633576 014175 0000000 0000000 #ifndef SQL_API_H
#define SQL_API_H
struct timespec;
/* This SQL API is designed to work asynchronously. The underlying drivers
however may not. */
enum sql_db_flags {
/* Set if queries are not executed asynchronously */
SQL_DB_FLAG_BLOCKING = 0x01,
/* Set if database wants to use connection pooling */
SQL_DB_FLAG_POOLED = 0x02,
/* Prepared statements are supported by the database. If they aren't,
the functions can still be used, but they're just internally
convered into regular statements. */
SQL_DB_FLAG_PREP_STATEMENTS = 0x04,
/* Database supports INSERT .. ON DUPLICATE KEY syntax. */
SQL_DB_FLAG_ON_DUPLICATE_KEY = 0x08,
/* Database supports INSERT .. ON CONFLICT DO UPDATE syntax. */
SQL_DB_FLAG_ON_CONFLICT_DO = 0x10,
};
enum sql_field_type {
SQL_TYPE_STR,
SQL_TYPE_UINT,
SQL_TYPE_ULLONG,
SQL_TYPE_BOOL
};
struct sql_field_def {
enum sql_field_type type;
const char *name;
size_t offset;
};
enum sql_result_error_type {
SQL_RESULT_ERROR_TYPE_UNKNOWN = 0,
/* It's unknown whether write succeeded or not. This could be due to
a timeout or a disconnection from server. */
SQL_RESULT_ERROR_TYPE_WRITE_UNCERTAIN
};
enum sql_result_next {
/* Row was returned */
SQL_RESULT_NEXT_OK = 1,
/* There are no more rows */
SQL_RESULT_NEXT_LAST = 0,
/* Error occurred - see sql_result_get_error*() */
SQL_RESULT_NEXT_ERROR = -1,
/* There are more results - call sql_result_more() */
SQL_RESULT_NEXT_MORE = -99
};
#define SQL_DEF_STRUCT(name, struct_name, type, c_type) \
{ (type) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
((struct struct_name *)0)->name, c_type), \
#name, offsetof(struct struct_name, name) }
#define SQL_DEF_STRUCT_STR(name, struct_name) \
SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_STR, const char *)
#define SQL_DEF_STRUCT_UINT(name, struct_name) \
SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_UINT, unsigned int)
#define SQL_DEF_STRUCT_ULLONG(name, struct_name) \
SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_ULLONG, unsigned long long)
#define SQL_DEF_STRUCT_BOOL(name, struct_name) \
SQL_DEF_STRUCT(name, struct_name, SQL_TYPE_BOOL, bool)
struct sql_db;
struct sql_result;
struct sql_commit_result {
const char *error;
enum sql_result_error_type error_type;
};
struct sql_settings {
const char *driver;
const char *connect_string;
struct event *event_parent;
};
typedef void sql_query_callback_t(struct sql_result *result, void *context);
typedef void sql_commit_callback_t(const struct sql_commit_result *result, void *context);
void sql_drivers_init(void);
void sql_drivers_deinit(void);
/* register all built-in SQL drivers */
void sql_drivers_register_all(void);
void sql_driver_register(const struct sql_db *driver);
void sql_driver_unregister(const struct sql_db *driver);
/* Initialize database connections. db_driver is the database driver name,
eg. "mysql" or "pgsql". connect_string is driver-specific. */
struct sql_db *sql_init(const char *db_driver, const char *connect_string);
int sql_init_full(const struct sql_settings *set, struct sql_db **db_r,
const char **error_r);
void sql_ref(struct sql_db *db);
void sql_unref(struct sql_db **db);
/* Returns SQL database state flags. */
enum sql_db_flags sql_get_flags(struct sql_db *db);
/* Explicitly connect to the database. It's not required to call this function
though. Returns -1 if we're not connected, 0 if we started connecting or
1 if we are fully connected now. */
int sql_connect(struct sql_db *db);
/* Explicitly disconnect from database and abort pending auth requests. */
void sql_disconnect(struct sql_db *db);
/* Escape the given string if needed and return it. */
const char *sql_escape_string(struct sql_db *db, const char *string);
/* Escape the given data as a string. */
const char *sql_escape_blob(struct sql_db *db,
const unsigned char *data, size_t size);
/* Execute SQL query without waiting for results. */
void sql_exec(struct sql_db *db, const char *query);
/* Execute SQL query and return result in callback. If fields list is given,
the returned fields are validated to be of correct type, and you can use
sql_result_next_row_get() */
void sql_query(struct sql_db *db, const char *query,
sql_query_callback_t *callback, void *context);
#define sql_query(db, query, callback, context) \
sql_query(db, query - \
CALLBACK_TYPECHECK(callback, void (*)( \
struct sql_result *, typeof(context))), \
(sql_query_callback_t *)callback, context)
/* Execute blocking SQL query and return result. */
struct sql_result *sql_query_s(struct sql_db *db, const char *query);
struct sql_prepared_statement *
sql_prepared_statement_init(struct sql_db *db, const char *query_template);
void sql_prepared_statement_unref(struct sql_prepared_statement **prep_stmt);
struct sql_statement *
sql_statement_init(struct sql_db *db, const char *query_template);
struct sql_statement *
sql_statement_init_prepared(struct sql_prepared_statement *prep_stmt);
void sql_statement_abort(struct sql_statement **stmt);
void sql_statement_set_timestamp(struct sql_statement *stmt,
const struct timespec *ts);
void sql_statement_set_no_log_expanded_values(struct sql_statement *stmt,
bool no_expand);
void sql_statement_bind_str(struct sql_statement *stmt,
unsigned int column_idx, const char *value);
void sql_statement_bind_binary(struct sql_statement *stmt,
unsigned int column_idx, const void *value,
size_t value_size);
void sql_statement_bind_int64(struct sql_statement *stmt,
unsigned int column_idx, int64_t value);
void sql_statement_query(struct sql_statement **stmt,
sql_query_callback_t *callback, void *context);
#define sql_statement_query(stmt, callback, context) \
sql_statement_query(stmt, \
(sql_query_callback_t *)callback, TRUE ? context : \
CALLBACK_TYPECHECK(callback, void (*)( \
struct sql_result *, typeof(context))))
struct sql_result *sql_statement_query_s(struct sql_statement **stmt);
void sql_result_setup_fetch(struct sql_result *result,
const struct sql_field_def *fields,
void *dest, size_t dest_size);
/* Go to next row. See enum sql_result_next. */
int sql_result_next_row(struct sql_result *result);
/* If sql_result_next_row() returned SQL_RESULT_NEXT_MORE, this can be called
to continue returning more results. The result is freed with this call, so
it must not be accesed anymore until the callback is finished. */
void sql_result_more(struct sql_result **result,
sql_query_callback_t *callback, void *context);
#define sql_result_more(result, callback, context) \
sql_result_more(result - \
CALLBACK_TYPECHECK(callback, void (*)( \
struct sql_result *, typeof(context))), \
(sql_query_callback_t *)callback, context)
/* Synchronous version of sql_result_more(). The result will be replaced with
the new result. */
void sql_result_more_s(struct sql_result **result);
void sql_result_ref(struct sql_result *result);
/* Needs to be called only with sql_query_s() or when result has been
explicitly referenced. */
void sql_result_unref(struct sql_result *result);
/* Return number of fields in result. */
unsigned int sql_result_get_fields_count(struct sql_result *result);
/* Return name of the given field index. */
const char *sql_result_get_field_name(struct sql_result *result,
unsigned int idx);
/* Return field index for given name, or -1 if not found. */
int sql_result_find_field(struct sql_result *result, const char *field_name);
/* Returns value of given field as string. Note that it can be NULL. */
const char *sql_result_get_field_value(struct sql_result *result,
unsigned int idx);
/* Returns a binary value. Note that a NULL is returned as NULL with size=0,
while empty string returns non-NULL with size=0. */
const unsigned char *
sql_result_get_field_value_binary(struct sql_result *result,
unsigned int idx, size_t *size_r);
/* Find the field and return its value. NULL return value can mean that either
the field didn't exist or that its value is NULL. */
const char *sql_result_find_field_value(struct sql_result *result,
const char *field_name);
/* Return all values of current row. Note that this array is not
NULL-terminated - you must use sql_result_get_fields_count() to find out
the array's length. It's also possible that some of the values inside the
array are NULL. */
const char *const *sql_result_get_values(struct sql_result *result);
/* Return last error message in result. */
const char *sql_result_get_error(struct sql_result *result);
enum sql_result_error_type sql_result_get_error_type(struct sql_result *result);
/* Begin a new transaction. Currently you're limited to only one open
transaction at a time. */
struct sql_transaction_context *sql_transaction_begin(struct sql_db *db);
/* Commit transaction. */
void sql_transaction_commit(struct sql_transaction_context **ctx,
sql_commit_callback_t *callback, void *context);
#define sql_transaction_commit(ctx, callback, context) \
sql_transaction_commit(ctx - \
CALLBACK_TYPECHECK(callback, void (*)( \
const struct sql_commit_result *, typeof(context))), \
(sql_commit_callback_t *)callback, context)
/* Synchronous commit. Returns 0 if ok, -1 if error. */
int sql_transaction_commit_s(struct sql_transaction_context **ctx,
const char **error_r);
void sql_transaction_rollback(struct sql_transaction_context **ctx);
/* Execute query in given transaction. */
void sql_update(struct sql_transaction_context *ctx, const char *query);
void sql_update_stmt(struct sql_transaction_context *ctx,
struct sql_statement **stmt);
/* Save the number of rows updated by this query. The value is set before
commit callback is called. */
void sql_update_get_rows(struct sql_transaction_context *ctx, const char *query,
unsigned int *affected_rows);
void sql_update_stmt_get_rows(struct sql_transaction_context *ctx,
struct sql_statement **stmt,
unsigned int *affected_rows);
/* Wait for SQL query results. */
void sql_wait(struct sql_db *db);
#endif
dovecot-2.3.21.1/src/lmtp/ 0000755 0000000 0000000 00000000000 14656633640 012130 5 0000000 0000000 dovecot-2.3.21.1/src/lmtp/lmtp-recipient.h 0000644 0000000 0000000 00000002146 14656633576 015170 0000000 0000000 #ifndef LMTP_RECIPIENT_H
#define LMTP_RECIPIENT_H
struct smtp_address;
struct smtp_server_cmd_ctx;
struct smtp_server_cmd_rcpt;
struct smtp_server_recipient;
union lmtp_recipient_module_context;
struct client;
enum lmtp_recipient_type {
LMTP_RECIPIENT_TYPE_LOCAL,
LMTP_RECIPIENT_TYPE_PROXY,
};
struct lmtp_recipient {
struct client *client;
struct smtp_server_recipient *rcpt;
enum lmtp_recipient_type type;
void *backend_context;
const char *session_id;
const char *forward_fields;
/* Module-specific contexts. */
ARRAY(union lmtp_recipient_module_context *) module_contexts;
};
struct lmtp_recipient_module_register {
unsigned int id;
};
union lmtp_recipient_module_context {
struct lmtp_recipient_module_register *reg;
};
extern struct lmtp_recipient_module_register lmtp_recipient_module_register;
struct lmtp_recipient *
lmtp_recipient_create(struct client *client,
struct smtp_server_transaction *trans,
struct smtp_server_recipient *rcpt);
struct lmtp_recipient *
lmtp_recipient_find_duplicate(struct lmtp_recipient *lrcpt,
struct smtp_server_transaction *trans);
#endif
dovecot-2.3.21.1/src/lmtp/lmtp-local.c 0000644 0000000 0000000 00000054651 14656633576 014303 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lmtp-common.h"
#include "str.h"
#include "istream.h"
#include "strescape.h"
#include "time-util.h"
#include "hostpid.h"
#include "var-expand.h"
#include "restrict-access.h"
#include "anvil-client.h"
#include "settings-parser.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "mail-namespace.h"
#include "mail-deliver.h"
#include "mail-autoexpunge.h"
#include "index/raw/raw-storage.h"
#include "smtp-common.h"
#include "smtp-params.h"
#include "smtp-address.h"
#include "smtp-submit-settings.h"
#include "lda-settings.h"
#include "lmtp-settings.h"
#include "lmtp-recipient.h"
#include "lmtp-local.h"
struct lmtp_local_recipient {
struct lmtp_recipient *rcpt;
char *detail;
struct mail_storage_service_user *service_user;
struct anvil_query *anvil_query;
struct lmtp_local_recipient *duplicate;
bool anvil_connect_sent:1;
};
struct lmtp_local {
struct client *client;
ARRAY(struct lmtp_local_recipient *) rcpt_to;
struct mail *raw_mail, *first_saved_mail;
struct mail_user *rcpt_user;
};
/*
* LMTP local
*/
static struct lmtp_local *
lmtp_local_init(struct client *client)
{
struct lmtp_local *local;
local = i_new(struct lmtp_local, 1);
local->client = client;
i_array_init(&local->rcpt_to, 8);
return local;
}
void lmtp_local_deinit(struct lmtp_local **_local)
{
struct lmtp_local *local = *_local;
*_local = NULL;
if (array_is_created(&local->rcpt_to))
array_free(&local->rcpt_to);
if (local->raw_mail != NULL) {
struct mailbox_transaction_context *raw_trans =
local->raw_mail->transaction;
struct mailbox *raw_box = local->raw_mail->box;
mail_free(&local->raw_mail);
mailbox_transaction_rollback(&raw_trans);
mailbox_free(&raw_box);
}
i_free(local);
}
/*
* Recipient
*/
static void
lmtp_local_rcpt_anvil_disconnect(struct lmtp_local_recipient *llrcpt)
{
const struct mail_storage_service_input *input;
if (!llrcpt->anvil_connect_sent)
return;
llrcpt->anvil_connect_sent = FALSE;
input = mail_storage_service_user_get_input(llrcpt->service_user);
master_service_anvil_send(master_service, t_strconcat(
"DISCONNECT\t", my_pid, "\t", master_service_get_name(master_service),
"/", input->username, "\n", NULL));
}
static void
lmtp_local_rcpt_destroy(struct smtp_server_recipient *rcpt ATTR_UNUSED,
struct lmtp_local_recipient *llrcpt)
{
if (llrcpt->anvil_query != NULL)
anvil_client_query_abort(anvil, &llrcpt->anvil_query);
lmtp_local_rcpt_anvil_disconnect(llrcpt);
mail_storage_service_user_unref(&llrcpt->service_user);
}
static void
lmtp_local_rcpt_reply_overquota(struct lmtp_local_recipient *llrcpt,
const char *error)
{
struct smtp_server_recipient *rcpt = llrcpt->rcpt->rcpt;
struct lda_settings *lda_set =
mail_storage_service_user_get_set(llrcpt->service_user)[2];
if (lda_set->quota_full_tempfail)
smtp_server_recipient_reply(rcpt, 452, "4.2.2", "%s", error);
else
smtp_server_recipient_reply(rcpt, 552, "5.2.2", "%s", error);
}
static void ATTR_FORMAT(4,5)
lmtp_local_rcpt_fail_all(struct lmtp_local *local,
unsigned int status, const char *enh_code,
const char *fmt, ...)
{
struct lmtp_local_recipient *const *llrcpts;
const char *msg;
unsigned int count, i;
va_list args;
va_start(args, fmt);
msg = t_strdup_vprintf(fmt, args);
va_end(args);
llrcpts = array_get(&local->rcpt_to, &count);
for (i = 0; i < count; i++) {
struct smtp_server_recipient *rcpt = llrcpts[i]->rcpt->rcpt;
smtp_server_recipient_reply(rcpt, status, enh_code, "%s", msg);
}
}
/*
* RCPT command
*/
static int
lmtp_local_rcpt_check_quota(struct lmtp_local_recipient *llrcpt)
{
struct client *client = llrcpt->rcpt->client;
struct smtp_server_recipient *rcpt = llrcpt->rcpt->rcpt;
struct smtp_address *address = rcpt->path;
struct mail_user *user;
struct mail_namespace *ns;
struct mailbox *box;
struct mailbox_status status;
enum mail_error mail_error;
const char *error;
int ret;
if (!client->lmtp_set->lmtp_rcpt_check_quota)
return 0;
/* mail user will be created second time when mail is saved,
so it's session_id needs to be different,
but second time session_id needs to be the same as rcpt session_id and
mail user session id for the first rcpt should not overlap with session id
of the second recipient, so add custom ":quota" suffix to the session_id without
session_id counter increment, so next time mail user will get
the same session id as rcpt */
ret = mail_storage_service_next_with_session_suffix(storage_service,
llrcpt->service_user,
"quota",
&user, &error);
if (ret < 0) {
e_error(rcpt->event, "Failed to initialize user %s: %s",
smtp_address_encode(address), error);
ret = -1;
} else {
/* Set the log prefix for the user. The default log prefix is
automatically restored later when user context gets
deactivated. */
i_set_failure_prefix("%s",
mail_storage_service_user_get_log_prefix(llrcpt->service_user));
ns = mail_namespace_find_inbox(user->namespaces);
box = mailbox_alloc(ns->list, "INBOX", 0);
ret = mailbox_get_status(box, STATUS_CHECK_OVER_QUOTA, &status);
if (ret < 0) {
error = mailbox_get_last_error(box, &mail_error);
if (mail_error == MAIL_ERROR_NOQUOTA) {
lmtp_local_rcpt_reply_overquota(llrcpt, error);
} else {
e_error(rcpt->event,
"mailbox_get_status(%s, STATUS_CHECK_OVER_QUOTA) "
"failed: %s",
mailbox_get_vname(box),
mailbox_get_last_internal_error(box, NULL));
}
ret = -1;
}
mailbox_free(&box);
mail_user_deinit(&user);
mail_storage_service_io_deactivate_user(llrcpt->service_user);
}
if (ret < 0 && !smtp_server_recipient_is_replied(rcpt)) {
smtp_server_recipient_reply(rcpt, 451, "4.3.0",
"Temporary internal error");
}
return ret;
}
static void
lmtp_local_rcpt_approved(struct smtp_server_recipient *rcpt,
struct lmtp_local_recipient *llrcpt)
{
struct client *client = llrcpt->rcpt->client;
struct lmtp_recipient *drcpt;
/* resolve duplicate recipient */
drcpt = lmtp_recipient_find_duplicate(llrcpt->rcpt, rcpt->trans);
if (drcpt != NULL) {
i_assert(drcpt->type == LMTP_RECIPIENT_TYPE_LOCAL);
llrcpt->duplicate = drcpt->backend_context;
i_assert(llrcpt->duplicate->duplicate == NULL);
}
/* add to local recipients */
array_push_back(&client->local->rcpt_to, &llrcpt);
}
static bool
lmtp_local_rcpt_anvil_finish(struct lmtp_local_recipient *llrcpt)
{
struct smtp_server_recipient *rcpt = llrcpt->rcpt->rcpt;
struct smtp_server_cmd_ctx *cmd = rcpt->cmd;
if (lmtp_local_rcpt_check_quota(llrcpt) < 0)
return FALSE;
smtp_server_cmd_rcpt_reply_success(cmd);
return TRUE;
}
static void
lmtp_local_rcpt_anvil_cb(const char *reply, void *context)
{
struct lmtp_local_recipient *llrcpt =
(struct lmtp_local_recipient *)context;
struct client *client = llrcpt->rcpt->client;
struct smtp_server_recipient *rcpt = llrcpt->rcpt->rcpt;
const struct mail_storage_service_input *input;
unsigned int parallel_count = 0;
llrcpt->anvil_query = NULL;
if (reply == NULL) {
/* lookup failed */
} else if (str_to_uint(reply, ¶llel_count) < 0) {
e_error(rcpt->event, "Invalid reply from anvil: %s", reply);
}
if (parallel_count >= client->lmtp_set->lmtp_user_concurrency_limit) {
smtp_server_recipient_reply(
rcpt, 451, "4.3.0",
"Too many concurrent deliveries for user");
} else if (lmtp_local_rcpt_anvil_finish(llrcpt)) {
llrcpt->anvil_connect_sent = TRUE;
input = mail_storage_service_user_get_input(llrcpt->service_user);
master_service_anvil_send(master_service, t_strconcat(
"CONNECT\t", my_pid, "\t", master_service_get_name(master_service),
"/", input->username, "\n", NULL));
}
}
int lmtp_local_rcpt(struct client *client,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct lmtp_recipient *lrcpt, const char *username,
const char *detail)
{
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
struct lmtp_local_recipient *llrcpt;
struct mail_storage_service_input input;
struct mail_storage_service_user *service_user;
const char *error = NULL;
int ret = 0;
i_zero(&input);
input.module = input.service = "lmtp";
input.username = username;
input.local_ip = client->local_ip;
input.remote_ip = client->remote_ip;
input.local_port = client->local_port;
input.remote_port = client->remote_port;
input.session_id = lrcpt->session_id;
input.conn_ssl_secured =
smtp_server_connection_is_ssl_secured(client->conn);
input.conn_secured = input.conn_ssl_secured ||
smtp_server_connection_is_trusted(client->conn);
input.forward_fields = lrcpt->forward_fields;
input.event_parent = rcpt->event;
ret = mail_storage_service_lookup(storage_service, &input,
&service_user, &error);
if (ret < 0) {
e_error(rcpt->event, "Failed to lookup user %s: %s",
username, error);
smtp_server_recipient_reply(rcpt, 451, "4.3.0",
"Temporary internal error");
return -1;
}
if (ret == 0) {
smtp_server_recipient_reply(rcpt, 550, "5.1.1",
"User doesn't exist: %s",
username);
return -1;
}
if (client->local == NULL)
client->local = lmtp_local_init(client);
llrcpt = p_new(rcpt->pool, struct lmtp_local_recipient, 1);
llrcpt->rcpt = lrcpt;
llrcpt->detail = p_strdup(rcpt->pool, detail);
llrcpt->service_user = service_user;
lrcpt->type = LMTP_RECIPIENT_TYPE_LOCAL;
lrcpt->backend_context = llrcpt;
smtp_server_recipient_add_hook(
rcpt, SMTP_SERVER_RECIPIENT_HOOK_DESTROY,
lmtp_local_rcpt_destroy, llrcpt);
smtp_server_recipient_add_hook(
rcpt, SMTP_SERVER_RECIPIENT_HOOK_APPROVED,
lmtp_local_rcpt_approved, llrcpt);
if (client->lmtp_set->lmtp_user_concurrency_limit == 0) {
(void)lmtp_local_rcpt_anvil_finish(llrcpt);
} else {
/* NOTE: username may change as the result of the userdb
lookup. Look up the new one via service_user. */
const struct mail_storage_service_input *input =
mail_storage_service_user_get_input(llrcpt->service_user);
const char *query = t_strconcat("LOOKUP\t",
master_service_get_name(master_service),
"/", str_tabescape(input->username), NULL);
llrcpt->anvil_query = anvil_client_query(anvil, query,
lmtp_local_rcpt_anvil_cb, llrcpt);
return 0;
}
return 1;
}
/*
* DATA command
*/
void lmtp_local_add_headers(struct lmtp_local *local,
struct smtp_server_transaction *trans,
string_t *headers)
{
struct client *client = local->client;
const struct lmtp_settings *lmtp_set = client->lmtp_set;
struct lmtp_local_recipient *const *llrcpts;
const struct smtp_address *rcpt_to = NULL;
unsigned int count;
str_printfa(headers, "Return-Path: <%s>\r\n",
smtp_address_encode(trans->mail_from));
llrcpts = array_get(&local->rcpt_to, &count);
if (count == 1) {
struct smtp_server_recipient *rcpt = llrcpts[0]->rcpt->rcpt;
switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
case LMTP_HDR_DELIVERY_ADDRESS_NONE:
break;
case LMTP_HDR_DELIVERY_ADDRESS_FINAL:
rcpt_to = rcpt->path;
break;
case LMTP_HDR_DELIVERY_ADDRESS_ORIGINAL:
rcpt_to = rcpt->params.orcpt.addr;
break;
}
}
if (rcpt_to != NULL) {
str_printfa(headers, "Delivered-To: %s\r\n",
smtp_address_encode(rcpt_to));
}
}
static int
lmtp_local_deliver(struct lmtp_local *local,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_transaction *trans,
struct lmtp_local_recipient *llrcpt,
struct mail *src_mail,
struct mail_deliver_session *session)
{
struct client *client = local->client;
struct lmtp_recipient *lrcpt = llrcpt->rcpt;
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
struct mail_storage_service_user *service_user = llrcpt->service_user;
struct lmtp_local_deliver_context lldctx;
struct mail_user *rcpt_user;
const struct mail_storage_service_input *input;
const struct mail_storage_settings *mail_set;
struct smtp_submit_settings *smtp_set;
struct smtp_proxy_data proxy_data;
struct lda_settings *lda_set;
struct mail_namespace *ns;
struct setting_parser_context *set_parser;
const struct var_expand_table *var_table;
void **sets;
const char *line, *error, *username;
int ret;
input = mail_storage_service_user_get_input(service_user);
username = t_strdup(input->username);
mail_set = mail_storage_service_user_get_mail_set(service_user);
set_parser = mail_storage_service_user_get_settings_parser(service_user);
smtp_server_connection_get_proxy_data
(client->conn, &proxy_data);
if (proxy_data.timeout_secs > 0 &&
(mail_set->mail_max_lock_timeout == 0 ||
mail_set->mail_max_lock_timeout > proxy_data.timeout_secs)) {
/* set lock timeout waits to be less than when proxy has
advertised that it's going to timeout the connection.
this avoids duplicate deliveries in case the delivery
succeeds after the proxy has already disconnected from us. */
line = t_strdup_printf("mail_max_lock_timeout=%us",
proxy_data.timeout_secs <= 1 ? 1 :
proxy_data.timeout_secs-1);
if (settings_parse_line(set_parser, line) < 0)
i_unreached();
}
i_zero(&lldctx);
lldctx.session_id = lrcpt->session_id;
lldctx.src_mail = src_mail;
lldctx.session = session;
/* get the timestamp before user is created, since it starts the I/O */
io_loop_time_refresh();
lldctx.delivery_time_started = ioloop_timeval;
client_update_data_state(client, username);
if (mail_storage_service_next(storage_service, service_user,
&rcpt_user, &error) < 0) {
e_error(rcpt->event, "Failed to initialize user: %s", error);
smtp_server_recipient_reply(rcpt, 451, "4.3.0",
"Temporary internal error");
return -1;
}
local->rcpt_user = rcpt_user;
sets = mail_storage_service_user_get_set(service_user);
var_table = mail_user_var_expand_table(rcpt_user);
smtp_set = sets[1];
lda_set = sets[2];
ret = settings_var_expand(
&smtp_submit_setting_parser_info,
smtp_set, client->pool, var_table,
&error);
if (ret > 0) {
ret = settings_var_expand(
&lda_setting_parser_info,
lda_set, client->pool, var_table,
&error);
}
if (ret <= 0) {
e_error(rcpt->event, "Failed to expand settings: %s", error);
smtp_server_recipient_reply(rcpt, 451, "4.3.0",
"Temporary internal error");
return -1;
}
/* Set the log prefix for the user. The default log prefix is
automatically restored later when user context gets deactivated. */
i_set_failure_prefix("%s",
mail_storage_service_user_get_log_prefix(service_user));
lldctx.rcpt_user = rcpt_user;
lldctx.smtp_set = smtp_set;
lldctx.lda_set = lda_set;
if (*llrcpt->detail == '\0' ||
!client->lmtp_set->lmtp_save_to_detail_mailbox)
lldctx.rcpt_default_mailbox = "INBOX";
else {
ns = mail_namespace_find_inbox(rcpt_user->namespaces);
lldctx.rcpt_default_mailbox =
t_strconcat(ns->prefix, llrcpt->detail, NULL);
}
ret = client->v.local_deliver(client, lrcpt, cmd, trans, &lldctx);
lmtp_local_rcpt_anvil_disconnect(llrcpt);
return ret;
}
static int
lmtp_local_default_do_deliver(struct lmtp_local *local,
struct lmtp_local_recipient *llrcpt,
struct lmtp_local_deliver_context *lldctx,
struct mail_deliver_context *dctx)
{
struct smtp_server_recipient *rcpt = llrcpt->rcpt->rcpt;
enum mail_deliver_error error_code;
const char *error;
if (mail_deliver(dctx, &error_code, &error) == 0) {
if (dctx->dest_mail != NULL) {
i_assert(local->first_saved_mail == NULL);
local->first_saved_mail = dctx->dest_mail;
}
smtp_server_recipient_reply(rcpt, 250, "2.0.0", "%s Saved",
lldctx->session_id);
return 0;
}
switch (error_code) {
case MAIL_DELIVER_ERROR_NONE:
i_unreached();
case MAIL_DELIVER_ERROR_TEMPORARY:
smtp_server_recipient_reply(rcpt, 451, "4.2.0", "%s", error);
break;
case MAIL_DELIVER_ERROR_REJECTED:
smtp_server_recipient_reply(rcpt, 552, "5.2.0", "%s", error);
break;
case MAIL_DELIVER_ERROR_NOQUOTA:
lmtp_local_rcpt_reply_overquota(llrcpt, error);
break;
case MAIL_DELIVER_ERROR_INTERNAL:
/* This shouldn't happen */
smtp_server_recipient_reply(rcpt, 451, "4.3.0", "%s", error);
break;
}
return -1;
}
int lmtp_local_default_deliver(struct client *client,
struct lmtp_recipient *lrcpt,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_transaction *trans,
struct lmtp_local_deliver_context *lldctx)
{
struct lmtp_local *local = client->local;
struct lmtp_local_recipient *llrcpt = lrcpt->backend_context;
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
struct smtp_address *rcpt_to = rcpt->path;
struct mail_deliver_input dinput;
struct mail_deliver_context dctx;
struct event *event;
int ret;
event = event_create(rcpt->event);
event_drop_parent_log_prefixes(event, 3);
i_zero(&dinput);
dinput.session = lldctx->session;
dinput.set = lldctx->lda_set;
dinput.smtp_set = lldctx->smtp_set;
dinput.session_id = lldctx->session_id;
dinput.event_parent = event;
dinput.src_mail = lldctx->src_mail;
/* MAIL FROM */
dinput.mail_from = trans->mail_from;
dinput.mail_params = trans->params;
/* RCPT TO */
dinput.rcpt_user = lldctx->rcpt_user;
dinput.rcpt_params = rcpt->params;
if (dinput.rcpt_params.orcpt.addr == NULL &&
*dinput.set->lda_original_recipient_header != '\0') {
dinput.rcpt_params.orcpt.addr =
mail_deliver_get_address(
lldctx->src_mail,
dinput.set->lda_original_recipient_header);
}
if (dinput.rcpt_params.orcpt.addr == NULL)
dinput.rcpt_params.orcpt.addr = rcpt_to;
dinput.rcpt_to = rcpt_to;
dinput.rcpt_default_mailbox = lldctx->rcpt_default_mailbox;
dinput.save_dest_mail = array_count(&trans->rcpt_to) > 1 &&
local->first_saved_mail == NULL;
dinput.session_time_msecs =
timeval_diff_msecs(&client->state.data_end_timeval,
&trans->timestamp);
dinput.delivery_time_started = lldctx->delivery_time_started;
mail_deliver_init(&dctx, &dinput);
ret = lmtp_local_default_do_deliver(local, llrcpt, lldctx, &dctx);
mail_deliver_deinit(&dctx);
event_unref(&event);
return ret;
}
static uid_t
lmtp_local_deliver_to_rcpts(struct lmtp_local *local,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct mail_deliver_session *session)
{
struct client *client = local->client;
uid_t first_uid = (uid_t)-1;
struct mail *src_mail;
struct lmtp_local_recipient *const *llrcpts;
unsigned int count, i;
int ret;
src_mail = local->raw_mail;
llrcpts = array_get(&local->rcpt_to, &count);
for (i = 0; i < count; i++) {
struct lmtp_local_recipient *llrcpt = llrcpts[i];
struct smtp_server_recipient *rcpt = llrcpt->rcpt->rcpt;
if (llrcpt->duplicate != NULL) {
struct smtp_server_recipient *drcpt =
llrcpt->duplicate->rcpt->rcpt;
/* don't deliver more than once to the same recipient */
smtp_server_reply_submit_duplicate(cmd, rcpt->index,
drcpt->index);
continue;
}
ret = lmtp_local_deliver(local, cmd,
trans, llrcpt, src_mail, session);
client_update_data_state(client, NULL);
/* succeeded and mail_user is not saved in first_saved_mail */
if ((ret == 0 &&
(local->first_saved_mail == NULL ||
local->first_saved_mail == src_mail)) ||
/* failed. try the next one. */
(ret != 0 && local->rcpt_user != NULL)) {
if (i == (count - 1))
mail_user_autoexpunge(local->rcpt_user);
mail_storage_service_io_deactivate_user(local->rcpt_user->_service_user);
mail_user_deinit(&local->rcpt_user);
} else if (ret == 0) {
/* use the first saved message to save it elsewhere too.
this might allow hard linking the files.
mail_user is saved in first_saved_mail,
will be unreferenced later on */
mail_storage_service_io_deactivate_user(local->rcpt_user->_service_user);
local->rcpt_user = NULL;
src_mail = local->first_saved_mail;
first_uid = geteuid();
i_assert(first_uid != 0);
} else if (local->rcpt_user != NULL) {
mail_storage_service_io_deactivate_user(local->rcpt_user->_service_user);
}
}
return first_uid;
}
static int
lmtp_local_open_raw_mail(struct lmtp_local *local,
struct smtp_server_transaction *trans,
struct istream *input)
{
static const char *wanted_headers[] = {
"From", "To", "Message-ID", "Subject", "Return-Path",
NULL
};
struct client *client = local->client;
struct mailbox *box;
struct mailbox_transaction_context *mtrans;
struct mailbox_header_lookup_ctx *headers_ctx;
enum mail_error error;
if (raw_mailbox_alloc_stream(client->raw_mail_user, input,
(time_t)-1, smtp_address_encode(trans->mail_from),
&box) < 0) {
e_error(client->event, "Can't open delivery mail as raw: %s",
mailbox_get_last_internal_error(box, &error));
mailbox_free(&box);
lmtp_local_rcpt_fail_all(local, 451, "4.3.0",
"Temporary internal error");
return -1;
}
mtrans = mailbox_transaction_begin(box, 0, __func__);
headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
local->raw_mail = mail_alloc(mtrans, 0, headers_ctx);
mailbox_header_lookup_unref(&headers_ctx);
mail_set_seq(local->raw_mail, 1);
return 0;
}
void lmtp_local_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *input)
{
struct lmtp_local *local = client->local;
struct mail_deliver_session *session;
uid_t old_uid, first_uid;
if (lmtp_local_open_raw_mail(local, trans, input) < 0)
return;
session = mail_deliver_session_init();
old_uid = geteuid();
first_uid = lmtp_local_deliver_to_rcpts(local, cmd, trans, session);
mail_deliver_session_deinit(&session);
if (local->first_saved_mail != NULL) {
struct mail *mail = local->first_saved_mail;
struct mailbox_transaction_context *trans = mail->transaction;
struct mailbox *box = trans->box;
struct mail_user *user = box->storage->user;
/* just in case these functions are going to write anything,
change uid back to user's own one */
if (first_uid != old_uid) {
if (seteuid(0) < 0)
i_fatal("seteuid(0) failed: %m");
if (seteuid(first_uid) < 0)
i_fatal("seteuid() failed: %m");
}
mail_storage_service_io_activate_user(user->_service_user);
mail_free(&mail);
mailbox_transaction_rollback(&trans);
mailbox_free(&box);
mail_user_autoexpunge(user);
mail_storage_service_io_deactivate_user(user->_service_user);
mail_user_deinit(&user);
}
if (old_uid == 0) {
/* switch back to running as root, since that's what we're
practically doing anyway. it's also important in case we
lose e.g. config connection and need to reconnect to it. */
if (seteuid(0) < 0)
i_fatal("seteuid(0) failed: %m");
/* enable core dumping again. we need to chdir also to
root-owned directory to get core dumps. */
restrict_access_allow_coredumps(TRUE);
if (chdir(base_dir) < 0) {
e_error(client->event,
"chdir(%s) failed: %m", base_dir);
}
}
}
dovecot-2.3.21.1/src/lmtp/Makefile.in 0000644 0000000 0000000 00000072671 14656633611 014130 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = lmtp$(EXEEXT)
subdir = src/lmtp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(pkginc_lib_HEADERS) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)" \
"$(DESTDIR)$(pkginc_libdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_lmtp_OBJECTS = main.$(OBJEXT) lmtp-client.$(OBJEXT) \
lmtp-commands.$(OBJEXT) lmtp-recipient.$(OBJEXT) \
lmtp-local.$(OBJEXT) lmtp-proxy.$(OBJEXT) \
lmtp-settings.$(OBJEXT)
lmtp_OBJECTS = $(am_lmtp_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
lmtp_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(lmtp_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/lmtp-client.Po \
./$(DEPDIR)/lmtp-commands.Po ./$(DEPDIR)/lmtp-local.Po \
./$(DEPDIR)/lmtp-proxy.Po ./$(DEPDIR)/lmtp-recipient.Po \
./$(DEPDIR)/lmtp-settings.Po ./$(DEPDIR)/main.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(lmtp_SOURCES)
DIST_SOURCES = $(lmtp_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-smtp \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-lda \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index \
-I$(top_srcdir)/src/lib-storage/index/raw \
-DMODULEDIR=\""$(moduledir)"\" \
$(BINARY_CFLAGS)
lmtp_LDFLAGS = -export-dynamic \
$(BINARY_LDFLAGS)
lmtp_LDADD = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT)
lmtp_DEPENDENCIES = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
lmtp_SOURCES = \
main.c \
lmtp-client.c \
lmtp-commands.c \
lmtp-recipient.c \
lmtp-local.c \
lmtp-proxy.c \
lmtp-settings.c
noinst_HEADERS = \
lmtp-local.h \
lmtp-proxy.h
headers = \
lmtp-common.h \
lmtp-commands.h \
lmtp-recipient.h \
lmtp-client.h \
lmtp-settings.h
pkginc_libdir = $(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lmtp/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/lmtp/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
lmtp$(EXEEXT): $(lmtp_OBJECTS) $(lmtp_DEPENDENCIES) $(EXTRA_lmtp_DEPENDENCIES)
@rm -f lmtp$(EXEEXT)
$(AM_V_CCLD)$(lmtp_LINK) $(lmtp_OBJECTS) $(lmtp_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmtp-client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmtp-commands.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmtp-local.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmtp-proxy.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmtp-recipient.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmtp-settings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
done
uninstall-pkginc_libHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(pkginc_libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/lmtp-client.Po
-rm -f ./$(DEPDIR)/lmtp-commands.Po
-rm -f ./$(DEPDIR)/lmtp-local.Po
-rm -f ./$(DEPDIR)/lmtp-proxy.Po
-rm -f ./$(DEPDIR)/lmtp-recipient.Po
-rm -f ./$(DEPDIR)/lmtp-settings.Po
-rm -f ./$(DEPDIR)/main.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkginc_libHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/lmtp-client.Po
-rm -f ./$(DEPDIR)/lmtp-commands.Po
-rm -f ./$(DEPDIR)/lmtp-local.Po
-rm -f ./$(DEPDIR)/lmtp-proxy.Po
-rm -f ./$(DEPDIR)/lmtp-recipient.Po
-rm -f ./$(DEPDIR)/lmtp-settings.Po
-rm -f ./$(DEPDIR)/main.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-pkginc_libHEADERS \
install-pkglibexecPROGRAMS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/lmtp/lmtp-local.h 0000644 0000000 0000000 00000001655 14656633576 014304 0000000 0000000 #ifndef LMTP_LOCAL_H
#define LMTP_LOCAL_H
#include "net.h"
struct mail_deliver_session;
struct smtp_server_cmd_ctx;
struct smtp_server_cmd_rcpt;
struct lmtp_local;
struct client;
void lmtp_local_deinit(struct lmtp_local **_local);
int lmtp_local_rcpt(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct lmtp_recipient *lrcpt, const char *username,
const char *detail);
void lmtp_local_add_headers(struct lmtp_local *local,
struct smtp_server_transaction *trans,
string_t *headers);
int lmtp_local_default_deliver(struct client *client,
struct lmtp_recipient *lrcpt,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct lmtp_local_deliver_context *lldctx);
void lmtp_local_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *input);
#endif
dovecot-2.3.21.1/src/lmtp/lmtp-commands.c 0000644 0000000 0000000 00000022371 14656633576 015004 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lmtp-common.h"
#include "str.h"
#include "istream.h"
#include "istream-concat.h"
#include "ostream.h"
#include "iostream-temp.h"
#include "master-service.h"
#include "settings-parser.h"
#include "lda-settings.h"
#include "mail-user.h"
#include "smtp-address.h"
#include "mail-deliver.h"
#include "mail-error.h"
#include "lmtp-recipient.h"
#include "lmtp-proxy.h"
#include "lmtp-local.h"
#include "lmtp-commands.h"
/*
* MAIL command
*/
int cmd_mail(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data)
{
struct client *client = (struct client *)conn_ctx;
return client->v.cmd_mail(client, cmd, data);
}
int client_default_cmd_mail(struct client *client,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_cmd_mail *data ATTR_UNUSED)
{
if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
/* Connect to anvil before dropping privileges */
lmtp_anvil_init();
}
return 1;
}
/*
* RCPT command
*/
static int
cmd_rcpt_handle_forward_fields(struct smtp_server_cmd_ctx *cmd,
struct lmtp_recipient *lrcpt)
{
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
string_t *xforward;
const char *error;
int ret;
ret = smtp_params_rcpt_decode_extra(&rcpt->params,
LMTP_RCPT_FORWARD_PARAMETER,
&xforward, FALSE, &error);
if (ret < 0) {
smtp_server_reply(cmd, 501, "5.5.4",
"Invalid "LMTP_RCPT_FORWARD_PARAMETER"= "
"parameter: %s", error);
return -1;
}
if (ret == 0)
return 0;
/* Drop the parameter */
(void)smtp_params_rcpt_drop_extra(&rcpt->params,
LMTP_RCPT_FORWARD_PARAMETER, NULL);
/* Check the real IP rather than the proxied client IP, since XCLIENT
command will update that, thereby making it untrusted. Unlike the
XCLIENT command, the RCPT forward parameter needs to be used after
the XCLIENT is first issued. */
if (!smtp_server_connection_is_trusted(rcpt->conn)) {
smtp_server_reply(cmd, 550, "5.7.14",
"Unacceptable "LMTP_RCPT_FORWARD_PARAMETER"= "
"parameter: You are not from trusted IP");
return -1;
}
lrcpt->forward_fields = p_strdup(rcpt->pool, str_c(xforward));
return 0;
}
int cmd_rcpt(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_recipient *rcpt)
{
struct client *client = (struct client *)conn_ctx;
struct smtp_server_transaction *trans;
struct lmtp_recipient *lrcpt;
trans = smtp_server_connection_get_transaction(rcpt->conn);
i_assert(trans != NULL); /* MAIL command is synchronous */
lrcpt = lmtp_recipient_create(client, trans, rcpt);
if (cmd_rcpt_handle_forward_fields(cmd, lrcpt) < 0)
return -1;
return client->v.cmd_rcpt(client, cmd, lrcpt);
}
int client_default_cmd_rcpt(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct lmtp_recipient *lrcpt)
{
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
const char *username, *detail;
char delim = '\0';
int ret;
i_assert(!smtp_address_isnull(rcpt->path));
if (*rcpt->path->localpart == '\0' && rcpt->path->domain == NULL) {
smtp_server_recipient_reply(
rcpt, 550, "5.1.1",
"Unacceptable TO: Empty path not allowed");
return -1;
}
smtp_address_detail_parse_temp(
client->unexpanded_lda_set->recipient_delimiter,
rcpt->path, &username, &delim, &detail);
i_assert(*username != '\0');
/* Make user name and detail available in the recipient event. The
mail_user event (for local delivery) also adds the user field, but
adding it here makes it available to the recipient event in general.
Additionally, the auth lookups performed for local and proxy delivery
can further override the "user" recipient event when the auth service
returns a different user name. In any case, we provide the initial
value here.
*/
event_add_str(rcpt->event, "user", username);
if (detail[0] != '\0')
event_add_str(rcpt->event, "detail", detail);
if (client->lmtp_set->lmtp_proxy) {
/* proxied? */
if ((ret=lmtp_proxy_rcpt(client, cmd, lrcpt,
username, detail, delim)) != 0)
return (ret < 0 ? -1 : 0);
/* no */
}
/* local delivery */
return lmtp_local_rcpt(client, cmd, lrcpt, username, detail);
}
/*
* DATA command
*/
static void
cmd_data_create_added_headers(struct client *client,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_transaction *trans)
{
size_t proxy_offset = 0;
string_t *str;
str = t_str_new(512);
/* Headers for local deliveries only */
if (client->local != NULL)
lmtp_local_add_headers(client->local, trans, str);
/* Headers for local and proxied messages */
proxy_offset = str_len(str);
if (client->lmtp_set->lmtp_add_received_header) {
const struct lmtp_settings *lmtp_set = client->lmtp_set;
enum smtp_server_trace_rcpt_to_address rcpt_to_address =
SMTP_SERVER_TRACE_RCPT_TO_ADDRESS_FINAL;
switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
case LMTP_HDR_DELIVERY_ADDRESS_NONE:
rcpt_to_address =
SMTP_SERVER_TRACE_RCPT_TO_ADDRESS_NONE;
break;
case LMTP_HDR_DELIVERY_ADDRESS_FINAL:
rcpt_to_address =
SMTP_SERVER_TRACE_RCPT_TO_ADDRESS_FINAL;
break;
case LMTP_HDR_DELIVERY_ADDRESS_ORIGINAL:
rcpt_to_address =
SMTP_SERVER_TRACE_RCPT_TO_ADDRESS_ORIGINAL;
break;
}
smtp_server_transaction_write_trace_record(
str, trans, rcpt_to_address);
}
client->state.added_headers_local =
p_strdup(client->state_pool, str_c(str));
client->state.added_headers_proxy =
client->state.added_headers_local + proxy_offset;
}
static int
cmd_data_finish(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans)
{
struct client_state *state = &client->state;
struct istream *input_msg;
int ret;
i_assert(HAS_ALL_BITS(trans->flags,
SMTP_SERVER_TRANSACTION_FLAG_REPLY_PER_RCPT));
client->state.data_end_timeval = ioloop_timeval;
/* finish the message */
input_msg = iostream_temp_finish(&state->mail_data_output,
IO_BLOCK_SIZE);
ret = client->v.cmd_data(client, cmd, trans,
input_msg, client->state.data_size);
i_stream_unref(&input_msg);
return ret;
}
int cmd_data_continue(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans)
{
struct client *client = (struct client *)conn_ctx;
struct client_state *state = &client->state;
struct istream *data_input = state->data_input;
const unsigned char *data;
size_t size;
ssize_t ret;
i_assert(state->mail_data_output != NULL);
while ((ret = i_stream_read(data_input)) > 0 || ret == -2) {
data = i_stream_get_data(data_input, &size);
if (o_stream_send(state->mail_data_output,
data, size) != (ssize_t)size) {
e_error(client->event, "write(%s) failed: %s",
o_stream_get_name(state->mail_data_output),
o_stream_get_error(state->mail_data_output));
smtp_server_reply(cmd, 451, "4.3.0",
"Temporary internal failure");
return -1;
}
i_stream_skip(data_input, size);
if (!smtp_server_cmd_data_check_size(cmd))
return -1;
}
if (ret == 0)
return 0;
if (ret < 0 && data_input->stream_errno != 0) {
/* Client probably disconnected */
return -1;
}
/* Current data stream position is the data size */
client->state.data_size = data_input->v_offset;
/* The ending "." line was seen. finish delivery. */
return cmd_data_finish(client, cmd, trans);
}
int cmd_data_begin(void *conn_ctx,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_transaction *trans ATTR_UNUSED,
struct istream *data_input)
{
struct client *client = (struct client *)conn_ctx;
string_t *path;
i_assert(client->state.mail_data_output == NULL);
path = t_str_new(256);
mail_user_set_get_temp_prefix(path, client->raw_mail_user->set);
client->state.mail_data_output =
iostream_temp_create_named(str_c(path), 0, "(lmtp data)");
client->state.data_input = data_input;
return 0;
}
int client_default_cmd_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input,
uoff_t data_size ATTR_UNUSED)
{
struct client_state *state = &client->state;
struct istream *input_local, *input_proxy;
struct istream *inputs[3];
/* Formulate prepended headers for both local and proxy delivery */
cmd_data_create_added_headers(client, cmd, trans);
/* Construct message streams for local and proxy delivery */
input_local = input_proxy = NULL;
if (client->local != NULL) {
inputs[0] = i_stream_create_from_data(
state->added_headers_local,
strlen(state->added_headers_local));
inputs[1] = data_input;
inputs[2] = NULL;
input_local = i_stream_create_concat(inputs);
i_stream_set_name(input_local, "");
i_stream_unref(&inputs[0]);
}
if (client->proxy != NULL) {
inputs[0] = i_stream_create_from_data(
state->added_headers_proxy,
strlen(state->added_headers_proxy));
inputs[1] = data_input;
inputs[2] = NULL;
input_proxy = i_stream_create_concat(inputs);
i_stream_set_name(input_proxy, "");
i_stream_unref(&inputs[0]);
}
/* local delivery */
if (client->local != NULL) {
lmtp_local_data(client, cmd, trans, input_local);
i_stream_unref(&input_local);
}
/* proxy delivery */
if (client->proxy != NULL) {
lmtp_proxy_data(client, cmd, trans, input_proxy);
i_stream_unref(&input_proxy);
}
return 0;
}
dovecot-2.3.21.1/src/lmtp/lmtp-proxy.c 0000644 0000000 0000000 00000060535 14656633576 014370 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lmtp-common.h"
#include "istream.h"
#include "istream-sized.h"
#include "ostream.h"
#include "iostream-ssl.h"
#include "str.h"
#include "strescape.h"
#include "time-util.h"
#include "smtp-common.h"
#include "smtp-params.h"
#include "smtp-address.h"
#include "smtp-client.h"
#include "smtp-client-connection.h"
#include "smtp-client-transaction.h"
#include "auth-master.h"
#include "master-service-ssl-settings.h"
#include "mail-storage-service.h"
#include "lda-settings.h"
#include "lmtp-recipient.h"
#include "lmtp-proxy.h"
#define LMTP_MAX_REPLY_SIZE 4096
#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*125)
enum lmtp_proxy_ssl_flags {
/* Use SSL/TLS enabled */
PROXY_SSL_FLAG_YES = 0x01,
/* Don't do SSL handshake immediately after connected */
PROXY_SSL_FLAG_STARTTLS = 0x02,
/* Don't require that the received certificate is valid */
PROXY_SSL_FLAG_ANY_CERT = 0x04
};
struct lmtp_proxy_rcpt_settings {
enum smtp_protocol protocol;
const char *host;
struct ip_addr hostip, source_ip;
in_port_t port;
enum lmtp_proxy_ssl_flags ssl_flags;
unsigned int timeout_msecs;
struct smtp_params_rcpt params;
bool proxy_not_trusted:1;
};
struct lmtp_proxy_recipient {
struct lmtp_recipient *rcpt;
struct lmtp_proxy_connection *conn;
struct smtp_address *address;
const unsigned char *forward_fields;
size_t forward_fields_size;
bool rcpt_to_failed:1;
bool data_reply_received:1;
};
struct lmtp_proxy_connection {
struct lmtp_proxy *proxy;
struct lmtp_proxy_rcpt_settings set;
char *host;
struct smtp_client_connection *lmtp_conn;
struct smtp_client_transaction *lmtp_trans;
struct istream *data_input;
struct timeout *to;
bool finished:1;
bool failed:1;
};
struct lmtp_proxy {
struct client *client;
struct smtp_server_transaction *trans;
struct smtp_client *lmtp_client;
ARRAY(struct lmtp_proxy_connection *) connections;
ARRAY(struct lmtp_proxy_recipient *) rcpt_to;
unsigned int next_data_reply_idx;
struct timeout *to_finish;
struct istream *data_input;
unsigned int max_timeout_msecs;
unsigned int proxy_session_seq;
bool finished:1;
};
static void
lmtp_proxy_data_cb(const struct smtp_reply *reply,
struct lmtp_proxy_recipient *lprcpt);
/*
* LMTP proxy
*/
static struct lmtp_proxy *
lmtp_proxy_init(struct client *client,
struct smtp_server_transaction *trans)
{
const char *extra_capabilities[] = {
LMTP_RCPT_FORWARD_CAPABILITY,
NULL };
struct smtp_client_settings lmtp_set;
struct lmtp_proxy *proxy;
proxy = i_new(struct lmtp_proxy, 1);
proxy->client = client;
proxy->trans = trans;
i_array_init(&proxy->rcpt_to, 32);
i_array_init(&proxy->connections, 32);
i_zero(&lmtp_set);
lmtp_set.my_hostname = client->my_domain;
lmtp_set.extra_capabilities = extra_capabilities;
lmtp_set.dns_client_socket_path = dns_client_socket_path;
lmtp_set.max_reply_size = LMTP_MAX_REPLY_SIZE;
lmtp_set.rawlog_dir = client->lmtp_set->lmtp_proxy_rawlog_dir;
smtp_server_connection_get_proxy_data(client->conn,
&lmtp_set.proxy_data);
lmtp_set.proxy_data.source_ip = client->remote_ip;
lmtp_set.proxy_data.source_port = client->remote_port;
/* This initial session_id is used only locally by lib-smtp. Each LMTP
proxy connection gets a more specific updated session_id. */
lmtp_set.proxy_data.session = trans->id;
if (lmtp_set.proxy_data.ttl_plus_1 == 0)
lmtp_set.proxy_data.ttl_plus_1 = LMTP_PROXY_DEFAULT_TTL + 1;
else
lmtp_set.proxy_data.ttl_plus_1--;
lmtp_set.event_parent = client->event;
proxy->lmtp_client = smtp_client_init(&lmtp_set);
return proxy;
}
static void lmtp_proxy_connection_deinit(struct lmtp_proxy_connection *conn)
{
if (conn->lmtp_trans != NULL)
smtp_client_transaction_destroy(&conn->lmtp_trans);
if (conn->lmtp_conn != NULL)
smtp_client_connection_close(&conn->lmtp_conn);
timeout_remove(&conn->to);
i_stream_unref(&conn->data_input);
i_free(conn->host);
i_free(conn);
}
void lmtp_proxy_deinit(struct lmtp_proxy **_proxy)
{
struct lmtp_proxy *proxy = *_proxy;
struct lmtp_proxy_connection *conn;
*_proxy = NULL;
array_foreach_elem(&proxy->connections, conn)
lmtp_proxy_connection_deinit(conn);
smtp_client_deinit(&proxy->lmtp_client);
i_stream_unref(&proxy->data_input);
timeout_remove(&proxy->to_finish);
array_free(&proxy->rcpt_to);
array_free(&proxy->connections);
i_free(proxy);
}
static void
lmtp_proxy_mail_cb(const struct smtp_reply *proxy_reply ATTR_UNUSED,
struct lmtp_proxy_connection *conn ATTR_UNUSED)
{
/* nothing */
}
static void lmtp_proxy_connection_finish(struct lmtp_proxy_connection *conn)
{
conn->finished = TRUE;
conn->lmtp_trans = NULL;
}
static void
lmtp_proxy_connection_init_ssl(struct lmtp_proxy_connection *conn,
struct ssl_iostream_settings *ssl_set_r,
enum smtp_client_connection_ssl_mode *ssl_mode_r)
{
const struct master_service_ssl_settings *master_ssl_set;
*ssl_mode_r = SMTP_CLIENT_SSL_MODE_NONE;
if ((conn->set.ssl_flags & PROXY_SSL_FLAG_YES) == 0) {
i_zero(ssl_set_r);
return;
}
master_ssl_set = master_service_ssl_settings_get(master_service);
master_service_ssl_client_settings_to_iostream_set(
master_ssl_set, pool_datastack_create(), ssl_set_r);
if ((conn->set.ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0)
ssl_set_r->allow_invalid_cert = TRUE;
if ((conn->set.ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0)
*ssl_mode_r = SMTP_CLIENT_SSL_MODE_IMMEDIATE;
else
*ssl_mode_r = SMTP_CLIENT_SSL_MODE_STARTTLS;
}
static bool
lmtp_proxy_connection_has_rcpt_forward(struct lmtp_proxy_connection *conn)
{
const struct smtp_capability_extra *cap_extra =
smtp_client_connection_get_extra_capability(
conn->lmtp_conn, LMTP_RCPT_FORWARD_CAPABILITY);
return (cap_extra != NULL);
}
static struct lmtp_proxy_connection *
lmtp_proxy_get_connection(struct lmtp_proxy *proxy,
const struct lmtp_proxy_rcpt_settings *set)
{
static const char *rcpt_param_extensions[] =
{ LMTP_RCPT_FORWARD_PARAMETER, NULL };
static const struct smtp_client_capability_extra cap_rcpt_forward = {
.name = LMTP_RCPT_FORWARD_CAPABILITY,
.rcpt_param_extensions = rcpt_param_extensions,
};
struct smtp_client_settings lmtp_set;
struct smtp_server_transaction *trans = proxy->trans;
struct client *client = proxy->client;
struct lmtp_proxy_connection *conn;
enum smtp_client_connection_ssl_mode ssl_mode;
struct ssl_iostream_settings ssl_set;
i_assert(set->timeout_msecs > 0);
array_foreach_elem(&proxy->connections, conn) {
if (conn->set.protocol == set->protocol &&
conn->set.port == set->port &&
strcmp(conn->set.host, set->host) == 0 &&
net_ip_compare(&conn->set.hostip, &set->hostip) &&
net_ip_compare(&conn->set.source_ip, &set->source_ip) &&
conn->set.ssl_flags == set->ssl_flags)
return conn;
}
conn = i_new(struct lmtp_proxy_connection, 1);
conn->proxy = proxy;
conn->set.protocol = set->protocol;
conn->set.hostip = set->hostip;
conn->host = i_strdup(set->host);
conn->set.host = conn->host;
conn->set.source_ip = set->source_ip;
conn->set.port = set->port;
conn->set.ssl_flags = set->ssl_flags;
conn->set.timeout_msecs = set->timeout_msecs;
array_push_back(&proxy->connections, &conn);
lmtp_proxy_connection_init_ssl(conn, &ssl_set, &ssl_mode);
i_zero(&lmtp_set);
lmtp_set.my_ip = conn->set.source_ip;
lmtp_set.ssl = &ssl_set;
lmtp_set.peer_trusted = !conn->set.proxy_not_trusted;
lmtp_set.forced_capabilities = SMTP_CAPABILITY__ORCPT;
lmtp_set.mail_send_broken_path = TRUE;
lmtp_set.verbose_user_errors = client->lmtp_set->lmtp_verbose_replies;
if (conn->set.hostip.family != 0) {
conn->lmtp_conn = smtp_client_connection_create_ip(
proxy->lmtp_client, set->protocol,
&conn->set.hostip, conn->set.port,
conn->set.host, ssl_mode, &lmtp_set);
} else {
conn->lmtp_conn = smtp_client_connection_create(
proxy->lmtp_client, set->protocol,
conn->set.host, conn->set.port,
ssl_mode, &lmtp_set);
}
struct smtp_proxy_data proxy_data = {
.session = t_strdup_printf("%s:P%u", proxy->trans->id,
++proxy->proxy_session_seq),
};
smtp_client_connection_update_proxy_data(conn->lmtp_conn, &proxy_data);
smtp_client_connection_accept_extra_capability(conn->lmtp_conn,
&cap_rcpt_forward);
smtp_client_connection_connect(conn->lmtp_conn, NULL, NULL);
conn->lmtp_trans = smtp_client_transaction_create(
conn->lmtp_conn, trans->mail_from, &trans->params, 0,
lmtp_proxy_connection_finish, conn);
smtp_client_transaction_start(conn->lmtp_trans,
lmtp_proxy_mail_cb, conn);
if (proxy->max_timeout_msecs < set->timeout_msecs)
proxy->max_timeout_msecs = set->timeout_msecs;
return conn;
}
static void
lmtp_proxy_handle_connection_error(struct lmtp_proxy_recipient *lprcpt,
const struct smtp_reply *reply)
{
struct lmtp_recipient *lrcpt = lprcpt->rcpt;
struct client *client = lrcpt->client;
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
const char *detail = "";
if (client->lmtp_set->lmtp_verbose_replies) {
smtp_server_command_fail(rcpt->cmd->cmd, 451, "4.4.0",
"Proxy failed: %s (session=%s)",
smtp_reply_log(reply),
lrcpt->session_id);
return;
}
switch (reply->status) {
case SMTP_CLIENT_COMMAND_ERROR_ABORTED:
break;
case SMTP_CLIENT_COMMAND_ERROR_HOST_LOOKUP_FAILED:
detail = "DNS lookup, ";
break;
case SMTP_CLIENT_COMMAND_ERROR_CONNECT_FAILED:
case SMTP_CLIENT_COMMAND_ERROR_AUTH_FAILED:
detail = "connect, ";
break;
case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_LOST:
case SMTP_CLIENT_COMMAND_ERROR_CONNECTION_CLOSED:
detail = "connection lost, ";
break;
case SMTP_CLIENT_COMMAND_ERROR_BAD_REPLY:
detail = "bad reply, ";
break;
case SMTP_CLIENT_COMMAND_ERROR_TIMED_OUT:
detail = "timed out, ";
break;
default:
break;
}
smtp_server_command_fail(rcpt->cmd->cmd, 451, "4.4.0",
"Proxy failed (%ssession=%s)",
detail, lrcpt->session_id);
}
static bool
lmtp_proxy_handle_reply(struct lmtp_proxy_recipient *lprcpt,
const struct smtp_reply *reply,
struct smtp_reply *reply_r)
{
*reply_r = *reply;
if (!smtp_reply_is_remote(reply) ||
reply->status == SMTP_CLIENT_COMMAND_ERROR_CONNECTION_CLOSED) {
lmtp_proxy_handle_connection_error(lprcpt, reply);
return FALSE;
}
if (!smtp_reply_has_enhanced_code(reply)) {
reply_r->enhanced_code =
SMTP_REPLY_ENH_CODE(reply->status / 100, 0, 0);
}
return TRUE;
}
/*
* RCPT command
*/
static bool
lmtp_proxy_rcpt_parse_fields(struct lmtp_recipient *lrcpt,
struct lmtp_proxy_rcpt_settings *set,
const char *const *args, const char **address)
{
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
const char *p, *key, *value;
bool proxying = FALSE, port_set = FALSE;
for (; *args != NULL; args++) {
p = strchr(*args, '=');
if (p == NULL) {
key = *args;
value = "";
} else {
key = t_strdup_until(*args, p);
value = p + 1;
}
if (strcmp(key, "proxy") == 0)
proxying = TRUE;
else if (strcmp(key, "host") == 0)
set->host = value;
else if (strcmp(key, "hostip") == 0) {
if (net_addr2ip(value, &set->hostip) < 0) {
e_error(rcpt->event,
"proxy: Invalid hostip %s", value);
return FALSE;
}
} else if (strcmp(key, "source_ip") == 0) {
if (net_addr2ip(value, &set->source_ip) < 0) {
e_error(rcpt->event,
"proxy: Invalid source_ip %s", value);
return FALSE;
}
} else if (strcmp(key, "port") == 0) {
if (net_str2port(value, &set->port) < 0) {
e_error(rcpt->event,
"proxy: Invalid port number %s", value);
return FALSE;
}
port_set = TRUE;
} else if (strcmp(key, "proxy_timeout") == 0) {
if (str_to_uint(value, &set->timeout_msecs) < 0) {
e_error(rcpt->event,"proxy: "
"Invalid proxy_timeout value %s", value);
return FALSE;
}
set->timeout_msecs *= 1000;
} else if (strcmp(key, "proxy_not_trusted") == 0) {
set->proxy_not_trusted = TRUE;
} else if (strcmp(key, "protocol") == 0) {
if (strcmp(value, "lmtp") == 0) {
set->protocol = SMTP_PROTOCOL_LMTP;
if (!port_set)
set->port = 24;
} else if (strcmp(value, "smtp") == 0) {
set->protocol = SMTP_PROTOCOL_SMTP;
if (!port_set)
set->port = 25;
} else {
e_error(rcpt->event,
"proxy: Unknown protocol %s", value);
return FALSE;
}
} else if (strcmp(key, "ssl") == 0) {
set->ssl_flags |= PROXY_SSL_FLAG_YES;
if (strcmp(value, "any-cert") == 0)
set->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
} else if (strcmp(key, "starttls") == 0) {
set->ssl_flags |= PROXY_SSL_FLAG_YES |
PROXY_SSL_FLAG_STARTTLS;
if (strcmp(value, "any-cert") == 0)
set->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
} else if (strcmp(key, "user") == 0 ||
strcmp(key, "destuser") == 0) {
/* Changing the username */
*address = value;
} else {
/* Just ignore it */
}
}
if (proxying && set->host == NULL) {
e_error(rcpt->event, "proxy: host not given");
return FALSE;
}
return proxying;
}
static bool
lmtp_proxy_is_ourself(const struct client *client,
const struct lmtp_proxy_rcpt_settings *set)
{
struct ip_addr ip;
if (set->port != client->local_port)
return FALSE;
if (set->hostip.family != 0)
ip = set->hostip;
else {
if (net_addr2ip(set->host, &ip) < 0)
return FALSE;
}
if (!net_ip_compare(&ip, &client->local_ip))
return FALSE;
return TRUE;
}
static void
lmtp_proxy_rcpt_approved(struct smtp_server_recipient *rcpt ATTR_UNUSED,
struct lmtp_proxy_recipient *lprcpt)
{
struct client *client = lprcpt->rcpt->client;
/* Add to proxy recipients */
array_push_back(&client->proxy->rcpt_to, &lprcpt);
}
static void
lmtp_proxy_rcpt_cb(const struct smtp_reply *proxy_reply,
struct lmtp_proxy_recipient *lprcpt)
{
struct smtp_server_recipient *rcpt = lprcpt->rcpt->rcpt;
struct smtp_reply reply;
if (!lmtp_proxy_handle_reply(lprcpt, proxy_reply, &reply))
return;
if (smtp_reply_is_success(proxy_reply)) {
/* If backend accepts it, we accept it too */
/* The default 2.0.0 code won't do */
if (!smtp_reply_has_enhanced_code(proxy_reply))
reply.enhanced_code = SMTP_REPLY_ENH_CODE(2, 1, 0);
}
/* Forward reply */
smtp_server_recipient_reply_forward(rcpt, &reply);
}
static void
lmtp_proxy_rcpt_login_cb(const struct smtp_reply *proxy_reply, void *context)
{
struct lmtp_proxy_recipient *lprcpt = context;
struct lmtp_recipient *lrcpt = lprcpt->rcpt;
struct lmtp_proxy_connection *conn = lprcpt->conn;
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
struct smtp_reply reply;
struct smtp_client_transaction_rcpt *relay_rcpt;
struct smtp_params_rcpt *rcpt_params = &rcpt->params;
bool add_orcpt_param = FALSE, add_xrcptforward_param = FALSE;
pool_t param_pool;
if (!lmtp_proxy_handle_reply(lprcpt, proxy_reply, &reply))
return;
if (!smtp_reply_is_success(proxy_reply)) {
smtp_server_recipient_reply_forward(rcpt, &reply);
return;
}
/* Add an ORCPT parameter when passdb changed the username (and
therefore the RCPT address changed) and there is no ORCPT parameter
yet. */
if (!smtp_params_rcpt_has_orcpt(rcpt_params) &&
!smtp_address_equals(lprcpt->address, rcpt->path))
add_orcpt_param = TRUE;
/* Add forward fields parameter when passdb returned forward_* fields */
if (lprcpt->forward_fields != NULL &&
lmtp_proxy_connection_has_rcpt_forward(conn))
add_xrcptforward_param = TRUE;
/* Copy params when changes are pending */
param_pool = NULL;
if (add_orcpt_param || add_xrcptforward_param) {
param_pool = pool_datastack_create();
rcpt_params = p_new(param_pool, struct smtp_params_rcpt, 1);
smtp_params_rcpt_copy(param_pool, rcpt_params, &rcpt->params);
}
/* Add ORCPT */
if (add_orcpt_param) {
smtp_params_rcpt_set_orcpt(rcpt_params, param_pool,
rcpt->path);
}
/* Add forward fields parameter */
if (add_xrcptforward_param) {
smtp_params_rcpt_encode_extra(
rcpt_params, param_pool, LMTP_RCPT_FORWARD_PARAMETER,
lprcpt->forward_fields, lprcpt->forward_fields_size);
}
smtp_server_recipient_add_hook(
rcpt, SMTP_SERVER_RECIPIENT_HOOK_APPROVED,
lmtp_proxy_rcpt_approved, lprcpt);
relay_rcpt = smtp_client_transaction_add_pool_rcpt(
conn->lmtp_trans, rcpt->pool, lprcpt->address, rcpt_params,
lmtp_proxy_rcpt_cb, lprcpt);
smtp_client_transaction_rcpt_set_data_callback(
relay_rcpt, lmtp_proxy_data_cb, lprcpt);
}
int lmtp_proxy_rcpt(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct lmtp_recipient *lrcpt,
const char *username, const char *detail,
char delim)
{
struct auth_master_connection *auth_conn;
struct lmtp_proxy_rcpt_settings set;
struct lmtp_proxy_connection *conn;
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
struct lmtp_proxy_recipient *lprcpt;
struct smtp_server_transaction *trans;
struct smtp_address *address = rcpt->path;
struct auth_user_info info;
struct mail_storage_service_input input;
const char *const *fields, *errstr, *orig_username = username;
struct smtp_proxy_data proxy_data;
struct smtp_address *user;
string_t *fwfields;
pool_t auth_pool;
int ret;
trans = smtp_server_connection_get_transaction(cmd->conn);
i_assert(trans != NULL); /* MAIL command is synchronous */
i_zero(&input);
input.module = input.service = "lmtp";
mail_storage_service_init_settings(storage_service, &input);
i_zero(&info);
info.service = master_service_get_name(master_service);
info.local_ip = client->local_ip;
info.real_local_ip = client->real_local_ip;
info.remote_ip = client->remote_ip;
info.real_remote_ip = client->real_remote_ip;
info.local_port = client->local_port;
info.real_local_port = client->real_local_port;
info.remote_port = client->remote_port;
info.real_remote_port = client->real_remote_port;
info.forward_fields = lrcpt->forward_fields;
// FIXME: make this async
auth_pool = pool_alloconly_create("auth lookup", 1024);
auth_conn = mail_storage_service_get_auth_conn(storage_service);
ret = auth_master_pass_lookup(auth_conn, username, &info,
auth_pool, &fields);
if (ret <= 0) {
errstr = (ret < 0 && fields[0] != NULL ?
t_strdup(fields[0]) :
"Temporary user lookup failure");
pool_unref(&auth_pool);
if (ret < 0) {
smtp_server_recipient_reply(rcpt, 451, "4.3.0", "%s",
errstr);
return -1;
} else {
/* User not found from passdb: revert to local delivery.
*/
return 0;
}
}
i_zero(&set);
set.port = client->local_port;
set.protocol = SMTP_PROTOCOL_LMTP;
set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
if (!lmtp_proxy_rcpt_parse_fields(lrcpt, &set, fields, &username)) {
/* Not proxying this user */
pool_unref(&auth_pool);
return 0;
}
if (strcmp(username, orig_username) != 0) {
/* The existing "user" event field is overridden with the new
user name, while old username is available as "orig_user" */
event_add_str(rcpt->event, "user", username);
event_add_str(rcpt->event, "original_user", orig_username);
if (smtp_address_parse_username(pool_datastack_create(),
username, &user, &errstr) < 0) {
e_error(rcpt->event, "%s: "
"Username `%s' returned by passdb lookup is not a valid SMTP address",
orig_username, username);
smtp_server_recipient_reply(
rcpt, 550, "5.3.5",
"Internal user lookup failure");
pool_unref(&auth_pool);
return -1;
}
/* Username changed. change the address as well */
if (*detail == '\0') {
address = user;
} else {
address = smtp_address_add_detail_temp(
user, detail, delim);
}
} else if (lmtp_proxy_is_ourself(client, &set)) {
e_error(rcpt->event, "Proxying to <%s> loops to itself",
username);
smtp_server_recipient_reply(rcpt, 554, "5.4.6",
"Proxying loops to itself");
pool_unref(&auth_pool);
return -1;
}
smtp_server_connection_get_proxy_data(cmd->conn, &proxy_data);
if (proxy_data.ttl_plus_1 == 1) {
e_error(rcpt->event,
"Proxying to <%s> appears to be looping (TTL=0)",
username);
smtp_server_recipient_reply(rcpt, 554, "5.4.6",
"Proxying appears to be looping "
"(TTL=0)");
pool_unref(&auth_pool);
return -1;
}
if (client->proxy == NULL)
client->proxy = lmtp_proxy_init(client, trans);
conn = lmtp_proxy_get_connection(client->proxy, &set);
lprcpt = p_new(rcpt->pool, struct lmtp_proxy_recipient, 1);
lprcpt->rcpt = lrcpt;
lprcpt->address = smtp_address_clone(rcpt->pool, address);
lprcpt->conn = conn;
lrcpt->type = LMTP_RECIPIENT_TYPE_PROXY;
lrcpt->backend_context = lprcpt;
/* Copy forward fields returned from passdb */
fwfields = NULL;
for (const char *const *ptr = fields; *ptr != NULL; ptr++) {
if (strncasecmp(*ptr, "forward_", 8) != 0)
continue;
if (fwfields == NULL)
fwfields = t_str_new(128);
else
str_append_c(fwfields, '\t');
str_append_tabescaped(fwfields, (*ptr) + 8);
}
if (fwfields != NULL) {
lprcpt->forward_fields = p_memdup(
rcpt->pool, str_data(fwfields), str_len(fwfields));
lprcpt->forward_fields_size = str_len(fwfields);
}
pool_unref(&auth_pool);
smtp_client_connection_connect(conn->lmtp_conn,
lmtp_proxy_rcpt_login_cb, lprcpt);
return 1;
}
/*
* DATA command
*/
static void
lmtp_proxy_data_cb(const struct smtp_reply *proxy_reply,
struct lmtp_proxy_recipient *lprcpt)
{
struct lmtp_proxy_connection *conn = lprcpt->conn;
struct lmtp_recipient *lrcpt = lprcpt->rcpt;
struct smtp_server_recipient *rcpt = lrcpt->rcpt;
struct lmtp_proxy *proxy = conn->proxy;
struct smtp_server_transaction *trans = proxy->trans;
struct smtp_address *address = lprcpt->address;
const struct smtp_client_transaction_times *times =
smtp_client_transaction_get_times(conn->lmtp_trans);
unsigned int rcpt_index = rcpt->index;
struct smtp_reply reply;
string_t *msg;
/* Compose log message */
msg = t_str_new(128);
str_printfa(msg, "<%s>: ", lrcpt->session_id);
if (smtp_reply_is_success(proxy_reply))
str_append(msg, "Sent message to");
else
str_append(msg, "Failed to send message to");
str_printfa(msg, " <%s> at %s:%u: %s (%u/%u at %u ms)",
smtp_address_encode(address),
conn->set.host, conn->set.port,
smtp_reply_log(proxy_reply),
rcpt_index + 1, array_count(&trans->rcpt_to),
timeval_diff_msecs(&ioloop_timeval, ×->started));
/* Handle reply */
if (smtp_reply_is_success(proxy_reply)) {
/* If backend accepts it, we accept it too */
e_info(rcpt->event, "%s", str_c(msg));
/* Substitute our own success message */
smtp_reply_printf(&reply, 250, "%s Saved", lrcpt->session_id);
/* Do let the enhanced code through */
if (!smtp_reply_has_enhanced_code(proxy_reply))
reply.enhanced_code = SMTP_REPLY_ENH_CODE(2, 0, 0);
else
reply.enhanced_code = proxy_reply->enhanced_code;
} else {
if (smtp_reply_is_remote(proxy_reply)) {
/* The problem isn't with the proxy, it's with the
remote side. so the remote side will log an error,
while for us this is just an info event */
e_info(rcpt->event, "%s", str_c(msg));
} else {
e_error(rcpt->event, "%s", str_c(msg));
}
if (!lmtp_proxy_handle_reply(lprcpt, proxy_reply, &reply))
return;
}
/* Forward reply */
smtp_server_recipient_reply_forward(rcpt, &reply);
}
static void
lmtp_proxy_data_dummy_cb(const struct smtp_reply *proxy_reply ATTR_UNUSED,
struct lmtp_proxy_connection *conn ATTR_UNUSED)
{
/* nothing */
}
void lmtp_proxy_data(struct client *client,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_transaction *trans ATTR_UNUSED,
struct istream *data_input)
{
struct lmtp_proxy *proxy = client->proxy;
struct lmtp_proxy_connection *conn;
uoff_t size;
i_assert(data_input->seekable);
i_assert(proxy->data_input == NULL);
client_update_data_state(client, "proxying");
proxy->data_input = data_input;
i_stream_ref(proxy->data_input);
if (i_stream_get_size(proxy->data_input, TRUE, &size) < 0) {
e_error(client->event,
"i_stream_get_size(data_input) failed: %s",
i_stream_get_error(proxy->data_input));
size = UOFF_T_MAX;
}
/* Create the data_input streams first */
array_foreach_elem(&proxy->connections, conn) {
if (conn->finished) {
/* This connection had already failed */
continue;
}
if (size == UOFF_T_MAX) {
conn->data_input =
i_stream_create_limit(data_input, UOFF_T_MAX);
} else {
conn->data_input =
i_stream_create_sized(data_input, size);
}
}
/* Now that all the streams are created, start reading them
(reading them earlier could have caused the data_input parent's
offset to change) */
array_foreach_elem(&proxy->connections, conn) {
if (conn->finished) {
/* This connection had already failed */
continue;
}
smtp_client_transaction_set_timeout(conn->lmtp_trans,
proxy->max_timeout_msecs);
smtp_client_transaction_send(conn->lmtp_trans, conn->data_input,
lmtp_proxy_data_dummy_cb, conn);
}
}
dovecot-2.3.21.1/src/lmtp/lmtp-client.c 0000644 0000000 0000000 00000027157 14656633576 014470 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lmtp-common.h"
#include "base64.h"
#include "str.h"
#include "llist.h"
#include "iostream.h"
#include "istream.h"
#include "ostream.h"
#include "hostpid.h"
#include "process-title.h"
#include "var-expand.h"
#include "module-dir.h"
#include "master-service-ssl.h"
#include "master-service-settings.h"
#include "iostream-ssl.h"
#include "mail-namespace.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "raw-storage.h"
#include "lda-settings.h"
#include "lmtp-local.h"
#include "lmtp-proxy.h"
#include "lmtp-commands.h"
#include
#define CLIENT_IDLE_TIMEOUT_MSECS (1000*60*5)
static const struct smtp_server_callbacks lmtp_callbacks;
static const struct lmtp_client_vfuncs lmtp_client_vfuncs;
struct lmtp_module_register lmtp_module_register = { 0 };
static struct client *clients = NULL;
static unsigned int clients_count = 0;
static bool verbose_proctitle = FALSE;
static const char *client_remote_id(struct client *client)
{
const char *addr;
addr = net_ip2addr(&client->remote_ip);
if (addr[0] == '\0')
addr = "local";
return addr;
}
static void refresh_proctitle(void)
{
struct client *client;
string_t *title;
if (!verbose_proctitle)
return;
title = t_str_new(128);
str_append_c(title, '[');
switch (clients_count) {
case 0:
str_append(title, "idling");
break;
case 1:
client = clients;
str_append(title, client_remote_id(client));
str_append_c(title, ' ');
str_append(title, smtp_server_state_names[client->state.state]);
if (client->state.args != NULL && *client->state.args != '\0') {
str_append_c(title, ' ');
str_append(title, client->state.args);
}
break;
default:
str_printfa(title, "%u connections", clients_count);
break;
}
str_append_c(title, ']');
process_title_set(str_c(title));
}
static void client_load_modules(struct client *client)
{
struct module_dir_load_settings mod_set;
i_zero(&mod_set);
mod_set.abi_version = DOVECOT_ABI_VERSION;
mod_set.require_init_funcs = TRUE;
mod_set.binary_name = "lmtp";
/* pre-load all configured mail plugins */
mail_storage_service_modules =
module_dir_load_missing(mail_storage_service_modules,
client->lmtp_set->mail_plugin_dir,
client->lmtp_set->mail_plugins,
&mod_set);
module_dir_init(mail_storage_service_modules);
}
static void client_raw_user_create(struct client *client)
{
void **sets;
sets = master_service_settings_get_others(master_service);
client->raw_mail_user =
raw_storage_create_from_set(client->user_set_info, sets[0]);
}
static void client_read_settings(struct client *client, bool ssl)
{
struct mail_storage_service_input input;
const struct setting_parser_context *set_parser;
struct mail_user_settings *user_set;
struct lmtp_settings *lmtp_set;
struct lda_settings *lda_set;
const char *error;
i_zero(&input);
input.module = input.service = "lmtp";
input.local_ip = client->local_ip;
input.remote_ip = client->remote_ip;
input.local_port = client->local_port;
input.remote_port = client->remote_port;
input.conn_secured = ssl;
input.conn_ssl_secured = ssl;
input.username = "";
if (mail_storage_service_read_settings(storage_service, &input,
client->pool,
&client->user_set_info,
&set_parser, &error) < 0)
i_fatal("%s", error);
lmtp_settings_dup(set_parser, client->pool,
&user_set, &lmtp_set, &lda_set);
const struct var_expand_table *tab =
mail_storage_service_get_var_expand_table(storage_service, &input);
if (settings_var_expand(&lmtp_setting_parser_info, lmtp_set,
client->pool, tab, &error) <= 0)
i_fatal("Failed to expand settings: %s", error);
client->service_set = master_service_settings_get(master_service);
client->user_set = user_set;
client->lmtp_set = lmtp_set;
client->unexpanded_lda_set = lda_set;
}
struct client *client_create(int fd_in, int fd_out,
const struct master_service_connection *conn)
{
static const char *rcpt_param_extensions[] = {
LMTP_RCPT_FORWARD_PARAMETER, NULL };
static const struct smtp_capability_extra cap_rcpt_forward = {
.name = LMTP_RCPT_FORWARD_CAPABILITY };
enum lmtp_client_workarounds workarounds;
struct smtp_server_settings lmtp_set;
struct client *client;
pool_t pool;
pool = pool_alloconly_create("lmtp client", 2048);
client = p_new(pool, struct client, 1);
client->pool = pool;
client->v = lmtp_client_vfuncs;
client->remote_ip = conn->remote_ip;
client->remote_port = conn->remote_port;
client->local_ip = conn->local_ip;
client->local_port = conn->local_port;
client->real_local_ip = conn->real_local_ip;
client->real_local_port = conn->real_local_port;
client->real_remote_ip = conn->real_remote_ip;
client->real_remote_port = conn->real_remote_port;
client->state_pool = pool_alloconly_create("client state", 4096);
client->event = event_create(NULL);
event_add_category(client->event, &event_category_lmtp);
client_read_settings(client, conn->ssl);
client_raw_user_create(client);
client_load_modules(client);
client->my_domain = client->unexpanded_lda_set->hostname;
if (client->service_set->verbose_proctitle)
verbose_proctitle = TRUE;
p_array_init(&client->module_contexts, client->pool, 5);
i_zero(&lmtp_set);
lmtp_set.capabilities =
SMTP_CAPABILITY_PIPELINING |
SMTP_CAPABILITY_ENHANCEDSTATUSCODES |
SMTP_CAPABILITY_8BITMIME |
SMTP_CAPABILITY_CHUNKING |
SMTP_CAPABILITY_XCLIENT |
SMTP_CAPABILITY__ORCPT;
if (!conn->ssl && master_service_ssl_is_enabled(master_service))
lmtp_set.capabilities |= SMTP_CAPABILITY_STARTTLS;
lmtp_set.hostname = client->unexpanded_lda_set->hostname;
lmtp_set.login_greeting = client->lmtp_set->login_greeting;
lmtp_set.max_message_size = UOFF_T_MAX;
lmtp_set.rcpt_param_extensions = rcpt_param_extensions;
lmtp_set.rcpt_domain_optional = TRUE;
lmtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS;
lmtp_set.rawlog_dir = client->lmtp_set->lmtp_rawlog_dir;
lmtp_set.event_parent = client->event;
workarounds = client->lmtp_set->parsed_workarounds;
if ((workarounds & LMTP_WORKAROUND_WHITESPACE_BEFORE_PATH) != 0) {
lmtp_set.workarounds |=
SMTP_SERVER_WORKAROUND_WHITESPACE_BEFORE_PATH;
}
if ((workarounds & LMTP_WORKAROUND_MAILBOX_FOR_PATH) != 0) {
lmtp_set.workarounds |=
SMTP_SERVER_WORKAROUND_MAILBOX_FOR_PATH;
}
client->conn = smtp_server_connection_create(
lmtp_server, fd_in, fd_out,
&conn->remote_ip, conn->remote_port, conn->ssl,
&lmtp_set, &lmtp_callbacks, client);
if (smtp_server_connection_is_trusted(client->conn)) {
smtp_server_connection_add_extra_capability(
client->conn, &cap_rcpt_forward);
}
DLLIST_PREPEND(&clients, client);
clients_count++;
e_info(client->event, "Connect from %s", client_remote_id(client));
if (hook_client_created != NULL)
hook_client_created(&client);
smtp_server_connection_start(client->conn);
refresh_proctitle();
return client;
}
void client_state_reset(struct client *client)
{
i_free(client->state.args);
if (client->local != NULL)
lmtp_local_deinit(&client->local);
if (client->proxy != NULL)
lmtp_proxy_deinit(&client->proxy);
o_stream_unref(&client->state.mail_data_output);
i_zero(&client->state);
p_clear(client->state_pool);
}
void client_destroy(struct client **_client, const char *enh_code,
const char *reason)
{
struct client *client = *_client;
*_client = NULL;
smtp_server_connection_terminate(&client->conn,
(enh_code == NULL ? "4.0.0" : enh_code), reason);
}
static void
client_default_destroy(struct client *client)
{
if (client->destroyed)
return;
client->destroyed = TRUE;
clients_count--;
DLLIST_REMOVE(&clients, client);
if (client->raw_mail_user != NULL)
mail_user_deinit(&client->raw_mail_user);
client_state_reset(client);
event_unref(&client->event);
pool_unref(&client->state_pool);
pool_unref(&client->pool);
master_service_client_connection_destroyed(master_service);
}
static void
client_connection_trans_start(void *context,
struct smtp_server_transaction *trans)
{
struct client *client = context;
client->v.trans_start(client, trans);
}
static void
client_default_trans_start(struct client *client ATTR_UNUSED,
struct smtp_server_transaction *trans ATTR_UNUSED)
{
/* nothing */
}
static void
client_connection_trans_free(void *context,
struct smtp_server_transaction *trans)
{
struct client *client = (struct client *)context;
client->v.trans_free(client, trans);
}
static void
client_default_trans_free(struct client *client,
struct smtp_server_transaction *trans ATTR_UNUSED)
{
client_state_reset(client);
}
static void
client_connection_state_changed(void *context,
enum smtp_server_state new_state,
const char *new_args)
{
struct client *client = (struct client *)context;
i_free(client->state.args);
client->state.state = new_state;
client->state.args = i_strdup(new_args);
if (clients_count == 1)
refresh_proctitle();
}
void client_update_data_state(struct client *client, const char *new_args)
{
i_assert(client->state.state == SMTP_SERVER_STATE_DATA);
i_free(client->state.args);
client->state.args = i_strdup(new_args);
if (clients_count == 1)
refresh_proctitle();
}
static void
client_connection_proxy_data_updated(void *context,
const struct smtp_proxy_data *data)
{
struct client *client = (struct client *)context;
client->remote_ip = data->source_ip;
client->remote_port = data->source_port;
if (clients_count == 1)
refresh_proctitle();
}
static void client_connection_disconnect(void *context, const char *reason)
{
struct client *client = (struct client *)context;
if (client->disconnected)
return;
client->disconnected = TRUE;
if (reason == NULL)
reason = "Connection closed";
e_info(client->event, "Disconnect from %s: %s",
client_remote_id(client), reason);
}
static void client_connection_free(void *context)
{
struct client *client = (struct client *)context;
client->v.destroy(client);
}
static bool client_connection_is_trusted(void *context)
{
struct client *client = (struct client *)context;
const char *const *net;
struct ip_addr net_ip;
unsigned int bits;
if (client->lmtp_set->login_trusted_networks == NULL)
return FALSE;
net = t_strsplit_spaces(client->lmtp_set->login_trusted_networks, ", ");
for (; *net != NULL; net++) {
if (net_parse_range(*net, &net_ip, &bits) < 0) {
e_error(client->event, "login_trusted_networks: "
"Invalid network '%s'", *net);
break;
}
if (net_is_in_network(&client->real_remote_ip, &net_ip, bits))
return TRUE;
}
return FALSE;
}
void clients_destroy(void)
{
while (clients != NULL) {
struct client *client = clients;
client_destroy(&client, "4.3.2", "Shutting down");
}
}
static const struct smtp_server_callbacks lmtp_callbacks = {
.conn_cmd_mail = cmd_mail,
.conn_cmd_rcpt = cmd_rcpt,
.conn_cmd_data_begin = cmd_data_begin,
.conn_cmd_data_continue = cmd_data_continue,
.conn_trans_start = client_connection_trans_start,
.conn_trans_free = client_connection_trans_free,
.conn_state_changed = client_connection_state_changed,
.conn_proxy_data_updated = client_connection_proxy_data_updated,
.conn_disconnect = client_connection_disconnect,
.conn_free = client_connection_free,
.conn_is_trusted = client_connection_is_trusted
};
static const struct lmtp_client_vfuncs lmtp_client_vfuncs = {
.destroy = client_default_destroy,
.trans_start = client_default_trans_start,
.trans_free = client_default_trans_free,
.cmd_mail = client_default_cmd_mail,
.cmd_rcpt = client_default_cmd_rcpt,
.cmd_data = client_default_cmd_data,
.local_deliver = lmtp_local_default_deliver,
};
dovecot-2.3.21.1/src/lmtp/lmtp-common.h 0000644 0000000 0000000 00000001714 14656633576 014476 0000000 0000000 #ifndef LMTP_COMMON_H
#define LMTP_COMMON_H
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "settings-parser.h"
#include "master-service.h"
#include "smtp-reply.h"
#include "smtp-server.h"
#include "lmtp-client.h"
#include "lmtp-settings.h"
#define LMTP_RCPT_FORWARD_CAPABILITY "XRCPTFORWARD"
#define LMTP_RCPT_FORWARD_PARAMETER "XRCPTFORWARD"
typedef void lmtp_client_created_func_t(struct client **client);
extern lmtp_client_created_func_t *hook_client_created;
extern struct event_category event_category_lmtp;
extern char *dns_client_socket_path, *base_dir;
extern struct mail_storage_service_ctx *storage_service;
extern struct anvil_client *anvil;
extern struct smtp_server *lmtp_server;
/* Sets the hook_client_created and returns the previous hook,
which the new_hook should call if it's non-NULL. */
lmtp_client_created_func_t *
lmtp_client_created_hook_set(lmtp_client_created_func_t *new_hook);
void lmtp_anvil_init(void);
#endif
dovecot-2.3.21.1/src/lmtp/lmtp-settings.h 0000644 0000000 0000000 00000002477 14656633576 015055 0000000 0000000 #ifndef LMTP_SETTINGS_H
#define LMTP_SETTINGS_H
struct mail_user_settings;
struct lda_settings;
struct lmtp_settings;
/* */
enum lmtp_hdr_delivery_address {
LMTP_HDR_DELIVERY_ADDRESS_NONE,
LMTP_HDR_DELIVERY_ADDRESS_FINAL,
LMTP_HDR_DELIVERY_ADDRESS_ORIGINAL
};
enum lmtp_client_workarounds {
LMTP_WORKAROUND_WHITESPACE_BEFORE_PATH = BIT(0),
LMTP_WORKAROUND_MAILBOX_FOR_PATH = BIT(1),
};
/* */
struct lmtp_settings {
bool lmtp_proxy;
bool lmtp_save_to_detail_mailbox;
bool lmtp_rcpt_check_quota;
bool lmtp_add_received_header;
bool lmtp_verbose_replies;
unsigned int lmtp_user_concurrency_limit;
const char *lmtp_hdr_delivery_address;
const char *lmtp_rawlog_dir;
const char *lmtp_proxy_rawlog_dir;
const char *lmtp_client_workarounds;
const char *login_greeting;
const char *login_trusted_networks;
const char *mail_plugins;
const char *mail_plugin_dir;
enum lmtp_hdr_delivery_address parsed_lmtp_hdr_delivery_address;
enum lmtp_client_workarounds parsed_workarounds;
};
extern const struct setting_parser_info lmtp_setting_parser_info;
void lmtp_settings_dup(const struct setting_parser_context *set_parser,
pool_t pool,
struct mail_user_settings **user_set_r,
struct lmtp_settings **lmtp_set_r,
struct lda_settings **lda_set_r);
#endif
dovecot-2.3.21.1/src/lmtp/lmtp-client.h 0000644 0000000 0000000 00000006205 14656633576 014464 0000000 0000000 #ifndef CLIENT_H
#define CLIENT_H
#include "net.h"
#include "smtp-server.h"
#define CLIENT_MAIL_DATA_MAX_INMEMORY_SIZE (1024*128)
struct mail_storage;
struct mail_deliver_context;
union lmtp_module_context;
struct lmtp_recipient;
struct client;
struct lmtp_local_deliver_context {
struct mail *src_mail;
const char *session_id;
struct timeval delivery_time_started;
struct mail_user *rcpt_user;
const char *rcpt_default_mailbox;
const struct mail_storage_settings *mail_set;
const struct smtp_submit_settings *smtp_set;
const struct lda_settings *lda_set;
struct mail_deliver_session *session;
};
struct client_state {
enum smtp_server_state state;
char *args;
unsigned int session_id_seq;
struct istream *data_input;
uoff_t data_size;
struct timeval data_end_timeval;
struct ostream *mail_data_output;
const char *added_headers_local;
const char *added_headers_proxy;
};
struct lmtp_client_vfuncs {
void (*destroy)(struct client *client);
void (*trans_start)(struct client *client,
struct smtp_server_transaction *trans);
void (*trans_free)(struct client *client,
struct smtp_server_transaction *trans);
int (*cmd_mail)(struct client *client, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
int (*cmd_rcpt)(struct client *client, struct smtp_server_cmd_ctx *cmd,
struct lmtp_recipient *lrcpt);
int (*cmd_data)(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size);
int (*local_deliver)(struct client *client,
struct lmtp_recipient *lrcpt,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct lmtp_local_deliver_context *lldctx);
};
struct client {
struct client *prev, *next;
pool_t pool;
struct lmtp_client_vfuncs v;
struct event *event;
const struct setting_parser_info *user_set_info;
const struct mail_user_settings *user_set;
const struct lda_settings *unexpanded_lda_set;
const struct lmtp_settings *lmtp_set;
const struct master_service_settings *service_set;
struct smtp_server_connection *conn;
struct ip_addr remote_ip, local_ip, real_local_ip, real_remote_ip;
in_port_t remote_port, local_port, real_local_port, real_remote_port;
struct mail_user *raw_mail_user;
const char *my_domain;
pool_t state_pool;
struct client_state state;
struct istream *dot_input;
struct lmtp_local *local;
struct lmtp_proxy *proxy;
/* Module-specific contexts. */
ARRAY(union lmtp_module_context *) module_contexts;
bool disconnected:1;
bool destroyed:1;
};
struct lmtp_module_register {
unsigned int id;
};
union lmtp_module_context {
struct lmtp_client_vfuncs super;
struct lmtp_module_register *reg;
};
extern struct lmtp_module_register lmtp_module_register;
struct client *client_create(int fd_in, int fd_out,
const struct master_service_connection *conn);
void client_destroy(struct client **client, const char *enh_code,
const char *reason) ATTR_NULL(2, 3);
void client_state_reset(struct client *client);
void client_update_data_state(struct client *client, const char *new_args);
void clients_destroy(void);
#endif
dovecot-2.3.21.1/src/lmtp/lmtp-proxy.h 0000644 0000000 0000000 00000001250 14656633576 014362 0000000 0000000 #ifndef LMTP_PROXY_H
#define LMTP_PROXY_H
#include "net.h"
#include "smtp-common.h"
#include "smtp-params.h"
#include "smtp-client.h"
#define LMTP_PROXY_DEFAULT_TTL 5
struct smtp_server_cmd_ctx;
struct smtp_server_cmd_rcpt;
struct lmtp_proxy;
struct client;
void lmtp_proxy_deinit(struct lmtp_proxy **proxy);
int lmtp_proxy_rcpt(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct lmtp_recipient *rcpt, const char *username,
const char *detail, char delim);
void lmtp_proxy_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans ATTR_UNUSED,
struct istream *data_input);
#endif
dovecot-2.3.21.1/src/lmtp/main.c 0000644 0000000 0000000 00000010742 14656633576 013154 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lmtp-common.h"
#include "ioloop.h"
#include "path-util.h"
#include "restrict-access.h"
#include "anvil-client.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "master-interface.h"
#include "mail-deliver.h"
#include "mail-storage-service.h"
#include "smtp-submit-settings.h"
#include "lda-settings.h"
#include
#define DNS_CLIENT_SOCKET_PATH "dns-client"
#define LMTP_MASTER_FIRST_LISTEN_FD 3
#define IS_STANDALONE() \
(getenv(MASTER_IS_PARENT_ENV) == NULL)
struct smtp_server *lmtp_server = NULL;
char *dns_client_socket_path, *base_dir;
struct mail_storage_service_ctx *storage_service;
struct anvil_client *anvil;
lmtp_client_created_func_t *hook_client_created = NULL;
struct event_category event_category_lmtp = {
.name = "lmtp",
};
lmtp_client_created_func_t *
lmtp_client_created_hook_set(lmtp_client_created_func_t *new_hook)
{
lmtp_client_created_func_t *old_hook = hook_client_created;
hook_client_created = new_hook;
return old_hook;
}
void lmtp_anvil_init(void)
{
if (anvil == NULL) {
const char *path = t_strdup_printf("%s/anvil", base_dir);
anvil = anvil_client_init(path, NULL, 0);
}
}
static void client_connected(struct master_service_connection *conn)
{
master_service_client_connection_accept(conn);
(void)client_create(conn->fd, conn->fd, conn);
}
static void drop_privileges(void)
{
struct restrict_access_settings set;
const char *error;
/* by default we don't drop any privileges, but keep running as root. */
restrict_access_get_env(&set);
/* open config connection before dropping privileges */
struct master_service_settings_input input;
struct master_service_settings_output output;
i_zero(&input);
input.module = "lmtp";
input.service = "lmtp";
if (master_service_settings_read(master_service,
&input, &output, &error) < 0)
i_fatal("Error reading configuration: %s", error);
restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
}
static void main_init(void)
{
struct master_service_connection conn;
struct smtp_server_settings lmtp_set;
i_zero(&lmtp_set);
lmtp_set.protocol = SMTP_PROTOCOL_LMTP;
lmtp_set.auth_optional = TRUE;
lmtp_set.rcpt_domain_optional = TRUE;
lmtp_set.mail_path_allow_broken = TRUE;
lmtp_set.reason_code_module = "lmtp";
lmtp_server = smtp_server_init(&lmtp_set);
if (IS_STANDALONE()) {
i_zero(&conn);
(void)client_create(STDIN_FILENO, STDOUT_FILENO, &conn);
}
const char *error, *tmp_socket_path;
if (t_abspath(DNS_CLIENT_SOCKET_PATH, &tmp_socket_path, &error) < 0) {
i_fatal("t_abspath(%s) failed: %s", DNS_CLIENT_SOCKET_PATH, error);
}
dns_client_socket_path = i_strdup(tmp_socket_path);
mail_deliver_hooks_init();
}
static void main_deinit(void)
{
clients_destroy();
if (anvil != NULL)
anvil_client_deinit(&anvil);
i_free(dns_client_socket_path);
i_free(base_dir);
smtp_server_deinit(&lmtp_server);
}
int main(int argc, char *argv[])
{
const struct setting_parser_info *set_roots[] = {
&smtp_submit_setting_parser_info,
&lda_setting_parser_info,
&lmtp_setting_parser_info,
NULL
};
enum master_service_flags service_flags =
MASTER_SERVICE_FLAG_HAVE_STARTTLS;
enum mail_storage_service_flags storage_service_flags =
MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP |
MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP |
MAIL_STORAGE_SERVICE_FLAG_NO_IDLE_TIMEOUT;
const char *tmp_base_dir;
int c;
if (IS_STANDALONE()) {
service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
MASTER_SERVICE_FLAG_STD_CLIENT;
} else {
service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN ;
}
master_service = master_service_init("lmtp", service_flags,
&argc, &argv, "D");
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'D':
storage_service_flags |=
MAIL_STORAGE_SERVICE_FLAG_ENABLE_CORE_DUMPS;
break;
default:
return FATAL_DEFAULT;
}
}
const char *error;
if (t_get_working_dir(&tmp_base_dir, &error) < 0)
i_fatal("Could not get working directory: %s", error);
base_dir = i_strdup(tmp_base_dir);
drop_privileges();
master_service_init_log_with_pid(master_service);
storage_service = mail_storage_service_init(master_service, set_roots,
storage_service_flags);
restrict_access_allow_coredumps(TRUE);
main_init();
master_service_init_finish(master_service);
master_service_run(master_service, client_connected);
main_deinit();
mail_storage_service_deinit(&storage_service);
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/lmtp/Makefile.am 0000644 0000000 0000000 00000002206 14656633576 014114 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = lmtp
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-smtp \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-lda \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index \
-I$(top_srcdir)/src/lib-storage/index/raw \
-DMODULEDIR=\""$(moduledir)"\" \
$(BINARY_CFLAGS)
lmtp_LDFLAGS = -export-dynamic \
$(BINARY_LDFLAGS)
lmtp_LDADD = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT)
lmtp_DEPENDENCIES = \
$(LIBDOVECOT_LDA) \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
lmtp_SOURCES = \
main.c \
lmtp-client.c \
lmtp-commands.c \
lmtp-recipient.c \
lmtp-local.c \
lmtp-proxy.c \
lmtp-settings.c
noinst_HEADERS = \
lmtp-local.h \
lmtp-proxy.h
headers = \
lmtp-common.h \
lmtp-commands.h \
lmtp-recipient.h \
lmtp-client.h \
lmtp-settings.h
pkginc_libdir=$(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
dovecot-2.3.21.1/src/lmtp/lmtp-settings.c 0000644 0000000 0000000 00000012712 14656633576 015041 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "var-expand.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "lda-settings.h"
#include "lmtp-settings.h"
#include "mail-storage-settings.h"
#include
#include
static bool lmtp_settings_check(void *_set, pool_t pool, const char **error_r);
/* */
static struct file_listener_settings lmtp_unix_listeners_array[] = {
{ "lmtp", 0666, "", "" }
};
static struct file_listener_settings *lmtp_unix_listeners[] = {
&lmtp_unix_listeners_array[0]
};
static buffer_t lmtp_unix_listeners_buf = {
{ { lmtp_unix_listeners, sizeof(lmtp_unix_listeners) } }
};
/* */
struct service_settings lmtp_service_settings = {
.name = "lmtp",
.protocol = "lmtp",
.type = "",
.executable = "lmtp",
.user = "",
.group = "",
.privileged_group = "",
.extra_groups = "$default_internal_group",
.chroot = "",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 0,
.client_limit = 1,
.service_count = 0,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &lmtp_unix_listeners_buf,
sizeof(lmtp_unix_listeners[0]) } },
.fifo_listeners = ARRAY_INIT,
.inet_listeners = ARRAY_INIT
};
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct lmtp_settings)
static const struct setting_define lmtp_setting_defines[] = {
DEF(BOOL, lmtp_proxy),
DEF(BOOL, lmtp_save_to_detail_mailbox),
DEF(BOOL, lmtp_rcpt_check_quota),
DEF(BOOL, lmtp_add_received_header),
DEF(BOOL, lmtp_verbose_replies),
DEF(UINT, lmtp_user_concurrency_limit),
DEF(ENUM, lmtp_hdr_delivery_address),
DEF(STR_VARS, lmtp_rawlog_dir),
DEF(STR_VARS, lmtp_proxy_rawlog_dir),
DEF(STR, lmtp_client_workarounds),
DEF(STR_VARS, login_greeting),
DEF(STR, login_trusted_networks),
DEF(STR, mail_plugins),
DEF(STR, mail_plugin_dir),
SETTING_DEFINE_LIST_END
};
static const struct lmtp_settings lmtp_default_settings = {
.lmtp_proxy = FALSE,
.lmtp_save_to_detail_mailbox = FALSE,
.lmtp_rcpt_check_quota = FALSE,
.lmtp_add_received_header = TRUE,
.lmtp_verbose_replies = FALSE,
.lmtp_user_concurrency_limit = 0,
.lmtp_hdr_delivery_address = "final:none:original",
.lmtp_rawlog_dir = "",
.lmtp_proxy_rawlog_dir = "",
.lmtp_client_workarounds = "",
.login_greeting = PACKAGE_NAME" ready.",
.login_trusted_networks = "",
.mail_plugins = "",
.mail_plugin_dir = MODULEDIR,
};
static const struct setting_parser_info *lmtp_setting_dependencies[] = {
&lda_setting_parser_info,
NULL
};
const struct setting_parser_info lmtp_setting_parser_info = {
.module_name = "lmtp",
.defines = lmtp_setting_defines,
.defaults = &lmtp_default_settings,
.type_offset = SIZE_MAX,
.struct_size = sizeof(struct lmtp_settings),
.parent_offset = SIZE_MAX,
.check_func = lmtp_settings_check,
.dependencies = lmtp_setting_dependencies
};
/* */
struct lmtp_client_workaround_list {
const char *name;
enum lmtp_client_workarounds num;
};
static const struct lmtp_client_workaround_list
lmtp_client_workaround_list[] = {
{ "whitespace-before-path", LMTP_WORKAROUND_WHITESPACE_BEFORE_PATH },
{ "mailbox-for-path", LMTP_WORKAROUND_MAILBOX_FOR_PATH },
{ NULL, 0 }
};
static int
lmtp_settings_parse_workarounds(struct lmtp_settings *set,
const char **error_r)
{
enum lmtp_client_workarounds client_workarounds = 0;
const struct lmtp_client_workaround_list *list;
const char *const *str;
str = t_strsplit_spaces(set->lmtp_client_workarounds, " ,");
for (; *str != NULL; str++) {
list = lmtp_client_workaround_list;
for (; list->name != NULL; list++) {
if (strcasecmp(*str, list->name) == 0) {
client_workarounds |= list->num;
break;
}
}
if (list->name == NULL) {
*error_r = t_strdup_printf(
"lmtp_client_workarounds: "
"Unknown workaround: %s", *str);
return -1;
}
}
set->parsed_workarounds = client_workarounds;
return 0;
}
static bool lmtp_settings_check(void *_set, pool_t pool ATTR_UNUSED,
const char **error_r)
{
struct lmtp_settings *set = _set;
if (lmtp_settings_parse_workarounds(set, error_r) < 0)
return FALSE;
if (strcmp(set->lmtp_hdr_delivery_address, "none") == 0) {
set->parsed_lmtp_hdr_delivery_address =
LMTP_HDR_DELIVERY_ADDRESS_NONE;
} else if (strcmp(set->lmtp_hdr_delivery_address, "final") == 0) {
set->parsed_lmtp_hdr_delivery_address =
LMTP_HDR_DELIVERY_ADDRESS_FINAL;
} else if (strcmp(set->lmtp_hdr_delivery_address, "original") == 0) {
set->parsed_lmtp_hdr_delivery_address =
LMTP_HDR_DELIVERY_ADDRESS_ORIGINAL;
} else {
*error_r = t_strdup_printf("Unknown lmtp_hdr_delivery_address: %s",
set->lmtp_hdr_delivery_address);
return FALSE;
}
return TRUE;
}
/* */
void lmtp_settings_dup(const struct setting_parser_context *set_parser,
pool_t pool,
struct mail_user_settings **user_set_r,
struct lmtp_settings **lmtp_set_r,
struct lda_settings **lda_set_r)
{
const char *error;
void **sets;
sets = master_service_settings_parser_get_others(master_service,
set_parser);
*user_set_r = settings_dup(&mail_user_setting_parser_info, sets[0], pool);
*lda_set_r = settings_dup(&lda_setting_parser_info, sets[2], pool);
*lmtp_set_r = settings_dup(&lmtp_setting_parser_info, sets[3], pool);
if (!lmtp_settings_check(*lmtp_set_r, pool, &error))
i_unreached();
}
dovecot-2.3.21.1/src/lmtp/lmtp-recipient.c 0000644 0000000 0000000 00000002753 14656633576 015167 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "lmtp-common.h"
#include "array.h"
#include "smtp-server.h"
#include "lmtp-recipient.h"
struct lmtp_recipient_module_register
lmtp_recipient_module_register = { 0 };
struct lmtp_recipient *
lmtp_recipient_create(struct client *client,
struct smtp_server_transaction *trans,
struct smtp_server_recipient *rcpt)
{
struct lmtp_recipient *lrcpt;
lrcpt = p_new(rcpt->pool, struct lmtp_recipient, 1);
lrcpt->rcpt = rcpt;
lrcpt->client = client;
rcpt->context = lrcpt;
p_array_init(&lrcpt->module_contexts, rcpt->pool, 5);
/* Use a unique session_id for each mail delivery. This is especially
important for stats process to not see duplicate sessions. */
if (client->state.session_id_seq++ == 0)
lrcpt->session_id = trans->id;
else {
lrcpt->session_id = p_strdup_printf(rcpt->pool, "%s:R%u",
trans->id, client->state.session_id_seq);
}
event_add_str(rcpt->event, "session", lrcpt->session_id);
return lrcpt;
}
struct lmtp_recipient *
lmtp_recipient_find_duplicate(struct lmtp_recipient *lrcpt,
struct smtp_server_transaction *trans)
{
struct smtp_server_recipient *drcpt;
struct lmtp_recipient *dup_lrcpt;
i_assert(lrcpt->rcpt != NULL);
drcpt = smtp_server_transaction_find_rcpt_duplicate(trans, lrcpt->rcpt);
if (drcpt == NULL)
return NULL;
dup_lrcpt = drcpt->context;
i_assert(dup_lrcpt->rcpt == drcpt);
i_assert(dup_lrcpt->type == lrcpt->type);
return dup_lrcpt;
}
dovecot-2.3.21.1/src/lmtp/lmtp-commands.h 0000644 0000000 0000000 00000002211 14656633576 015000 0000000 0000000 #ifndef COMMANDS_H
#define COMMANDS_H
struct client;
struct smtp_server_cmd_ctx;
struct smtp_server_cmd_helo;
/*
* MAIL command
*/
int cmd_mail(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);
int client_default_cmd_mail(struct client *client,
struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_cmd_mail *data ATTR_UNUSED);
/*
* RCPT command
*/
int cmd_rcpt(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_recipient *rcpt);
int client_default_cmd_rcpt(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct lmtp_recipient *lrcpt);
/*
* DATA command
*/
int cmd_data_continue(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans);
int cmd_data_begin(void *conn_ctx, struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
struct smtp_server_transaction *trans,
struct istream *data_input);
int client_default_cmd_data(struct client *client,
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct istream *data_input, uoff_t data_size);
#endif
dovecot-2.3.21.1/src/lib-oauth2/ 0000755 0000000 0000000 00000000000 14656633636 013127 5 0000000 0000000 dovecot-2.3.21.1/src/lib-oauth2/test-oauth2-jwt.c 0000644 0000000 0000000 00000061235 14656633576 016206 0000000 0000000 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "str.h"
#include "ostream.h"
#include "hmac.h"
#include "sha2.h"
#include "base64.h"
#include "randgen.h"
#include "array.h"
#include "json-parser.h"
#include "iso8601-date.h"
#include "oauth2.h"
#include "oauth2-private.h"
#include "dcrypt.h"
#include "dict.h"
#include "dict-private.h"
#include "test-common.h"
#include "unlink-directory.h"
#include
#include
#define base64url_encode_str(str, dest) \
base64url_encode(BASE64_ENCODE_FLAG_NO_PADDING, SIZE_MAX, (str), \
strlen((str)), (dest))
/**
* Test keypair used only for this test.
*/
static const char *rsa_public_key =
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv\n"
"vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc\n"
"aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy\n"
"tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0\n"
"e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb\n"
"V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9\n"
"MwIDAQAB\n"
"-----END PUBLIC KEY-----";
static const char *rsa_private_key =
"-----BEGIN PRIVATE KEY-----\n"
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfPKKzVmN80HRs\n"
"GAoUxK++RO3CW8GxomrtLnAD6TN5U5WlVbCRZ1WFrizfxcz+lr/Kvjtq/v7PdVOa\n"
"8NHIAdxpP3bCFEQWku/1yPmVN4lKJvKv8yub9i2MJlVaBo5giHCtfAouo+v/XWKd\n"
"awCR8jK28dZPFlgRxcuABcW5S5pLe4X2ASI1DDMZNTW/QWqSpMGvgHydbccI3jtd\n"
"S7S3xjR76V/izg7FBrBYPv0n3/l3dHLS9tXcCbUW0YmIm87BGwh9UKEOlhK1NwdM\n"
"Iyq29ZtXovXUFaSnMZdJbge/jepr4ZJg4PZBTrwxvn2hKTY4H4G04ukmh+ZsYQaC\n"
"+bDIIj0zAgMBAAECggEAKIBGrbCSW2O1yOyQW9nvDUkA5EdsS58Q7US7bvM4iWpu\n"
"DIBwCXur7/VuKnhn/HUhURLzj/JNozynSChqYyG+CvL+ZLy82LUE3ZIBkSdv/vFL\n"
"Ft+VvvRtf1EcsmoqenkZl7aN7HD7DJeXBoz5tyVQKuH17WW0fsi9StGtCcUl+H6K\n"
"zV9Gif0Kj0uLQbCg3THRvKuueBTwCTdjoP0PwaNADgSWb3hJPeLMm/yII4tIMGbO\n"
"w+xd9wJRl+ZN9nkNtQMxszFGdKjedB6goYLQuP0WRZx+YtykaVJdM75bDUvsQar4\n"
"9Pc21Fp7UVk/CN11DX/hX3TmTJAUtqYADliVKkTbCQKBgQDLU48tBxm3g1CdDM/P\n"
"ZIEmpA3Y/m7e9eX7M1Uo/zDh4G/S9a4kkX6GQY2dLFdCtOS8M4hR11Io7MceBKDi\n"
"djorTZ5zJPQ8+b9Rm+1GlaucGNwRW0cQk2ltT2ksPmJnQn2xvM9T8vE+a4A/YGzw\n"
"mZOfpoVGykWs/tbSzU2aTaOybQKBgQDIfRf6OmirGPh59l+RSuDkZtISF/51mCV/\n"
"S1M4DltWDwhjC2Y2T+meIsb/Mjtz4aVNz0EHB8yvn0TMGr94Uwjv4uBdpVSwz+xL\n"
"hHL7J4rpInH+i0gxa0N+rGwsPwI8wJG95wLY+Kni5KCuXQw55uX1cqnnsahpRZFZ\n"
"EerBXhjqHwKBgBmEjiaHipm2eEqNjhMoOPFBi59dJ0sCL2/cXGa9yEPA6Cfgv49F\n"
"V0zAM2azZuwvSbm4+fXTgTMzrDW/PPXPArPmlOk8jQ6OBY3XdOrz48q+b/gZrYyO\n"
"A6A9ZCSyW6U7+gxxds/BYLeFxF2v21xC2f0iZ/2faykv/oQMUh34en/tAoGACqVZ\n"
"2JexZyR0TUWf3X80YexzyzIq+OOTWicNzDQ29WLm9xtr2gZ0SUlfd72bGpQoyvDu\n"
"awkm/UxfwtbIxALkvpg1gcN9s8XWrkviLyPyZF7H3tRWiQlBFEDjnZXa8I7pLkRO\n"
"Cmdp3fp17cxTEeAI5feovfzZDH39MdWZuZrdh9ECgYBTEv8S7nK8wrxIC390kroV\n"
"52eBwzckQU2mWa0thUtaGQiU1EYPCSDcjkrLXwB72ft0dW57KyWtvrB6rt1ORgOL\n"
"eI5hFbwdGQhCHTrAR1vG3SyFPMAm+8JB+sGOD/fvjtZKx//MFNweKFNEF0C/o6Z2\n"
"FXj90PlgF8sCQut36ZfuIQ==\n"
"-----END PRIVATE KEY-----";
static buffer_t *hs_sign_key = NULL;
static struct dict *keys_dict = NULL;
static bool skip_dcrypt = FALSE;
static struct oauth2_validation_key_cache *key_cache = NULL;
static int parse_jwt_token(struct oauth2_request *req, const char *token,
bool *is_jwt_r, const char **error_r)
{
struct oauth2_settings set;
i_zero(&set);
set.key_dict = keys_dict;
set.key_cache = key_cache;
i_zero(req);
req->pool = pool_datastack_create();
req->set = &set;
t_array_init(&req->fields, 8);
return oauth2_try_parse_jwt(&set, token, &req->fields, is_jwt_r,
error_r);
}
static void test_jwt_token(const char *token)
{
/* then see what the parser likes it */
struct oauth2_request req;
const char *error = NULL;
bool is_jwt;
test_assert(parse_jwt_token(&req, token, &is_jwt, &error) == 0);
test_assert(is_jwt == TRUE);
test_assert(error == NULL);
/* check fields */
test_assert(array_is_created(&req.fields));
if (array_is_created(&req.fields)) {
const struct oauth2_field *field;
bool got_sub = FALSE;
array_foreach(&req.fields, field) {
if (strcmp(field->name, "sub") == 0) {
test_assert_strcmp(field->value, "testuser");
got_sub = TRUE;
}
}
test_assert(got_sub == TRUE);
}
if (error != NULL)
i_error("%s", error);
}
static buffer_t *create_jwt_token_kid(const char *algo, const char *kid)
{
/* make a token */
buffer_t *tokenbuf = t_buffer_create(64);
/* header */
base64url_encode_str(
t_strdup_printf(
"{\"alg\":\"%s\",\"typ\":\"JWT\",\"kid\":\"%s\"}",
algo, kid),
tokenbuf);
buffer_append(tokenbuf, ".", 1);
/* body */
base64url_encode_str(
t_strdup_printf("{\"sub\":\"testuser\","\
"\"iat\":%"PRIdTIME_T","
"\"exp\":%"PRIdTIME_T"}",
time(NULL), time(NULL)+600),
tokenbuf);
return tokenbuf;
}
static buffer_t *create_jwt_token(const char *algo)
{
/* make a token */
buffer_t *tokenbuf = t_buffer_create(64);
/* header */
base64url_encode_str(
t_strdup_printf("{\"alg\":\"%s\",\"typ\":\"JWT\"}", algo),
tokenbuf);
buffer_append(tokenbuf, ".", 1);
/* body */
base64url_encode_str(
t_strdup_printf("{\"sub\":\"testuser\","\
"\"iat\":%"PRIdTIME_T","
"\"exp\":%"PRIdTIME_T"}",
time(NULL), time(NULL)+600),
tokenbuf);
return tokenbuf;
}
static void
append_key_value(string_t *dest, const char *key, const char *value, bool str)
{
str_append_c(dest, '"');
json_append_escaped(dest, key);
str_append(dest, "\":");
if (str)
str_append_c(dest, '"');
json_append_escaped(dest, value);
if (str)
str_append_c(dest, '"');
}
#define create_jwt_token_fields(algo, exp, iat, nbf, fields) \
create_jwt_token_fields_kid(algo, "default", exp, iat, nbf, fields)
static buffer_t *
create_jwt_token_fields_kid(const char *algo, const char *kid, time_t exp, time_t iat,
time_t nbf, ARRAY_TYPE(oauth2_field) *fields)
{
const struct oauth2_field *field;
buffer_t *tokenbuf = t_buffer_create(64);
string_t *hdr = t_str_new(32);
str_printfa(hdr, "{\"alg\":\"%s\",\"typ\":\"JWT\"", algo);
if (kid != NULL && *kid != '\0') {
str_append(hdr, ",\"kid\":\"");
json_append_escaped(hdr, kid);
str_append_c(hdr, '"');
}
str_append(hdr, "}");
base64url_encode_str(str_c(hdr), tokenbuf);
buffer_append(tokenbuf, ".", 1);
string_t *bodybuf = t_str_new(64);
str_append_c(bodybuf, '{');
if (exp > 0) {
append_key_value(bodybuf, "exp", dec2str(exp), FALSE);
}
if (iat > 0) {
if (exp > 0)
str_append_c(bodybuf, ',');
append_key_value(bodybuf, "iat", dec2str(iat), FALSE);
}
if (nbf > 0) {
if (exp > 0 || iat > 0)
str_append_c(bodybuf, ',');
append_key_value(bodybuf, "nbf", dec2str(nbf), FALSE);
}
array_foreach(fields, field) {
if (str_data(bodybuf)[bodybuf->used-1] != '{')
str_append_c(bodybuf, ',');
append_key_value(bodybuf, field->name, field->value, TRUE);
}
str_append_c(bodybuf, '}');
base64url_encode_str(str_c(bodybuf), tokenbuf);
return tokenbuf;
}
#define save_key(algo, key) save_key_to(algo, "default", (key))
#define save_key_to(algo, name, key) save_key_azp_to(algo, "default", name, (key))
static void save_key_azp_to(const char *algo, const char *azp,
const char *name, const char *keydata)
{
const char *error;
struct dict_op_settings set = {
.username = "testuser",
};
struct dict_transaction_context *ctx =
dict_transaction_begin(keys_dict, &set);
algo = t_str_ucase(algo);
dict_set(ctx, t_strconcat(DICT_PATH_SHARED, azp, "/", algo, "/",
name, NULL),
keydata);
if (dict_transaction_commit(&ctx, &error) < 0)
i_error("dict_set(%s) failed: %s", name, error);
}
static void sign_jwt_token_hs256(buffer_t *tokenbuf, buffer_t *key)
{
i_assert(key != NULL);
buffer_t *sig = t_hmac_buffer(&hash_method_sha256, key->data, key->used,
tokenbuf);
buffer_append(tokenbuf, ".", 1);
base64url_encode(BASE64_ENCODE_FLAG_NO_PADDING, SIZE_MAX,
sig->data, sig->used, tokenbuf);
}
static void sign_jwt_token_hs384(buffer_t *tokenbuf, buffer_t *key)
{
i_assert(key != NULL);
buffer_t *sig = t_hmac_buffer(&hash_method_sha384, key->data, key->used,
tokenbuf);
buffer_append(tokenbuf, ".", 1);
base64url_encode(BASE64_ENCODE_FLAG_NO_PADDING, SIZE_MAX,
sig->data, sig->used, tokenbuf);
}
static void sign_jwt_token_hs512(buffer_t *tokenbuf, buffer_t *key)
{
i_assert(key != NULL);
buffer_t *sig = t_hmac_buffer(&hash_method_sha512, key->data, key->used,
tokenbuf);
buffer_append(tokenbuf, ".", 1);
base64url_encode(BASE64_ENCODE_FLAG_NO_PADDING, SIZE_MAX,
sig->data, sig->used, tokenbuf);
}
static void test_jwt_hs_token(void)
{
test_begin("JWT HMAC token");
buffer_t *sign_key_384 = t_buffer_create(384/8);
void *ptr = buffer_append_space_unsafe(sign_key_384, 384/8);
random_fill(ptr, 384/8);
buffer_t *b64_key = t_base64_encode(0, SIZE_MAX,
sign_key_384->data,
sign_key_384->used);
save_key_to("HS384", "default", str_c(b64_key));
buffer_t *sign_key_512 = t_buffer_create(512/8);
ptr = buffer_append_space_unsafe(sign_key_512, 512/8);
random_fill(ptr, 512/8);
b64_key = t_base64_encode(0, SIZE_MAX,
sign_key_512->data,
sign_key_512->used);
save_key_to("HS512", "default", str_c(b64_key));
/* make a token */
buffer_t *tokenbuf = create_jwt_token("HS256");
/* sign it */
sign_jwt_token_hs256(tokenbuf, hs_sign_key);
test_jwt_token(str_c(tokenbuf));
tokenbuf = create_jwt_token("HS384");
sign_jwt_token_hs384(tokenbuf, sign_key_384);
test_jwt_token(str_c(tokenbuf));
tokenbuf = create_jwt_token("HS512");
sign_jwt_token_hs512(tokenbuf, sign_key_512);
test_jwt_token(str_c(tokenbuf));
test_end();
}
static void test_jwt_token_escape(void)
{
struct test_case {
const char *azp;
const char *alg;
const char *kid;
const char *esc_azp;
const char *esc_kid;
} test_cases[] = {
{ "", "hs256", "", "default", "default" },
{ "", "hs256", "test", "default", "test" },
{ "test", "hs256", "test", "test", "test" },
{
"http://test.unit/local%key",
"hs256",
"http://test.unit/local%key",
"http:%2f%2ftest.unit%2flocal%25key",
"http:%2f%2ftest.unit%2flocal%25key"
},
{ "../", "hs256", "../", "..%2f", "..%2f" },
};
test_begin("JWT token escaping");
buffer_t *b64_key =
t_base64_encode(0, SIZE_MAX, hs_sign_key->data, hs_sign_key->used);
ARRAY_TYPE(oauth2_field) fields;
t_array_init(&fields, 8);
for (size_t i = 0; i < N_ELEMENTS(test_cases); i++) {
const struct test_case *test_case = &test_cases[i];
array_clear(&fields);
struct oauth2_field *field = array_append_space(&fields);
field->name = "sub";
field->value = "testuser";
if (*test_case->azp != '\0') {
field = array_append_space(&fields);
field->name = "azp";
field->value = test_case->azp;
}
if (*test_case->kid != '\0') {
field = array_append_space(&fields);
field->name = "kid";
field->value = test_case->kid;
}
save_key_azp_to(test_case->alg, test_case->esc_azp, test_case->esc_kid,
str_c(b64_key));
buffer_t *token = create_jwt_token_fields_kid(test_case->alg,
test_case->kid,
time(NULL)+500,
time(NULL)-500,
0, &fields);
sign_jwt_token_hs256(token, hs_sign_key);
test_jwt_token(str_c(token));
}
test_end();
}
static void test_jwt_broken_token(void)
{
struct test_cases {
const char *token;
bool is_jwt;
} test_cases[] = {
{ /* empty token */
.token = "",
.is_jwt = FALSE
},
{ /* not base64 */
.token = "{\"alg\":\"HS256\":\"typ\":\"JWT\"}",
.is_jwt = FALSE
},
{ /* not jwt */
.token = "aGVsbG8sIHdvcmxkCg",
.is_jwt = FALSE
},
{ /* no alg field */
.token = "eyJ0eXAiOiAiSldUIn0.e30.e30",
.is_jwt = FALSE
},
{ /* typ field is wrong */
.token = "e3R5cDogamtzLCBhbGc6IEhTMjU2fQ."
"eyJhbGdvIjogIldURiIsICJ0eXAiOiAiSldUIn0."
"q2wwwWWJVJxqw-J3uQ0DdlIyWfoZ7Z0QrdzvMW_B-jo",
.is_jwt = FALSE
},
{ /* unknown algorithm */
.token = "eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJXVEYifQ."
"eyJhbGdvIjogIldURiIsICJ0eXAiOiAiSldUIn0."
"q2wwwWWJVJxqw-J3uQ0DdlIyWfoZ7Z0QrdzvMW_B-jo",
.is_jwt = TRUE
},
{ /* truncated base64 */
.token = "yJhbGciOiJIUzI1NiIsInR5",
.is_jwt = FALSE
},
{ /* missing body and signature */
.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
.is_jwt = FALSE
},
{ /* empty body and signature */
.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..",
.is_jwt = TRUE
},
{ /* empty signature */
.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJleHAiOjE1ODEzMzA3OTN9.",
.is_jwt = TRUE
},
{ /* bad signature */
.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJleHAiOjE1ODEzMzA3OTN9."
"q2wwwWWJVJxqw-J3uQ0DdlIyWfoZ7Z0QrdzvMW_B-jo",
.is_jwt = TRUE
},
{ /* algorithm is 'none' */
.token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0."
"eyJleHAiOjE1ODEzMzA3OTN9.",
.is_jwt = TRUE
}
};
test_begin("JWT broken tokens");
for (size_t i = 0; i < N_ELEMENTS(test_cases); i++) T_BEGIN {
struct test_cases *test_case = &test_cases[i];
struct oauth2_request req;
const char *error = NULL;
bool is_jwt;
test_assert_idx(parse_jwt_token(&req, test_case->token,
&is_jwt, &error) != 0, i);
test_assert_idx(test_case->is_jwt == is_jwt, i);
test_assert_idx(error != NULL, i);
} T_END;
test_end();
}
static void test_jwt_bad_valid_token(void)
{
test_begin("JWT bad token tests");
time_t now = time(NULL);
struct test_cases {
time_t exp;
time_t iat;
time_t nbf;
const char *key_values[20];
const char *error;
} test_cases[] =
{
{ /* "empty" token */
.exp = 0,
.iat = 0,
.nbf = 0,
.key_values = { NULL },
.error = "Missing 'sub' field",
},
{ /* missing sub field */
.exp = now+500,
.iat = 0,
.nbf = 0,
.key_values = { NULL },
.error = "Missing 'sub' field",
},
{ /* no expiration */
.key_values = {
"sub", "testuser",
NULL
},
.error = "Missing 'exp' field",
},
{ /* non-ISO date as iat */
.exp = now+500,
.iat = 0,
.nbf = 0,
.key_values = { "sub", "testuser", "iat",
"1.1.2019 16:00", NULL },
.error = "Malformed 'iat' field"
},
{ /* expired token */
.exp = now-500,
.iat = 0,
.nbf = 0,
.key_values = { "sub", "testuser", NULL },
.error = "Token has expired",
},
{ /* future token */
.exp = now+1000,
.iat = now+500,
.nbf = 0,
.key_values = { "sub", "testuser", NULL },
.error = "Token is issued in future",
},
{ /* token not valid yet */
.exp = now+500,
.iat = now,
.nbf = now+250,
.key_values = { "sub", "testuser", NULL },
.error = "Token is not valid yet",
},
};
for (size_t i = 0; i < N_ELEMENTS(test_cases); i++) T_BEGIN {
const struct test_cases *test_case = &test_cases[i];
const char *key = NULL;
ARRAY_TYPE(oauth2_field) fields;
t_array_init(&fields, 8);
for (const char *const *value = test_case->key_values;
*value != NULL; value++) {
if (key == NULL) {
key = *value;
} else {
struct oauth2_field *field =
array_append_space(&fields);
field->name = key;
field->value = *value;
key = NULL;
}
}
buffer_t *tokenbuf =
create_jwt_token_fields("HS256", test_case->exp,
test_case->iat, test_case->nbf,
&fields);
sign_jwt_token_hs256(tokenbuf, hs_sign_key);
struct oauth2_request req;
const char *error = NULL;
bool is_jwt;
test_assert_idx(parse_jwt_token(&req, str_c(tokenbuf),
&is_jwt, &error) != 0, i);
test_assert_idx(is_jwt == TRUE, i);
if (test_case->error != NULL) {
test_assert_strcmp(test_case->error, error);
}
test_assert(error != NULL);
} T_END;
test_end();
}
static void test_jwt_valid_token(void)
{
test_begin("JWT valid token tests");
time_t now = time(NULL);
struct test_cases {
time_t exp;
time_t iat;
time_t nbf;
const char *key_values[20];
} test_cases[] = {
{ /* valid token */
.exp = now + 500,
.key_values = {
"sub", "testuser",
NULL
},
},
{
.exp = now + 500,
.nbf = now - 500,
.iat = now - 250,
.key_values = {
"sub", "testuser",
NULL
},
},
{ /* token issued in advance */
.exp = now + 500,
.nbf = now - 500,
.iat = now - 3600,
.key_values = {
"sub", "testuser",
NULL,
},
},
};
for (size_t i = 0; i < N_ELEMENTS(test_cases); i++) T_BEGIN {
const struct test_cases *test_case = &test_cases[i];
ARRAY_TYPE(oauth2_field) fields;
t_array_init(&fields, 8);
for (unsigned int i = 0; test_case->key_values[i] != NULL; i += 2) {
struct oauth2_field *field = array_append_space(&fields);
field->name = test_case->key_values[i];
field->value = test_case->key_values[i+1];
}
buffer_t *tokenbuf =
create_jwt_token_fields("HS256", test_case->exp,
test_case->iat, test_case->nbf,
&fields);
sign_jwt_token_hs256(tokenbuf, hs_sign_key);
struct oauth2_request req;
const char *error = NULL;
bool is_jwt;
test_assert_idx(parse_jwt_token(&req, str_c(tokenbuf),
&is_jwt, &error) == 0, i);
test_assert_idx(is_jwt == TRUE, i);
test_assert_idx(error == NULL, i);
if (error != NULL)
i_error("JWT validation error: %s", error);
} T_END;
test_end();
}
static void test_jwt_dates(void)
{
test_begin("JWT Token dates");
/* simple check to make sure ISO8601 dates work too */
ARRAY_TYPE(oauth2_field) fields;
t_array_init(&fields, 8);
struct oauth2_field *field;
struct tm tm_b;
struct tm *tm;
time_t now = time(NULL);
time_t exp = now+500;
time_t nbf = now-250;
time_t iat = now-500;
field = array_append_space(&fields);
field->name = "sub";
field->value = "testuser";
field = array_append_space(&fields);
field->name = "exp";
tm = gmtime_r(&exp, &tm_b);
field->value = iso8601_date_create_tm(tm, INT_MAX);
field = array_append_space(&fields);
field->name = "nbf";
tm = gmtime_r(&nbf, &tm_b);
field->value = iso8601_date_create_tm(tm, INT_MAX);
field = array_append_space(&fields);
field->name = "iat";
tm = gmtime_r(&iat, &tm_b);
field->value = iso8601_date_create_tm(tm, INT_MAX);
buffer_t *tokenbuf = create_jwt_token_fields("HS256", 0, 0, 0, &fields);
sign_jwt_token_hs256(tokenbuf, hs_sign_key);
test_jwt_token(str_c(tokenbuf));
str_truncate(tokenbuf, 0);
base64url_encode_str("{\"alg\":\"HS256\",\"typ\":\"JWT\"}", tokenbuf);
str_append_c(tokenbuf, '.');
base64url_encode_str(t_strdup_printf("{\"sub\":\"testuser\","
"\"exp\":%"PRIdTIME_T","
"\"nbf\":0,\"iat\":%"PRIdTIME_T"}",
exp, iat),
tokenbuf);
sign_jwt_token_hs256(tokenbuf, hs_sign_key);
test_jwt_token(str_c(tokenbuf));
test_end();
}
static void test_jwt_key_files(void)
{
test_begin("JWT key id");
/* write HMAC secrets */
struct oauth2_request req;
bool is_jwt;
const char *error = NULL;
buffer_t *secret = t_buffer_create(32);
void *ptr = buffer_append_space_unsafe(secret, 32);
random_fill(ptr, 32);
buffer_t *b64_key = t_base64_encode(0, SIZE_MAX,
secret->data, secret->used);
save_key_to("HS256", "first", str_c(b64_key));
buffer_t *secret2 = t_buffer_create(32);
ptr = buffer_append_space_unsafe(secret2, 32);
random_fill(ptr, 32);
b64_key = t_base64_encode(0, SIZE_MAX, secret2->data, secret2->used);
save_key_to("HS256", "second", str_c(b64_key));
/* create and sign token */
buffer_t *token_1 = create_jwt_token_kid("HS256", "first");
buffer_t *token_2 = create_jwt_token_kid("HS256", "second");
buffer_t *token_3 = create_jwt_token_kid("HS256", "missing");
buffer_t *token_4 = create_jwt_token_kid("HS256", "");
sign_jwt_token_hs256(token_1, secret);
sign_jwt_token_hs256(token_2, secret2);
sign_jwt_token_hs256(token_3, secret);
sign_jwt_token_hs256(token_4, secret);
test_jwt_token(str_c(token_1));
test_jwt_token(str_c(token_2));
test_assert(parse_jwt_token(&req, str_c(token_3), &is_jwt, &error) != 0);
test_assert(is_jwt == TRUE);
test_assert_strcmp(error, "HS256 key 'missing' not found");
test_assert(parse_jwt_token(&req, str_c(token_4), &is_jwt, &error) != 0);
test_assert(is_jwt == TRUE);
test_assert_strcmp(error, "'kid' field is empty");
test_end();
}
static void test_jwt_kid_escape(void)
{
test_begin("JWT kid escape");
/* save a token */
buffer_t *secret = t_buffer_create(32);
void *ptr = buffer_append_space_unsafe(secret, 32);
random_fill(ptr, 32);
buffer_t *b64_key = t_base64_encode(0, SIZE_MAX,
secret->data, secret->used);
save_key_to("HS256", "hello.world%2f%25", str_c(b64_key));
/* make a token */
buffer_t *tokenbuf = create_jwt_token_kid("HS256", "hello.world/%");
/* sign it */
sign_jwt_token_hs256(tokenbuf, secret);
test_jwt_token(str_c(tokenbuf));
test_end();
}
static void test_jwt_rs_token(void)
{
const char *error;
if (skip_dcrypt)
return;
test_begin("JWT RSA token");
/* write public key to file */
oauth2_validation_key_cache_evict(key_cache, "default");
save_key("RS256", rsa_public_key);
buffer_t *tokenbuf = create_jwt_token("RS256");
/* sign token */
buffer_t *sig = t_buffer_create(64);
struct dcrypt_private_key *key;
if (!dcrypt_key_load_private(&key, rsa_private_key, NULL, NULL,
&error) ||
!dcrypt_sign(key, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
tokenbuf->data, tokenbuf->used, sig,
DCRYPT_PADDING_RSA_PKCS1, &error)) {
i_error("dcrypt signing failed: %s", error);
lib_exit(1);
}
dcrypt_key_unref_private(&key);
/* convert to base64 */
buffer_append(tokenbuf, ".", 1);
base64url_encode(BASE64_ENCODE_FLAG_NO_PADDING, SIZE_MAX,
sig->data, sig->used, tokenbuf);
test_jwt_token(str_c(tokenbuf));
test_end();
}
static void test_jwt_ps_token(void)
{
const char *error;
if (skip_dcrypt)
return;
test_begin("JWT RSAPSS token");
/* write public key to file */
oauth2_validation_key_cache_evict(key_cache, "default");
save_key("PS256", rsa_public_key);
buffer_t *tokenbuf = create_jwt_token("PS256");
/* sign token */
buffer_t *sig = t_buffer_create(64);
struct dcrypt_private_key *key;
if (!dcrypt_key_load_private(&key, rsa_private_key, NULL, NULL,
&error) ||
!dcrypt_sign(key, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
tokenbuf->data, tokenbuf->used, sig,
DCRYPT_PADDING_RSA_PKCS1_PSS, &error)) {
i_error("dcrypt signing failed: %s", error);
lib_exit(1);
}
dcrypt_key_unref_private(&key);
/* convert to base64 */
buffer_append(tokenbuf, ".", 1);
base64url_encode(BASE64_ENCODE_FLAG_NO_PADDING, SIZE_MAX,
sig->data, sig->used, tokenbuf);
test_jwt_token(str_c(tokenbuf));
test_end();
}
static void test_jwt_ec_token(void)
{
const char *error;
if (skip_dcrypt)
return;
test_begin("JWT ECDSA token");
struct dcrypt_keypair pair;
i_zero(&pair);
if (!dcrypt_keypair_generate(&pair, DCRYPT_KEY_EC, 0,
"prime256v1", &error)) {
i_error("dcrypt keypair generate failed: %s", error);
lib_exit(1);
}
/* export public key */
buffer_t *keybuf = t_buffer_create(256);
if (!dcrypt_key_store_public(pair.pub, DCRYPT_FORMAT_PEM, keybuf,
&error)) {
i_error("dcrypt key store failed: %s", error);
lib_exit(1);
}
oauth2_validation_key_cache_evict(key_cache, "default");
save_key("ES256", str_c(keybuf));
buffer_t *tokenbuf = create_jwt_token("ES256");
/* sign token */
buffer_t *sig = t_buffer_create(64);
if (!dcrypt_sign(pair.priv, "sha256", DCRYPT_SIGNATURE_FORMAT_X962,
tokenbuf->data, tokenbuf->used, sig,
DCRYPT_PADDING_DEFAULT, &error)) {
i_error("dcrypt signing failed: %s", error);
lib_exit(1);
}
dcrypt_keypair_unref(&pair);
/* convert to base64 */
buffer_append(tokenbuf, ".", 1);
base64url_encode(BASE64_ENCODE_FLAG_NO_PADDING, SIZE_MAX,
sig->data, sig->used, tokenbuf);
test_jwt_token(str_c(tokenbuf));
test_end();
}
static void test_do_init(void)
{
const char *error;
struct dcrypt_settings dcrypt_set = {
.module_dir = "../lib-dcrypt/.libs",
};
struct dict_settings dict_set = {
.base_dir = ".",
};
i_unlink_if_exists(".keys");
dict_driver_register(&dict_driver_file);
if (dict_init("file:.keys", &dict_set, &keys_dict, &error) < 0)
i_fatal("dict_init(file:.keys): %s", error);
if (!dcrypt_initialize(NULL, &dcrypt_set, &error)) {
i_error("No functional dcrypt backend found - "
"skipping some tests: %s", error);
skip_dcrypt = TRUE;
}
key_cache = oauth2_validation_key_cache_init();
/* write HMAC secret */
hs_sign_key =buffer_create_dynamic(default_pool, 32);
void *ptr = buffer_append_space_unsafe(hs_sign_key, 32);
random_fill(ptr, 32);
buffer_t *b64_key = t_base64_encode(0, SIZE_MAX,
hs_sign_key->data,
hs_sign_key->used);
save_key("HS256", str_c(b64_key));
}
static void test_do_deinit(void)
{
dict_deinit(&keys_dict);
dict_driver_unregister(&dict_driver_file);
oauth2_validation_key_cache_deinit(&key_cache);
i_unlink(".keys");
buffer_free(&hs_sign_key);
dcrypt_deinitialize();
}
int main(void)
{
static void (*test_functions[])(void) = {
test_do_init,
test_jwt_hs_token,
test_jwt_token_escape,
test_jwt_valid_token,
test_jwt_bad_valid_token,
test_jwt_broken_token,
test_jwt_dates,
test_jwt_key_files,
test_jwt_kid_escape,
test_jwt_rs_token,
test_jwt_ps_token,
test_jwt_ec_token,
test_do_deinit,
NULL
};
int ret;
ret = test_run(test_functions);
return ret;
}
dovecot-2.3.21.1/src/lib-oauth2/oauth2-key-cache.c 0000644 0000000 0000000 00000010234 14656633576 016247 0000000 0000000 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "llist.h"
#include "buffer.h"
#include "hash.h"
#include "dcrypt.h"
#include "oauth2.h"
#include "oauth2-private.h"
struct oauth2_key_cache_entry {
const char *key_id;
struct dcrypt_public_key *pubkey;
buffer_t *hmac_key;
struct oauth2_key_cache_entry *prev, *next;
};
HASH_TABLE_DEFINE_TYPE(oauth2_key_cache, const char *,
struct oauth2_key_cache_entry *);
struct oauth2_validation_key_cache {
pool_t pool;
HASH_TABLE_TYPE(oauth2_key_cache) keys;
struct oauth2_key_cache_entry *list_start;
};
struct oauth2_validation_key_cache *oauth2_validation_key_cache_init(void)
{
pool_t pool = pool_alloconly_create(
MEMPOOL_GROWING"oauth2 key cache", 128);
struct oauth2_validation_key_cache *cache =
p_new(pool, struct oauth2_validation_key_cache, 1);
cache->pool = pool;
hash_table_create(&cache->keys, pool, 8, str_hash, strcmp);
return cache;
}
void oauth2_validation_key_cache_deinit(
struct oauth2_validation_key_cache **_cache)
{
struct oauth2_validation_key_cache *cache = *_cache;
*_cache = NULL;
if (cache == NULL)
return;
/* free resources */
struct oauth2_key_cache_entry *entry = cache->list_start;
while (entry != NULL) {
if (entry->pubkey != NULL)
dcrypt_key_unref_public(&entry->pubkey);
entry = entry->next;
}
hash_table_destroy(&cache->keys);
pool_unref(&cache->pool);
}
int oauth2_validation_key_cache_lookup_pubkey(
struct oauth2_validation_key_cache *cache, const char *key_id,
struct dcrypt_public_key **pubkey_r)
{
if (cache == NULL)
return -1;
struct oauth2_key_cache_entry *entry =
hash_table_lookup(cache->keys, key_id);
if (entry == NULL || entry->pubkey == NULL)
return -1;
*pubkey_r = entry->pubkey;
return 0;
}
int oauth2_validation_key_cache_lookup_hmac_key(
struct oauth2_validation_key_cache *cache, const char *key_id,
const buffer_t **hmac_key_r)
{
if (cache == NULL)
return -1;
struct oauth2_key_cache_entry *entry =
hash_table_lookup(cache->keys, key_id);
if (entry == NULL || entry->hmac_key == NULL ||
entry->hmac_key->used == 0)
return -1;
*hmac_key_r = entry->hmac_key;
return 0;
}
void oauth2_validation_key_cache_insert_pubkey(
struct oauth2_validation_key_cache *cache, const char *key_id,
struct dcrypt_public_key *pubkey)
{
if (cache == NULL)
return;
struct oauth2_key_cache_entry *entry =
hash_table_lookup(cache->keys, key_id);
if (entry != NULL) {
dcrypt_key_unref_public(&entry->pubkey);
entry->pubkey = pubkey;
if (entry->hmac_key != NULL)
buffer_set_used_size(entry->hmac_key, 0);
return;
}
entry = p_new(cache->pool, struct oauth2_key_cache_entry, 1);
entry->key_id = p_strdup(cache->pool, key_id);
entry->pubkey = pubkey;
DLLIST_PREPEND(&cache->list_start, entry);
hash_table_insert(cache->keys, entry->key_id, entry);
}
void oauth2_validation_key_cache_insert_hmac_key(
struct oauth2_validation_key_cache *cache, const char *key_id,
const buffer_t *hmac_key)
{
if (cache == NULL)
return;
struct oauth2_key_cache_entry *entry =
hash_table_lookup(cache->keys, key_id);
if (entry != NULL) {
dcrypt_key_unref_public(&entry->pubkey);
if (entry->hmac_key == NULL) {
entry->hmac_key = buffer_create_dynamic(
cache->pool, hmac_key->used);
} else {
buffer_set_used_size(entry->hmac_key, 0);
}
buffer_append(entry->hmac_key, hmac_key->data, hmac_key->used);
return;
}
entry = p_new(cache->pool, struct oauth2_key_cache_entry, 1);
entry->key_id = p_strdup(cache->pool, key_id);
entry->hmac_key = buffer_create_dynamic(cache->pool, hmac_key->used);
buffer_append(entry->hmac_key, hmac_key->data, hmac_key->used);
DLLIST_PREPEND(&cache->list_start, entry);
hash_table_insert(cache->keys, entry->key_id, entry);
}
int oauth2_validation_key_cache_evict(struct oauth2_validation_key_cache *cache,
const char *key_id)
{
if (cache == NULL)
return -1;
struct oauth2_key_cache_entry *entry =
hash_table_lookup(cache->keys, key_id);
if (entry == NULL)
return -1;
if (entry->pubkey != NULL)
dcrypt_key_unref_public(&entry->pubkey);
DLLIST_REMOVE(&cache->list_start, entry);
hash_table_remove(cache->keys, key_id);
return 0;
}
dovecot-2.3.21.1/src/lib-oauth2/test-oauth2-json.c 0000644 0000000 0000000 00000005167 14656633576 016355 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "json-parser.h"
#include "oauth2.h"
#include "oauth2-private.h"
#include "test-common.h"
static void
test_oauth_json_valid_parsed(struct oauth2_request *req ATTR_UNUSED,
const char *error)
{
test_assert(error == NULL);
}
static void test_oauth2_json_valid(void)
{
static const char *test_input =
"{\"access_token\":\"9a2dea3c-f8be-4271-b9c8-5b37da4f2f7e\","
"\"grant_type\":\"authorization_code\","
"\"openid\":\"\","
"\"scope\":[\"openid\",\"profile\",\"email\"],"
"\"profile\":\"\","
"\"realm\":\"/employees\","
"\"token_type\":\"Bearer\","
"\"expires_in\":2377,"
"\"client_id\":\"mosaic\","
"\"email\":\"\","
"\"extensions\":"
"{\"algorithm\":\"cuttlefish\","
"\"tentacles\":8"
"}"
"}";
static const struct oauth2_field fields[] = {
{ .name = "access_token",
.value = "9a2dea3c-f8be-4271-b9c8-5b37da4f2f7e" },
{ .name = "grant_type",
.value = "authorization_code" },
{ .name = "openid",
.value = "" },
{ .name = "profile",
.value = "" },
{ .name = "realm",
.value = "/employees" },
{ .name = "token_type",
.value = "Bearer" },
{ .name = "expires_in",
.value = "2377" },
{ .name = "client_id",
.value = "mosaic" },
{ .name = "email",
.value = "" },
};
static const unsigned int fields_count = N_ELEMENTS(fields);
struct oauth2_request *req;
const struct oauth2_field *pfields;
unsigned int count, i;
pool_t pool;
size_t pos;
test_begin("oauth json skip");
/* Create mock request */
pool = pool_alloconly_create_clean("oauth2 json test", 1024);
req = p_new(pool, struct oauth2_request, 1);
req->pool = pool;
p_array_init(&req->fields, req->pool, 1);
req->is = test_istream_create_data(test_input, strlen(test_input));
req->parser = json_parser_init(req->is);
req->json_parsed_cb = test_oauth_json_valid_parsed;
/* Parse the JSON response */
for (pos = 0; pos <= strlen(test_input); pos +=2) {
test_istream_set_size(req->is, pos);
oauth2_request_parse_json(req);
if (req->is == NULL)
break;
}
/* Verify the parsed fields */
pfields = array_get(&req->fields, &count);
test_assert(count == fields_count);
if (count > fields_count)
count = fields_count;
for (i = 0; i < count; i++) {
test_assert(strcmp(pfields[i].name, fields[i].name) == 0);
test_assert(strcmp(pfields[i].value, fields[i].value) == 0);
}
/* Clean up */
pool_unref(&req->pool);
test_end();
}
int main(void)
{
static void (*const test_functions[])(void) = {
test_oauth2_json_valid,
NULL
};
return test_run(test_functions);
}
dovecot-2.3.21.1/src/lib-oauth2/Makefile.in 0000644 0000000 0000000 00000073242 14656633610 015114 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
noinst_PROGRAMS = $(am__EXEEXT_1)
subdir = src/lib-oauth2
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(pkginc_lib_HEADERS) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = test-oauth2-json$(EXEEXT) test-oauth2-jwt$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
LTLIBRARIES = $(noinst_LTLIBRARIES)
liboauth2_la_LIBADD =
am_liboauth2_la_OBJECTS = oauth2.lo oauth2-request.lo oauth2-jwt.lo \
oauth2-key-cache.lo
liboauth2_la_OBJECTS = $(am_liboauth2_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am_test_oauth2_json_OBJECTS = test-oauth2-json.$(OBJEXT)
test_oauth2_json_OBJECTS = $(am_test_oauth2_json_OBJECTS)
am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = $(noinst_LTLIBRARIES) ../lib-dcrypt/libdcrypt.la \
../lib-http/libhttp.la ../lib-dns/libdns.la \
../lib-ssl-iostream/libssl_iostream.la \
../lib-master/libmaster.la ../lib-auth/libauth.la \
../lib-dict/libdict.la ../lib-settings/libsettings.la \
../lib-test/libtest.la ../lib/liblib.la $(am__DEPENDENCIES_1)
am_test_oauth2_jwt_OBJECTS = test-oauth2-jwt.$(OBJEXT)
test_oauth2_jwt_OBJECTS = $(am_test_oauth2_jwt_OBJECTS)
test_oauth2_jwt_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(test_oauth2_jwt_LDFLAGS) $(LDFLAGS) \
-o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/oauth2-jwt.Plo \
./$(DEPDIR)/oauth2-key-cache.Plo \
./$(DEPDIR)/oauth2-request.Plo ./$(DEPDIR)/oauth2.Plo \
./$(DEPDIR)/test-oauth2-json.Po ./$(DEPDIR)/test-oauth2-jwt.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(liboauth2_la_SOURCES) $(test_oauth2_json_SOURCES) \
$(test_oauth2_jwt_SOURCES)
DIST_SOURCES = $(liboauth2_la_SOURCES) $(test_oauth2_json_SOURCES) \
$(test_oauth2_jwt_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-http \
-I$(top_srcdir)/src/lib-dcrypt \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-settings
noinst_LTLIBRARIES = liboauth2.la
pkginc_libdir = $(pkgincludedir)
pkginc_lib_HEADERS = \
oauth2.h
noinst_HEADERS = \
oauth2-private.h
liboauth2_la_SOURCES = \
oauth2.c \
oauth2-request.c \
oauth2-jwt.c \
oauth2-key-cache.c
test_programs = \
test-oauth2-json \
test-oauth2-jwt
test_libs = \
$(noinst_LTLIBRARIES) \
../lib-dcrypt/libdcrypt.la \
../lib-http/libhttp.la \
../lib-dns/libdns.la \
../lib-ssl-iostream/libssl_iostream.la \
../lib-master/libmaster.la \
../lib-auth/libauth.la \
../lib-dict/libdict.la \
../lib-settings/libsettings.la \
../lib-test/libtest.la \
../lib/liblib.la \
$(MODULE_LIBS)
test_deps = \
$(noinst_LTLIBRARIES) \
../lib-dcrypt/libdcrypt.la \
../lib-http/libhttp.la \
../lib-dns/libdns.la \
../lib-ssl-iostream/libssl_iostream.la \
../lib-master/libmaster.la \
../lib-auth/libauth.la \
../lib-dict/libdict.la \
../lib-settings/libsettings.la \
../lib-test/libtest.la \
../lib/liblib.la
test_oauth2_json_SOURCES = test-oauth2-json.c
test_oauth2_json_LDADD = $(test_libs)
test_oauth2_json_DEPENDENCIES = $(test_deps)
test_oauth2_jwt_SOURCES = test-oauth2-jwt.c
test_oauth2_jwt_LDADD = $(test_libs)
@HAVE_WHOLE_ARCHIVE_TRUE@test_oauth2_jwt_LDFLAGS = -Wl,$(LD_WHOLE_ARCHIVE),../lib-ssl-iostream/.libs/libssl_iostream.a,$(LD_NO_WHOLE_ARCHIVE)
test_oauth2_jwt_DEPENDENCIES = $(test_deps)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-oauth2/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/lib-oauth2/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
liboauth2.la: $(liboauth2_la_OBJECTS) $(liboauth2_la_DEPENDENCIES) $(EXTRA_liboauth2_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(liboauth2_la_OBJECTS) $(liboauth2_la_LIBADD) $(LIBS)
test-oauth2-json$(EXEEXT): $(test_oauth2_json_OBJECTS) $(test_oauth2_json_DEPENDENCIES) $(EXTRA_test_oauth2_json_DEPENDENCIES)
@rm -f test-oauth2-json$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_oauth2_json_OBJECTS) $(test_oauth2_json_LDADD) $(LIBS)
test-oauth2-jwt$(EXEEXT): $(test_oauth2_jwt_OBJECTS) $(test_oauth2_jwt_DEPENDENCIES) $(EXTRA_test_oauth2_jwt_DEPENDENCIES)
@rm -f test-oauth2-jwt$(EXEEXT)
$(AM_V_CCLD)$(test_oauth2_jwt_LINK) $(test_oauth2_jwt_OBJECTS) $(test_oauth2_jwt_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oauth2-jwt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oauth2-key-cache.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oauth2-request.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oauth2.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-oauth2-json.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-oauth2-jwt.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
done
uninstall-pkginc_libHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-local
check: check-am
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/oauth2-jwt.Plo
-rm -f ./$(DEPDIR)/oauth2-key-cache.Plo
-rm -f ./$(DEPDIR)/oauth2-request.Plo
-rm -f ./$(DEPDIR)/oauth2.Plo
-rm -f ./$(DEPDIR)/test-oauth2-json.Po
-rm -f ./$(DEPDIR)/test-oauth2-jwt.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkginc_libHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/oauth2-jwt.Plo
-rm -f ./$(DEPDIR)/oauth2-key-cache.Plo
-rm -f ./$(DEPDIR)/oauth2-request.Plo
-rm -f ./$(DEPDIR)/oauth2.Plo
-rm -f ./$(DEPDIR)/test-oauth2-json.Po
-rm -f ./$(DEPDIR)/test-oauth2-jwt.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkginc_libHEADERS
.MAKE: check-am install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \
check-local clean clean-generic clean-libtool \
clean-noinstLTLIBRARIES clean-noinstPROGRAMS cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-pkginc_libHEADERS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-pkginc_libHEADERS
.PRECIOUS: Makefile
check-local:
for bin in $(test_programs); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/lib-oauth2/oauth2-jwt.c 0000644 0000000 0000000 00000034440 14656633576 015227 0000000 0000000 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "str.h"
#include "strescape.h"
#include "hmac.h"
#include "array.h"
#include "hash-method.h"
#include "istream.h"
#include "iso8601-date.h"
#include "json-tree.h"
#include "array.h"
#include "base64.h"
#include "str-sanitize.h"
#include "dcrypt.h"
#include "var-expand.h"
#include "oauth2.h"
#include "oauth2-private.h"
#include "dict.h"
#include
static const char *get_field(const struct json_tree *tree, const char *key)
{
const struct json_tree_node *root = json_tree_root(tree);
const struct json_tree_node *value_node = json_tree_find_key(root, key);
if (value_node == NULL || value_node->value_type == JSON_TYPE_OBJECT ||
value_node->value_type == JSON_TYPE_ARRAY)
return NULL;
return json_tree_get_value_str(value_node);
}
static const char *get_field_multiple(const struct json_tree *tree, const char *key)
{
const struct json_tree_node *root = json_tree_root(tree);
const struct json_tree_node *value_node = json_tree_find_key(root, key);
if (value_node == NULL || value_node->value_type == JSON_TYPE_OBJECT)
return NULL;
if (value_node->value_type != JSON_TYPE_ARRAY)
return json_tree_get_value_str(value_node);
const struct json_tree_node *entry_node = json_tree_get_child(value_node);
string_t *values = t_str_new(64);
for (; entry_node != NULL; entry_node = entry_node->next) {
if (entry_node->value_type == JSON_TYPE_OBJECT ||
entry_node->value_type == JSON_TYPE_ARRAY)
continue;
const char *value_str = json_tree_get_value_str(entry_node);
if (str_len(values) > 0)
str_append_c(values, '\t');
str_append_tabescaped(values, value_str);
}
return str_c(values);
}
static int get_time_field(const struct json_tree *tree, const char *key,
int64_t *value_r)
{
time_t tvalue;
const char *value = get_field(tree, key);
int tz_offset ATTR_UNUSED;
if (value == NULL)
return 0;
if (str_to_int64(value, value_r) == 0) {
if (*value_r < 0)
return -1;
return 1;
} else if (iso8601_date_parse((const unsigned char*)value, strlen(value),
&tvalue, &tz_offset)) {
if (tvalue < 0)
return -1;
*value_r = tvalue;
return 1;
}
return -1;
}
/* Escapes '/' and '%' in identifier to %hex */
static const char *escape_identifier(const char *identifier)
{
size_t pos = strcspn(identifier, "/%");
/* nothing to escape */
if (identifier[pos] == '\0')
return identifier;
size_t len = strlen(identifier);
string_t *new_id = t_str_new(len);
str_append_data(new_id, identifier, pos);
for (size_t i = pos; i < len; i++) {
switch (identifier[i]) {
case '/':
str_append(new_id, "%2f");
break;
case '%':
str_append(new_id, "%25");
break;
default:
str_append_c(new_id, identifier[i]);
break;
}
}
return str_c(new_id);
}
static int
oauth2_lookup_hmac_key(const struct oauth2_settings *set, const char *azp,
const char *alg, const char *key_id,
const buffer_t **hmac_key_r, const char **error_r)
{
const char *base64_key;
const char *cache_key_id, *lookup_key;
int ret;
cache_key_id = t_strconcat(azp, ".", alg, ".", key_id, NULL);
if (oauth2_validation_key_cache_lookup_hmac_key(
set->key_cache, cache_key_id, hmac_key_r) == 0)
return 0;
/* do a synchronous dict lookup */
lookup_key = t_strconcat(DICT_PATH_SHARED, azp, "/", alg, "/", key_id,
NULL);
struct dict_op_settings dict_set = {
.username = NULL,
};
if ((ret = dict_lookup(set->key_dict, &dict_set, pool_datastack_create(),
lookup_key, &base64_key, error_r)) < 0) {
return -1;
} else if (ret == 0) {
*error_r = t_strdup_printf("%s key '%s' not found",
alg, key_id);
return -1;
}
/* decode key */
buffer_t *key = t_base64_decode_str(base64_key);
if (key->used == 0) {
*error_r = "Invalid base64 encoded key";
return -1;
}
oauth2_validation_key_cache_insert_hmac_key(set->key_cache,
cache_key_id, key);
*hmac_key_r = key;
return 0;
}
static int
oauth2_validate_hmac(const struct oauth2_settings *set, const char *azp,
const char *alg, const char *key_id,
const char *const *blobs, const char **error_r)
{
const struct hash_method *method;
if (strcmp(alg, "HS256") == 0)
method = hash_method_lookup("sha256");
else if (strcmp(alg, "HS384") == 0)
method = hash_method_lookup("sha384");
else if (strcmp(alg, "HS512") == 0)
method = hash_method_lookup("sha512");
else {
*error_r = t_strdup_printf("unsupported algorithm '%s'", alg);
return -1;
}
const buffer_t *key;
if (oauth2_lookup_hmac_key(set, azp, alg, key_id, &key, error_r) < 0)
return -1;
struct hmac_context ctx;
hmac_init(&ctx, key->data, key->used, method);
hmac_update(&ctx, blobs[0], strlen(blobs[0]));
hmac_update(&ctx, ".", 1);
hmac_update(&ctx, blobs[1], strlen(blobs[1]));
unsigned char digest[method->digest_size];
hmac_final(&ctx, digest);
buffer_t *their_digest =
t_base64url_decode_str(BASE64_DECODE_FLAG_NO_PADDING, blobs[2]);
if (method->digest_size != their_digest->used ||
!mem_equals_timing_safe(digest, their_digest->data,
method->digest_size)) {
*error_r = "Incorrect JWT signature";
return -1;
}
return 0;
}
static int
oauth2_lookup_pubkey(const struct oauth2_settings *set, const char *azp,
const char *alg, const char *key_id,
struct dcrypt_public_key **key_r, const char **error_r)
{
const char *key_str;
const char *cache_key_id, *lookup_key;
int ret;
cache_key_id = t_strconcat(azp, ".", alg, ".", key_id, NULL);
if (oauth2_validation_key_cache_lookup_pubkey(
set->key_cache, cache_key_id, key_r) == 0)
return 0;
/* do a synchronous dict lookup */
lookup_key = t_strconcat(DICT_PATH_SHARED, azp, "/", alg, "/", key_id,
NULL);
struct dict_op_settings dict_set = {
.username = NULL,
};
if ((ret = dict_lookup(set->key_dict, &dict_set, pool_datastack_create(),
lookup_key, &key_str, error_r)) < 0) {
return -1;
} else if (ret == 0) {
*error_r = t_strdup_printf("%s key '%s' not found",
alg, key_id);
return -1;
}
/* try to load key */
struct dcrypt_public_key *pubkey;
const char *error;
if (!dcrypt_key_load_public(&pubkey, key_str, &error)) {
*error_r = t_strdup_printf("Cannot load key: %s", error);
return -1;
}
/* cache key */
oauth2_validation_key_cache_insert_pubkey(set->key_cache, cache_key_id,
pubkey);
*key_r = pubkey;
return 0;
}
static int
oauth2_validate_rsa_ecdsa(const struct oauth2_settings *set,
const char *azp, const char *alg, const char *key_id,
const char *const *blobs, const char **error_r)
{
const char *method;
enum dcrypt_padding padding;
enum dcrypt_signature_format sig_format;
if (!dcrypt_is_initialized()) {
*error_r = "No crypto library loaded";
return -1;
}
if (str_begins(alg, "RS")) {
padding = DCRYPT_PADDING_RSA_PKCS1;
sig_format = DCRYPT_SIGNATURE_FORMAT_DSS;
} else if (str_begins(alg, "PS")) {
padding = DCRYPT_PADDING_RSA_PKCS1_PSS;
sig_format = DCRYPT_SIGNATURE_FORMAT_DSS;
} else if (str_begins(alg, "ES")) {
padding = DCRYPT_PADDING_DEFAULT;
sig_format = DCRYPT_SIGNATURE_FORMAT_X962;
} else {
/* this should be checked by caller */
i_unreached();
}
if (strcmp(alg+2, "256") == 0) {
method = "sha256";
} else if (strcmp(alg+2, "384") == 0) {
method = "sha384";
} else if (strcmp(alg+2, "512") == 0) {
method = "sha512";
} else {
*error_r = t_strdup_printf("Unsupported algorithm '%s'", alg);
return -1;
}
buffer_t *signature =
t_base64url_decode_str(BASE64_DECODE_FLAG_NO_PADDING, blobs[2]);
struct dcrypt_public_key *pubkey;
if (oauth2_lookup_pubkey(set, azp, alg, key_id, &pubkey, error_r) < 0)
return -1;
/* data to verify */
const char *data = t_strconcat(blobs[0], ".", blobs[1], NULL);
/* verify signature */
bool valid;
if (!dcrypt_verify(pubkey, method, sig_format, data, strlen(data),
signature->data, signature->used, &valid, padding,
error_r)) {
valid = FALSE;
} else if (!valid) {
*error_r = "Bad signature";
}
return valid ? 0 : -1;
}
static int
oauth2_validate_signature(const struct oauth2_settings *set, const char *azp,
const char *alg, const char *key_id,
const char *const *blobs, const char **error_r)
{
if (str_begins(alg, "HS")) {
return oauth2_validate_hmac(set, azp, alg, key_id, blobs,
error_r);
} else if (str_begins(alg, "RS") || str_begins(alg, "PS") ||
str_begins(alg, "ES")) {
return oauth2_validate_rsa_ecdsa(set, azp, alg, key_id, blobs,
error_r);
}
*error_r = t_strdup_printf("Unsupported algorithm '%s'", alg);
return -1;
}
static void
oauth2_jwt_copy_fields(ARRAY_TYPE(oauth2_field) *fields, struct json_tree *tree)
{
pool_t pool = array_get_pool(fields);
ARRAY(const struct json_tree_node*) nodes;
const struct json_tree_node *root = json_tree_root(tree);
t_array_init(&nodes, 1);
array_push_back(&nodes, &root);
while (array_count(&nodes) > 0) {
const struct json_tree_node *const *pnode = array_front(&nodes);
const struct json_tree_node *node = *pnode;
array_pop_front(&nodes);
while (node != NULL) {
if (node->value_type == JSON_TYPE_OBJECT) {
root = node->value.child;
array_push_back(&nodes, &root);
} else if (node->key != NULL) {
struct oauth2_field *field =
array_append_space(fields);
field->name = p_strdup(pool, node->key);
field->value = p_strdup(
pool, json_tree_get_value_str(node));
}
node = node->next;
}
}
}
static int
oauth2_jwt_header_process(struct json_tree *tree, const char **alg_r,
const char **kid_r, const char **error_r)
{
const char *alg = get_field(tree, "alg");
const char *kid = get_field(tree, "kid");
if (alg == NULL) {
*error_r = "Cannot find 'alg' field";
return -1;
}
/* These are lost when tree is deinitialized.
Make sure algorithm is uppercased. */
*alg_r = t_str_ucase(alg);
*kid_r = t_strdup(kid);
return 0;
}
static bool check_scope(const char *req, const char *got)
{
const char *const *scope_req = t_strsplit_spaces(req, " ,");
const char *const *scope_got = t_strsplit_spaces(got, " ,");
for (; *scope_req != NULL; scope_req++)
if (!str_array_icase_find(scope_got, *scope_req))
return FALSE;
return TRUE;
}
static int
oauth2_jwt_body_process(const struct oauth2_settings *set, const char *alg,
const char *kid, ARRAY_TYPE(oauth2_field) *fields,
struct json_tree *tree, const char *const *blobs,
const char **error_r)
{
const char *sub = get_field(tree, "sub");
int ret;
int64_t t0 = time(NULL);
/* default IAT and NBF to now */
int64_t iat, nbf, exp;
int tz_offset ATTR_UNUSED;
if (sub == NULL) {
*error_r = "Missing 'sub' field";
return -1;
}
if ((ret = get_time_field(tree, "exp", &exp)) < 1) {
*error_r = t_strdup_printf("%s 'exp' field",
ret == 0 ? "Missing" : "Malformed");
return -1;
}
if ((ret = get_time_field(tree, "nbf", &nbf)) < 0) {
*error_r = "Malformed 'nbf' field";
return -1;
} else if (ret == 0 || nbf == 0)
nbf = t0;
if ((ret = get_time_field(tree, "iat", &iat)) < 0) {
*error_r = "Malformed 'iat' field";
return -1;
} else if (ret == 0 || iat == 0)
iat = t0;
if (nbf > t0) {
*error_r = "Token is not valid yet";
return -1;
}
if (iat > t0) {
*error_r = "Token is issued in future";
return -1;
}
if (exp < t0) {
*error_r = "Token has expired";
return -1;
}
/* ensure token dates are not conflicting */
if (exp < iat ||
exp < nbf) {
*error_r = "Token time values are conflicting";
return -1;
}
const char *iss = get_field(tree, "iss");
if (set->issuers != NULL && *set->issuers != NULL) {
if (iss == NULL) {
*error_r = "Token is missing 'iss' field";
return -1;
}
if (!str_array_find(set->issuers, iss)) {
*error_r = t_strdup_printf("Issuer '%s' is not allowed",
str_sanitize_utf8(iss, 128));
return -1;
}
}
const char *aud = get_field_multiple(tree, "aud");
/* if there is client_id configured, then aud should be present */
if (set->client_id != NULL && *set->client_id != '\0') {
if (aud == NULL) {
*error_r = "client_id set but aud is missing";
return -1;
}
const char *const *auds = t_strsplit_tabescaped(aud);
if (!str_array_find(auds, set->client_id)) {
*error_r = "client_id not found in aud field";
return -1;
}
}
const char *got_scope = get_field(tree, "scope");
const char *req_scope = set->scope;
if (req_scope != NULL && *req_scope != '\0') {
if (got_scope == NULL) {
*error_r = "scope set but not found in token";
return -1;
}
if (!check_scope(req_scope, got_scope)) {
*error_r = t_strdup_printf("configured scope '%s' missing from token scope '%s'",
req_scope, got_scope);
return -1;
}
}
/* see if there is azp */
const char *azp = get_field(tree, "azp");
if (azp == NULL)
azp = "default";
else
azp = escape_identifier(azp);
if (oauth2_validate_signature(set, azp, alg, kid, blobs, error_r) < 0)
return -1;
oauth2_jwt_copy_fields(fields, tree);
return 0;
}
int oauth2_try_parse_jwt(const struct oauth2_settings *set,
const char *token, ARRAY_TYPE(oauth2_field) *fields,
bool *is_jwt_r, const char **error_r)
{
const char *const *blobs = t_strsplit(token, ".");
int ret;
i_assert(set->key_dict != NULL);
/* we don't know if it's JWT token yet */
*is_jwt_r = FALSE;
if (str_array_length(blobs) != 3) {
*error_r = "Not a JWT token";
return -1;
}
/* attempt to decode header */
buffer_t *header =
t_base64url_decode_str(BASE64_DECODE_FLAG_NO_PADDING, blobs[0]);
if (header->used == 0) {
*error_r = "Not a JWT token";
return -1;
}
struct json_tree *header_tree;
if (oauth2_json_tree_build(header, &header_tree, error_r) < 0)
return -1;
const char *alg, *kid;
ret = oauth2_jwt_header_process(header_tree, &alg, &kid, error_r);
json_tree_deinit(&header_tree);
if (ret < 0)
return -1;
/* it is now assumed to be a JWT token */
*is_jwt_r = TRUE;
if (kid == NULL)
kid = "default";
else if (*kid == '\0') {
*error_r = "'kid' field is empty";
return -1;
} else {
kid = escape_identifier(kid);
}
/* parse body */
struct json_tree *body_tree;
buffer_t *body =
t_base64url_decode_str(BASE64_DECODE_FLAG_NO_PADDING, blobs[1]);
if (oauth2_json_tree_build(body, &body_tree, error_r) == -1)
return -1;
ret = oauth2_jwt_body_process(set, alg, kid, fields, body_tree, blobs,
error_r);
json_tree_deinit(&body_tree);
return ret;
}
dovecot-2.3.21.1/src/lib-oauth2/oauth2.h 0000644 0000000 0000000 00000011404 14656633576 014425 0000000 0000000 #ifndef OAUTH2_H
#define OAUTH2_H
#include "net.h"
struct dict;
struct oauth2_request;
struct oauth2_validation_key_cache;
struct oauth2_field {
const char *name;
const char *value;
};
ARRAY_DEFINE_TYPE(oauth2_field, struct oauth2_field);
struct oauth2_settings {
struct http_client *client;
/* GET tokeninfo from this URL, token is appended to URL
http://some.host/path?access_token= */
const char *tokeninfo_url;
/* POST grant password here, needs user credentials and client_*
settings */
const char *grant_url;
/* GET more information from this URL, uses Bearer authentication */
const char *introspection_url;
/* POST refresh here, needs refresh token and client_* settings */
const char *refresh_url;
/* client identificator for oauth2 server */
const char *client_id;
/* client secret for oauth2 server */
const char *client_secret;
/* access request scope for oauth2 server (optional) */
const char *scope;
/* key dict for looking up validation keys */
struct dict *key_dict;
/* cache for validation keys */
struct oauth2_validation_key_cache *key_cache;
/* valid issuer names */
const char *const *issuers;
enum {
INTROSPECTION_MODE_GET_AUTH,
INTROSPECTION_MODE_GET,
INTROSPECTION_MODE_POST,
INTROSPECTION_MODE_LOCAL,
} introspection_mode;
unsigned int timeout_msecs;
/* Should X-Dovecot-Auth-* headers be sent */
bool send_auth_headers;
/* Should use grant password mechanism for authentication */
bool use_grant_password;
};
struct oauth2_request_result {
/* Oauth2 server response fields */
ARRAY_TYPE(oauth2_field) *fields;
/* Non-NULL if there was an unexpected internal error. */
const char *error;
/* timestamp token expires at */
time_t expires_at;
/* User authenticated successfully. Implies that error==NULL. */
bool valid:1;
};
struct oauth2_request_input {
const char *token;
const char *service;
struct ip_addr local_ip, real_local_ip, remote_ip, real_remote_ip;
in_port_t local_port, real_local_port, remote_port, real_remote_port;
};
typedef void
oauth2_request_callback_t(struct oauth2_request_result*, void*);
bool oauth2_valid_token(const char *token);
struct oauth2_request*
oauth2_passwd_grant_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
const char *username,
const char *password,
oauth2_request_callback_t *callback,
void *context);
#define oauth2_passwd_grant_start(set, input, username, password, callback, \
context) \
oauth2_passwd_grant_start( \
set, input - CALLBACK_TYPECHECK( \
callback, void(*)(struct oauth2_request_result*, \
typeof(context))), \
username, password, \
(oauth2_request_callback_t*)callback, (void*)context);
struct oauth2_request*
oauth2_token_validation_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
oauth2_request_callback_t *callback,
void *context);
#define oauth2_token_validation_start(set, input, callback, context) \
oauth2_token_validation_start( \
set, input - CALLBACK_TYPECHECK( \
callback, void(*)(struct oauth2_request_result*, \
typeof(context))), \
(oauth2_request_callback_t*)callback, (void*)context);
struct oauth2_request*
oauth2_introspection_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
oauth2_request_callback_t *callback,
void *context);
#define oauth2_introspection_start(set, input, callback, context) \
oauth2_introspection_start( \
set, input - CALLBACK_TYPECHECK( \
callback, void(*)(struct oauth2_request_result*, \
typeof(context))), \
(oauth2_request_callback_t*)callback, (void*)context);
struct oauth2_request *
oauth2_refresh_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
oauth2_request_callback_t *callback,
void *context);
#define oauth2_refresh_start(set, input, callback, context) \
oauth2_refresh_start( \
set, input - CALLBACK_TYPECHECK( \
callback, void(*)(struct oauth2_request_result*, \
typeof(context))), \
(oauth2_request_callback_t*)callback, (void*)context);
/* Abort without calling callback, use this to cancel the request */
void oauth2_request_abort(struct oauth2_request **);
int oauth2_try_parse_jwt(const struct oauth2_settings *set,
const char *token, ARRAY_TYPE(oauth2_field) *fields,
bool *is_jwt_r, const char **error_r);
/* Initialize validation key cache */
struct oauth2_validation_key_cache *oauth2_validation_key_cache_init(void);
/* Evict given key ID from cache, returns 0 on successful eviction */
int oauth2_validation_key_cache_evict(struct oauth2_validation_key_cache *cache,
const char *key_id);
/* Deinitialize validation key cache */
void oauth2_validation_key_cache_deinit(
struct oauth2_validation_key_cache **_cache);
#endif
dovecot-2.3.21.1/src/lib-oauth2/oauth2-request.c 0000644 0000000 0000000 00000023771 14656633576 016120 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "istream.h"
#include "str.h"
#include "http-client.h"
#include "http-url.h"
#include "json-parser.h"
#include "oauth2.h"
#include "oauth2-private.h"
static void oauth2_request_free(struct oauth2_request *req)
{
timeout_remove(&req->to_delayed_error);
pool_unref(&req->pool);
}
static void
oauth2_request_callback(struct oauth2_request *req,
struct oauth2_request_result *res)
{
i_assert(req->req_callback != NULL);
oauth2_request_callback_t *callback = req->req_callback;
req->req_callback = NULL;
callback(res, req->req_context);
oauth2_request_free(req);
}
static bool
oauth2_request_field_parse(const struct oauth2_field *field,
struct oauth2_request_result *res)
{
if (strcasecmp(field->name, "expires_in") == 0) {
uint32_t expires_in = 0;
if (str_to_uint32(field->value, &expires_in) < 0) {
res->error = t_strdup_printf(
"Malformed number '%s' in expires_in",
field->value);
return FALSE;
} else {
res->expires_at = ioloop_time + expires_in;
}
} else if (strcasecmp(field->name, "token_type") == 0) {
if (strcasecmp(field->value, "bearer") != 0) {
res->error = t_strdup_printf(
"Expected Bearer token, got '%s'",
field->value);
return FALSE;
}
}
return TRUE;
}
static void
oauth2_request_continue(struct oauth2_request *req, const char *error)
{
struct oauth2_request_result res;
i_zero(&res);
unsigned int status_hi = req->response_status/100;
i_assert(status_hi == 2 || status_hi == 4);
if (error != NULL)
res.error = error;
else {
const struct oauth2_field *field;
/* see if we can figure out when it expires */
array_foreach(&req->fields, field) {
if (!oauth2_request_field_parse(field, &res))
break;
}
res.valid = (status_hi == 2) && res.error == NULL;
}
res.fields = &req->fields;
oauth2_request_callback(req, &res);
}
void oauth2_request_parse_json(struct oauth2_request *req)
{
enum json_type type;
const char *token, *error;
int ret;
while((ret = json_parse_next(req->parser, &type, &token)) > 0) {
if (req->field_name == NULL) {
if (type != JSON_TYPE_OBJECT_KEY) break;
/* cannot use t_strdup because we might
have to read more */
req->field_name = p_strdup(req->pool, token);
} else if (type < JSON_TYPE_STRING) {
/* this should be last allocation */
p_free(req->pool, req->field_name);
json_parse_skip(req->parser);
} else {
if (!array_is_created(&req->fields))
p_array_init(&req->fields, req->pool, 4);
struct oauth2_field *field =
array_append_space(&req->fields);
field->name = req->field_name;
req->field_name = NULL;
field->value = p_strdup(req->pool, token);
}
}
/* read more */
if (ret == 0) return;
io_remove(&req->io);
if (ret > 0) {
(void)json_parser_deinit(&req->parser, &error);
error = "Invalid response data";
} else if (i_stream_read_eof(req->is) &&
req->is->v_offset == 0 && req->is->stream_errno == 0) {
/* discard error, empty response is OK. */
(void)json_parser_deinit(&req->parser, &error);
error = NULL;
} else if (json_parser_deinit(&req->parser, &error) == 0) {
error = NULL;
} else {
i_assert(error != NULL);
}
i_stream_unref(&req->is);
req->json_parsed_cb(req, error);
}
static void
oauth2_request_response(const struct http_response *response,
struct oauth2_request *req)
{
req->response_status = response->status;
unsigned int status_hi = req->response_status/100;
if (status_hi != 2 && status_hi != 4) {
/* Unexpected internal error */
struct oauth2_request_result res = {
.error = http_response_get_message(response),
};
oauth2_request_callback(req, &res);
return;
}
if (response->payload != NULL) {
req->is = response->payload;
i_stream_ref(req->is);
} else {
req->is = i_stream_create_from_data("", 0);
}
p_array_init(&req->fields, req->pool, 1);
req->parser = json_parser_init(req->is);
req->json_parsed_cb = oauth2_request_continue;
req->io = io_add_istream(req->is, oauth2_request_parse_json, req);
oauth2_request_parse_json(req);
}
static void
oauth2_request_fail(struct oauth2_request *req)
{
struct oauth2_request_result res = {
.error = "No token provided",
.valid = FALSE,
};
oauth2_request_callback(req, &res);
}
static void
oauth2_request_set_headers(struct oauth2_request *req,
const struct oauth2_request_input *input)
{
if (!req->set->send_auth_headers)
return;
if (input->service != NULL) {
http_client_request_add_header(
req->req, "X-Dovecot-Auth-Service", input->service);
}
if (input->local_ip.family != 0) {
const char *addr;
if (net_ipport2str(&input->local_ip, input->local_port,
&addr) == 0) {
http_client_request_add_header(
req->req, "X-Dovecot-Auth-Local", addr);
}
}
if (input->remote_ip.family != 0) {
const char *addr;
if (net_ipport2str(&input->remote_ip, input->remote_port,
&addr) == 0) {
http_client_request_add_header(
req->req, "X-Dovecot-Auth-Remote", addr);
}
}
}
static struct oauth2_request *
oauth2_request_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
oauth2_request_callback_t *callback,
void *context,
pool_t p,
const char *method,
const char *url,
const string_t *payload,
bool add_auth_bearer)
{
pool_t pool = (p == NULL) ?
pool_alloconly_create_clean("oauth2 request", 1024) : p;
struct oauth2_request *req =
p_new(pool, struct oauth2_request, 1);
req->pool = pool;
req->set = set;
req->req_callback = callback;
req->req_context = context;
if (!oauth2_valid_token(input->token)) {
req->to_delayed_error =
timeout_add_short(0, oauth2_request_fail, req);
return req;
}
req->req = http_client_request_url_str(req->set->client, method, url,
oauth2_request_response, req);
oauth2_request_set_headers(req, input);
if (payload != NULL && strcmp(method, "POST") == 0) {
struct istream *is = i_stream_create_from_string(payload);
http_client_request_add_header(
req->req, "Content-Type",
"application/x-www-form-urlencoded");
http_client_request_set_payload(req->req, is, FALSE);
i_stream_unref(&is);
}
if (add_auth_bearer &&
http_client_request_get_origin_url(req->req)->user == NULL &&
set->introspection_mode == INTROSPECTION_MODE_GET_AUTH) {
http_client_request_add_header(req->req,
"Authorization",
t_strdup_printf("Bearer %s",
input->token));
}
http_client_request_set_timeout_msecs(req->req,
req->set->timeout_msecs);
http_client_request_submit(req->req);
return req;
}
#undef oauth2_refresh_start
struct oauth2_request *
oauth2_refresh_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
oauth2_request_callback_t *callback, void *context)
{
string_t *payload = t_str_new(128);
str_append(payload, "grant_type=refresh_token&refresh_token=");
http_url_escape_param(payload, input->token);
return oauth2_request_start(set, input, callback, context, NULL,
"POST", set->refresh_url, NULL, FALSE);
}
#undef oauth2_introspection_start
struct oauth2_request *
oauth2_introspection_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
oauth2_request_callback_t *callback, void *context)
{
string_t *enc;
const char *url;
const char *method;
string_t *payload = NULL;
pool_t p = NULL;
switch (set->introspection_mode) {
case INTROSPECTION_MODE_GET:
enc = t_str_new(64);
str_append(enc, set->introspection_url);
http_url_escape_param(enc, input->token);
if (*set->client_id != '\0') {
str_append(enc, "&client_id=");
http_url_escape_param(enc, set->client_id);
}
if (*set->client_secret != '\0') {
str_append(enc, "&client_secret=");
http_url_escape_param(enc, set->client_secret);
}
url = str_c(enc);
method = "GET";
break;
case INTROSPECTION_MODE_GET_AUTH:
url = set->introspection_url;
method = "GET";
break;
case INTROSPECTION_MODE_POST:
p = pool_alloconly_create_clean("oauth2 request", 1024);
payload = str_new(p, strlen(input->token)+6);
str_append(payload, "token=");
http_url_escape_param(payload, input->token);
url = set->introspection_url;
method = "POST";
break;
default:
i_unreached();
break;
}
return oauth2_request_start(set, input, callback, context, p,
method, url, payload, TRUE);
}
#undef oauth2_token_validation_start
struct oauth2_request *
oauth2_token_validation_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
oauth2_request_callback_t *callback,
void *context)
{
string_t *enc = t_str_new(64);
str_append(enc, set->tokeninfo_url);
http_url_escape_param(enc, input->token);
return oauth2_request_start(set, input, callback, context,
NULL, "GET", str_c(enc), NULL, TRUE);
}
#undef oauth2_passwd_grant_start
struct oauth2_request *
oauth2_passwd_grant_start(const struct oauth2_settings *set,
const struct oauth2_request_input *input,
const char *username, const char *password,
oauth2_request_callback_t *callback, void *context)
{
pool_t pool = pool_alloconly_create_clean("oauth2 request", 1024);
string_t *payload = str_new(pool, 128);
/* add token */
str_append(payload, "grant_type=password&username=");
http_url_escape_param(payload, username);
str_append(payload, "&password=");
http_url_escape_param(payload, password);
if (*set->client_id != '\0') {
str_append(payload, "&client_id=");
http_url_escape_param(payload, set->client_id);
}
if (*set->client_secret != '\0') {
str_append(payload, "&client_secret=");
http_url_escape_param(payload, set->client_secret);
}
if (set->scope[0] != '\0') {
str_append(payload, "&scope=");
http_url_escape_param(payload, set->scope);
}
return oauth2_request_start(set, input, callback, context,
pool, "POST", set->grant_url,
payload, FALSE);
}
void oauth2_request_abort(struct oauth2_request **_req)
{
struct oauth2_request *req = *_req;
*_req = NULL;
http_client_request_abort(&req->req);
oauth2_request_free(req);
}
dovecot-2.3.21.1/src/lib-oauth2/oauth2-private.h 0000644 0000000 0000000 00000002603 14656633576 016076 0000000 0000000 #ifndef OAUTH2_PRIVATE_H
#define OAUTH2_PRIVATE_H
struct json_tree;
struct dcrypt_public_key;
struct oauth2_request {
pool_t pool;
const struct oauth2_settings *set;
struct http_client_request *req;
struct json_parser *parser;
struct istream *is;
struct io *io;
const char *delayed_error;
struct timeout *to_delayed_error;
const char *username;
const char *key_file_template;
void (*json_parsed_cb)(struct oauth2_request *, const char *error);
ARRAY_TYPE(oauth2_field) fields;
char *field_name;
oauth2_request_callback_t *req_callback;
void *req_context;
/* indicates whether token is valid */
unsigned int response_status;
};
void oauth2_request_parse_json(struct oauth2_request *req);
int oauth2_json_tree_build(const buffer_t *json, struct json_tree **tree_r,
const char **error_r);
int oauth2_validation_key_cache_lookup_pubkey(
struct oauth2_validation_key_cache *cache, const char *key_id,
struct dcrypt_public_key **pubkey_r);
int oauth2_validation_key_cache_lookup_hmac_key(
struct oauth2_validation_key_cache *cache, const char *key_id,
const buffer_t **hmac_key_r);
void oauth2_validation_key_cache_insert_pubkey(
struct oauth2_validation_key_cache *cache, const char *key_id,
struct dcrypt_public_key *pubkey);
void oauth2_validation_key_cache_insert_hmac_key(
struct oauth2_validation_key_cache *cache, const char *key_id,
const buffer_t *hmac_key);
#endif
dovecot-2.3.21.1/src/lib-oauth2/oauth2.c 0000644 0000000 0000000 00000002033 14656633576 014416 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "istream.h"
#include "json-tree.h"
#include "oauth2.h"
#include "oauth2-private.h"
int oauth2_json_tree_build(const buffer_t *json, struct json_tree **tree_r,
const char **error_r)
{
struct istream *is = i_stream_create_from_buffer(json);
struct json_parser *parser = json_parser_init(is);
struct json_tree *tree = json_tree_init();
enum json_type type;
const char *value;
int ret;
while ((ret = json_parse_next(parser, &type, &value)) > 0) {
/* this is safe to reuse here because it gets rewritten in while
loop */
ret = json_tree_append(tree, type, value);
i_assert(ret == 0);
}
i_assert(ret != 0);
ret = json_parser_deinit(&parser, error_r);
i_stream_unref(&is);
if (ret != 0)
json_tree_deinit(&tree);
else
*tree_r = tree;
return ret;
}
bool oauth2_valid_token(const char *token)
{
if (token == NULL || *token == '\0' || strpbrk(token, "\r\n") != NULL)
return FALSE;
return TRUE;
}
dovecot-2.3.21.1/src/lib-oauth2/Makefile.am 0000644 0000000 0000000 00000003237 14656633576 015113 0000000 0000000 AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-http \
-I$(top_srcdir)/src/lib-dcrypt \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-settings
noinst_LTLIBRARIES=liboauth2.la
pkginc_libdir=$(pkgincludedir)
pkginc_lib_HEADERS = \
oauth2.h
noinst_HEADERS = \
oauth2-private.h
liboauth2_la_SOURCES = \
oauth2.c \
oauth2-request.c \
oauth2-jwt.c \
oauth2-key-cache.c
test_programs = \
test-oauth2-json \
test-oauth2-jwt
noinst_PROGRAMS = $(test_programs)
test_libs = \
$(noinst_LTLIBRARIES) \
../lib-dcrypt/libdcrypt.la \
../lib-http/libhttp.la \
../lib-dns/libdns.la \
../lib-ssl-iostream/libssl_iostream.la \
../lib-master/libmaster.la \
../lib-auth/libauth.la \
../lib-dict/libdict.la \
../lib-settings/libsettings.la \
../lib-test/libtest.la \
../lib/liblib.la \
$(MODULE_LIBS)
test_deps = \
$(noinst_LTLIBRARIES) \
../lib-dcrypt/libdcrypt.la \
../lib-http/libhttp.la \
../lib-dns/libdns.la \
../lib-ssl-iostream/libssl_iostream.la \
../lib-master/libmaster.la \
../lib-auth/libauth.la \
../lib-dict/libdict.la \
../lib-settings/libsettings.la \
../lib-test/libtest.la \
../lib/liblib.la
test_oauth2_json_SOURCES = test-oauth2-json.c
test_oauth2_json_LDADD = $(test_libs)
test_oauth2_json_DEPENDENCIES = $(test_deps)
test_oauth2_jwt_SOURCES = test-oauth2-jwt.c
test_oauth2_jwt_LDADD = $(test_libs)
if HAVE_WHOLE_ARCHIVE
test_oauth2_jwt_LDFLAGS = -Wl,$(LD_WHOLE_ARCHIVE),../lib-ssl-iostream/.libs/libssl_iostream.a,$(LD_NO_WHOLE_ARCHIVE)
endif
test_oauth2_jwt_DEPENDENCIES = $(test_deps)
check-local:
for bin in $(test_programs); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
dovecot-2.3.21.1/src/pop3-login/ 0000755 0000000 0000000 00000000000 14656633640 013143 5 0000000 0000000 dovecot-2.3.21.1/src/pop3-login/pop3-proxy.h 0000644 0000000 0000000 00000000553 14656633576 015307 0000000 0000000 #ifndef POP3_PROXY_H
#define POP3_PROXY_H
void pop3_proxy_reset(struct client *client);
int pop3_proxy_parse_line(struct client *client, const char *line);
void pop3_proxy_failed(struct client *client,
enum login_proxy_failure_type type,
const char *reason, bool reconnecting);
const char *pop3_proxy_get_state(struct client *client);
#endif
dovecot-2.3.21.1/src/pop3-login/pop3-login-settings.c 0000644 0000000 0000000 00000003652 14656633576 017072 0000000 0000000 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "login-settings.h"
#include "pop3-login-settings.h"
#include
/* */
static struct inet_listener_settings pop3_login_inet_listeners_array[] = {
{ .name = "pop3", .address = "", .port = 110 },
{ .name = "pop3s", .address = "", .port = 995, .ssl = TRUE }
};
static struct inet_listener_settings *pop3_login_inet_listeners[] = {
&pop3_login_inet_listeners_array[0],
&pop3_login_inet_listeners_array[1]
};
static buffer_t pop3_login_inet_listeners_buf = {
{ { pop3_login_inet_listeners, sizeof(pop3_login_inet_listeners) } }
};
/* */
struct service_settings pop3_login_service_settings = {
.name = "pop3-login",
.protocol = "pop3",
.type = "login",
.executable = "pop3-login",
.user = "$default_login_user",
.group = "",
.privileged_group = "",
.extra_groups = "",
.chroot = "login",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 0,
.client_limit = 0,
.service_count = 1,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = ARRAY_INIT,
.fifo_listeners = ARRAY_INIT,
.inet_listeners = { { &pop3_login_inet_listeners_buf,
sizeof(pop3_login_inet_listeners[0]) } }
};
static const struct setting_define pop3_login_setting_defines[] = {
SETTING_DEFINE_LIST_END
};
static const struct setting_parser_info *pop3_login_setting_dependencies[] = {
&login_setting_parser_info,
NULL
};
const struct setting_parser_info pop3_login_setting_parser_info = {
.module_name = "pop3-login",
.defines = pop3_login_setting_defines,
.type_offset = SIZE_MAX,
.parent_offset = SIZE_MAX,
.dependencies = pop3_login_setting_dependencies
};
const struct setting_parser_info *pop3_login_setting_roots[] = {
&login_setting_parser_info,
&pop3_login_setting_parser_info,
NULL
};
dovecot-2.3.21.1/src/pop3-login/client-authenticate.c 0000644 0000000 0000000 00000016376 14656633576 017206 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "login-common.h"
#include "base64.h"
#include "buffer.h"
#include "hex-binary.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "safe-memset.h"
#include "str.h"
#include "str-sanitize.h"
#include "auth-client.h"
#include "../pop3/pop3-capability.h"
#include "client.h"
#include "client-authenticate.h"
#include "pop3-proxy.h"
static const char *capability_string = POP3_CAPABILITY_REPLY;
bool cmd_capa(struct pop3_client *client, const char *args ATTR_UNUSED)
{
const struct auth_mech_desc *mech;
unsigned int i, count;
string_t *str;
str = t_str_new(128);
str_append(str, "+OK\r\n");
str_append(str, capability_string);
if (client_is_tls_enabled(&client->common) && !client->common.tls)
str_append(str, "STLS\r\n");
if (!client->common.set->disable_plaintext_auth ||
client->common.secured)
str_append(str, "USER\r\n");
str_append(str, "SASL");
mech = sasl_server_get_advertised_mechs(&client->common, &count);
for (i = 0; i < count; i++) {
str_append_c(str, ' ');
str_append(str, mech[i].name);
}
str_append(str, "\r\n.\r\n");
client_send_raw(&client->common, str_c(str));
return TRUE;
}
void pop3_client_auth_result(struct client *client,
enum client_auth_result result,
const struct client_auth_reply *reply ATTR_UNUSED,
const char *text)
{
switch (result) {
case CLIENT_AUTH_RESULT_SUCCESS:
/* nothing to be done for POP3 */
break;
case CLIENT_AUTH_RESULT_TEMPFAIL:
client_send_reply(client, POP3_CMD_REPLY_TEMPFAIL, text);
break;
case CLIENT_AUTH_RESULT_AUTHFAILED:
case CLIENT_AUTH_RESULT_AUTHFAILED_REASON:
case CLIENT_AUTH_RESULT_AUTHZFAILED:
case CLIENT_AUTH_RESULT_PASS_EXPIRED:
case CLIENT_AUTH_RESULT_SSL_REQUIRED:
case CLIENT_AUTH_RESULT_LOGIN_DISABLED:
case CLIENT_AUTH_RESULT_MECH_INVALID:
case CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED:
case CLIENT_AUTH_RESULT_INVALID_BASE64:
client_send_reply(client, POP3_CMD_REPLY_AUTH_ERROR, text);
break;
default:
client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
break;
}
}
int cmd_auth(struct pop3_client *pop3_client)
{
/* NOTE: This command's input is handled specially because the
SASL-IR can be large. */
struct client *client = &pop3_client->common;
const unsigned char *data;
size_t i, size;
int ret;
/* [] */
if (!pop3_client->auth_mech_name_parsed) {
data = i_stream_get_data(client->input, &size);
for (i = 0; i < size; i++) {
if (data[i] == ' ' ||
data[i] == '\r' || data[i] == '\n')
break;
}
if (i == size)
return 0;
if (i == 0) {
/* Old-style SASL discovery, used by MS Outlook */
unsigned int i, count;
const struct auth_mech_desc *mech;
client_send_raw(client, "+OK\r\n");
mech = sasl_server_get_advertised_mechs(client, &count);
for (i = 0; i < count; i++) {
client_send_raw(client, mech[i].name);
client_send_raw(client, "\r\n");
}
client_send_raw(client, ".\r\n");
(void)i_stream_read_next_line(client->input);
return 1;
}
i_free(client->auth_mech_name);
client->auth_mech_name = i_strndup(data, i);
pop3_client->auth_mech_name_parsed = TRUE;
if (data[i] == ' ')
i++;
i_stream_skip(client->input, i);
}
/* get SASL-IR, if any */
if ((ret = client_auth_read_line(client)) <= 0)
return ret;
const char *ir = NULL;
if (client->auth_response->used > 0)
ir = t_strdup(str_c(client->auth_response));
pop3_client->auth_mech_name_parsed = FALSE;
/* The whole AUTH line command is parsed now. The rest of the SASL
protocol exchange happens in login-common code. We can free the
current command here already, because no pop3-login code is called
until the authentication is finished. Also, there's currently no
single location that is called in pop3-login code after the
authentication is finished. For example it could be an auth failure
or it could be a successful authentication with a proxying
failure. */
i_free(pop3_client->current_cmd);
return client_auth_begin(client, t_strdup(client->auth_mech_name), ir);
}
bool cmd_user(struct pop3_client *pop3_client, const char *args)
{
if (!client_check_plaintext_auth(&pop3_client->common, FALSE)) {
if (pop3_client->common.virtual_user == NULL)
pop3_client->common.virtual_user = i_strdup(args);
return TRUE;
}
i_free(pop3_client->last_user);
pop3_client->last_user = i_strdup(args);
client_send_raw(&pop3_client->common, "+OK\r\n");
return TRUE;
}
bool cmd_pass(struct pop3_client *pop3_client, const char *args)
{
struct client *client = &pop3_client->common;
string_t *plain_login, *base64;
if (pop3_client->last_user == NULL) {
/* client may ignore the USER reply and only display the error
message from PASS */
if (!client_check_plaintext_auth(client, TRUE))
return TRUE;
client_send_reply(client, POP3_CMD_REPLY_ERROR,
"No username given.");
return TRUE;
}
/* authorization ID \0 authentication ID \0 pass */
plain_login = t_str_new(128);
str_append_c(plain_login, '\0');
str_append(plain_login, pop3_client->last_user);
str_append_c(plain_login, '\0');
str_append(plain_login, args);
i_free_and_null(pop3_client->last_user);
base64 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(plain_login->used));
base64_encode(plain_login->data, plain_login->used, base64);
(void)client_auth_begin(client, "PLAIN", str_c(base64));
return TRUE;
}
bool cmd_apop(struct pop3_client *pop3_client, const char *args)
{
struct client *client = &pop3_client->common;
buffer_t *apop_data, *base64;
const char *p;
unsigned int server_pid, connect_uid;
if (pop3_client->apop_challenge == NULL) {
if (client->set->auth_verbose)
e_info(client->event, "APOP failed: APOP not enabled");
client_send_reply(client, POP3_CMD_REPLY_ERROR,
"APOP not enabled.");
return TRUE;
}
/* */
p = strchr(args, ' ');
if (p == NULL || strlen(p+1) != 32) {
if (client->set->auth_verbose)
e_info(client->event, "APOP failed: Invalid parameters");
client_send_reply(client, POP3_CMD_REPLY_ERROR,
"Invalid parameters.");
return TRUE;
}
/* APOP challenge \0 username \0 APOP response */
apop_data = t_buffer_create(128);
buffer_append(apop_data, pop3_client->apop_challenge,
strlen(pop3_client->apop_challenge)+1);
buffer_append(apop_data, args, (size_t)(p-args));
buffer_append_c(apop_data, '\0');
if (hex_to_binary(p+1, apop_data) < 0) {
if (client->set->auth_verbose) {
e_info(client->event, "APOP failed: "
"Invalid characters in MD5 response");
}
client_send_reply(client, POP3_CMD_REPLY_ERROR,
"Invalid characters in MD5 response.");
return TRUE;
}
base64 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(apop_data->used));
base64_encode(apop_data->data, apop_data->used, base64);
auth_client_get_connect_id(auth_client, &server_pid, &connect_uid);
if (pop3_client->apop_server_pid != server_pid ||
pop3_client->apop_connect_uid != connect_uid) {
/* we reconnected to auth server and can't authenticate
with APOP in this session anymore. disconnecting the user
is probably the best solution now. */
client_destroy(client,
"Reconnected to auth server, can't do APOP");
return TRUE;
}
(void)client_auth_begin_private(client, "APOP", str_c(base64));
return TRUE;
}
dovecot-2.3.21.1/src/pop3-login/Makefile.in 0000644 0000000 0000000 00000064140 14656633613 015135 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = pop3-login$(EXEEXT)
subdir = src/pop3-login
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_pop3_login_OBJECTS = client.$(OBJEXT) client-authenticate.$(OBJEXT) \
pop3-login-settings.$(OBJEXT) pop3-proxy.$(OBJEXT)
pop3_login_OBJECTS = $(am_pop3_login_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/client-authenticate.Po \
./$(DEPDIR)/client.Po ./$(DEPDIR)/pop3-login-settings.Po \
./$(DEPDIR)/pop3-proxy.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(pop3_login_SOURCES)
DIST_SOURCES = $(pop3_login_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(noinst_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-sasl \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/login-common \
$(BINARY_CFLAGS)
pop3_login_LDADD = \
$(LIBDOVECOT_LOGIN) \
$(LIBDOVECOT) \
$(SSL_LIBS) \
$(BINARY_LDFLAGS)
pop3_login_DEPENDENCIES = \
$(LIBDOVECOT_LOGIN) \
$(LIBDOVECOT_DEPS)
pop3_login_SOURCES = \
client.c \
client-authenticate.c \
pop3-login-settings.c \
pop3-proxy.c
noinst_HEADERS = \
client.h \
client-authenticate.h \
pop3-login-settings.h \
pop3-proxy.h
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/pop3-login/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/pop3-login/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
pop3-login$(EXEEXT): $(pop3_login_OBJECTS) $(pop3_login_DEPENDENCIES) $(EXTRA_pop3_login_DEPENDENCIES)
@rm -f pop3-login$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(pop3_login_OBJECTS) $(pop3_login_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-authenticate.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pop3-login-settings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pop3-proxy.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/client-authenticate.Po
-rm -f ./$(DEPDIR)/client.Po
-rm -f ./$(DEPDIR)/pop3-login-settings.Po
-rm -f ./$(DEPDIR)/pop3-proxy.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/client-authenticate.Po
-rm -f ./$(DEPDIR)/client.Po
-rm -f ./$(DEPDIR)/pop3-login-settings.Po
-rm -f ./$(DEPDIR)/pop3-proxy.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-pkglibexecPROGRAMS install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/pop3-login/client.h 0000644 0000000 0000000 00000001345 14656633576 014525 0000000 0000000 #ifndef CLIENT_H
#define CLIENT_H
#include "net.h"
#include "client-common.h"
#include "auth-client.h"
enum pop3_proxy_state {
POP3_PROXY_BANNER = 0,
POP3_PROXY_STARTTLS,
POP3_PROXY_XCLIENT,
POP3_PROXY_LOGIN1,
POP3_PROXY_LOGIN2,
POP3_PROXY_STATE_COUNT
};
struct pop3_client {
struct client common;
char *current_cmd;
char *last_user;
char *apop_challenge;
unsigned int apop_server_pid, apop_connect_uid;
enum pop3_proxy_state proxy_state;
bool proxy_xclient;
bool auth_mech_name_parsed;
};
enum pop3_cmd_reply {
POP3_CMD_REPLY_OK,
POP3_CMD_REPLY_ERROR,
POP3_CMD_REPLY_AUTH_ERROR,
POP3_CMD_REPLY_TEMPFAIL
};
void client_send_reply(struct client *client, enum pop3_cmd_reply reply,
const char *text);
#endif
dovecot-2.3.21.1/src/pop3-login/client-authenticate.h 0000644 0000000 0000000 00000001012 14656633576 017170 0000000 0000000 #ifndef CLIENT_AUTHENTICATE_H
#define CLIENT_AUTHENTICATE_H
void pop3_client_auth_result(struct client *client,
enum client_auth_result result,
const struct client_auth_reply *reply,
const char *text);
bool cmd_capa(struct pop3_client *client, const char *args);
bool cmd_user(struct pop3_client *client, const char *args);
bool cmd_pass(struct pop3_client *client, const char *args);
int cmd_auth(struct pop3_client *client);
bool cmd_apop(struct pop3_client *client, const char *args);
#endif
dovecot-2.3.21.1/src/pop3-login/Makefile.am 0000644 0000000 0000000 00000001234 14656633576 015127 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = pop3-login
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-sasl \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/login-common \
$(BINARY_CFLAGS)
pop3_login_LDADD = \
$(LIBDOVECOT_LOGIN) \
$(LIBDOVECOT) \
$(SSL_LIBS) \
$(BINARY_LDFLAGS)
pop3_login_DEPENDENCIES = \
$(LIBDOVECOT_LOGIN) \
$(LIBDOVECOT_DEPS)
pop3_login_SOURCES = \
client.c \
client-authenticate.c \
pop3-login-settings.c \
pop3-proxy.c
noinst_HEADERS = \
client.h \
client-authenticate.h \
pop3-login-settings.h \
pop3-proxy.h
dovecot-2.3.21.1/src/pop3-login/pop3-proxy.c 0000644 0000000 0000000 00000023347 14656633576 015310 0000000 0000000 /* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "login-common.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "base64.h"
#include "safe-memset.h"
#include "str.h"
#include "str-sanitize.h"
#include "strescape.h"
#include "dsasl-client.h"
#include "client.h"
#include "pop3-proxy.h"
static const char *pop3_proxy_state_names[POP3_PROXY_STATE_COUNT] = {
"banner", "starttls", "xclient", "login1", "login2"
};
static int proxy_send_login(struct pop3_client *client, struct ostream *output)
{
struct dsasl_client_settings sasl_set;
const unsigned char *sasl_output;
size_t len;
const char *mech_name, *error;
string_t *str = t_str_new(128);
i_assert(client->common.proxy_ttl > 1);
if (client->proxy_xclient &&
!client->common.proxy_not_trusted) {
string_t *fwd = t_str_new(128);
for(const char *const *ptr = client->common.auth_passdb_args;*ptr != NULL; ptr++) {
if (strncasecmp(*ptr, "forward_", 8) == 0) {
if (str_len(fwd) > 0)
str_append_c(fwd, '\t');
str_append_tabescaped(fwd, (*ptr)+8);
}
}
str_printfa(str, "XCLIENT ADDR=%s PORT=%u SESSION=%s TTL=%u",
net_ip2addr(&client->common.ip),
client->common.remote_port,
client_get_session_id(&client->common),
client->common.proxy_ttl - 1);
if (str_len(fwd) > 0) {
str_append(str, " FORWARD=");
base64_encode(str_data(fwd), str_len(fwd), str);
}
str_append(str, "\r\n");
/* remote supports XCLIENT, send it */
o_stream_nsend(output, str_data(str), str_len(str));
client->proxy_state = POP3_PROXY_XCLIENT;
} else {
client->proxy_state = POP3_PROXY_LOGIN1;
}
str_truncate(str, 0);
if (client->common.proxy_mech == NULL) {
/* send USER command */
str_append(str, "USER ");
str_append(str, client->common.proxy_user);
str_append(str, "\r\n");
o_stream_nsend(output, str_data(str), str_len(str));
return 0;
}
i_assert(client->common.proxy_sasl_client == NULL);
i_zero(&sasl_set);
sasl_set.authid = client->common.proxy_master_user != NULL ?
client->common.proxy_master_user : client->common.proxy_user;
sasl_set.authzid = client->common.proxy_user;
sasl_set.password = client->common.proxy_password;
client->common.proxy_sasl_client =
dsasl_client_new(client->common.proxy_mech, &sasl_set);
mech_name = dsasl_client_mech_get_name(client->common.proxy_mech);
str_printfa(str, "AUTH %s ", mech_name);
if (dsasl_client_output(client->common.proxy_sasl_client,
&sasl_output, &len, &error) < 0) {
const char *reason = t_strdup_printf(
"SASL mechanism %s init failed: %s",
mech_name, error);
login_proxy_failed(client->common.login_proxy,
login_proxy_get_event(client->common.login_proxy),
LOGIN_PROXY_FAILURE_TYPE_INTERNAL, reason);
return -1;
}
if (len == 0)
str_append_c(str, '=');
else
base64_encode(sasl_output, len, str);
str_append(str, "\r\n");
o_stream_nsend(output, str_data(str), str_len(str));
if (client->proxy_state != POP3_PROXY_XCLIENT)
client->proxy_state = POP3_PROXY_LOGIN2;
return 0;
}
static int
pop3_proxy_continue_sasl_auth(struct client *client, struct ostream *output,
const char *line)
{
string_t *str;
const unsigned char *data;
size_t data_len;
const char *error;
int ret;
str = t_str_new(128);
if (base64_decode(line, strlen(line), NULL, str) < 0) {
const char *reason = t_strdup_printf(
"Invalid base64 data in AUTH response");
login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
return -1;
}
ret = dsasl_client_input(client->proxy_sasl_client,
str_data(str), str_len(str), &error);
if (ret == 0) {
ret = dsasl_client_output(client->proxy_sasl_client,
&data, &data_len, &error);
}
if (ret < 0) {
const char *reason = t_strdup_printf(
"Invalid authentication data: %s", error);
login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
return -1;
}
i_assert(ret == 0);
str_truncate(str, 0);
base64_encode(data, data_len, str);
str_append(str, "\r\n");
o_stream_nsend(output, str_data(str), str_len(str));
return 0;
}
int pop3_proxy_parse_line(struct client *client, const char *line)
{
struct pop3_client *pop3_client = (struct pop3_client *)client;
struct ostream *output;
enum login_proxy_ssl_flags ssl_flags;
i_assert(!client->destroyed);
output = login_proxy_get_ostream(client->login_proxy);
switch (pop3_client->proxy_state) {
case POP3_PROXY_BANNER:
/* this is a banner */
if (!str_begins(line, "+OK")) {
const char *reason = t_strdup_printf(
"Invalid banner: %s", str_sanitize(line, 160));
login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
return -1;
}
pop3_client->proxy_xclient =
str_begins(line+3, " [XCLIENT]");
ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
if (proxy_send_login(pop3_client, output) < 0)
return -1;
} else {
o_stream_nsend_str(output, "STLS\r\n");
pop3_client->proxy_state = POP3_PROXY_STARTTLS;
}
return 0;
case POP3_PROXY_STARTTLS:
if (!str_begins(line, "+OK")) {
const char *reason = t_strdup_printf(
"STLS failed: %s", str_sanitize(line, 160));
login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
return -1;
}
if (login_proxy_starttls(client->login_proxy) < 0)
return -1;
/* i/ostreams changed. */
output = login_proxy_get_ostream(client->login_proxy);
if (proxy_send_login(pop3_client, output) < 0)
return -1;
return 1;
case POP3_PROXY_XCLIENT:
if (!str_begins(line, "+OK")) {
const char *reason = t_strdup_printf(
"XCLIENT failed: %s", str_sanitize(line, 160));
login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy),
LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
return -1;
}
pop3_client->proxy_state = client->proxy_sasl_client == NULL ?
POP3_PROXY_LOGIN1 : POP3_PROXY_LOGIN2;
return 0;
case POP3_PROXY_LOGIN1:
i_assert(client->proxy_sasl_client == NULL);
if (!str_begins(line, "+OK"))
break;
/* USER successful, send PASS */
o_stream_nsend_str(output, t_strdup_printf(
"PASS %s\r\n", client->proxy_password));
pop3_client->proxy_state = POP3_PROXY_LOGIN2;
return 0;
case POP3_PROXY_LOGIN2:
if (str_begins(line, "+ ") &&
client->proxy_sasl_client != NULL) {
/* continue SASL authentication */
if (pop3_proxy_continue_sasl_auth(client, output,
line+2) < 0)
return -1;
return 0;
}
if (!str_begins(line, "+OK"))
break;
/* Login successful. Send this line to client. */
line = t_strconcat(line, "\r\n", NULL);
o_stream_nsend_str(client->output, line);
client_proxy_finish_destroy_client(client);
return 1;
case POP3_PROXY_STATE_COUNT:
i_unreached();
}
/* Login failed. Pass through the error message to client.
If the backend server isn't Dovecot, the error message may
be different from Dovecot's "user doesn't exist" error. This
would allow an attacker to find out what users exist in the
system.
The optimal way to handle this would be to replace the
backend's "password failed" error message with Dovecot's
AUTH_FAILED_MSG, but this would require a new setting and
the sysadmin to actually bother setting it properly.
So for now we'll just forward the error message. This
shouldn't be a real problem since of course everyone will
be using only Dovecot as their backend :) */
enum login_proxy_failure_type failure_type =
LOGIN_PROXY_FAILURE_TYPE_AUTH;
if (!str_begins(line, "-ERR ")) {
client_send_reply(client, POP3_CMD_REPLY_ERROR,
AUTH_FAILED_MSG);
} else if (str_begins(line, "-ERR [SYS/TEMP]")) {
/* delay sending the reply until we know if we reconnect */
failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL;
line += 5;
} else {
client_send_raw(client, t_strconcat(line, "\r\n", NULL));
line += 5;
}
login_proxy_failed(client->login_proxy,
login_proxy_get_event(client->login_proxy),
failure_type, line);
return -1;
}
void pop3_proxy_reset(struct client *client)
{
struct pop3_client *pop3_client = (struct pop3_client *)client;
pop3_client->proxy_state = POP3_PROXY_BANNER;
}
static void
pop3_proxy_send_failure_reply(struct client *client,
enum login_proxy_failure_type type,
const char *reason)
{
switch (type) {
case LOGIN_PROXY_FAILURE_TYPE_CONNECT:
case LOGIN_PROXY_FAILURE_TYPE_INTERNAL:
case LOGIN_PROXY_FAILURE_TYPE_REMOTE:
case LOGIN_PROXY_FAILURE_TYPE_PROTOCOL:
client_send_reply(client, POP3_CMD_REPLY_TEMPFAIL,
LOGIN_PROXY_FAILURE_MSG);
break;
case LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG:
case LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG:
client_send_reply(client, POP3_CMD_REPLY_ERROR,
LOGIN_PROXY_FAILURE_MSG);
break;
case LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL:
/* [SYS/TEMP] prefix is already in the reason string */
client_send_reply(client, POP3_CMD_REPLY_ERROR, reason);
break;
case LOGIN_PROXY_FAILURE_TYPE_AUTH:
/* reply was already sent */
break;
}
}
void pop3_proxy_failed(struct client *client,
enum login_proxy_failure_type type,
const char *reason, bool reconnecting)
{
if (!reconnecting)
pop3_proxy_send_failure_reply(client, type, reason);
client_common_proxy_failed(client, type, reason, reconnecting);
}
const char *pop3_proxy_get_state(struct client *client)
{
struct pop3_client *pop3_client = (struct pop3_client *)client;
return pop3_proxy_state_names[pop3_client->proxy_state];
}
dovecot-2.3.21.1/src/pop3-login/client.c 0000644 0000000 0000000 00000024541 14656633576 014523 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "login-common.h"
#include "base64.h"
#include "buffer.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "randgen.h"
#include "hostpid.h"
#include "safe-memset.h"
#include "str.h"
#include "strescape.h"
#include "master-service.h"
#include "client.h"
#include "client-authenticate.h"
#include "auth-client.h"
#include "pop3-proxy.h"
#include "pop3-login-settings.h"
#include
/* Disconnect client when it sends too many bad commands */
#define CLIENT_MAX_BAD_COMMANDS 3
#define CLIENT_MAX_CMD_LEN 8
static bool cmd_stls(struct pop3_client *client)
{
client_cmd_starttls(&client->common);
return TRUE;
}
static bool cmd_quit(struct pop3_client *client)
{
client_send_reply(&client->common, POP3_CMD_REPLY_OK, "Logging out");
client_destroy(&client->common, CLIENT_UNAUTHENTICATED_LOGOUT_MSG);
return TRUE;
}
static bool cmd_xclient(struct pop3_client *client, const char *args)
{
const char *const *tmp;
in_port_t remote_port;
bool args_ok = TRUE;
if (!client->common.trusted) {
client_send_reply(&client->common, POP3_CMD_REPLY_OK,
"You are not from trusted IP - ignoring");
return TRUE;
}
for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) {
if (strncasecmp(*tmp, "ADDR=", 5) == 0) {
if (net_addr2ip(*tmp + 5, &client->common.ip) < 0)
args_ok = FALSE;
} else if (strncasecmp(*tmp, "PORT=", 5) == 0) {
if (net_str2port(*tmp + 5, &remote_port) < 0)
args_ok = FALSE;
else
client->common.remote_port = remote_port;
} else if (strncasecmp(*tmp, "SESSION=", 8) == 0) {
const char *value = *tmp + 8;
if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) {
client->common.session_id =
p_strdup(client->common.pool, value);
}
} else if (strncasecmp(*tmp, "TTL=", 4) == 0) {
if (str_to_uint(*tmp + 4, &client->common.proxy_ttl) < 0)
args_ok = FALSE;
} else if (strncasecmp(*tmp, "FORWARD=", 8) == 0) {
size_t value_len = strlen((*tmp)+8);
client->common.forward_fields =
str_new(client->common.preproxy_pool,
MAX_BASE64_DECODED_SIZE(value_len));
if (base64_decode((*tmp)+8, value_len, NULL,
client->common.forward_fields) < 0)
args_ok = FALSE;
}
}
if (!args_ok) {
client_send_reply(&client->common, POP3_CMD_REPLY_ERROR,
"Invalid parameters");
return TRUE;
}
/* args ok, set them and reset the state */
client_send_reply(&client->common, POP3_CMD_REPLY_OK, "Updated");
return TRUE;
}
static bool client_command_execute(struct pop3_client *client, const char *cmd,
const char *args)
{
if (strcmp(cmd, "CAPA") == 0)
return cmd_capa(client, args);
if (strcmp(cmd, "USER") == 0)
return cmd_user(client, args);
if (strcmp(cmd, "PASS") == 0)
return cmd_pass(client, args);
if (strcmp(cmd, "APOP") == 0)
return cmd_apop(client, args);
if (strcmp(cmd, "STLS") == 0)
return cmd_stls(client);
if (strcmp(cmd, "QUIT") == 0)
return cmd_quit(client);
if (strcmp(cmd, "XCLIENT") == 0)
return cmd_xclient(client, args);
if (strcmp(cmd, "XOIP") == 0) {
/* Compatibility with Zimbra's patched nginx */
return cmd_xclient(client, t_strconcat("ADDR=", args, NULL));
}
client_send_reply(&client->common, POP3_CMD_REPLY_ERROR,
"Unknown command.");
return FALSE;
}
static void pop3_client_input(struct client *client)
{
i_assert(!client->authenticating);
if (!client_read(client))
return;
client_ref(client);
o_stream_cork(client->output);
/* if a command starts an authentication, stop processing further
commands until the authentication is finished. */
while (!client->output->closed && !client->authenticating &&
auth_client_is_connected(auth_client)) {
if (!client->v.input_next_cmd(client))
break;
}
if (auth_client != NULL && !auth_client_is_connected(auth_client))
client->input_blocked = TRUE;
o_stream_uncork(client->output);
client_unref(&client);
}
static bool client_read_cmd_name(struct client *client, const char **cmd_r)
{
const unsigned char *data;
size_t size, i;
string_t *cmd = t_str_new(CLIENT_MAX_CMD_LEN);
if (i_stream_read_more(client->input, &data, &size) <= 0)
return FALSE;
for(i = 0; i < size; i++) {
if (data[i] == '\r') continue;
if (data[i] == ' ' ||
data[i] == '\n' ||
data[i] == '\0' ||
i >= CLIENT_MAX_CMD_LEN) {
*cmd_r = str_c(cmd);
/* only skip ws */
i_stream_skip(client->input, i + (data[i] == ' ' ? 1 : 0));
return TRUE;
}
str_append_c(cmd, i_toupper(data[i]));
}
return FALSE;
}
static bool pop3_client_input_next_cmd(struct client *client)
{
struct pop3_client *pop3_client = (struct pop3_client *)client;
const char *cmd, *args;
if (pop3_client->current_cmd == NULL) {
if (!client_read_cmd_name(client, &cmd))
return FALSE;
pop3_client->current_cmd = i_strdup(cmd);
}
if (strcmp(pop3_client->current_cmd, "AUTH") == 0) {
if (cmd_auth(pop3_client) <= 0) {
/* Need more input / destroyed. We also get here when
SASL authentication is actually started. */
return FALSE;
}
/* AUTH command finished already (SASL probe or ERR reply) */
i_free(pop3_client->current_cmd);
return TRUE;
}
if ((args = i_stream_next_line(client->input)) == NULL)
return FALSE;
if (client_command_execute(pop3_client, pop3_client->current_cmd, args))
client->bad_counter = 0;
else if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
client_send_reply(client, POP3_CMD_REPLY_ERROR,
"Too many invalid bad commands.");
client_destroy(client,
"Disconnected: Too many bad commands");
return FALSE;
}
i_free(pop3_client->current_cmd);
return TRUE;
}
static struct client *pop3_client_alloc(pool_t pool)
{
struct pop3_client *pop3_client;
pop3_client = p_new(pool, struct pop3_client, 1);
return &pop3_client->common;
}
static void pop3_client_create(struct client *client ATTR_UNUSED,
void **other_sets ATTR_UNUSED)
{
}
static void pop3_client_destroy(struct client *client)
{
struct pop3_client *pop3_client = (struct pop3_client *)client;
i_free_and_null(pop3_client->current_cmd);
i_free_and_null(pop3_client->last_user);
i_free_and_null(pop3_client->apop_challenge);
}
static char *get_apop_challenge(struct pop3_client *client)
{
unsigned char buffer[16];
unsigned char buffer_base64[MAX_BASE64_ENCODED_SIZE(sizeof(buffer)) + 1];
buffer_t buf;
if (sasl_server_find_available_mech(&client->common, "APOP") == NULL) {
/* disabled, no need to present the challenge */
return NULL;
}
auth_client_get_connect_id(auth_client, &client->apop_server_pid,
&client->apop_connect_uid);
random_fill(buffer, sizeof(buffer));
buffer_create_from_data(&buf, buffer_base64, sizeof(buffer_base64));
base64_encode(buffer, sizeof(buffer), &buf);
buffer_append_c(&buf, '\0');
return i_strdup_printf("<%x.%x.%lx.%s@%s>",
client->apop_server_pid,
client->apop_connect_uid,
(unsigned long)ioloop_time,
(const char *)buf.data, my_hostname);
}
static void pop3_client_notify_auth_ready(struct client *client)
{
struct pop3_client *pop3_client = (struct pop3_client *)client;
string_t *str;
client->io = io_add_istream(client->input, client_input, client);
str = t_str_new(128);
if (client->trusted) {
/* Dovecot extension to avoid extra roundtrip for CAPA */
str_append(str, "[XCLIENT] ");
}
str_append(str, client->set->login_greeting);
pop3_client->apop_challenge = get_apop_challenge(pop3_client);
if (pop3_client->apop_challenge != NULL)
str_printfa(str, " %s", pop3_client->apop_challenge);
client_send_reply(client, POP3_CMD_REPLY_OK, str_c(str));
client->banner_sent = TRUE;
}
static void
pop3_client_notify_starttls(struct client *client,
bool success, const char *text)
{
if (success)
client_send_reply(client, POP3_CMD_REPLY_OK, text);
else
client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
}
static void pop3_client_starttls(struct client *client ATTR_UNUSED)
{
}
void client_send_reply(struct client *client, enum pop3_cmd_reply reply,
const char *text)
{
const char *prefix = "-ERR";
switch (reply) {
case POP3_CMD_REPLY_OK:
prefix = "+OK";
break;
case POP3_CMD_REPLY_TEMPFAIL:
prefix = "-ERR [SYS/TEMP]";
break;
case POP3_CMD_REPLY_AUTH_ERROR:
if (text[0] == '[')
prefix = "-ERR";
else
prefix = "-ERR [AUTH]";
break;
case POP3_CMD_REPLY_ERROR:
break;
}
T_BEGIN {
string_t *line = t_str_new(256);
str_append(line, prefix);
str_append_c(line, ' ');
str_append(line, text);
str_append(line, "\r\n");
client_send_raw_data(client, str_data(line), str_len(line));
} T_END;
}
static void
pop3_client_notify_disconnect(struct client *client,
enum client_disconnect_reason reason,
const char *text)
{
if (reason == CLIENT_DISCONNECT_INTERNAL_ERROR)
client_send_reply(client, POP3_CMD_REPLY_TEMPFAIL, text);
else
client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
}
static void pop3_login_die(void)
{
/* do nothing. pop3 connections typically die pretty quick anyway. */
}
static void pop3_login_preinit(void)
{
login_set_roots = pop3_login_setting_roots;
}
static void pop3_login_init(void)
{
/* override the default login_die() */
master_service_set_die_callback(master_service, pop3_login_die);
}
static void pop3_login_deinit(void)
{
clients_destroy_all();
}
static struct client_vfuncs pop3_client_vfuncs = {
.alloc = pop3_client_alloc,
.create = pop3_client_create,
.destroy = pop3_client_destroy,
.notify_auth_ready = pop3_client_notify_auth_ready,
.notify_disconnect = pop3_client_notify_disconnect,
.notify_starttls = pop3_client_notify_starttls,
.starttls = pop3_client_starttls,
.input = pop3_client_input,
.auth_result = pop3_client_auth_result,
.proxy_reset = pop3_proxy_reset,
.proxy_parse_line = pop3_proxy_parse_line,
.proxy_failed = pop3_proxy_failed,
.proxy_get_state = pop3_proxy_get_state,
.send_raw_data = client_common_send_raw_data,
.input_next_cmd = pop3_client_input_next_cmd,
.free = client_common_default_free,
};
static struct login_binary pop3_login_binary = {
.protocol = "pop3",
.process_name = "pop3-login",
.default_port = 110,
.default_ssl_port = 995,
.event_category = {
.name = "pop3",
},
.client_vfuncs = &pop3_client_vfuncs,
.preinit = pop3_login_preinit,
.init = pop3_login_init,
.deinit = pop3_login_deinit,
.sasl_support_final_reply = FALSE,
.anonymous_login_acceptable = TRUE,
};
int main(int argc, char *argv[])
{
return login_binary_run(&pop3_login_binary, argc, argv);
}
dovecot-2.3.21.1/src/pop3-login/pop3-login-settings.h 0000644 0000000 0000000 00000000212 14656633576 017064 0000000 0000000 #ifndef POP3_LOGIN_SETTINGS_H
#define POP3_LOGIN_SETTINGS_H
extern const struct setting_parser_info *pop3_login_setting_roots[];
#endif
dovecot-2.3.21.1/src/imap-urlauth/ 0000755 0000000 0000000 00000000000 14656633640 013564 5 0000000 0000000 dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth.c 0000644 0000000 0000000 00000021135 14656633576 016272 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
/*
The imap-urlauth service provides URLAUTH access between different accounts. If
user A has an URLAUTH that references a mail from user B, it makes a connection
to the imap-urlauth service to access user B's mail store to retrieve the
mail.
The authentication and authorization of the URLAUTH is performed within
this service. Because access to the mailbox and the associated mailbox keys is
necessary to retrieve the message and for verification of the URLAUTH, the
urlauth services need root privileges. To mitigate security concerns, the
retrieval and verification of the URLs is performed in a worker service that
drops root privileges and acts as target user B.
The imap-urlauth service thus consists of three separate stages:
- imap-urlauth-login:
This is the login service which operates identical to imap-login and
pop3-login equivalents, except for the fact that only token authentication is
allowed. It verifies that the connecting client is an IMAP service acting on
behaf of an authenticated user.
- imap-urlauth:
Once the client is authenticated, the connection gets passed to the
imap-urlauth service (as implemented here). The goal of this stage is
to prevent the need for re-authenticating to the imap-urlauth service when
the clients wants to switch to a different target user. It normally runs as
$default_internal_user and starts workers to perform the actual work. To start
a worker, the imap-urlauth service establishes a control connection to the
imap-urlauth-worker service. In the handshake phase of the control protocol,
the connection of the client is passed to the worker. Once the worker
finishes, a new worker is started and the client connection is transfered to
it, unless the client is disconnected.
- imap-urlauth-worker:
The worker handles the URLAUTH requests from the client, so this is where the
mail store of the target user is accessed. The worker starts as root. In the
protocol interaction the client first indicates what the target user is.
The worker then performs a userdb lookup and drops privileges. The client can
then submit URLAUTH requests, which are limited to that user. Once the client
wants to access a different user, the worker terminates and the imap-urlauth
service starts a new worker for the next target user.
*/
#include "imap-urlauth-common.h"
#include "lib-signals.h"
#include "ioloop.h"
#include "buffer.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "path-util.h"
#include "base64.h"
#include "str.h"
#include "process-title.h"
#include "auth-master.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "master-login.h"
#include "master-interface.h"
#include "var-expand.h"
#include
#include
#define IS_STANDALONE() \
(getenv(MASTER_IS_PARENT_ENV) == NULL)
bool verbose_proctitle = FALSE;
static struct master_login *master_login = NULL;
static const struct imap_urlauth_settings *imap_urlauth_settings;
void imap_urlauth_refresh_proctitle(void)
{
struct client *client;
string_t *title = t_str_new(128);
if (!verbose_proctitle)
return;
str_append_c(title, '[');
switch (imap_urlauth_client_count) {
case 0:
str_append(title, "idling");
break;
case 1:
client = imap_urlauth_clients;
str_append(title, client->username);
break;
default:
str_printfa(title, "%u connections", imap_urlauth_client_count);
break;
}
str_append_c(title, ']');
process_title_set(str_c(title));
}
static void imap_urlauth_die(void)
{
/* do nothing. imap_urlauth connections typically die pretty quick anyway. */
}
static int
client_create_from_input(const char *service, const char *username,
int fd_in, int fd_out)
{
struct client *client;
if (client_create(service, username, fd_in, fd_out,
imap_urlauth_settings, &client) < 0)
return -1;
if (!IS_STANDALONE())
client_send_line(client, "OK");
return 0;
}
static void main_stdio_run(const char *username)
{
username = username != NULL ? username : getenv("USER");
if (username == NULL && IS_STANDALONE())
username = getlogin();
if (username == NULL)
i_fatal("USER environment missing");
(void)client_create_from_input("", username, STDIN_FILENO, STDOUT_FILENO);
}
static void
login_client_connected(const struct master_login_client *client,
const char *username, const char *const *extra_fields)
{
const char *msg = "NO\n";
struct auth_user_reply reply;
struct net_unix_cred cred;
const char *const *fields;
const char *service = NULL;
unsigned int count, i;
auth_user_fields_parse(extra_fields, pool_datastack_create(), &reply);
/* check peer credentials if possible */
if (reply.uid != (uid_t)-1 && net_getunixcred(client->fd, &cred) == 0 &&
reply.uid != cred.uid) {
i_error("Peer's credentials (uid=%ld) do not match "
"the user that logged in (uid=%ld).",
(long)cred.uid, (long)reply.uid);
if (write(client->fd, msg, strlen(msg)) < 0) {
/* ignored */
}
net_disconnect(client->fd);
return;
}
fields = array_get(&reply.extra_fields, &count);
for (i = 0; i < count; i++) {
if (str_begins(fields[i], "client_service=")) {
service = fields[i] + 15;
break;
}
}
if (service == NULL) {
i_error("Auth did not yield required client_service field (BUG).");
if (write(client->fd, msg, strlen(msg)) < 0) {
/* ignored */
}
net_disconnect(client->fd);
return;
}
if (reply.anonymous)
username = NULL;
if (client_create_from_input(service, username, client->fd, client->fd) < 0)
net_disconnect(client->fd);
}
static void login_client_failed(const struct master_login_client *client,
const char *errormsg ATTR_UNUSED)
{
const char *msg = "NO\n";
if (write(client->fd, msg, strlen(msg)) < 0) {
/* ignored */
}
}
static void client_connected(struct master_service_connection *conn)
{
/* when running standalone, we shouldn't even get here */
i_assert(master_login != NULL);
master_service_client_connection_accept(conn);
master_login_add(master_login, conn->fd);
}
int main(int argc, char *argv[])
{
static const struct setting_parser_info *set_roots[] = {
&imap_urlauth_setting_parser_info,
NULL
};
struct master_login_settings login_set;
struct master_service_settings_input input;
struct master_service_settings_output output;
void **sets;
enum master_service_flags service_flags = 0;
const char *error = NULL, *username = NULL;
const char *auth_socket_path = "auth-master";
int c;
i_zero(&login_set);
login_set.postlogin_timeout_secs = MASTER_POSTLOGIN_TIMEOUT_DEFAULT;
if (IS_STANDALONE() && getuid() == 0 &&
net_getpeername(1, NULL, NULL) == 0) {
printf("NO imap_urlauth binary must not be started from "
"inetd, use imap-urlauth-login instead.\n");
return 1;
}
if (IS_STANDALONE()) {
service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
MASTER_SERVICE_FLAG_STD_CLIENT;
} else {
service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
}
master_service = master_service_init("imap-urlauth", service_flags,
&argc, &argv, "a:");
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'a':
auth_socket_path = optarg;
break;
default:
return FATAL_DEFAULT;
}
}
master_service_init_log(master_service);
i_zero(&input);
input.roots = set_roots;
input.module = "imap-urlauth";
input.service = "imap-urlauth";
if (master_service_settings_read(master_service, &input, &output,
&error) < 0)
i_fatal("Error reading configuration: %s", error);
sets = master_service_settings_get_others(master_service);
imap_urlauth_settings = sets[0];
if (imap_urlauth_settings->verbose_proctitle)
verbose_proctitle = TRUE;
if (t_abspath(auth_socket_path, &login_set.auth_socket_path, &error) < 0) {
i_fatal("t_abspath(%s) failed: %s", auth_socket_path, error);
}
login_set.callback = login_client_connected;
login_set.failure_callback = login_client_failed;
login_set.update_proctitle = verbose_proctitle &&
master_service_get_client_limit(master_service) == 1;
master_service_init_finish(master_service);
master_service_set_die_callback(master_service, imap_urlauth_die);
/* fake that we're running, so we know if client was destroyed
while handling its initial input */
io_loop_set_running(current_ioloop);
if (IS_STANDALONE()) {
T_BEGIN {
main_stdio_run(username);
} T_END;
} else {
master_login = master_login_init(master_service, &login_set);
io_loop_set_running(current_ioloop);
}
if (io_loop_is_running(current_ioloop))
master_service_run(master_service, client_connected);
clients_destroy_all();
if (master_login != NULL)
master_login_deinit(&master_login);
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-worker-settings.c 0000644 0000000 0000000 00000004577 14656633576 021452 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "mail-storage-settings.h"
#include "imap-urlauth-worker-settings.h"
#include
#include
/* */
static struct file_listener_settings imap_urlauth_worker_unix_listeners_array[] = {
{ "imap-urlauth-worker", 0600, "$default_internal_user", "" }
};
static struct file_listener_settings *imap_urlauth_worker_unix_listeners[] = {
&imap_urlauth_worker_unix_listeners_array[0]
};
static buffer_t imap_urlauth_worker_unix_listeners_buf = {
{ { imap_urlauth_worker_unix_listeners,
sizeof(imap_urlauth_worker_unix_listeners) } }
};
/* */
struct service_settings imap_urlauth_worker_service_settings = {
.name = "imap-urlauth-worker",
.protocol = "imap",
.type = "",
.executable = "imap-urlauth-worker",
.user = "",
.group = "",
.privileged_group = "",
.extra_groups = "$default_internal_group",
.chroot = "",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 1024,
.client_limit = 1,
.service_count = 1,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &imap_urlauth_worker_unix_listeners_buf,
sizeof(imap_urlauth_worker_unix_listeners[0]) } },
.fifo_listeners = ARRAY_INIT,
.inet_listeners = ARRAY_INIT
};
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct imap_urlauth_worker_settings)
static const struct setting_define imap_urlauth_worker_setting_defines[] = {
DEF(BOOL, verbose_proctitle),
DEF(STR, imap_urlauth_host),
DEF(IN_PORT, imap_urlauth_port),
SETTING_DEFINE_LIST_END
};
const struct imap_urlauth_worker_settings imap_urlauth_worker_default_settings = {
.verbose_proctitle = FALSE,
.imap_urlauth_host = "",
.imap_urlauth_port = 143
};
static const struct setting_parser_info *imap_urlauth_worker_setting_dependencies[] = {
&mail_user_setting_parser_info,
NULL
};
const struct setting_parser_info imap_urlauth_worker_setting_parser_info = {
.module_name = "imap-urlauth-worker",
.defines = imap_urlauth_worker_setting_defines,
.defaults = &imap_urlauth_worker_default_settings,
.type_offset = SIZE_MAX,
.struct_size = sizeof(struct imap_urlauth_worker_settings),
.parent_offset = SIZE_MAX,
.dependencies = imap_urlauth_worker_setting_dependencies
};
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-client.c 0000644 0000000 0000000 00000022734 14656633576 017554 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "imap-urlauth-common.h"
#include "array.h"
#include "ioloop.h"
#include "net.h"
#include "fdpass.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "strescape.h"
#include "eacces-error.h"
#include "llist.h"
#include "hostpid.h"
#include "execv-const.h"
#include "env-util.h"
#include "var-expand.h"
#include "restrict-access.h"
#include "master-service.h"
#include "master-interface.h"
#include
#include
#define IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION 1
#define IMAP_URLAUTH_PROTOCOL_MINOR_VERSION 0
#define IMAP_URLAUTH_WORKER_SOCKET "imap-urlauth-worker"
/* max. length of input lines (URLs) */
#define MAX_INBUF_SIZE 2048
/* Disconnect client after idling this many milliseconds */
#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
#define USER_EXECUTABLE "imap-urlauth-worker"
#define IS_STANDALONE() \
(getenv(MASTER_IS_PARENT_ENV) == NULL)
static struct event_category event_category_urlauth = {
.name = "imap-urlauth",
};
struct client *imap_urlauth_clients;
unsigned int imap_urlauth_client_count;
static int client_worker_connect(struct client *client);
static void client_worker_disconnect(struct client *client);
static void client_worker_input(struct client *client);
int client_create(const char *service, const char *username,
int fd_in, int fd_out, const struct imap_urlauth_settings *set,
struct client **client_r)
{
struct client *client;
const char *app;
/* always use nonblocking I/O */
net_set_nonblock(fd_in, TRUE);
net_set_nonblock(fd_out, TRUE);
client = i_new(struct client, 1);
client->fd_in = fd_in;
client->fd_out = fd_out;
client->fd_ctrl = -1;
client->set = set;
client->event = event_create(NULL);
event_set_forced_debug(client->event, set->mail_debug);
event_add_category(client->event, &event_category_urlauth);
event_set_append_log_prefix(client->event, t_strdup_printf(
"user %s: ", username));
if (client_worker_connect(client) < 0) {
event_unref(&client->event);
i_free(client);
return -1;
}
/* determine user's special privileges */
i_array_init(&client->access_apps, 4);
if (username != NULL) {
if (set->imap_urlauth_submit_user != NULL &&
strcmp(set->imap_urlauth_submit_user, username) == 0) {
e_debug(client->event, "User has URLAUTH submit access");
app = "submit+";
array_push_back(&client->access_apps, &app);
}
if (set->imap_urlauth_stream_user != NULL &&
strcmp(set->imap_urlauth_stream_user, username) == 0) {
e_debug(client->event, "User has URLAUTH stream access");
app = "stream";
array_push_back(&client->access_apps, &app);
}
}
client->username = i_strdup(username);
client->service = i_strdup(service);
client->output = o_stream_create_fd(fd_out, SIZE_MAX);
imap_urlauth_client_count++;
DLLIST_PREPEND(&imap_urlauth_clients, client);
imap_urlauth_refresh_proctitle();
*client_r = client;
return 0;
}
void client_send_line(struct client *client, const char *fmt, ...)
{
va_list va;
ssize_t ret;
if (client->output->closed)
return;
va_start(va, fmt);
T_BEGIN {
string_t *str;
str = t_str_new(256);
str_vprintfa(str, fmt, va);
str_append(str, "\n");
ret = o_stream_send(client->output,
str_data(str), str_len(str));
i_assert(ret < 0 || (size_t)ret == str_len(str));
} T_END;
va_end(va);
}
static int client_worker_connect(struct client *client)
{
static const char handshake[] = "VERSION\timap-urlauth-worker\t2\t0\n";
const char *socket_path;
ssize_t ret;
unsigned char data;
socket_path = t_strconcat(client->set->base_dir,
"/"IMAP_URLAUTH_WORKER_SOCKET, NULL);
e_debug(client->event, "Connecting to worker socket %s", socket_path);
client->fd_ctrl = net_connect_unix_with_retries(socket_path, 1000);
if (client->fd_ctrl < 0) {
if (errno == EACCES) {
e_error(client->event, "imap-urlauth-client: %s",
eacces_error_get("net_connect_unix",
socket_path));
} else {
e_error(client->event, "imap-urlauth-client: "
"net_connect_unix(%s) failed: %m",
socket_path);
}
return -1;
}
/* transfer one or two fds */
data = (client->fd_in == client->fd_out ? '0' : '1');
ret = fd_send(client->fd_ctrl, client->fd_in, &data, sizeof(data));
if (ret > 0 && client->fd_in != client->fd_out) {
data = '0';
ret = fd_send(client->fd_ctrl, client->fd_out,
&data, sizeof(data));
}
if (ret <= 0) {
if (ret < 0) {
e_error(client->event, "fd_send(%s, %d) failed: %m",
socket_path, client->fd_ctrl);
} else {
e_error(client->event, "fd_send(%s, %d) failed to send byte",
socket_path, client->fd_ctrl);
}
client_worker_disconnect(client);
return -1;
}
client->ctrl_output = o_stream_create_fd(client->fd_ctrl, SIZE_MAX);
/* send protocol version handshake */
if (o_stream_send_str(client->ctrl_output, handshake) < 0) {
e_error(client->event,
"Error sending handshake to imap-urlauth worker: %m");
client_worker_disconnect(client);
return -1;
}
client->ctrl_input =
i_stream_create_fd(client->fd_ctrl, MAX_INBUF_SIZE);
client->ctrl_io =
io_add(client->fd_ctrl, IO_READ, client_worker_input, client);
return 0;
}
void client_worker_disconnect(struct client *client)
{
client->worker_state = IMAP_URLAUTH_WORKER_STATE_INACTIVE;
io_remove(&client->ctrl_io);
o_stream_destroy(&client->ctrl_output);
i_stream_destroy(&client->ctrl_input);
if (client->fd_ctrl >= 0) {
net_disconnect(client->fd_ctrl);
client->fd_ctrl = -1;
}
}
static int
client_worker_input_line(struct client *client, const char *response)
{
const char *const *apps;
unsigned int count, i;
bool restart;
string_t *str;
int ret;
switch (client->worker_state) {
case IMAP_URLAUTH_WORKER_STATE_INACTIVE:
if (strcasecmp(response, "OK") != 0) {
client_disconnect(client, "Worker handshake failed");
return -1;
}
client->worker_state = IMAP_URLAUTH_WORKER_STATE_CONNECTED;
str = t_str_new(256);
str_append(str, "ACCESS\t");
if (client->username != NULL)
str_append_tabescaped(str, client->username);
str_append(str, "\t");
str_append_tabescaped(str, client->service);
if (client->set->mail_debug)
str_append(str, "\tdebug");
if (array_count(&client->access_apps) > 0) {
str_append(str, "\tapps=");
apps = array_get(&client->access_apps, &count);
str_append(str, apps[0]);
for (i = 1; i < count; i++) {
str_append_c(str, ',');
str_append_tabescaped(str, apps[i]);
}
}
str_append(str, "\n");
ret = o_stream_send(client->ctrl_output,
str_data(str), str_len(str));
i_assert(ret < 0 || (size_t)ret == str_len(str));
if (ret < 0) {
client_disconnect(client,
"Failed to send ACCESS control command to worker");
return -1;
}
break;
case IMAP_URLAUTH_WORKER_STATE_CONNECTED:
if (strcasecmp(response, "OK") != 0) {
client_disconnect(client,
"Failed to negotiate access parameters");
return -1;
}
client->worker_state = IMAP_URLAUTH_WORKER_STATE_ACTIVE;
break;
case IMAP_URLAUTH_WORKER_STATE_ACTIVE:
restart = TRUE;
if (strcasecmp(response, "DISCONNECTED") == 0) {
/* worker detected client disconnect */
restart = FALSE;
} else if (strcasecmp(response, "FINISHED") != 0) {
/* unknown response */
client_disconnect(client,
"Worker finished with unknown response");
return -1;
}
e_debug(client->event, "Worker finished successfully");
if (restart) {
/* connect to new worker for accessing different user */
client_worker_disconnect(client);
if (client_worker_connect(client) < 0) {
client_disconnect(client,
"Failed to connect to new worker");
return -1;
}
/* indicate success of "END" command */
client_send_line(client, "OK");
} else {
client_disconnect(client, "Client disconnected");
}
return -1;
default:
i_unreached();
}
return 0;
}
void client_worker_input(struct client *client)
{
struct istream *input = client->ctrl_input;
const char *line;
if (input->closed) {
/* disconnected */
client_disconnect(client, "Worker disconnected unexpectedly");
return;
}
switch (i_stream_read(input)) {
case -1:
/* disconnected */
client_disconnect(client, "Worker disconnected unexpectedly");
return;
case -2:
/* input buffer full */
client_disconnect(client, "Worker sent too large input");
return;
}
while ((line = i_stream_next_line(input)) != NULL) {
if (client_worker_input_line(client, line) < 0)
return;
}
}
void client_destroy(struct client *client, const char *reason)
{
i_assert(reason != NULL || client->disconnected);
if (!client->disconnected)
e_info(client->event, "Disconnected: %s", reason);
imap_urlauth_client_count--;
DLLIST_REMOVE(&imap_urlauth_clients, client);
timeout_remove(&client->to_idle);
client_worker_disconnect(client);
o_stream_destroy(&client->output);
fd_close_maybe_stdio(&client->fd_in, &client->fd_out);
event_unref(&client->event);
i_free(client->username);
i_free(client->service);
array_free(&client->access_apps);
i_free(client);
master_service_client_connection_destroyed(master_service);
imap_urlauth_refresh_proctitle();
}
static void client_destroy_timeout(struct client *client)
{
client_destroy(client, NULL);
}
void client_disconnect(struct client *client, const char *reason)
{
if (client->disconnected)
return;
client->disconnected = TRUE;
e_info(client->event, "Disconnected: %s", reason);
client->to_idle = timeout_add(0, client_destroy_timeout, client);
}
void clients_destroy_all(void)
{
while (imap_urlauth_clients != NULL)
client_destroy(imap_urlauth_clients, "Server shutting down.");
}
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-login-settings.h 0000644 0000000 0000000 00000000242 14656633576 021237 0000000 0000000 #ifndef IMAP_URLAUTH_LOGIN_SETTINGS_H
#define IMAP_URLAUTH_LOGIN_SETTINGS_H
extern const struct setting_parser_info *imap_urlauth_login_setting_roots[];
#endif
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-client.h 0000644 0000000 0000000 00000002227 14656633576 017554 0000000 0000000 #ifndef IMAP_URLAUTH_CLIENT_H
#define IMAP_URLAUTH_CLIENT_H
struct client;
struct mail_storage;
enum imap_urlauth_worker_state {
IMAP_URLAUTH_WORKER_STATE_INACTIVE = 0,
IMAP_URLAUTH_WORKER_STATE_CONNECTED,
IMAP_URLAUTH_WORKER_STATE_ACTIVE,
};
struct client {
struct client *prev, *next;
int fd_in, fd_out, fd_ctrl;
struct io *ctrl_io;
struct ostream *output, *ctrl_output;
struct istream *ctrl_input;
struct timeout *to_idle;
struct event *event;
char *username, *service;
ARRAY_TYPE(const_string) access_apps;
/* settings: */
const struct imap_urlauth_settings *set;
enum imap_urlauth_worker_state worker_state;
bool disconnected:1;
};
extern struct client *imap_urlauth_clients;
extern unsigned int imap_urlauth_client_count;
int client_create(const char *service, const char *username,
int fd_in, int fd_out, const struct imap_urlauth_settings *set,
struct client **client_r);
void client_destroy(struct client *client, const char *reason);
void client_send_line(struct client *client, const char *fmt, ...)
ATTR_FORMAT(2, 3);
void client_disconnect(struct client *client, const char *reason);
void clients_destroy_all(void);
#endif
dovecot-2.3.21.1/src/imap-urlauth/Makefile.in 0000644 0000000 0000000 00000134356 14656633607 015570 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = imap-urlauth-login$(EXEEXT) \
imap-urlauth$(EXEEXT) imap-urlauth-worker$(EXEEXT)
subdir = src/imap-urlauth
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_imap_urlauth_OBJECTS = imap_urlauth-imap-urlauth.$(OBJEXT) \
imap_urlauth-imap-urlauth-client.$(OBJEXT) \
imap_urlauth-imap-urlauth-settings.$(OBJEXT)
imap_urlauth_OBJECTS = $(am_imap_urlauth_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
imap_urlauth_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(imap_urlauth_LDFLAGS) $(LDFLAGS) -o $@
am_imap_urlauth_login_OBJECTS = \
imap_urlauth_login-imap-urlauth-login.$(OBJEXT) \
imap_urlauth_login-imap-urlauth-login-settings.$(OBJEXT)
imap_urlauth_login_OBJECTS = $(am_imap_urlauth_login_OBJECTS)
am_imap_urlauth_worker_OBJECTS = \
imap_urlauth_worker-imap-urlauth-worker.$(OBJEXT) \
imap_urlauth_worker-imap-urlauth-worker-settings.$(OBJEXT)
imap_urlauth_worker_OBJECTS = $(am_imap_urlauth_worker_OBJECTS)
imap_urlauth_worker_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(imap_urlauth_worker_LDFLAGS) \
$(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/imap_urlauth-imap-urlauth-client.Po \
./$(DEPDIR)/imap_urlauth-imap-urlauth-settings.Po \
./$(DEPDIR)/imap_urlauth-imap-urlauth.Po \
./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Po \
./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Po \
./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Po \
./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(imap_urlauth_SOURCES) $(imap_urlauth_login_SOURCES) \
$(imap_urlauth_worker_SOURCES)
DIST_SOURCES = $(imap_urlauth_SOURCES) $(imap_urlauth_login_SOURCES) \
$(imap_urlauth_worker_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(noinst_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-master \
$(BINARY_CFLAGS)
# imap-urlauth-login
imap_urlauth_login_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir)/src/login-common
imap_urlauth_login_LDADD = \
$(LIBDOVECOT_LOGIN) \
$(LIBDOVECOT) \
$(SSL_LIBS) \
$(BINARY_LDFLAGS)
imap_urlauth_login_DEPENDENCIES = \
$(LIBDOVECOT_LOGIN_DEPS) \
$(LIBDOVECOT_DEPS)
imap_urlauth_login_SOURCES = \
imap-urlauth-login.c \
imap-urlauth-login-settings.c
# imap-urlauth
imap_urlauth_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir)/src/lib-dict \
-DPKG_RUNDIR=\""$(rundir)"\"
imap_urlauth_LDFLAGS = -export-dynamic
imap_urlauth_LDADD = $(LIBDOVECOT) \
$(BINARY_LDFLAGS)
imap_urlauth_DEPENDENCIES = $(LIBDOVECOT_DEPS)
imap_urlauth_SOURCES = \
imap-urlauth.c \
imap-urlauth-client.c \
imap-urlauth-settings.c
# imap-urlauth-worker
imap_urlauth_worker_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/imap \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-imap-storage \
-I$(top_srcdir)/src/lib-imap-urlauth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/login-common
imap_urlauth_worker_LDFLAGS = -export-dynamic \
$(BINARY_LDFLAGS)
urlauth_libs = \
$(top_builddir)/src/lib-imap-urlauth/libimap-urlauth.la
imap_urlauth_worker_LDADD = $(urlauth_libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT)
imap_urlauth_worker_DEPENDENCIES = $(urlauth_libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS)
imap_urlauth_worker_SOURCES = \
imap-urlauth-worker.c \
imap-urlauth-worker-settings.c
noinst_HEADERS = \
imap-urlauth-client.h \
imap-urlauth-common.h \
imap-urlauth-settings.h \
imap-urlauth-login-settings.h \
imap-urlauth-worker-settings.h
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/imap-urlauth/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/imap-urlauth/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
imap-urlauth$(EXEEXT): $(imap_urlauth_OBJECTS) $(imap_urlauth_DEPENDENCIES) $(EXTRA_imap_urlauth_DEPENDENCIES)
@rm -f imap-urlauth$(EXEEXT)
$(AM_V_CCLD)$(imap_urlauth_LINK) $(imap_urlauth_OBJECTS) $(imap_urlauth_LDADD) $(LIBS)
imap-urlauth-login$(EXEEXT): $(imap_urlauth_login_OBJECTS) $(imap_urlauth_login_DEPENDENCIES) $(EXTRA_imap_urlauth_login_DEPENDENCIES)
@rm -f imap-urlauth-login$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(imap_urlauth_login_OBJECTS) $(imap_urlauth_login_LDADD) $(LIBS)
imap-urlauth-worker$(EXEEXT): $(imap_urlauth_worker_OBJECTS) $(imap_urlauth_worker_DEPENDENCIES) $(EXTRA_imap_urlauth_worker_DEPENDENCIES)
@rm -f imap-urlauth-worker$(EXEEXT)
$(AM_V_CCLD)$(imap_urlauth_worker_LINK) $(imap_urlauth_worker_OBJECTS) $(imap_urlauth_worker_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_urlauth-imap-urlauth-client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_urlauth-imap-urlauth-settings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_urlauth-imap-urlauth.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
imap_urlauth-imap-urlauth.o: imap-urlauth.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth-imap-urlauth.o -MD -MP -MF $(DEPDIR)/imap_urlauth-imap-urlauth.Tpo -c -o imap_urlauth-imap-urlauth.o `test -f 'imap-urlauth.c' || echo '$(srcdir)/'`imap-urlauth.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth-imap-urlauth.Tpo $(DEPDIR)/imap_urlauth-imap-urlauth.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth.c' object='imap_urlauth-imap-urlauth.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth-imap-urlauth.o `test -f 'imap-urlauth.c' || echo '$(srcdir)/'`imap-urlauth.c
imap_urlauth-imap-urlauth.obj: imap-urlauth.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth-imap-urlauth.obj -MD -MP -MF $(DEPDIR)/imap_urlauth-imap-urlauth.Tpo -c -o imap_urlauth-imap-urlauth.obj `if test -f 'imap-urlauth.c'; then $(CYGPATH_W) 'imap-urlauth.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth-imap-urlauth.Tpo $(DEPDIR)/imap_urlauth-imap-urlauth.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth.c' object='imap_urlauth-imap-urlauth.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth-imap-urlauth.obj `if test -f 'imap-urlauth.c'; then $(CYGPATH_W) 'imap-urlauth.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth.c'; fi`
imap_urlauth-imap-urlauth-client.o: imap-urlauth-client.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth-imap-urlauth-client.o -MD -MP -MF $(DEPDIR)/imap_urlauth-imap-urlauth-client.Tpo -c -o imap_urlauth-imap-urlauth-client.o `test -f 'imap-urlauth-client.c' || echo '$(srcdir)/'`imap-urlauth-client.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth-imap-urlauth-client.Tpo $(DEPDIR)/imap_urlauth-imap-urlauth-client.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-client.c' object='imap_urlauth-imap-urlauth-client.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth-imap-urlauth-client.o `test -f 'imap-urlauth-client.c' || echo '$(srcdir)/'`imap-urlauth-client.c
imap_urlauth-imap-urlauth-client.obj: imap-urlauth-client.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth-imap-urlauth-client.obj -MD -MP -MF $(DEPDIR)/imap_urlauth-imap-urlauth-client.Tpo -c -o imap_urlauth-imap-urlauth-client.obj `if test -f 'imap-urlauth-client.c'; then $(CYGPATH_W) 'imap-urlauth-client.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-client.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth-imap-urlauth-client.Tpo $(DEPDIR)/imap_urlauth-imap-urlauth-client.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-client.c' object='imap_urlauth-imap-urlauth-client.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth-imap-urlauth-client.obj `if test -f 'imap-urlauth-client.c'; then $(CYGPATH_W) 'imap-urlauth-client.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-client.c'; fi`
imap_urlauth-imap-urlauth-settings.o: imap-urlauth-settings.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth-imap-urlauth-settings.o -MD -MP -MF $(DEPDIR)/imap_urlauth-imap-urlauth-settings.Tpo -c -o imap_urlauth-imap-urlauth-settings.o `test -f 'imap-urlauth-settings.c' || echo '$(srcdir)/'`imap-urlauth-settings.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth-imap-urlauth-settings.Tpo $(DEPDIR)/imap_urlauth-imap-urlauth-settings.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-settings.c' object='imap_urlauth-imap-urlauth-settings.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth-imap-urlauth-settings.o `test -f 'imap-urlauth-settings.c' || echo '$(srcdir)/'`imap-urlauth-settings.c
imap_urlauth-imap-urlauth-settings.obj: imap-urlauth-settings.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth-imap-urlauth-settings.obj -MD -MP -MF $(DEPDIR)/imap_urlauth-imap-urlauth-settings.Tpo -c -o imap_urlauth-imap-urlauth-settings.obj `if test -f 'imap-urlauth-settings.c'; then $(CYGPATH_W) 'imap-urlauth-settings.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-settings.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth-imap-urlauth-settings.Tpo $(DEPDIR)/imap_urlauth-imap-urlauth-settings.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-settings.c' object='imap_urlauth-imap-urlauth-settings.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth-imap-urlauth-settings.obj `if test -f 'imap-urlauth-settings.c'; then $(CYGPATH_W) 'imap-urlauth-settings.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-settings.c'; fi`
imap_urlauth_login-imap-urlauth-login.o: imap-urlauth-login.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_login-imap-urlauth-login.o -MD -MP -MF $(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Tpo -c -o imap_urlauth_login-imap-urlauth-login.o `test -f 'imap-urlauth-login.c' || echo '$(srcdir)/'`imap-urlauth-login.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Tpo $(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-login.c' object='imap_urlauth_login-imap-urlauth-login.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_login-imap-urlauth-login.o `test -f 'imap-urlauth-login.c' || echo '$(srcdir)/'`imap-urlauth-login.c
imap_urlauth_login-imap-urlauth-login.obj: imap-urlauth-login.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_login-imap-urlauth-login.obj -MD -MP -MF $(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Tpo -c -o imap_urlauth_login-imap-urlauth-login.obj `if test -f 'imap-urlauth-login.c'; then $(CYGPATH_W) 'imap-urlauth-login.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-login.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Tpo $(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-login.c' object='imap_urlauth_login-imap-urlauth-login.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_login-imap-urlauth-login.obj `if test -f 'imap-urlauth-login.c'; then $(CYGPATH_W) 'imap-urlauth-login.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-login.c'; fi`
imap_urlauth_login-imap-urlauth-login-settings.o: imap-urlauth-login-settings.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_login-imap-urlauth-login-settings.o -MD -MP -MF $(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Tpo -c -o imap_urlauth_login-imap-urlauth-login-settings.o `test -f 'imap-urlauth-login-settings.c' || echo '$(srcdir)/'`imap-urlauth-login-settings.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Tpo $(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-login-settings.c' object='imap_urlauth_login-imap-urlauth-login-settings.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_login-imap-urlauth-login-settings.o `test -f 'imap-urlauth-login-settings.c' || echo '$(srcdir)/'`imap-urlauth-login-settings.c
imap_urlauth_login-imap-urlauth-login-settings.obj: imap-urlauth-login-settings.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_login-imap-urlauth-login-settings.obj -MD -MP -MF $(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Tpo -c -o imap_urlauth_login-imap-urlauth-login-settings.obj `if test -f 'imap-urlauth-login-settings.c'; then $(CYGPATH_W) 'imap-urlauth-login-settings.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-login-settings.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Tpo $(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-login-settings.c' object='imap_urlauth_login-imap-urlauth-login-settings.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_login_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_login-imap-urlauth-login-settings.obj `if test -f 'imap-urlauth-login-settings.c'; then $(CYGPATH_W) 'imap-urlauth-login-settings.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-login-settings.c'; fi`
imap_urlauth_worker-imap-urlauth-worker.o: imap-urlauth-worker.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_worker-imap-urlauth-worker.o -MD -MP -MF $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Tpo -c -o imap_urlauth_worker-imap-urlauth-worker.o `test -f 'imap-urlauth-worker.c' || echo '$(srcdir)/'`imap-urlauth-worker.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Tpo $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-worker.c' object='imap_urlauth_worker-imap-urlauth-worker.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_worker-imap-urlauth-worker.o `test -f 'imap-urlauth-worker.c' || echo '$(srcdir)/'`imap-urlauth-worker.c
imap_urlauth_worker-imap-urlauth-worker.obj: imap-urlauth-worker.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_worker-imap-urlauth-worker.obj -MD -MP -MF $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Tpo -c -o imap_urlauth_worker-imap-urlauth-worker.obj `if test -f 'imap-urlauth-worker.c'; then $(CYGPATH_W) 'imap-urlauth-worker.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-worker.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Tpo $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-worker.c' object='imap_urlauth_worker-imap-urlauth-worker.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_worker-imap-urlauth-worker.obj `if test -f 'imap-urlauth-worker.c'; then $(CYGPATH_W) 'imap-urlauth-worker.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-worker.c'; fi`
imap_urlauth_worker-imap-urlauth-worker-settings.o: imap-urlauth-worker-settings.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_worker-imap-urlauth-worker-settings.o -MD -MP -MF $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Tpo -c -o imap_urlauth_worker-imap-urlauth-worker-settings.o `test -f 'imap-urlauth-worker-settings.c' || echo '$(srcdir)/'`imap-urlauth-worker-settings.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Tpo $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-worker-settings.c' object='imap_urlauth_worker-imap-urlauth-worker-settings.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_worker-imap-urlauth-worker-settings.o `test -f 'imap-urlauth-worker-settings.c' || echo '$(srcdir)/'`imap-urlauth-worker-settings.c
imap_urlauth_worker-imap-urlauth-worker-settings.obj: imap-urlauth-worker-settings.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT imap_urlauth_worker-imap-urlauth-worker-settings.obj -MD -MP -MF $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Tpo -c -o imap_urlauth_worker-imap-urlauth-worker-settings.obj `if test -f 'imap-urlauth-worker-settings.c'; then $(CYGPATH_W) 'imap-urlauth-worker-settings.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-worker-settings.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Tpo $(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imap-urlauth-worker-settings.c' object='imap_urlauth_worker-imap-urlauth-worker-settings.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(imap_urlauth_worker_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o imap_urlauth_worker-imap-urlauth-worker-settings.obj `if test -f 'imap-urlauth-worker-settings.c'; then $(CYGPATH_W) 'imap-urlauth-worker-settings.c'; else $(CYGPATH_W) '$(srcdir)/imap-urlauth-worker-settings.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/imap_urlauth-imap-urlauth-client.Po
-rm -f ./$(DEPDIR)/imap_urlauth-imap-urlauth-settings.Po
-rm -f ./$(DEPDIR)/imap_urlauth-imap-urlauth.Po
-rm -f ./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Po
-rm -f ./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Po
-rm -f ./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Po
-rm -f ./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/imap_urlauth-imap-urlauth-client.Po
-rm -f ./$(DEPDIR)/imap_urlauth-imap-urlauth-settings.Po
-rm -f ./$(DEPDIR)/imap_urlauth-imap-urlauth.Po
-rm -f ./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login-settings.Po
-rm -f ./$(DEPDIR)/imap_urlauth_login-imap-urlauth-login.Po
-rm -f ./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker-settings.Po
-rm -f ./$(DEPDIR)/imap_urlauth_worker-imap-urlauth-worker.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-pkglibexecPROGRAMS install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-settings.c 0000644 0000000 0000000 00000004524 14656633576 020133 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "imap-urlauth-settings.h"
#include
#include
/* */
static struct file_listener_settings imap_urlauth_unix_listeners_array[] = {
{ "token-login/imap-urlauth", 0666, "", "" }
};
static struct file_listener_settings *imap_urlauth_unix_listeners[] = {
&imap_urlauth_unix_listeners_array[0]
};
static buffer_t imap_urlauth_unix_listeners_buf = {
{ { imap_urlauth_unix_listeners, sizeof(imap_urlauth_unix_listeners) } }
};
/* */
struct service_settings imap_urlauth_service_settings = {
.name = "imap-urlauth",
.protocol = "imap",
.type = "",
.executable = "imap-urlauth",
.user = "$default_internal_user",
.group = "",
.privileged_group = "",
.extra_groups = "",
.chroot = "",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 1024,
.client_limit = 1,
.service_count = 1,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &imap_urlauth_unix_listeners_buf,
sizeof(imap_urlauth_unix_listeners[0]) } },
.fifo_listeners = ARRAY_INIT,
.inet_listeners = ARRAY_INIT
};
#undef DEF
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct imap_urlauth_settings)
static const struct setting_define imap_urlauth_setting_defines[] = {
DEF(STR, base_dir),
DEF(BOOL, mail_debug),
DEF(BOOL, verbose_proctitle),
DEF(STR, imap_urlauth_logout_format),
DEF(STR, imap_urlauth_submit_user),
DEF(STR, imap_urlauth_stream_user),
SETTING_DEFINE_LIST_END
};
const struct imap_urlauth_settings imap_urlauth_default_settings = {
.base_dir = PKG_RUNDIR,
.mail_debug = FALSE,
.verbose_proctitle = FALSE,
.imap_urlauth_logout_format = "in=%i out=%o",
.imap_urlauth_submit_user = NULL,
.imap_urlauth_stream_user = NULL
};
static const struct setting_parser_info *imap_urlauth_setting_dependencies[] = {
NULL
};
const struct setting_parser_info imap_urlauth_setting_parser_info = {
.module_name = "imap-urlauth",
.defines = imap_urlauth_setting_defines,
.defaults = &imap_urlauth_default_settings,
.type_offset = SIZE_MAX,
.struct_size = sizeof(struct imap_urlauth_settings),
.parent_offset = SIZE_MAX,
.dependencies = imap_urlauth_setting_dependencies
};
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-worker-settings.h 0000644 0000000 0000000 00000000645 14656633576 021447 0000000 0000000 #ifndef IMAP_URLAUTH_SETTINGS_H
#define IMAP_URLAUTH_SETTINGS_H
struct mail_user_settings;
struct imap_urlauth_worker_settings {
bool verbose_proctitle;
/* imap_urlauth: */
const char *imap_urlauth_host;
in_port_t imap_urlauth_port;
};
extern const struct imap_urlauth_worker_settings imap_urlauth_worker_default_settings;
extern const struct setting_parser_info imap_urlauth_worker_setting_parser_info;
#endif
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-settings.h 0000644 0000000 0000000 00000000756 14656633576 020143 0000000 0000000 #ifndef IMAP_URLAUTH_SETTINGS_H
#define IMAP_URLAUTH_SETTINGS_H
struct mail_user_settings;
struct imap_urlauth_settings {
const char *base_dir;
bool mail_debug;
bool verbose_proctitle;
/* imap_urlauth: */
const char *imap_urlauth_logout_format;
const char *imap_urlauth_submit_user;
const char *imap_urlauth_stream_user;
};
extern const struct imap_urlauth_settings imap_urlauth_default_settings;
extern const struct setting_parser_info imap_urlauth_setting_parser_info;
#endif
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-worker.c 0000644 0000000 0000000 00000063632 14656633576 017611 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "net.h"
#include "fdpass.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "str-sanitize.h"
#include "strescape.h"
#include "llist.h"
#include "hostpid.h"
#include "var-expand.h"
#include "process-title.h"
#include "randgen.h"
#include "restrict-access.h"
#include "settings-parser.h"
#include "master-service.h"
#include "master-interface.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "mail-namespace.h"
#include "imap-url.h"
#include "imap-msgpart-url.h"
#include "imap-urlauth.h"
#include "imap-urlauth-fetch.h"
#include "imap-urlauth-worker-settings.h"
#include
#include
#define MAX_CTRL_HANDSHAKE 255
/* max. length of input lines (URLs) */
#define MAX_INBUF_SIZE 2048
/* Disconnect client after idling this many milliseconds */
#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
#define IS_STANDALONE() \
(getenv(MASTER_IS_PARENT_ENV) == NULL)
#define IMAP_URLAUTH_WORKER_PROTOCOL_MAJOR_VERSION 2
#define IMAP_URLAUTH_WORKER_PROTOCOL_MINOR_VERSION 0
struct client {
struct client *prev, *next;
int fd_in, fd_out, fd_ctrl;
struct io *io, *ctrl_io;
struct istream *input, *ctrl_input;
struct ostream *output, *ctrl_output;
struct timeout *to_idle;
char *access_user, *access_service;
ARRAY_TYPE(string) access_apps;
struct mail_storage_service_user *service_user;
struct mail_user *mail_user;
struct imap_urlauth_context *urlauth_ctx;
struct imap_msgpart_url *url;
struct istream *msg_part_input;
uoff_t msg_part_size;
/* settings: */
const struct imap_urlauth_worker_settings *set;
const struct mail_storage_settings *mail_set;
bool debug:1;
bool finished:1;
bool waiting_input:1;
bool version_received:1;
bool access_received:1;
bool access_anonymous:1;
};
static bool verbose_proctitle = FALSE;
static struct mail_storage_service_ctx *storage_service;
struct client *imap_urlauth_worker_clients;
unsigned int imap_urlauth_worker_client_count;
static void client_destroy(struct client *client);
static void client_abort(struct client *client, const char *reason);
static int client_run_url(struct client *client);
static void client_input(struct client *client);
static bool client_handle_input(struct client *client);
static int client_output(struct client *client);
static void client_ctrl_input(struct client *client);
static void imap_urlauth_worker_refresh_proctitle(void)
{
struct client *client = imap_urlauth_worker_clients;
string_t *title;
if (!verbose_proctitle)
return;
title = t_str_new(128);
str_append_c(title, '[');
switch (imap_urlauth_worker_client_count) {
case 0:
str_append(title, "idling");
break;
case 1:
if (client->mail_user == NULL)
str_append(title, client->access_user);
else {
str_append(title, client->access_user);
str_append(title, "->");
str_append(title, client->mail_user->username);
}
break;
default:
str_printfa(title, "%u connections",
imap_urlauth_worker_client_count);
break;
}
str_append_c(title, ']');
process_title_set(str_c(title));
}
static void client_idle_timeout(struct client *client)
{
if (client->url != NULL) {
client_abort(client,
"Session closed for inactivity in reading our output");
} else {
client_destroy(client);
}
}
static struct client *client_create(int fd)
{
struct client *client;
/* always use nonblocking I/O */
net_set_nonblock(fd, TRUE);
client = i_new(struct client, 1);
i_array_init(&client->access_apps, 16);
client->fd_in = -1;
client->fd_out = -1;
client->fd_ctrl = fd;
client->access_anonymous = TRUE; /* default until overridden */
client->ctrl_io = io_add(fd, IO_READ, client_ctrl_input, client);
client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
client_idle_timeout, client);
imap_urlauth_worker_client_count++;
DLLIST_PREPEND(&imap_urlauth_worker_clients, client);
imap_urlauth_worker_refresh_proctitle();
return client;
}
static struct client *
client_create_standalone(const char *access_user,
const char *const *access_applications,
int fd_in, int fd_out, bool debug)
{
struct client *client;
/* always use nonblocking I/O */
net_set_nonblock(fd_in, TRUE);
net_set_nonblock(fd_out, TRUE);
client = i_new(struct client, 1);
i_array_init(&client->access_apps, 16);
client->fd_in = fd_in;
client->fd_out = fd_out;
client->fd_ctrl = -1;
if (access_user != NULL && *access_user != '\0')
client->access_user = i_strdup(access_user);
else {
client->access_user = i_strdup("anonymous");
client->access_anonymous = TRUE;
}
if (access_applications != NULL) {
const char *const *apps = access_applications;
for (; *apps != NULL; apps++) {
char *app = i_strdup(*apps);
array_push_back(&client->access_apps, &app);
}
}
client->debug = debug;
client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE);
client->output = o_stream_create_fd(fd_out, SIZE_MAX);
client->io = io_add(fd_in, IO_READ, client_input, client);
client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
client_idle_timeout, client);
o_stream_set_no_error_handling(client->output, TRUE);
o_stream_set_flush_callback(client->output, client_output, client);
imap_urlauth_worker_client_count++;
DLLIST_PREPEND(&imap_urlauth_worker_clients, client);
i_set_failure_prefix("imap-urlauth[%s](%s): ",
my_pid, client->access_user);
return client;
}
static void client_abort(struct client *client, const char *reason)
{
i_error("%s", reason);
client_destroy(client);
}
static void client_destroy(struct client *client)
{
char *app;
i_set_failure_prefix("imap-urlauth[%s](%s): ",
my_pid, client->access_user);
if (client->url != NULL) {
/* deinitialize url */
i_stream_close(client->input);
o_stream_close(client->output);
(void)client_run_url(client);
i_assert(client->url == NULL);
}
imap_urlauth_worker_client_count--;
DLLIST_REMOVE(&imap_urlauth_worker_clients, client);
if (client->urlauth_ctx != NULL)
imap_urlauth_deinit(&client->urlauth_ctx);
if (client->mail_user != NULL)
mail_user_deinit(&client->mail_user);
io_remove(&client->io);
io_remove(&client->ctrl_io);
timeout_remove(&client->to_idle);
i_stream_destroy(&client->input);
o_stream_destroy(&client->output);
i_stream_destroy(&client->ctrl_input);
o_stream_destroy(&client->ctrl_output);
fd_close_maybe_stdio(&client->fd_in, &client->fd_out);
if (client->fd_ctrl >= 0)
net_disconnect(client->fd_ctrl);
if (client->service_user != NULL)
mail_storage_service_user_unref(&client->service_user);
i_free(client->access_user);
i_free(client->access_service);
array_foreach_elem(&client->access_apps, app)
i_free(app);
array_free(&client->access_apps);
i_free(client);
imap_urlauth_worker_refresh_proctitle();
master_service_client_connection_destroyed(master_service);
}
static int client_run_url(struct client *client)
{
const unsigned char *data;
size_t size;
ssize_t ret = 0;
while (i_stream_read_more(client->msg_part_input, &data, &size) > 0) {
if ((ret = o_stream_send(client->output, data, size)) < 0)
break;
i_stream_skip(client->msg_part_input, ret);
if (o_stream_get_buffer_used_size(client->output) >= 4096) {
if ((ret = o_stream_flush(client->output)) < 0)
break;
if (ret == 0)
return 0;
}
}
if (client->output->closed || ret < 0) {
imap_msgpart_url_free(&client->url);
return -1;
}
if (client->msg_part_input->eof) {
o_stream_nsend(client->output, "\n", 1);
imap_msgpart_url_free(&client->url);
return 1;
}
return 0;
}
static void clients_destroy_all(void)
{
while (imap_urlauth_worker_clients != NULL)
client_destroy(imap_urlauth_worker_clients);
}
static void ATTR_FORMAT(2, 3)
client_send_line(struct client *client, const char *fmt, ...)
{
va_list va;
if (client->output->closed)
return;
va_start(va, fmt);
T_BEGIN {
string_t *str;
str = t_str_new(256);
str_vprintfa(str, fmt, va);
str_append(str, "\n");
o_stream_nsend(client->output, str_data(str), str_len(str));
} T_END;
va_end(va);
}
static int
client_fetch_urlpart(struct client *client, const char *url,
enum imap_urlauth_fetch_flags url_flags,
const char **bpstruct_r, bool *binary_with_nuls_r,
const char **errormsg_r)
{
const char *error;
struct imap_msgpart_open_result mpresult;
enum mail_error error_code;
int ret;
*bpstruct_r = NULL;
*errormsg_r = NULL;
*binary_with_nuls_r = FALSE;
ret = imap_urlauth_fetch(client->urlauth_ctx, url,
&client->url, &error_code, &error);
if (ret <= 0) {
if (ret < 0)
return -1;
error = t_strdup_printf("Failed to fetch URLAUTH \"%s\": %s",
url, error);
if (client->debug)
i_debug("%s", error);
/* don't leak info about existence/accessibility
of mailboxes */
if (error_code == MAIL_ERROR_PARAMS)
*errormsg_r = error;
return 0;
}
if ((url_flags & IMAP_URLAUTH_FETCH_FLAG_BINARY) != 0)
imap_msgpart_url_set_decode_to_binary(client->url);
if ((url_flags & IMAP_URLAUTH_FETCH_FLAG_BODYPARTSTRUCTURE) != 0) {
ret = imap_msgpart_url_get_bodypartstructure(client->url,
bpstruct_r, &error);
if (ret <= 0) {
*errormsg_r = t_strdup_printf(
"Failed to read URLAUTH \"%s\": %s", url, error);
if (client->debug)
i_debug("%s", *errormsg_r);
return ret;
}
}
/* if requested, read the message part the URL points to */
if ((url_flags & IMAP_URLAUTH_FETCH_FLAG_BODY) != 0 ||
(url_flags & IMAP_URLAUTH_FETCH_FLAG_BINARY) != 0) {
ret = imap_msgpart_url_read_part(client->url, &mpresult, &error);
if (ret <= 0) {
*errormsg_r = t_strdup_printf(
"Failed to read URLAUTH \"%s\": %s", url, error);
if (client->debug)
i_debug("%s", *errormsg_r);
return ret;
}
client->msg_part_size = mpresult.size;
client->msg_part_input = mpresult.input;
*binary_with_nuls_r = mpresult.binary_decoded_input_has_nuls;
}
return 1;
}
static int client_fetch_url(struct client *client, const char *url,
enum imap_urlauth_fetch_flags url_flags)
{
string_t *response;
const char *bpstruct, *errormsg;
bool binary_with_nuls;
int ret;
i_assert(client->url == NULL);
client->msg_part_size = 0;
client->msg_part_input = NULL;
if (client->debug)
i_debug("Fetching URLAUTH %s", url);
/* fetch URL */
ret = client_fetch_urlpart(client, url, url_flags, &bpstruct,
&binary_with_nuls, &errormsg);
if (ret <= 0) {
/* fetch failed */
if (client->url != NULL)
imap_msgpart_url_free(&client->url);
/* don't send error details to anonymous users: just to be sure
that no information about the target user account is unduly
leaked. */
if (client->access_anonymous || errormsg == NULL)
client_send_line(client, "NO");
else {
client_send_line(client, "NO\terror=%s",
str_tabescape(errormsg));
}
if (ret < 0) {
/* fetch failed badly */
client_abort(client, "Session aborted: Fatal failure while fetching URL");
}
return 0;
}
response = t_str_new(256);
str_append(response, "OK");
if (binary_with_nuls)
str_append(response, "\thasnuls");
if (bpstruct != NULL) {
str_append(response, "\tbpstruct=");
str_append(response, str_tabescape(bpstruct));
if (client->debug) {
i_debug("Fetched URLAUTH yielded BODYPARTSTRUCTURE (%s)",
bpstruct);
}
}
/* return content */
o_stream_cork(client->output);
if (client->msg_part_size == 0 || client->msg_part_input == NULL) {
/* empty */
str_append(response, "\t0");
client_send_line(client, "%s", str_c(response));
imap_msgpart_url_free(&client->url);
client->url = NULL;
if (client->debug)
i_debug("Fetched URLAUTH yielded empty result");
} else {
/* actual content */
str_printfa(response, "\t%"PRIuUOFF_T, client->msg_part_size);
client_send_line(client, "%s", str_c(response));
if (client->debug) {
i_debug("Fetched URLAUTH yielded %"PRIuUOFF_T" bytes "
"of %smessage data", client->msg_part_size,
(binary_with_nuls ? "binary " : ""));
}
if (client_run_url(client) < 0) {
client_abort(client,
"Session aborted: Fatal failure while transferring URL");
return 0;
}
}
if (client->url != NULL) {
/* URL not finished */
o_stream_set_flush_pending(client->output, TRUE);
client->waiting_input = TRUE;
}
o_stream_uncork(client->output);
return client->url != NULL ? 0 : 1;
}
static int
client_handle_command(struct client *client, const char *cmd,
const char *const *args, const char **error_r)
{
int ret;
*error_r = NULL;
/* "URL"["\tbody"]["\tbinary"]["\tbpstruct"]"\t":
fetch URL (meta)data */
if (strcmp(cmd, "URL") == 0) {
enum imap_urlauth_fetch_flags url_flags = 0;
const char *url;
if (*args == NULL) {
*error_r = "URL: Missing URL parameter";
return -1;
}
url = *args;
args++;
while (*args != NULL) {
if (strcasecmp(*args, "body") == 0)
url_flags |= IMAP_URLAUTH_FETCH_FLAG_BODY;
else if (strcasecmp(*args, "binary") == 0)
url_flags |= IMAP_URLAUTH_FETCH_FLAG_BINARY;
else if (strcasecmp(*args, "bpstruct") == 0)
url_flags |= IMAP_URLAUTH_FETCH_FLAG_BODYPARTSTRUCTURE;
args++;
}
if (url_flags == 0)
url_flags = IMAP_URLAUTH_FETCH_FLAG_BODY;
T_BEGIN {
ret = client_fetch_url(client, url, url_flags);
} T_END;
return ret;
}
/* "END": unselect current user (closes worker) */
if (strcmp(cmd, "END") == 0) {
if (args[0] != NULL) {
*error_r = "END: Invalid number of parameters";
return -1;
}
client->finished = TRUE;
if (client->ctrl_output != NULL)
o_stream_nsend_str(client->ctrl_output, "FINISHED\n");
client_destroy(client);
return 0;
}
*error_r = t_strconcat("Unknown or inappropriate command: ", cmd, NULL);
return -1;
}
static int
client_handle_user_command(struct client *client, const char *cmd,
const char *const *args, const char **error_r)
{
struct mail_storage_service_input input;
struct imap_urlauth_worker_settings *set;
struct mail_storage_service_user *user;
struct imap_urlauth_config config;
struct mail_user *mail_user;
const char *error;
unsigned int count;
int ret;
/* "USER\t" */
*error_r = NULL;
/* check command syntax */
if (strcmp(cmd, "USER") != 0) {
*error_r = t_strconcat("Unknown or inappropriate command: ",
cmd, NULL);
return -1;
}
if (args[0] == NULL || args[1] != NULL) {
*error_r = "USER: Invalid number of parameters";
return -1;
}
/* lookup user */
i_zero(&input);
input.module = "imap-urlauth-worker";
input.service = "imap-urlauth-worker";
input.username = args[0];
if (client->debug)
i_debug("Looking up user %s", input.username);
ret = mail_storage_service_lookup_next(storage_service, &input,
&user, &mail_user, &error);
if (ret < 0) {
i_error("Failed to lookup user %s: %s", input.username, error);
client_abort(client, "Session aborted: Failed to lookup user");
return 0;
} else if (ret == 0) {
if (client->debug)
i_debug("User %s doesn't exist", input.username);
client_send_line(client, "NO");
return 1;
}
client->debug = mail_user->mail_debug =
client->debug || mail_user->mail_debug;
/* drop privileges */
restrict_access_allow_coredumps(TRUE);
set = mail_storage_service_user_get_set(user)[1];
if (settings_var_expand(&imap_urlauth_worker_setting_parser_info, set,
mail_user->pool,
mail_user_var_expand_table(mail_user),
&error) <= 0) {
client_send_line(client, "NO");
client_abort(client, t_strdup_printf(
"Session aborted: Failed to expand settings: %s", error));
return 0;
}
if (set->verbose_proctitle) {
verbose_proctitle = TRUE;
imap_urlauth_worker_refresh_proctitle();
}
client->service_user = user;
client->mail_user = mail_user;
client->set = set;
if (client->debug) {
i_debug("Found user account `%s' on behalf of user `%s'",
mail_user->username, client->access_user);
}
/* initialize urlauth context */
if (*set->imap_urlauth_host == '\0') {
i_error("imap_urlauth_host setting is not configured for user %s",
mail_user->username);
client_send_line(client, "NO");
client_abort(client, "Session aborted: URLAUTH not configured");
return 0;
}
i_zero(&config);
config.url_host = set->imap_urlauth_host;
config.url_port = set->imap_urlauth_port;
config.access_user = client->access_user;
config.access_service = client->access_service;
config.access_anonymous = client->access_anonymous;
config.access_applications =
(const void *)array_get(&client->access_apps, &count);
client->urlauth_ctx = imap_urlauth_init(client->mail_user, &config);
if (client->debug) {
i_debug("Providing access to user account `%s' on behalf of user `%s' "
"using service `%s'", mail_user->username, client->access_user,
client->access_service);
}
i_set_failure_prefix("imap-urlauth[%s](%s->%s): ",
my_pid, client->access_user, mail_user->username);
client_send_line(client, "OK");
return 1;
}
static bool client_handle_input(struct client *client)
{
const char *line, *cmd, *error;
int ret;
if (client->url != NULL) {
/* we're still processing a URL. wait until it's
finished. */
io_remove(&client->io);
client->io = NULL;
client->waiting_input = TRUE;
return TRUE;
}
if (client->io == NULL) {
client->io = io_add(client->fd_in, IO_READ,
client_input, client);
}
client->waiting_input = FALSE;
timeout_reset(client->to_idle);
switch (i_stream_read(client->input)) {
case -1:
/* disconnected */
if (client->ctrl_output != NULL)
o_stream_nsend_str(client->ctrl_output, "DISCONNECTED\n");
client_destroy(client);
return FALSE;
case -2:
/* line too long, kill it */
client_abort(client, "Session aborted: Input line too long");
return FALSE;
}
while ((line = i_stream_next_line(client->input)) != NULL) {
const char *const *args = t_strsplit_tabescaped(line);
if (args[0] == NULL)
continue;
cmd = args[0]; args++;
if (client->mail_user == NULL)
ret = client_handle_user_command(client, cmd, args, &error);
else
ret = client_handle_command(client, cmd, args, &error);
if (ret <= 0) {
if (ret == 0)
break;
i_error("Client input error: %s", error);
client_abort(client, "Session aborted: Unexpected input");
return FALSE;
}
}
return TRUE;
}
static void client_input(struct client *client)
{
(void)client_handle_input(client);
}
static int client_output(struct client *client)
{
if (o_stream_flush(client->output) < 0) {
if (client->ctrl_output != NULL)
o_stream_nsend_str(client->ctrl_output, "DISCONNECTED\n");
client_destroy(client);
return 1;
}
timeout_reset(client->to_idle);
if (client->url != NULL) {
if (client_run_url(client) < 0) {
client_destroy(client);
return 1;
}
if (client->url == NULL && client->waiting_input) {
if (!client_handle_input(client)) {
/* client got destroyed */
return 1;
}
}
}
if (client->url != NULL) {
/* url not finished yet */
return 0;
} else if (client->io == NULL) {
/* data still in output buffer, get back here to add IO */
return 0;
} else {
return 1;
}
}
static int
client_ctrl_read_fds(struct client *client)
{
unsigned char data = 0;
ssize_t ret = 1;
if (client->fd_in == -1) {
ret = fd_read(client->fd_ctrl, &data,
sizeof(data), &client->fd_in);
if (ret > 0 && data == '0')
client->fd_out = client->fd_in;
}
if (ret > 0 && client->fd_out == -1) {
ret = fd_read(client->fd_ctrl, &data,
sizeof(data), &client->fd_out);
}
if (ret == 0) {
/* unexpectedly disconnected */
client_destroy(client);
return 0;
} else if (ret < 0) {
if (errno == EAGAIN)
return 0;
i_error("fd_read() failed: %m");
return -1;
} else if (data != '0') {
i_error("fd_read() returned invalid byte 0x%2x", data);
return -1;
}
if (client->fd_in == -1 || client->fd_out == -1) {
i_error("Handshake is missing a file descriptor");
return -1;
}
client->ctrl_input =
i_stream_create_fd(client->fd_ctrl, MAX_INBUF_SIZE);
client->ctrl_output = o_stream_create_fd(client->fd_ctrl, SIZE_MAX);
o_stream_set_no_error_handling(client->ctrl_output, TRUE);
return 1;
}
static void client_ctrl_input(struct client *client)
{
const char *const *args;
const char *line;
int ret;
timeout_reset(client->to_idle);
if (client->fd_in == -1 || client->fd_out == -1) {
if ((ret = client_ctrl_read_fds(client)) <= 0) {
if (ret < 0)
client_abort(client, "FD Transfer failed");
return;
}
}
switch (i_stream_read(client->ctrl_input)) {
case -1:
/* disconnected */
client_destroy(client);
return;
case -2:
/* line too long, kill it */
client_abort(client,
"Control session aborted: Input line too long");
return;
}
if (!client->version_received) {
if ((line = i_stream_next_line(client->ctrl_input)) == NULL)
return;
if (!version_string_verify(line, "imap-urlauth-worker",
IMAP_URLAUTH_WORKER_PROTOCOL_MAJOR_VERSION)) {
i_error("imap-urlauth-worker client not compatible with this server "
"(mixed old and new binaries?) %s", line);
client_abort(client, "Control session aborted: Version mismatch");
return;
}
client->version_received = TRUE;
if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) {
client_destroy(client);
return;
}
}
if (client->access_received) {
client_abort(client, "Control session aborted: Unexpected input");
return;
}
if ((line = i_stream_next_line(client->ctrl_input)) == NULL)
return;
args = t_strsplit_tabescaped(line);
if (*args == NULL || strcmp(*args, "ACCESS") != 0) {
i_error("Invalid control command: %s", str_sanitize(line, 80));
client_abort(client, "Control session aborted: Invalid command");
return;
}
args++;
if (args[0] == NULL || args[1] == NULL) {
i_error("Invalid ACCESS command: %s", str_sanitize(line, 80));
client_abort(client, "Control session aborted: Invalid command");
return;
}
i_assert(client->access_user == NULL);
i_assert(client->access_service == NULL);
if (**args != '\0') {
client->access_user = i_strdup(*args);
client->access_anonymous = FALSE;
} else {
client->access_user = i_strdup("anonymous");
client->access_anonymous = TRUE;
}
args++;
client->access_service = i_strdup(*args);
i_set_failure_prefix("imap-urlauth[%s](%s): ",
my_pid, client->access_user);
args++;
while (*args != NULL) {
/* debug */
if (strcasecmp(*args, "debug") == 0) {
client->debug = TRUE;
/* apps=[,access_apps, &app);
if (client->debug) {
i_debug("User %s has URLAUTH %s access",
client->access_user, app);
}
apps++;
}
} else {
i_error("Invalid ACCESS parameter: %s", str_sanitize(*args, 80));
client_abort(client, "Control session aborted: Invalid command");
return;
}
args++;
}
client->access_received = TRUE;
if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) {
client_destroy(client);
return;
}
client->input = i_stream_create_fd(client->fd_in, MAX_INBUF_SIZE);
client->output = o_stream_create_fd(client->fd_out, SIZE_MAX);
client->io = io_add(client->fd_in, IO_READ, client_input, client);
o_stream_set_no_error_handling(client->output, TRUE);
o_stream_set_flush_callback(client->output, client_output, client);
if (client->debug) {
i_debug("Worker activated for access by user `%s' using service `%s'",
client->access_user, client->access_service);
}
}
static void imap_urlauth_worker_die(void)
{
/* do nothing */
}
static void main_stdio_run(const char *access_user,
const char *const *access_applications)
{
bool debug;
debug = getenv("DEBUG") != NULL;
access_user = access_user != NULL ? access_user : getenv("USER");
if (access_user == NULL && IS_STANDALONE())
access_user = getlogin();
if (access_user == NULL)
i_fatal("USER environment missing");
(void)client_create_standalone(access_user, access_applications,
STDIN_FILENO, STDOUT_FILENO, debug);
}
static void client_connected(struct master_service_connection *conn)
{
master_service_client_connection_accept(conn);
(void)client_create(conn->fd);
}
int main(int argc, char *argv[])
{
static const struct setting_parser_info *set_roots[] = {
&imap_urlauth_worker_setting_parser_info,
NULL
};
enum master_service_flags service_flags = 0;
enum mail_storage_service_flags storage_service_flags =
MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP |
MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT;
ARRAY_TYPE (const_string) access_apps;
const char *access_user = NULL;
int c;
if (IS_STANDALONE()) {
service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
MASTER_SERVICE_FLAG_STD_CLIENT;
} else {
service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
}
master_service = master_service_init("imap-urlauth-worker", service_flags,
&argc, &argv, "a:");
t_array_init(&access_apps, 4);
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'a': {
const char *app = t_strdup(optarg);
array_push_back(&access_apps, &app);
break;
}
default:
return FATAL_DEFAULT;
}
}
if ( optind < argc ) {
access_user = argv[optind++];
}
if (optind != argc) {
i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]);
}
master_service_init_log_with_pid(master_service);
master_service_set_die_callback(master_service, imap_urlauth_worker_die);
storage_service =
mail_storage_service_init(master_service,
set_roots, storage_service_flags);
master_service_init_finish(master_service);
/* fake that we're running, so we know if client was destroyed
while handling its initial input */
io_loop_set_running(current_ioloop);
if (IS_STANDALONE()) {
T_BEGIN {
if (array_count(&access_apps) > 0) {
(void)array_append_space(&access_apps);
main_stdio_run(access_user,
array_front(&access_apps));
} else {
main_stdio_run(access_user, NULL);
}
} T_END;
} else {
io_loop_set_running(current_ioloop);
}
if (io_loop_is_running(current_ioloop))
master_service_run(master_service, client_connected);
clients_destroy_all();
mail_storage_service_deinit(&storage_service);
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/imap-urlauth/Makefile.am 0000644 0000000 0000000 00000004007 14656633576 015551 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
# Refer to comment in imap-urlauth.c for info on what these binaries are for.
pkglibexec_PROGRAMS = imap-urlauth-login imap-urlauth imap-urlauth-worker
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-master \
$(BINARY_CFLAGS)
# imap-urlauth-login
imap_urlauth_login_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir)/src/login-common
imap_urlauth_login_LDADD = \
$(LIBDOVECOT_LOGIN) \
$(LIBDOVECOT) \
$(SSL_LIBS) \
$(BINARY_LDFLAGS)
imap_urlauth_login_DEPENDENCIES = \
$(LIBDOVECOT_LOGIN_DEPS) \
$(LIBDOVECOT_DEPS)
imap_urlauth_login_SOURCES = \
imap-urlauth-login.c \
imap-urlauth-login-settings.c
# imap-urlauth
imap_urlauth_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir)/src/lib-dict \
-DPKG_RUNDIR=\""$(rundir)"\"
imap_urlauth_LDFLAGS = -export-dynamic
imap_urlauth_LDADD = $(LIBDOVECOT) \
$(BINARY_LDFLAGS)
imap_urlauth_DEPENDENCIES = $(LIBDOVECOT_DEPS)
imap_urlauth_SOURCES = \
imap-urlauth.c \
imap-urlauth-client.c \
imap-urlauth-settings.c
# imap-urlauth-worker
imap_urlauth_worker_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/imap \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-imap-storage \
-I$(top_srcdir)/src/lib-imap-urlauth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/login-common
imap_urlauth_worker_LDFLAGS = -export-dynamic \
$(BINARY_LDFLAGS)
urlauth_libs = \
$(top_builddir)/src/lib-imap-urlauth/libimap-urlauth.la
imap_urlauth_worker_LDADD = $(urlauth_libs) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT)
imap_urlauth_worker_DEPENDENCIES = $(urlauth_libs) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS)
imap_urlauth_worker_SOURCES = \
imap-urlauth-worker.c \
imap-urlauth-worker-settings.c
noinst_HEADERS = \
imap-urlauth-client.h \
imap-urlauth-common.h \
imap-urlauth-settings.h \
imap-urlauth-login-settings.h \
imap-urlauth-worker-settings.h
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-common.h 0000644 0000000 0000000 00000000437 14656633576 017567 0000000 0000000 #ifndef IMAP_URLAUTH_COMMON_H
#define IMAP_URLAUTH_COMMON_H
#include "lib.h"
#include "imap-urlauth-client.h"
#include "imap-urlauth-settings.h"
extern bool verbose_proctitle;
extern struct mail_storage_service_ctx *storage_service;
void imap_urlauth_refresh_proctitle(void);
#endif
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-login-settings.c 0000644 0000000 0000000 00000003742 14656633576 021242 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "login-settings.h"
#include "imap-urlauth-login-settings.h"
#include
/* */
static struct file_listener_settings
imap_urlauth_login_unix_listeners_array[] = {
{ "imap-urlauth", 0666, "", "" }
};
static struct file_listener_settings *imap_urlauth_login_unix_listeners[] = {
&imap_urlauth_login_unix_listeners_array[0]
};
static buffer_t imap_urlauth_login_unix_listeners_buf = {
{ { imap_urlauth_login_unix_listeners,
sizeof(imap_urlauth_login_unix_listeners) } }
};
/* */
struct service_settings imap_urlauth_login_service_settings = {
.name = "imap-urlauth-login",
.protocol = "imap",
.type = "login",
.executable = "imap-urlauth-login",
.user = "$default_login_user",
.group = "",
.privileged_group = "",
.extra_groups = "",
.chroot = "token-login",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 0,
.client_limit = 0,
.service_count = 1,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &imap_urlauth_login_unix_listeners_buf,
sizeof(imap_urlauth_login_unix_listeners[0]) } },
.fifo_listeners = ARRAY_INIT,
.inet_listeners = ARRAY_INIT
};
static const struct setting_define imap_urlauth_login_setting_defines[] = {
SETTING_DEFINE_LIST_END
};
static const struct setting_parser_info *imap_urlauth_login_setting_dependencies[] = {
&login_setting_parser_info,
NULL
};
const struct setting_parser_info imap_urlauth_login_setting_parser_info = {
.module_name = "imap-urlauth-login",
.defines = imap_urlauth_login_setting_defines,
.type_offset = SIZE_MAX,
.parent_offset = SIZE_MAX,
.dependencies = imap_urlauth_login_setting_dependencies
};
const struct setting_parser_info *imap_urlauth_login_setting_roots[] = {
&login_setting_parser_info,
&imap_urlauth_login_setting_parser_info,
NULL
};
dovecot-2.3.21.1/src/imap-urlauth/imap-urlauth-login.c 0000644 0000000 0000000 00000012363 14656633576 017403 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "login-common.h"
#include "str.h"
#include "strescape.h"
#include "base64.h"
#include "net.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "master-service.h"
#include "auth-client.h"
#include "client-common.h"
#include "imap-urlauth-login-settings.h"
#define IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION 2
#define IMAP_URLAUTH_PROTOCOL_MINOR_VERSION 0
struct imap_urlauth_client {
struct client common;
const struct imap_urlauth_login_settings *set;
bool version_received:1;
};
static void
imap_urlauth_client_auth_result(struct client *client,
enum client_auth_result result,
const struct client_auth_reply *reply ATTR_UNUSED,
const char *text ATTR_UNUSED)
{
if (result != CLIENT_AUTH_RESULT_SUCCESS) {
/* failed or otherwise invalid status */
client_send_raw(client, "FAILED\n");
client_destroy(client, "Authentication failed");
} else {
/* authentication succeeded */
}
}
static void imap_urlauth_client_handle_input(struct client *client)
{
#define AUTH_ARG_COUNT 6
struct imap_urlauth_client *uauth_client =
(struct imap_urlauth_client *)client;
struct net_unix_cred cred;
const char *line;
const char *const *args;
pid_t pid;
if (!uauth_client->version_received) {
if ((line = i_stream_next_line(client->input)) == NULL)
return;
if (!version_string_verify(line, "imap-urlauth",
IMAP_URLAUTH_PROTOCOL_MAJOR_VERSION)) {
e_error(client->event,
"IMAP URLAUTH client not compatible with this server "
"(mixed old and new binaries?) %s", line);
client_destroy(client, "Version mismatch");
return;
}
uauth_client->version_received = TRUE;
}
if ((line = i_stream_next_line(client->input)) == NULL)
return;
/* read authentication info from input;
"AUTH"\t\t\t\t\t */
args = t_strsplit_tabescaped(line);
if (str_array_length(args) < AUTH_ARG_COUNT ||
strcmp(args[0], "AUTH") != 0 || str_to_pid(args[2], &pid) < 0) {
e_error(client->event,
"IMAP URLAUTH client sent unexpected AUTH input: %s", line);
client_destroy(client, "Unexpected input");
return;
}
/* only imap and submission have direct access to urlauth service */
if (strcmp(args[1], "imap") != 0 && strcmp(args[1], "submission") != 0) {
e_error(client->event,
"IMAP URLAUTH accessed from inappropriate service: %s", args[1]);
client_destroy(client, "Unexpected input");
return;
}
/* verify session pid if possible */
if (net_getunixcred(client->fd, &cred) == 0 &&
cred.pid != (pid_t)-1 && pid != cred.pid) {
e_error(client->event,
"IMAP URLAUTH client sent invalid session pid %ld in AUTH request: "
"it did not match peer credentials (pid=%ld, uid=%ld)",
(long)pid, (long)cred.pid, (long)cred.uid);
client_destroy(client, "Invalid AUTH request");
return;
}
T_BEGIN {
string_t *auth_data = t_str_new(128);
string_t *init_resp;
unsigned int i;
str_append(auth_data, args[1]);
for (i = 2; i < AUTH_ARG_COUNT; i++) {
str_append_c(auth_data, '\0');
str_append(auth_data, args[i]);
}
init_resp = t_str_new(256);
base64_encode(str_data(auth_data),
str_len(auth_data), init_resp);
(void)client_auth_begin_private(client, "DOVECOT-TOKEN",
str_c(init_resp));
} T_END;
}
static void imap_urlauth_client_input(struct client *client)
{
if (!client_read(client))
return;
client_ref(client);
o_stream_cork(client->output);
if (!auth_client_is_connected(auth_client)) {
/* we're not currently connected to auth process -
don't allow any commands */
timeout_remove(&client->to_auth_waiting);
client->input_blocked = TRUE;
} else {
imap_urlauth_client_handle_input(client);
}
o_stream_uncork(client->output);
client_unref(&client);
}
static struct client *imap_urlauth_client_alloc(pool_t pool)
{
struct imap_urlauth_client *uauth_client;
uauth_client = p_new(pool, struct imap_urlauth_client, 1);
return &uauth_client->common;
}
static void imap_urlauth_client_create
(struct client *client, void **other_sets)
{
struct imap_urlauth_client *uauth_client =
(struct imap_urlauth_client *)client;
uauth_client->set = other_sets[0];
client->io = io_add_istream(client->input, client_input, client);
}
static void imap_urlauth_login_preinit(void)
{
login_set_roots = imap_urlauth_login_setting_roots;
}
static void imap_urlauth_login_init(void)
{
}
static void imap_urlauth_login_deinit(void)
{
clients_destroy_all();
}
static struct client_vfuncs imap_urlauth_vfuncs = {
.alloc = imap_urlauth_client_alloc,
.create = imap_urlauth_client_create,
.input = imap_urlauth_client_input,
.auth_result = imap_urlauth_client_auth_result,
.send_raw_data = client_common_send_raw_data,
.free = client_common_default_free,
};
static struct login_binary imap_urlauth_login_binary = {
.protocol = "imap-urlauth",
.process_name = "imap-urlauth-login",
.default_login_socket = LOGIN_TOKEN_DEFAULT_SOCKET,
.event_category = {
.name = "imap",
},
.client_vfuncs = &imap_urlauth_vfuncs,
.preinit = imap_urlauth_login_preinit,
.init = imap_urlauth_login_init,
.deinit = imap_urlauth_login_deinit,
.anonymous_login_acceptable = TRUE,
};
int main(int argc, char *argv[])
{
return login_binary_run(&imap_urlauth_login_binary, argc, argv);
}
dovecot-2.3.21.1/src/lib-imap-client/ 0000755 0000000 0000000 00000000000 14656633637 014130 5 0000000 0000000 dovecot-2.3.21.1/src/lib-imap-client/imapc-connection.c 0000644 0000000 0000000 00000216023 14656633576 017450 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "net.h"
#include "istream.h"
#include "ostream.h"
#include "base64.h"
#include "write-full.h"
#include "str.h"
#include "time-util.h"
#include "dns-lookup.h"
#include "dsasl-client.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"
#include "imap-quote.h"
#include "imap-util.h"
#include "imap-parser.h"
#include "imapc-client-private.h"
#include "imapc-connection.h"
#include
#include
#define IMAPC_COMMAND_STATE_AUTHENTICATE_CONTINUE 10000
#define IMAPC_MAX_INLINE_LITERAL_SIZE (1024*32)
/* If LOGOUT reply takes longer than this, disconnect. */
#define IMAPC_LOGOUT_TIMEOUT_MSECS 5000
enum imapc_input_state {
IMAPC_INPUT_STATE_NONE = 0,
IMAPC_INPUT_STATE_PLUS,
IMAPC_INPUT_STATE_UNTAGGED,
IMAPC_INPUT_STATE_UNTAGGED_NUM,
IMAPC_INPUT_STATE_TAGGED
};
struct imapc_command_stream {
unsigned int pos;
uoff_t size;
struct istream *input;
};
struct imapc_command {
pool_t pool;
buffer_t *data;
unsigned int send_pos;
unsigned int tag;
enum imapc_command_flags flags;
struct imapc_connection *conn;
/* If non-NULL, points to the mailbox where this command should be
executed */
struct imapc_client_mailbox *box;
ARRAY(struct imapc_command_stream) streams;
imapc_command_callback_t *callback;
void *context;
/* This is the AUTHENTICATE command */
bool authenticate:1;
/* This is the IDLE command */
bool idle:1;
/* Waiting for '+' literal reply before we can continue */
bool wait_for_literal:1;
/* Command is fully sent to server */
bool sent:1;
};
ARRAY_DEFINE_TYPE(imapc_command, struct imapc_command *);
struct imapc_connection_literal {
char *temp_path;
int fd;
uoff_t bytes_left;
const struct imap_arg *parent_arg;
unsigned int list_idx;
};
struct imapc_connection {
struct imapc_client *client;
char *name;
int refcount;
int fd;
struct io *io;
struct istream *input, *raw_input;
struct ostream *output, *raw_output;
struct imap_parser *parser;
struct timeout *to;
struct timeout *to_output;
struct dns_lookup *dns_lookup;
struct dsasl_client *sasl_client;
struct ssl_iostream *ssl_iostream;
int (*input_callback)(struct imapc_connection *conn);
enum imapc_input_state input_state;
unsigned int cur_tag;
uint32_t cur_num;
struct timeval last_connect;
unsigned int reconnect_count;
/* If QRESYNC isn't used, this is set immediately after issuing
SELECT/EXAMINE. We could differentiate better whether a mailbox is
"being selected" vs "fully selected", but that code is already in
the imapc-storage side so it would have to be moved or duplicated
here. And since nothing actually cares about this distinction (yet),
don't bother with it for now. This is set to NULL when the mailbox
is closed from imapc-storage point of view, even if the server is
still in selected state (see selected_on_server). */
struct imapc_client_mailbox *selected_box;
/* If QRESYNC is used, this is set when SELECT/EXAMINE is issued.
If the server is already in selected state, the selected_box is most
likely already NULL at this point, because imapc-storage has closed
it. */
struct imapc_client_mailbox *qresync_selecting_box;
enum imapc_connection_state state;
char *disconnect_reason;
enum imapc_capability capabilities;
char **capabilities_list;
imapc_command_callback_t *login_callback;
void *login_context;
/* commands pending in queue to be sent */
ARRAY_TYPE(imapc_command) cmd_send_queue;
/* commands that have been sent, waiting for their tagged reply */
ARRAY_TYPE(imapc_command) cmd_wait_list;
/* commands that were already sent, but were aborted since (due to
unselecting mailbox). */
ARRAY_TYPE(seq_range) aborted_cmd_tags;
unsigned int reconnect_command_count;
unsigned int ips_count, prev_connect_idx;
struct ip_addr *ips;
struct imapc_connection_literal literal;
ARRAY(struct imapc_arg_file) literal_files;
unsigned int throttle_msecs;
unsigned int throttle_shrink_msecs;
unsigned int last_successful_throttle_msecs;
bool throttle_pending;
struct timeval throttle_end_timeval;
struct timeout *to_throttle, *to_throttle_shrink;
bool reconnecting:1;
bool reconnect_waiting:1;
bool reconnect_ok:1;
bool idling:1;
bool idle_stopping:1;
bool idle_plus_waiting:1;
bool select_waiting_reply:1;
/* TRUE if IMAP server is in SELECTED state. select_box may be NULL
though, if we already closed the mailbox from client point of
view. */
bool selected_on_server:1;
};
static void imapc_connection_capability_cb(const struct imapc_command_reply *reply,
void *context);
static int imapc_connection_output(struct imapc_connection *conn);
static int imapc_connection_ssl_init(struct imapc_connection *conn);
static void imapc_command_free(struct imapc_command *cmd);
static void imapc_command_send_more(struct imapc_connection *conn);
static void
imapc_login_callback(struct imapc_connection *conn,
const struct imapc_command_reply *reply);
static void
imapc_auth_ok(struct imapc_connection *conn)
{
if (conn->client->set.debug)
i_debug("imapc(%s): Authenticated successfully", conn->name);
if (conn->client->state_change_callback == NULL)
return;
conn->client->state_change_callback(conn->client->state_change_context,
IMAPC_STATE_CHANGE_AUTH_OK, NULL);
}
static void
imapc_auth_failed(struct imapc_connection *conn, const struct imapc_command_reply *_reply,
const char *error)
{
struct imapc_command_reply reply = *_reply;
reply.text_without_resp = reply.text_full =
t_strdup_printf("Authentication failed: %s", error);
if (reply.state != IMAPC_COMMAND_STATE_DISCONNECTED) {
reply.state = IMAPC_COMMAND_STATE_AUTH_FAILED;
i_error("imapc(%s): %s", conn->name, reply.text_full);
}
imapc_login_callback(conn, &reply);
if (conn->client->state_change_callback == NULL)
return;
conn->client->state_change_callback(conn->client->state_change_context,
IMAPC_STATE_CHANGE_AUTH_FAILED,
error);
}
struct imapc_connection *
imapc_connection_init(struct imapc_client *client,
imapc_command_callback_t *login_callback,
void *login_context)
{
struct imapc_connection *conn;
conn = i_new(struct imapc_connection, 1);
conn->refcount = 1;
conn->client = client;
conn->login_callback = login_callback;
conn->login_context = login_context;
conn->fd = -1;
conn->name = i_strdup_printf("%s:%u", client->set.host,
client->set.port);
conn->literal.fd = -1;
conn->reconnect_ok = (client->set.connect_retry_count>0);
i_array_init(&conn->cmd_send_queue, 8);
i_array_init(&conn->cmd_wait_list, 32);
i_array_init(&conn->literal_files, 4);
i_array_init(&conn->aborted_cmd_tags, 8);
if (client->set.debug)
i_debug("imapc(%s): Created new connection", conn->name);
imapc_client_ref(client);
return conn;
}
static void imapc_connection_ref(struct imapc_connection *conn)
{
i_assert(conn->refcount > 0);
conn->refcount++;
}
static void imapc_connection_unref(struct imapc_connection **_conn)
{
struct imapc_connection *conn = *_conn;
i_assert(conn->refcount > 0);
*_conn = NULL;
if (--conn->refcount > 0)
return;
i_assert(conn->disconnect_reason == NULL);
if (conn->capabilities_list != NULL)
p_strsplit_free(default_pool, conn->capabilities_list);
array_free(&conn->cmd_send_queue);
array_free(&conn->cmd_wait_list);
array_free(&conn->literal_files);
array_free(&conn->aborted_cmd_tags);
imapc_client_unref(&conn->client);
i_free(conn->ips);
i_free(conn->name);
i_free(conn);
}
void imapc_connection_deinit(struct imapc_connection **_conn)
{
imapc_connection_disconnect(*_conn);
imapc_connection_unref(_conn);
}
void imapc_connection_ioloop_changed(struct imapc_connection *conn)
{
if (conn->io != NULL)
conn->io = io_loop_move_io(&conn->io);
if (conn->to != NULL)
conn->to = io_loop_move_timeout(&conn->to);
if (conn->to_throttle != NULL)
conn->to_throttle = io_loop_move_timeout(&conn->to_throttle);
if (conn->to_throttle_shrink != NULL)
conn->to_throttle_shrink = io_loop_move_timeout(&conn->to_throttle_shrink);
if (conn->output != NULL)
o_stream_switch_ioloop(conn->output);
if (conn->dns_lookup != NULL)
dns_lookup_switch_ioloop(conn->dns_lookup);
if (conn->client->ioloop == NULL && conn->to_output != NULL) {
/* we're only once moving the to_output to the main ioloop,
since timeout moves currently also reset the timeout.
(the rest of the times this is a no-op) */
conn->to_output = io_loop_move_timeout(&conn->to_output);
}
}
static const char *imapc_command_get_readable(struct imapc_command *cmd)
{
string_t *str = t_str_new(256);
const unsigned char *data = cmd->data->data;
unsigned int i;
for (i = 0; i < cmd->data->used; i++) {
if (data[i] != '\r' && data[i] != '\n')
str_append_c(str, data[i]);
}
return str_c(str);
}
static void
imapc_connection_abort_commands_array(ARRAY_TYPE(imapc_command) *cmd_array,
ARRAY_TYPE(imapc_command) *dest_array,
struct imapc_client_mailbox *only_box,
bool keep_retriable)
{
struct imapc_command *cmd;
unsigned int i;
for (i = 0; i < array_count(cmd_array); ) {
cmd = array_idx_elem(cmd_array, i);
if (cmd->box != only_box && only_box != NULL)
i++;
else if (keep_retriable &&
(cmd->flags & IMAPC_COMMAND_FLAG_RETRIABLE) != 0) {
cmd->send_pos = 0;
cmd->wait_for_literal = 0;
cmd->flags |= IMAPC_COMMAND_FLAG_RECONNECTED;
i++;
} else {
array_delete(cmd_array, i, 1);
array_push_back(dest_array, &cmd);
}
}
}
void imapc_connection_abort_commands(struct imapc_connection *conn,
struct imapc_client_mailbox *only_box,
bool keep_retriable)
{
struct imapc_command *cmd;
ARRAY_TYPE(imapc_command) tmp_array;
struct imapc_command_reply reply;
t_array_init(&tmp_array, 8);
imapc_connection_abort_commands_array(&conn->cmd_wait_list, &tmp_array,
only_box, keep_retriable);
imapc_connection_abort_commands_array(&conn->cmd_send_queue, &tmp_array,
only_box, keep_retriable);
if (array_count(&conn->cmd_wait_list) > 0 && only_box == NULL) {
/* need to move all the waiting commands to send queue */
array_append_array(&conn->cmd_wait_list,
&conn->cmd_send_queue);
array_clear(&conn->cmd_send_queue);
array_append_array(&conn->cmd_send_queue,
&conn->cmd_wait_list);
array_clear(&conn->cmd_wait_list);
}
/* abort the commands. we'll do it here later so that if the
callback recurses us back here we don't crash */
i_zero(&reply);
reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
if (only_box != NULL) {
reply.text_without_resp = reply.text_full =
"Unselecting mailbox";
} else {
reply.text_without_resp = reply.text_full =
"Disconnected from server";
}
array_foreach_elem(&tmp_array, cmd) {
if (cmd->sent && conn->state == IMAPC_CONNECTION_STATE_DONE) {
/* We're not disconnected, so the reply will still
come. Remember that it needs to be ignored. */
seq_range_array_add(&conn->aborted_cmd_tags, cmd->tag);
}
cmd->callback(&reply, cmd->context);
imapc_command_free(cmd);
}
if (array_count(&conn->cmd_wait_list) == 0)
timeout_remove(&conn->to);
}
static void
imapc_login_callback(struct imapc_connection *conn,
const struct imapc_command_reply *reply)
{
if (conn->login_callback != NULL)
conn->login_callback(reply, conn->login_context);
}
static void imapc_connection_set_state(struct imapc_connection *conn,
enum imapc_connection_state state)
{
struct imapc_command_reply reply;
conn->state = state;
switch (state) {
case IMAPC_CONNECTION_STATE_DISCONNECTED:
i_zero(&reply);
reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
reply.text_full = "Disconnected from server";
if (conn->disconnect_reason != NULL) {
reply.text_full = t_strdup_printf("%s: %s",
reply.text_full, conn->disconnect_reason);
i_free_and_null(conn->disconnect_reason);
}
reply.text_without_resp = reply.text_full;
if (!conn->reconnecting) {
imapc_login_callback(conn, &reply);
i_free(conn->ips);
conn->ips_count = 0;
}
array_clear(&conn->aborted_cmd_tags);
conn->idling = FALSE;
conn->idle_plus_waiting = FALSE;
conn->idle_stopping = FALSE;
conn->select_waiting_reply = FALSE;
conn->qresync_selecting_box = NULL;
conn->selected_box = NULL;
conn->selected_on_server = FALSE;
/* fall through */
case IMAPC_CONNECTION_STATE_DONE:
/* if we came from imapc_client_get_capabilities(), stop so
it can finish up and not just hang indefinitely. */
if (conn->client->stop_on_state_finish && !conn->reconnecting)
imapc_client_stop(conn->client);
break;
default:
break;
}
}
static void imapc_connection_lfiles_free(struct imapc_connection *conn)
{
struct imapc_arg_file *lfile;
array_foreach_modifiable(&conn->literal_files, lfile) {
if (close(lfile->fd) < 0)
i_error("imapc: close(literal file) failed: %m");
}
array_clear(&conn->literal_files);
}
static void
imapc_connection_literal_reset(struct imapc_connection_literal *literal)
{
i_close_fd_path(&literal->fd, literal->temp_path);
i_free_and_null(literal->temp_path);
i_zero(literal);
literal->fd = -1;
}
void imapc_connection_disconnect_full(struct imapc_connection *conn,
bool reconnecting)
{
/* timeout may be set also in disconnected state */
timeout_remove(&conn->to);
conn->reconnecting = reconnecting;
if (conn->state == IMAPC_CONNECTION_STATE_DISCONNECTED) {
i_assert(array_count(&conn->cmd_wait_list) == 0);
if (conn->reconnect_command_count == 0)
imapc_connection_abort_commands(conn, NULL,
reconnecting);
return;
}
if (conn->client->set.debug)
i_debug("imapc(%s): Disconnected", conn->name);
if (conn->dns_lookup != NULL)
dns_lookup_abort(&conn->dns_lookup);
imapc_connection_lfiles_free(conn);
imapc_connection_literal_reset(&conn->literal);
timeout_remove(&conn->to_output);
timeout_remove(&conn->to_throttle);
timeout_remove(&conn->to_throttle_shrink);
if (conn->parser != NULL)
imap_parser_unref(&conn->parser);
io_remove(&conn->io);
ssl_iostream_destroy(&conn->ssl_iostream);
if (conn->fd != -1) {
i_stream_destroy(&conn->input);
o_stream_destroy(&conn->output);
net_disconnect(conn->fd);
conn->fd = -1;
}
/* get capabilities again after reconnection. this is especially
important because post-login capabilities often do not contain AUTH=
capabilities. */
conn->capabilities = 0;
if (conn->capabilities_list != NULL) {
p_strsplit_free(default_pool, conn->capabilities_list);
conn->capabilities_list = NULL;
}
imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DISCONNECTED);
imapc_connection_abort_commands(conn, NULL, reconnecting);
if (!reconnecting) {
imapc_client_try_stop(conn->client);
}
}
void imapc_connection_set_no_reconnect(struct imapc_connection *conn)
{
conn->reconnect_ok = FALSE;
}
void imapc_connection_disconnect(struct imapc_connection *conn)
{
imapc_connection_disconnect_full(conn, FALSE);
}
static void imapc_connection_set_disconnected(struct imapc_connection *conn)
{
imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DISCONNECTED);
imapc_connection_abort_commands(conn, NULL, FALSE);
}
static bool imapc_connection_can_reconnect(struct imapc_connection *conn)
{
if (conn->client->logging_out)
return FALSE;
if (conn->client->set.connect_retry_count == 0 ||
(conn->client->set.connect_retry_count < UINT_MAX &&
conn->reconnect_count >= conn->client->set.connect_retry_count))
return FALSE;
if (conn->selected_box != NULL)
return imapc_client_mailbox_can_reconnect(conn->selected_box);
else {
return conn->reconnect_command_count == 0 &&
conn->reconnect_ok;
}
}
static void imapc_connection_reconnect(struct imapc_connection *conn)
{
conn->reconnect_ok = FALSE;
conn->reconnect_waiting = FALSE;
if (conn->selected_box != NULL) {
i_assert(!conn->selected_box->reconnecting);
conn->selected_box->reconnecting = TRUE;
/* if we fail again, avoid reconnecting immediately. if the
server is broken we could just get into an infinitely
failing reconnection loop. */
conn->selected_box->reconnect_ok = FALSE;
}
imapc_connection_disconnect_full(conn, TRUE);
imapc_connection_connect(conn);
}
void imapc_connection_try_reconnect(struct imapc_connection *conn,
const char *errstr,
unsigned int delay_msecs,
bool connect_error)
{
/* Try the next IP address only for connect() problems. */
if (conn->prev_connect_idx + 1 < conn->ips_count && connect_error) {
i_warning("imapc(%s): %s - trying the next IP", conn->name, errstr);
conn->reconnect_ok = TRUE;
imapc_connection_disconnect_full(conn, TRUE);
imapc_connection_connect(conn);
return;
}
if (!imapc_connection_can_reconnect(conn)) {
i_error("imapc(%s): %s - disconnecting", conn->name, errstr);
imapc_connection_disconnect(conn);
} else {
conn->reconnecting = TRUE;
i_warning("imapc(%s): %s - reconnecting (delay %u ms)", conn->name, errstr, delay_msecs);
if (delay_msecs == 0)
imapc_connection_reconnect(conn);
else {
imapc_connection_disconnect_full(conn, TRUE);
conn->to = timeout_add(delay_msecs, imapc_connection_reconnect, conn);
conn->reconnect_count++;
conn->reconnect_waiting = TRUE;
}
}
}
static void ATTR_FORMAT(2, 3)
imapc_connection_input_error(struct imapc_connection *conn,
const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
i_error("imapc(%s): Server sent invalid input: %s",
conn->name, t_strdup_vprintf(fmt, va));
imapc_connection_disconnect(conn);
va_end(va);
}
static bool last_arg_is_fetch_body(const struct imap_arg *args,
const struct imap_arg **parent_arg_r,
unsigned int *idx_r)
{
const struct imap_arg *list;
const char *name;
unsigned int count;
if (args[0].type == IMAP_ARG_ATOM &&
imap_arg_atom_equals(&args[1], "FETCH") &&
imap_arg_get_list_full(&args[2], &list, &count) && count >= 2 &&
list[count].type == IMAP_ARG_LITERAL_SIZE &&
imap_arg_get_atom(&list[count-1], &name) &&
strncasecmp(name, "BODY[", 5) == 0) {
*parent_arg_r = &args[2];
*idx_r = count;
return TRUE;
}
return FALSE;
}
static int
imapc_connection_read_literal_init(struct imapc_connection *conn, uoff_t size,
const struct imap_arg *args)
{
const char *path;
const struct imap_arg *parent_arg;
unsigned int idx;
i_assert(conn->literal.fd == -1);
if (size <= IMAPC_MAX_INLINE_LITERAL_SIZE ||
!last_arg_is_fetch_body(args, &parent_arg, &idx)) {
/* read the literal directly into parser */
return 0;
}
conn->literal.fd = imapc_client_create_temp_fd(conn->client, &path);
if (conn->literal.fd == -1)
return -1;
conn->literal.temp_path = i_strdup(path);
conn->literal.bytes_left = size;
conn->literal.parent_arg = parent_arg;
conn->literal.list_idx = idx;
return 1;
}
static int imapc_connection_read_literal(struct imapc_connection *conn)
{
struct imapc_arg_file *lfile;
const unsigned char *data;
size_t size;
if (conn->literal.bytes_left == 0)
return 1;
data = i_stream_get_data(conn->input, &size);
if (size > conn->literal.bytes_left)
size = conn->literal.bytes_left;
if (size > 0) {
if (write_full(conn->literal.fd, data, size) < 0) {
i_error("imapc(%s): write(%s) failed: %m",
conn->name, conn->literal.temp_path);
imapc_connection_disconnect(conn);
return -1;
}
i_stream_skip(conn->input, size);
conn->literal.bytes_left -= size;
}
if (conn->literal.bytes_left > 0)
return 0;
/* finished */
lfile = array_append_space(&conn->literal_files);
lfile->fd = conn->literal.fd;
lfile->parent_arg = conn->literal.parent_arg;
lfile->list_idx = conn->literal.list_idx;
conn->literal.fd = -1;
imapc_connection_literal_reset(&conn->literal);
return 1;
}
static int
imapc_connection_read_line_more(struct imapc_connection *conn,
const struct imap_arg **imap_args_r)
{
uoff_t literal_size;
int ret;
if ((ret = imapc_connection_read_literal(conn)) <= 0)
return ret;
ret = imap_parser_read_args(conn->parser, 0,
IMAP_PARSE_FLAG_LITERAL_SIZE |
IMAP_PARSE_FLAG_ATOM_ALLCHARS |
IMAP_PARSE_FLAG_LITERAL8 |
IMAP_PARSE_FLAG_SERVER_TEXT, imap_args_r);
if (ret == -2) {
/* need more data */
return 0;
}
if (ret < 0) {
enum imap_parser_error parser_error;
const char *err_msg = imap_parser_get_error(conn->parser, &parser_error);
if (parser_error != IMAP_PARSE_ERROR_BAD_SYNTAX)
imapc_connection_input_error(conn, "Error parsing input: %s", err_msg);
else
i_error("Error parsing input: %s", err_msg);
return -1;
}
if (imap_parser_get_literal_size(conn->parser, &literal_size)) {
if (imapc_connection_read_literal_init(conn, literal_size,
*imap_args_r) <= 0) {
imap_parser_read_last_literal(conn->parser);
return 2;
}
return imapc_connection_read_line_more(conn, imap_args_r);
}
return 1;
}
static int
imapc_connection_read_line(struct imapc_connection *conn,
const struct imap_arg **imap_args_r)
{
const unsigned char *data;
size_t size;
int ret;
while ((ret = imapc_connection_read_line_more(conn, imap_args_r)) == 2)
;
if (ret > 0) {
data = i_stream_get_data(conn->input, &size);
if (size >= 2 && data[0] == '\r' && data[1] == '\n')
i_stream_skip(conn->input, 2);
else if (size >= 1 && data[0] == '\n')
i_stream_skip(conn->input, 1);
else
i_panic("imapc: Missing LF from input line");
} else if (ret < 0) {
data = i_stream_get_data(conn->input, &size);
unsigned char *lf = memchr(data, '\n', size);
if (lf != NULL)
i_stream_skip(conn->input, (lf - data) + 1);
}
return ret;
}
static int
imapc_connection_parse_capability(struct imapc_connection *conn,
const char *value)
{
const char *const *tmp;
unsigned int i;
if (conn->client->set.debug) {
i_debug("imapc(%s): Server capabilities: %s",
conn->name, value);
}
conn->capabilities = 0;
if (conn->capabilities_list != NULL)
p_strsplit_free(default_pool, conn->capabilities_list);
conn->capabilities_list = p_strsplit(default_pool, value, " ");
for (tmp = t_strsplit(value, " "); *tmp != NULL; tmp++) {
for (i = 0; imapc_capability_names[i].name != NULL; i++) {
const struct imapc_capability_name *cap =
&imapc_capability_names[i];
if (strcasecmp(*tmp, cap->name) == 0) {
conn->capabilities |= cap->capability;
break;
}
}
}
if ((conn->capabilities & IMAPC_CAPABILITY_IMAP4REV1) == 0) {
imapc_connection_input_error(conn,
"CAPABILITY list is missing IMAP4REV1");
return -1;
}
return 0;
}
static int
imapc_connection_handle_resp_text_code(struct imapc_connection *conn,
const char *key, const char *value)
{
if (strcasecmp(key, "CAPABILITY") == 0) {
if (imapc_connection_parse_capability(conn, value) < 0)
return -1;
}
if (strcasecmp(key, "CLOSED") == 0) {
/* QRESYNC: SELECTing another mailbox */
if (conn->qresync_selecting_box != NULL) {
conn->selected_box = conn->qresync_selecting_box;
conn->qresync_selecting_box = NULL;
} else {
conn->selected_on_server = FALSE;
}
}
return 0;
}
static int
imapc_connection_handle_resp_text(struct imapc_connection *conn,
const char *text,
const char **key_r, const char **value_r)
{
const char *p, *value;
i_assert(text[0] == '[');
p = strchr(text, ']');
if (p == NULL) {
imapc_connection_input_error(conn, "Missing ']' in resp-text");
return -1;
}
text = t_strdup_until(text + 1, p);
value = strchr(text, ' ');
if (value != NULL) {
*key_r = t_strdup_until(text, value);
*value_r = value + 1;
} else {
*key_r = text;
*value_r = "";
}
return imapc_connection_handle_resp_text_code(conn, *key_r, *value_r);
}
static int
imapc_connection_handle_imap_resp_text(struct imapc_connection *conn,
const struct imap_arg *args,
const char **key_r, const char **value_r)
{
const char *text;
if (args->type != IMAP_ARG_ATOM)
return 0;
text = imap_args_to_str(args);
if (*text != '[') {
if (*text == '\0') {
imapc_connection_input_error(conn,
"Missing text in resp-text");
return -1;
}
return 0;
}
return imapc_connection_handle_resp_text(conn, text, key_r, value_r);
}
static bool need_literal(const char *str)
{
unsigned int i;
for (i = 0; str[i] != '\0'; i++) {
unsigned char c = str[i];
if ((c & 0x80) != 0 || c == '\r' || c == '\n')
return TRUE;
}
return FALSE;
}
static void imapc_connection_input_reset(struct imapc_connection *conn)
{
conn->input_state = IMAPC_INPUT_STATE_NONE;
conn->cur_tag = 0;
conn->cur_num = 0;
if (conn->parser != NULL)
imap_parser_reset(conn->parser);
imapc_connection_lfiles_free(conn);
}
static void
imapc_connection_auth_finish(struct imapc_connection *conn,
const struct imapc_command_reply *reply)
{
if (reply->state != IMAPC_COMMAND_STATE_OK) {
imapc_auth_failed(conn, reply, reply->text_full);
imapc_connection_disconnect(conn);
return;
}
imapc_auth_ok(conn);
i_assert(array_count(&conn->cmd_wait_list) == 0);
timeout_remove(&conn->to);
imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DONE);
imapc_login_callback(conn, reply);
imapc_command_send_more(conn);
}
static void imapc_connection_login_cb(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_connection *conn = context;
imapc_connection_auth_finish(conn, reply);
}
static void
imapc_connection_proxyauth_login_cb(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_connection *conn = context;
const struct imapc_client_settings *set = &conn->client->set;
struct imapc_command *cmd;
if (reply->state == IMAPC_COMMAND_STATE_OK) {
cmd = imapc_connection_cmd(conn, imapc_connection_login_cb,
conn);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
imapc_command_sendf(cmd, "PROXYAUTH %s", set->username);
imapc_command_send_more(conn);
} else {
imapc_connection_auth_finish(conn, reply);
}
}
static void
imapc_connection_authenticate_cb(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_connection *conn = context;
const unsigned char *sasl_output;
size_t input_len, sasl_output_len;
buffer_t *buf;
const char *error;
if ((int)reply->state != IMAPC_COMMAND_STATE_AUTHENTICATE_CONTINUE) {
dsasl_client_free(&conn->sasl_client);
imapc_connection_auth_finish(conn, reply);
return;
}
input_len = strlen(reply->text_full);
buf = t_buffer_create(MAX_BASE64_DECODED_SIZE(input_len));
if (base64_decode(reply->text_full, input_len, NULL, buf) < 0) {
imapc_auth_failed(conn, reply,
t_strdup_printf("Server sent non-base64 input for AUTHENTICATE: %s",
reply->text_full));
} else if (dsasl_client_input(conn->sasl_client, buf->data, buf->used, &error) < 0) {
imapc_auth_failed(conn, reply, error);
} else if (dsasl_client_output(conn->sasl_client, &sasl_output,
&sasl_output_len, &error) < 0) {
imapc_auth_failed(conn, reply, error);
} else {
string_t *imap_output =
t_str_new(MAX_BASE64_ENCODED_SIZE(sasl_output_len)+2);
base64_encode(sasl_output, sasl_output_len, imap_output);
str_append(imap_output, "\r\n");
o_stream_nsend(conn->output, str_data(imap_output),
str_len(imap_output));
return;
}
imapc_connection_disconnect(conn);
}
static bool imapc_connection_have_auth(struct imapc_connection *conn,
const char *mech_name)
{
char *const *capa;
for (capa = conn->capabilities_list; *capa != NULL; capa++) {
if (strncasecmp(*capa, "AUTH=", 5) == 0 &&
strcasecmp((*capa)+5, mech_name) == 0)
return TRUE;
}
return FALSE;
}
static int
imapc_connection_get_sasl_mech(struct imapc_connection *conn,
const struct dsasl_client_mech **mech_r,
const char **error_r)
{
const struct imapc_client_settings *set = &conn->client->set;
const char *const *mechanisms =
t_strsplit_spaces(set->sasl_mechanisms, ", ");
/* find one of the specified SASL mechanisms */
for (; *mechanisms != NULL; mechanisms++) {
if (imapc_connection_have_auth(conn, *mechanisms)) {
*mech_r = dsasl_client_mech_find(*mechanisms);
if (*mech_r != NULL)
return 0;
*error_r = t_strdup_printf(
"Support for SASL method '%s' is missing", *mechanisms);
return -1;
}
}
*error_r = t_strdup_printf("IMAP server doesn't support any of the requested SASL mechanisms: %s",
set->sasl_mechanisms);
return -1;
}
static void imapc_connection_authenticate(struct imapc_connection *conn)
{
const struct imapc_client_settings *set = &conn->client->set;
struct imapc_command *cmd;
struct dsasl_client_settings sasl_set;
const struct dsasl_client_mech *sasl_mech = NULL;
const char *error;
if (conn->client->set.debug) {
if (set->master_user == NULL) {
i_debug("imapc(%s): Authenticating as %s",
conn->name, set->username);
} else {
i_debug("imapc(%s): Authenticating as %s for user %s",
conn->name, set->master_user, set->username);
}
}
if (set->sasl_mechanisms != NULL && set->sasl_mechanisms[0] != '\0') {
if (imapc_connection_get_sasl_mech(conn, &sasl_mech, &error) < 0) {
struct imapc_command_reply reply;
i_zero(&reply);
reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
reply.text_full = "";
imapc_auth_failed(conn, &reply, error);
imapc_connection_disconnect(conn);
return;
}
}
if (set->use_proxyauth && set->master_user != NULL) {
/* We can use LOGIN command */
cmd = imapc_connection_cmd(conn, imapc_connection_proxyauth_login_cb,
conn);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
imapc_command_sendf(cmd, "LOGIN %s %s",
set->master_user, set->password);
return;
}
if (sasl_mech == NULL &&
((set->master_user == NULL &&
!need_literal(set->username) && !need_literal(set->password)) ||
(conn->capabilities & IMAPC_CAPABILITY_AUTH_PLAIN) == 0)) {
/* We can use LOGIN command */
cmd = imapc_connection_cmd(conn, imapc_connection_login_cb,
conn);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
imapc_command_sendf(cmd, "LOGIN %s %s",
set->username, set->password);
return;
}
i_zero(&sasl_set);
if (set->master_user == NULL)
sasl_set.authid = set->username;
else {
sasl_set.authid = set->master_user;
sasl_set.authzid = set->username;
}
sasl_set.password = set->password;
if (sasl_mech == NULL)
sasl_mech = &dsasl_client_mech_plain;
conn->sasl_client = dsasl_client_new(sasl_mech, &sasl_set);
cmd = imapc_connection_cmd(conn, imapc_connection_authenticate_cb, conn);
cmd->authenticate = TRUE;
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
if ((conn->capabilities & IMAPC_CAPABILITY_SASL_IR) != 0) {
const unsigned char *sasl_output;
size_t sasl_output_len;
string_t *sasl_output_base64;
const char *error;
if (dsasl_client_output(conn->sasl_client, &sasl_output,
&sasl_output_len, &error) < 0) {
i_error("imapc(%s): Failed to create initial SASL reply: %s",
conn->name, error);
imapc_connection_disconnect(conn);
return;
}
sasl_output_base64 = t_str_new(MAX_BASE64_ENCODED_SIZE(sasl_output_len));
base64_encode(sasl_output, sasl_output_len, sasl_output_base64);
imapc_command_sendf(cmd, "AUTHENTICATE %1s %1s",
dsasl_client_mech_get_name(sasl_mech),
str_c(sasl_output_base64));
} else {
imapc_command_sendf(cmd, "AUTHENTICATE %1s",
dsasl_client_mech_get_name(sasl_mech));
}
}
static void
imapc_connection_starttls_cb(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_connection *conn = context;
struct imapc_command *cmd;
if (reply->state != IMAPC_COMMAND_STATE_OK) {
imapc_connection_input_error(conn, "STARTTLS failed: %s",
reply->text_full);
return;
}
if (imapc_connection_ssl_init(conn) < 0)
imapc_connection_disconnect(conn);
else {
/* get updated capabilities */
cmd = imapc_connection_cmd(conn, imapc_connection_capability_cb,
conn);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
imapc_command_send(cmd, "CAPABILITY");
}
}
static void
imapc_connection_id_callback(const struct imapc_command_reply *reply ATTR_UNUSED,
void *context ATTR_UNUSED)
{
}
static void imapc_connection_send_id(struct imapc_connection *conn)
{
static unsigned int global_id_counter = 0;
struct imapc_command *cmd;
if ((conn->capabilities & IMAPC_CAPABILITY_ID) == 0 ||
conn->client->set.session_id_prefix == NULL)
return;
cmd = imapc_connection_cmd(conn, imapc_connection_id_callback, conn);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
imapc_command_send(cmd, t_strdup_printf(
"ID (\"name\" \"Dovecot\" \"x-session-ext-id\" \"%s-%u\")",
conn->client->set.session_id_prefix, ++global_id_counter));
}
static void imapc_connection_starttls(struct imapc_connection *conn)
{
struct imapc_command *cmd;
if (conn->client->set.ssl_mode == IMAPC_CLIENT_SSL_MODE_STARTTLS &&
conn->ssl_iostream == NULL) {
if ((conn->capabilities & IMAPC_CAPABILITY_STARTTLS) == 0) {
i_error("imapc(%s): Requested STARTTLS, "
"but server doesn't support it",
conn->name);
imapc_connection_disconnect(conn);
return;
}
cmd = imapc_connection_cmd(conn, imapc_connection_starttls_cb,
conn);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
imapc_command_send(cmd, "STARTTLS");
return;
}
imapc_connection_send_id(conn);
imapc_connection_authenticate(conn);
}
static void
imapc_connection_capability_cb(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_connection *conn = context;
if (reply->state != IMAPC_COMMAND_STATE_OK) {
imapc_connection_input_error(conn,
"Failed to get capabilities: %s", reply->text_full);
} else if (conn->capabilities == 0) {
imapc_connection_input_error(conn,
"Capabilities not returned by server");
} else {
imapc_connection_starttls(conn);
}
}
static int imapc_connection_input_banner(struct imapc_connection *conn)
{
const struct imap_arg *imap_args;
const char *key, *value;
struct imapc_command *cmd;
int ret;
if ((ret = imapc_connection_read_line(conn, &imap_args)) <= 0)
return ret;
/* we already verified that the banner beigns with OK */
i_assert(imap_arg_atom_equals(imap_args, "OK"));
imap_args++;
if (imapc_connection_handle_imap_resp_text(conn, imap_args,
&key, &value) < 0)
return -1;
imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_AUTHENTICATING);
if (conn->capabilities == 0) {
/* capabilities weren't sent in the banner. ask for them. */
cmd = imapc_connection_cmd(conn, imapc_connection_capability_cb,
conn);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN);
imapc_command_send(cmd, "CAPABILITY");
} else {
imapc_connection_starttls(conn);
}
conn->input_callback = NULL;
imapc_connection_input_reset(conn);
return 1;
}
static int imapc_connection_input_untagged(struct imapc_connection *conn)
{
const struct imap_arg *imap_args;
const unsigned char *data;
size_t size;
const char *name, *value;
struct imap_parser *parser;
struct imapc_untagged_reply reply;
int ret;
if (conn->state == IMAPC_CONNECTION_STATE_CONNECTING) {
/* input banner */
data = i_stream_get_data(conn->input, &size);
if (size < 3 && memchr(data, '\n', size) == NULL)
return 0;
if (i_memcasecmp(data, "OK ", 3) != 0) {
imapc_connection_input_error(conn,
"Banner doesn't begin with OK: %s",
t_strcut(t_strndup(data, size), '\n'));
return -1;
}
conn->input_callback = imapc_connection_input_banner;
return 1;
}
if ((ret = imapc_connection_read_line(conn, &imap_args)) == 0)
return 0;
else if (ret < 0) {
imapc_connection_input_reset(conn);
return 1;
}
if (!imap_arg_get_atom(&imap_args[0], &name)) {
imapc_connection_input_error(conn, "Invalid untagged reply");
return -1;
}
imap_args++;
if (conn->input_state == IMAPC_INPUT_STATE_UNTAGGED &&
str_to_uint32(name, &conn->cur_num) == 0) {
/* */
conn->input_state = IMAPC_INPUT_STATE_UNTAGGED_NUM;
if (!imap_arg_get_atom(&imap_args[0], &name)) {
imapc_connection_input_error(conn,
"Invalid untagged reply");
return -1;
}
imap_args++;
}
i_zero(&reply);
if (strcasecmp(name, "OK") == 0) {
if (imapc_connection_handle_imap_resp_text(conn, imap_args,
&reply.resp_text_key,
&reply.resp_text_value) < 0)
return -1;
} else if (strcasecmp(name, "CAPABILITY") == 0) {
value = imap_args_to_str(imap_args);
if (imapc_connection_parse_capability(conn, value) < 0)
return -1;
} else if (strcasecmp(name, "BYE") == 0) {
i_free(conn->disconnect_reason);
conn->disconnect_reason = i_strdup(imap_args_to_str(imap_args));
}
reply.name = name;
reply.num = conn->cur_num;
reply.args = imap_args;
reply.file_args = array_get(&conn->literal_files,
&reply.file_args_count);
if (conn->selected_box != NULL) {
reply.untagged_box_context =
conn->selected_box->untagged_box_context;
}
/* the callback may disconnect and destroy the parser */
parser = conn->parser;
imap_parser_ref(parser);
conn->client->untagged_callback(&reply, conn->client->untagged_context);
imap_parser_unref(&parser);
imapc_connection_input_reset(conn);
return 1;
}
static int imapc_connection_input_plus(struct imapc_connection *conn)
{
struct imapc_command *const *cmds;
unsigned int cmds_count;
const char *line;
if ((line = i_stream_next_line(conn->input)) == NULL)
return 0;
cmds = array_get(&conn->cmd_send_queue, &cmds_count);
if (conn->idle_plus_waiting) {
/* "+ idling" reply for IDLE command */
conn->idle_plus_waiting = FALSE;
conn->idling = TRUE;
/* no timing out while IDLEing */
if (conn->to != NULL && !conn->idle_stopping)
timeout_remove(&conn->to);
} else if (cmds_count > 0 && cmds[0]->wait_for_literal) {
/* reply for literal */
cmds[0]->wait_for_literal = FALSE;
imapc_command_send_more(conn);
} else {
cmds = array_get(&conn->cmd_wait_list, &cmds_count);
if (cmds_count > 0 && cmds[0]->authenticate) {
/* continue AUTHENTICATE */
struct imapc_command_reply reply;
i_zero(&reply);
reply.state = (enum imapc_command_state)IMAPC_COMMAND_STATE_AUTHENTICATE_CONTINUE;
reply.text_full = line;
cmds[0]->callback(&reply, cmds[0]->context);
} else {
imapc_connection_input_error(conn, "Unexpected '+': %s", line);
return -1;
}
}
imapc_connection_input_reset(conn);
return 1;
}
static void
imapc_connection_throttle_shrink_timeout(struct imapc_connection *conn)
{
if (conn->throttle_msecs <= 1)
conn->throttle_msecs = 0;
else
conn->throttle_msecs = conn->throttle_msecs*3 / 4;
if (conn->throttle_shrink_msecs <= conn->client->set.throttle_set.shrink_min_msecs)
conn->throttle_shrink_msecs = 0;
else
conn->throttle_shrink_msecs = conn->throttle_shrink_msecs*3 / 4;
timeout_remove(&conn->to_throttle_shrink);
if (conn->throttle_shrink_msecs > 0) {
conn->to_throttle_shrink =
timeout_add(conn->throttle_shrink_msecs,
imapc_connection_throttle_shrink_timeout, conn);
}
}
static void
imapc_connection_throttle(struct imapc_connection *conn,
const struct imapc_command_reply *reply)
{
timeout_remove(&conn->to_throttle);
/* If GMail returns [THROTTLED], start slowing down commands.
Unfortunately this isn't a nice resp-text-code, but just
appended at the end of the line (although we kind of support
it as resp-text-code also in here if it's uppercased). */
if (strstr(reply->text_full, "[THROTTLED]") != NULL) {
if (conn->throttle_msecs == 0)
conn->throttle_msecs = conn->client->set.throttle_set.init_msecs;
else if (conn->throttle_msecs < conn->last_successful_throttle_msecs)
conn->throttle_msecs = conn->last_successful_throttle_msecs;
else {
conn->throttle_msecs *= 2;
if (conn->throttle_msecs > conn->client->set.throttle_set.max_msecs)
conn->throttle_msecs = conn->client->set.throttle_set.max_msecs;
}
if (conn->throttle_shrink_msecs == 0)
conn->throttle_shrink_msecs = conn->client->set.throttle_set.shrink_min_msecs;
else
conn->throttle_shrink_msecs *= 2;
if (conn->to_throttle_shrink != NULL)
timeout_reset(conn->to_throttle_shrink);
} else {
if (conn->throttle_shrink_msecs > 0 &&
conn->to_throttle_shrink == NULL) {
conn->to_throttle_shrink =
timeout_add(conn->throttle_shrink_msecs,
imapc_connection_throttle_shrink_timeout, conn);
}
conn->last_successful_throttle_msecs = conn->throttle_msecs;
}
if (conn->throttle_msecs > 0) {
conn->throttle_end_timeval = ioloop_timeval;
timeval_add_msecs(&conn->throttle_end_timeval,
conn->throttle_msecs);
conn->throttle_pending = TRUE;
}
}
static void
imapc_command_reply_free(struct imapc_command *cmd,
const struct imapc_command_reply *reply)
{
cmd->callback(reply, cmd->context);
imapc_command_free(cmd);
}
static int imapc_connection_input_tagged(struct imapc_connection *conn)
{
struct imapc_command *const *cmds, *cmd = NULL;
unsigned int i, count;
char *line, *linep;
const char *p;
struct imapc_command_reply reply;
line = i_stream_next_line(conn->input);
if (line == NULL)
return 0;
/* make sure reply texts stays valid if input stream gets freed */
line = t_strdup_noconst(line);
i_zero(&reply);
linep = strchr(line, ' ');
if (linep == NULL)
reply.text_full = "";
else {
*linep = '\0';
reply.text_full = linep + 1;
}
if (strcasecmp(line, "ok") == 0)
reply.state = IMAPC_COMMAND_STATE_OK;
else if (strcasecmp(line, "no") == 0)
reply.state = IMAPC_COMMAND_STATE_NO;
else if (strcasecmp(line, "bad") == 0)
reply.state = IMAPC_COMMAND_STATE_BAD;
else {
imapc_connection_input_error(conn,
"Invalid state in tagged reply: %u %s %s",
conn->cur_tag, line, reply.text_full);
return -1;
}
if (reply.text_full[0] == '[') {
/* get resp-text */
if (imapc_connection_handle_resp_text(conn, reply.text_full,
&reply.resp_text_key,
&reply.resp_text_value) < 0)
return -1;
p = i_strchr_to_next(reply.text_full, ']');
i_assert(p != NULL);
reply.text_without_resp = p;
if (reply.text_without_resp[0] == ' ')
reply.text_without_resp++;
} else {
reply.text_without_resp = reply.text_full;
}
/* if we've pipelined multiple commands, handle [THROTTLED] reply
from only one of them */
if (!conn->throttle_pending)
imapc_connection_throttle(conn, &reply);
/* find the command. it's either the first command in send queue
(literal failed) or somewhere in wait list. */
cmds = array_get(&conn->cmd_send_queue, &count);
if (count > 0 && cmds[0]->tag == conn->cur_tag) {
cmd = cmds[0];
array_pop_front(&conn->cmd_send_queue);
} else {
cmds = array_get(&conn->cmd_wait_list, &count);
for (i = 0; i < count; i++) {
if (cmds[i]->tag == conn->cur_tag) {
cmd = cmds[i];
array_delete(&conn->cmd_wait_list, i, 1);
break;
}
}
}
if (array_count(&conn->cmd_wait_list) == 0 &&
array_count(&conn->cmd_send_queue) == 0 &&
conn->state == IMAPC_CONNECTION_STATE_DONE && conn->to != NULL)
timeout_remove(&conn->to);
if (cmd == NULL) {
if (seq_range_exists(&conn->aborted_cmd_tags, conn->cur_tag)) {
/* sent command was already aborted - ignore it */
seq_range_array_remove(&conn->aborted_cmd_tags,
conn->cur_tag);
imapc_connection_input_reset(conn);
return 1;
}
imapc_connection_input_error(conn,
"Unknown tag in a reply: %u %s %s",
conn->cur_tag, line, reply.text_full);
return -1;
}
if ((cmd->flags & IMAPC_COMMAND_FLAG_SELECT) != 0)
conn->select_waiting_reply = FALSE;
if (reply.state == IMAPC_COMMAND_STATE_BAD) {
i_error("imapc(%s): Command '%s' failed with BAD: %u %s",
conn->name, imapc_command_get_readable(cmd),
conn->cur_tag, reply.text_full);
imapc_connection_disconnect(conn);
}
if (reply.state == IMAPC_COMMAND_STATE_NO &&
(cmd->flags & IMAPC_COMMAND_FLAG_SELECT) != 0 &&
conn->selected_box != NULL) {
/* EXAMINE/SELECT failed: mailbox is no longer selected */
imapc_connection_unselect(conn->selected_box, TRUE);
}
if (conn->reconnect_command_count > 0 &&
(cmd->flags & IMAPC_COMMAND_FLAG_RECONNECTED) != 0) {
i_assert(conn->reconnect_command_count > 0);
if (--conn->reconnect_command_count == 0) {
/* we've received replies for all the commands started
before reconnection. if we get disconnected now, we
can safely reconnect without worrying about infinite
reconnect loops. */
if (conn->selected_box != NULL)
conn->selected_box->reconnect_ok = TRUE;
}
}
if (conn->reconnect_command_count == 0) {
/* we've successfully received replies to some commands. */
conn->reconnect_ok = TRUE;
}
imapc_connection_input_reset(conn);
imapc_command_reply_free(cmd, &reply);
imapc_command_send_more(conn);
return 1;
}
static int imapc_connection_input_one(struct imapc_connection *conn)
{
const char *tag;
int ret = -1;
if (conn->input_callback != NULL)
return conn->input_callback(conn);
switch (conn->input_state) {
case IMAPC_INPUT_STATE_NONE:
tag = imap_parser_read_word(conn->parser);
if (tag == NULL)
return 0;
if (strcmp(tag, "*") == 0) {
conn->input_state = IMAPC_INPUT_STATE_UNTAGGED;
conn->cur_num = 0;
ret = imapc_connection_input_untagged(conn);
} else if (strcmp(tag, "+") == 0) {
conn->input_state = IMAPC_INPUT_STATE_PLUS;
ret = imapc_connection_input_plus(conn);
} else {
conn->input_state = IMAPC_INPUT_STATE_TAGGED;
if (str_to_uint(tag, &conn->cur_tag) < 0 ||
conn->cur_tag == 0) {
imapc_connection_input_error(conn,
"Invalid command tag: %s", tag);
ret = -1;
} else {
ret = imapc_connection_input_tagged(conn);
}
}
break;
case IMAPC_INPUT_STATE_PLUS:
ret = imapc_connection_input_plus(conn);
break;
case IMAPC_INPUT_STATE_UNTAGGED:
case IMAPC_INPUT_STATE_UNTAGGED_NUM:
ret = imapc_connection_input_untagged(conn);
break;
case IMAPC_INPUT_STATE_TAGGED:
ret = imapc_connection_input_tagged(conn);
break;
}
return ret;
}
static void imapc_connection_input(struct imapc_connection *conn)
{
const char *errstr;
string_t *str;
ssize_t ret = 0;
/* we need to read as much as we can with SSL streams to avoid
hanging */
imapc_connection_ref(conn);
while (conn->input != NULL && (ret = i_stream_read(conn->input)) > 0)
imapc_connection_input_pending(conn);
if (ret < 0 && conn->client->logging_out &&
conn->disconnect_reason != NULL) {
/* expected disconnection */
imapc_connection_disconnect(conn);
} else if (ret < 0) {
/* disconnected or buffer full */
str = t_str_new(128);
if (conn->disconnect_reason != NULL) {
str_printfa(str, "Server disconnected with message: %s",
conn->disconnect_reason);
} else if (ret == -2) {
str_printfa(str, "Server sent too large input "
"(buffer full at %zu)",
i_stream_get_data_size(conn->input));
} else if (conn->ssl_iostream == NULL) {
errstr = conn->input->stream_errno == 0 ? "EOF" :
i_stream_get_error(conn->input);
str_printfa(str, "Server disconnected unexpectedly: %s",
errstr);
} else {
errstr = ssl_iostream_get_last_error(conn->ssl_iostream);
if (errstr == NULL) {
errstr = conn->input->stream_errno == 0 ? "EOF" :
i_stream_get_error(conn->input);
}
str_printfa(str, "Server disconnected unexpectedly: %s",
errstr);
}
imapc_connection_try_reconnect(conn, str_c(str), 0, FALSE);
}
imapc_connection_unref(&conn);
}
static int imapc_connection_ssl_handshaked(const char **error_r, void *context)
{
struct imapc_connection *conn = context;
const char *error;
if (ssl_iostream_check_cert_validity(conn->ssl_iostream,
conn->client->set.host, &error) == 0) {
if (conn->client->set.debug) {
i_debug("imapc(%s): SSL handshake successful",
conn->name);
}
return 0;
} else if (conn->client->set.ssl_set.allow_invalid_cert) {
if (conn->client->set.debug) {
i_debug("imapc(%s): SSL handshake successful, "
"ignoring invalid certificate: %s",
conn->name, error);
}
return 0;
} else {
*error_r = error;
return -1;
}
}
static int imapc_connection_ssl_init(struct imapc_connection *conn)
{
const char *error;
if (conn->client->ssl_ctx == NULL) {
i_error("imapc(%s): No SSL context", conn->name);
return -1;
}
if (conn->client->set.debug)
i_debug("imapc(%s): Starting SSL handshake", conn->name);
if (conn->raw_input != conn->input) {
/* recreate rawlog after STARTTLS */
i_stream_ref(conn->raw_input);
o_stream_ref(conn->raw_output);
i_stream_destroy(&conn->input);
o_stream_destroy(&conn->output);
conn->input = conn->raw_input;
conn->output = conn->raw_output;
}
io_remove(&conn->io);
if (io_stream_create_ssl_client(conn->client->ssl_ctx,
conn->client->set.host,
&conn->client->set.ssl_set,
&conn->input, &conn->output,
&conn->ssl_iostream, &error) < 0) {
i_error("imapc(%s): Couldn't initialize SSL client: %s",
conn->name, error);
return -1;
}
conn->io = io_add_istream(conn->input, imapc_connection_input, conn);
ssl_iostream_set_handshake_callback(conn->ssl_iostream,
imapc_connection_ssl_handshaked,
conn);
if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
i_error("imapc(%s): SSL handshake failed: %s", conn->name,
ssl_iostream_get_last_error(conn->ssl_iostream));
return -1;
}
if (*conn->client->set.rawlog_dir != '\0') {
iostream_rawlog_create(conn->client->set.rawlog_dir,
&conn->input, &conn->output);
}
imap_parser_set_streams(conn->parser, conn->input, NULL);
return 0;
}
static int imapc_connection_connected(struct imapc_connection *conn)
{
const struct ip_addr *ip = &conn->ips[conn->prev_connect_idx];
struct ip_addr local_ip;
in_port_t local_port;
int err;
i_assert(conn->io == NULL);
err = net_geterror(conn->fd);
if (err != 0) {
imapc_connection_try_reconnect(conn, t_strdup_printf(
"connect(%s, %u) failed: %s",
net_ip2addr(ip), conn->client->set.port,
strerror(err)), conn->client->set.connect_retry_interval_msecs, TRUE);
return -1;
}
if (net_getsockname(conn->fd, &local_ip, &local_port) < 0)
local_port = 0;
i_info("imapc(%s): Connected to %s:%u (local %s:%u)", conn->name,
net_ip2addr(ip), conn->client->set.port,
net_ip2addr(&local_ip), local_port);
conn->io = io_add(conn->fd, IO_READ, imapc_connection_input, conn);
o_stream_set_flush_callback(conn->output, imapc_connection_output,
conn);
if (conn->client->set.ssl_mode == IMAPC_CLIENT_SSL_MODE_IMMEDIATE) {
if (imapc_connection_ssl_init(conn) < 0)
imapc_connection_disconnect(conn);
}
return imapc_connection_output(conn);
}
static void imapc_connection_timeout(struct imapc_connection *conn)
{
const struct ip_addr *ip = &conn->ips[conn->prev_connect_idx];
const char *errstr;
bool connect_error = FALSE;
switch (conn->state) {
case IMAPC_CONNECTION_STATE_CONNECTING:
errstr = t_strdup_printf("connect(%s, %u) timed out after %u seconds",
net_ip2addr(ip), conn->client->set.port,
conn->client->set.connect_timeout_msecs/1000);
connect_error = TRUE;
break;
case IMAPC_CONNECTION_STATE_AUTHENTICATING:
errstr = t_strdup_printf("Authentication timed out after %u seconds",
conn->client->set.connect_timeout_msecs/1000);
break;
default:
i_unreached();
}
imapc_connection_try_reconnect(conn, errstr, 0, connect_error);
}
static void
imapc_noop_callback(const struct imapc_command_reply *reply ATTR_UNUSED,
void *context ATTR_UNUSED)
{
}
static void
imapc_reidle_callback(const struct imapc_command_reply *reply ATTR_UNUSED,
void *context)
{
struct imapc_connection *conn = context;
imapc_connection_idle(conn);
}
static void imapc_connection_reset_idle(struct imapc_connection *conn)
{
struct imapc_command *cmd;
if (conn->idling)
cmd = imapc_connection_cmd(conn, imapc_reidle_callback, conn);
else if (array_count(&conn->cmd_wait_list) == 0)
cmd = imapc_connection_cmd(conn, imapc_noop_callback, NULL);
else {
/* IMAP command reply is taking a long time */
return;
}
imapc_command_send(cmd, "NOOP");
}
static void imapc_connection_connect_next_ip(struct imapc_connection *conn)
{
const struct ip_addr *ip = NULL;
unsigned int i;
int fd;
i_assert(conn->client->set.max_idle_time > 0);
for (i = 0; iips_count;) {
conn->prev_connect_idx = (conn->prev_connect_idx+1) % conn->ips_count;
ip = &conn->ips[conn->prev_connect_idx];
fd = net_connect_ip(ip, conn->client->set.port, NULL);
if (fd != -1)
break;
/* failed to connect to one of the IPs immediately
(e.g. IPv6 address without connectivity). try all IPs
before failing completely. */
i_error("net_connect_ip(%s:%u) failed: %m",
net_ip2addr(ip), conn->client->set.port);
if (conn->prev_connect_idx+1 == conn->ips_count) {
imapc_connection_try_reconnect(conn, "No more IP address(es) to try",
conn->client->set.connect_retry_interval_msecs, TRUE);
return;
}
}
i_assert(ip != NULL);
conn->fd = fd;
conn->input = conn->raw_input =
i_stream_create_fd(fd, conn->client->set.max_line_length);
conn->output = conn->raw_output = o_stream_create_fd(fd, SIZE_MAX);
o_stream_set_no_error_handling(conn->output, TRUE);
if (*conn->client->set.rawlog_dir != '\0' &&
conn->client->set.ssl_mode != IMAPC_CLIENT_SSL_MODE_IMMEDIATE) {
iostream_rawlog_create(conn->client->set.rawlog_dir,
&conn->input, &conn->output);
}
o_stream_set_flush_pending(conn->output, TRUE);
o_stream_set_flush_callback(conn->output, imapc_connection_connected,
conn);
conn->parser = imap_parser_create(conn->input, NULL,
conn->client->set.max_line_length);
conn->to = timeout_add(conn->client->set.connect_timeout_msecs,
imapc_connection_timeout, conn);
conn->to_output = timeout_add(conn->client->set.max_idle_time*1000,
imapc_connection_reset_idle, conn);
if (conn->client->set.debug) {
i_debug("imapc(%s): Connecting to %s:%u", conn->name,
net_ip2addr(ip), conn->client->set.port);
}
}
static void
imapc_connection_dns_callback(const struct dns_lookup_result *result,
struct imapc_connection *conn)
{
conn->dns_lookup = NULL;
if (result->ret != 0) {
i_error("imapc(%s): dns_lookup(%s) failed: %s",
conn->name, conn->client->set.host, result->error);
imapc_connection_set_disconnected(conn);
return;
}
i_assert(result->ips_count > 0);
conn->ips_count = result->ips_count;
conn->ips = i_new(struct ip_addr, conn->ips_count);
memcpy(conn->ips, result->ips, sizeof(*conn->ips) * conn->ips_count);
conn->prev_connect_idx = conn->ips_count - 1;
imapc_connection_connect_next_ip(conn);
}
void imapc_connection_connect(struct imapc_connection *conn)
{
struct dns_lookup_settings dns_set;
struct ip_addr ip, *ips;
unsigned int ips_count;
int ret;
if (conn->fd != -1 || conn->dns_lookup != NULL)
return;
if (conn->reconnect_waiting) {
/* wait for the reconnection delay to finish before
doing anything. */
return;
}
conn->reconnecting = FALSE;
/* if we get disconnected before we've finished all the pending
commands, don't reconnect */
conn->reconnect_command_count = array_count(&conn->cmd_wait_list) +
array_count(&conn->cmd_send_queue);
imapc_connection_input_reset(conn);
conn->last_connect = ioloop_timeval;
if (conn->client->set.debug) {
i_debug("imapc(%s): Looking up IP address "
"(reconnect_ok=%s, last_connect=%ld)", conn->name,
(conn->reconnect_ok ? "true" : "false"),
(long)conn->last_connect.tv_sec);
}
i_zero(&dns_set);
dns_set.dns_client_socket_path =
conn->client->set.dns_client_socket_path;
dns_set.timeout_msecs = conn->client->set.connect_timeout_msecs;
dns_set.event_parent = conn->client->event;
imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_CONNECTING);
if (conn->ips_count > 0) {
/* do nothing */
} else if (net_addr2ip(conn->client->set.host, &ip) == 0) {
conn->ips_count = 1;
conn->ips = i_new(struct ip_addr, conn->ips_count);
conn->ips[0] = ip;
} else if (*dns_set.dns_client_socket_path == '\0') {
ret = net_gethostbyname(conn->client->set.host,
&ips, &ips_count);
if (ret != 0) {
i_error("imapc(%s): net_gethostbyname(%s) failed: %s",
conn->name, conn->client->set.host,
net_gethosterror(ret));
imapc_connection_set_disconnected(conn);
return;
}
conn->ips_count = ips_count;
conn->ips = i_new(struct ip_addr, ips_count);
memcpy(conn->ips, ips, ips_count * sizeof(*ips));
} else {
(void)dns_lookup(conn->client->set.host, &dns_set,
imapc_connection_dns_callback, conn,
&conn->dns_lookup);
return;
}
imapc_connection_connect_next_ip(conn);
}
void imapc_connection_input_pending(struct imapc_connection *conn)
{
int ret = 1;
if (conn->input == NULL)
return;
if (conn->to != NULL && !conn->idle_stopping)
timeout_reset(conn->to);
o_stream_cork(conn->output);
while (ret > 0 && conn->input != NULL) {
T_BEGIN {
ret = imapc_connection_input_one(conn);
} T_END;
}
if (conn->output != NULL)
o_stream_uncork(conn->output);
}
static struct imapc_command *
imapc_command_begin(imapc_command_callback_t *callback, void *context)
{
struct imapc_command *cmd;
pool_t pool;
i_assert(callback != NULL);
pool = pool_alloconly_create("imapc command", 2048);
cmd = p_new(pool, struct imapc_command, 1);
cmd->pool = pool;
cmd->callback = callback;
cmd->context = context;
/* use a globally unique tag counter so looking at rawlogs is
somewhat easier */
if (++imapc_client_cmd_tag_counter == 0)
imapc_client_cmd_tag_counter++;
cmd->tag = imapc_client_cmd_tag_counter;
return cmd;
}
static void imapc_command_free(struct imapc_command *cmd)
{
struct imapc_command_stream *stream;
if (array_is_created(&cmd->streams)) {
array_foreach_modifiable(&cmd->streams, stream)
i_stream_unref(&stream->input);
}
pool_unref(&cmd->pool);
}
const char *imapc_command_get_tag(struct imapc_command *cmd)
{
return t_strdup_printf("%u", cmd->tag);
}
void imapc_command_abort(struct imapc_command **_cmd)
{
struct imapc_command *cmd = *_cmd;
*_cmd = NULL;
imapc_command_free(cmd);
}
static void imapc_command_timeout(struct imapc_connection *conn)
{
struct imapc_command *const *cmds;
unsigned int count;
cmds = array_get(&conn->cmd_wait_list, &count);
i_assert(count > 0);
imapc_connection_try_reconnect(conn, t_strdup_printf(
"Command '%s' timed out", imapc_command_get_readable(cmds[0])), 0, FALSE);
}
static bool
parse_sync_literal(const unsigned char *data, unsigned int pos,
unsigned int *value_r)
{
unsigned int value = 0, mul = 1;
/* data should contain "{size}\r\n" and pos points after \n */
if (pos <= 4 || data[pos-1] != '\n' || data[pos-2] != '\r' ||
data[pos-3] != '}' || !i_isdigit(data[pos-4]))
return FALSE;
pos -= 4;
do {
value += (data[pos] - '0') * mul;
mul = mul*10;
pos--;
} while (pos > 0 && i_isdigit(data[pos]));
if (pos == 0 || data[pos] != '{')
return FALSE;
*value_r = value;
return TRUE;
}
static void imapc_command_send_finished(struct imapc_connection *conn,
struct imapc_command *cmd)
{
struct imapc_command *const *cmdp;
i_assert(conn->to != NULL);
if (cmd->idle)
conn->idle_plus_waiting = TRUE;
cmd->sent = TRUE;
/* everything sent. move command to wait list. */
cmdp = array_front(&conn->cmd_send_queue);
i_assert(*cmdp == cmd);
array_pop_front(&conn->cmd_send_queue);
array_push_back(&conn->cmd_wait_list, &cmd);
/* send the next command in queue */
imapc_command_send_more(conn);
}
static struct imapc_command_stream *
imapc_command_get_sending_stream(struct imapc_command *cmd)
{
struct imapc_command_stream *stream;
if (!array_is_created(&cmd->streams) || array_count(&cmd->streams) == 0)
return NULL;
stream = array_front_modifiable(&cmd->streams);
if (stream->pos != cmd->send_pos)
return NULL;
return stream;
}
static int imapc_command_try_send_stream(struct imapc_connection *conn,
struct imapc_command *cmd)
{
struct imapc_command_stream *stream;
enum ostream_send_istream_result res;
stream = imapc_command_get_sending_stream(cmd);
if (stream == NULL)
return -2;
/* we're sending the stream now */
o_stream_set_max_buffer_size(conn->output, 0);
res = o_stream_send_istream(conn->output, stream->input);
o_stream_set_max_buffer_size(conn->output, SIZE_MAX);
switch (res) {
case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
break;
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
i_unreached();
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
i_assert(stream->input->v_offset < stream->size);
return 0;
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
i_error("imapc: read(%s) failed: %s",
i_stream_get_name(stream->input),
i_stream_get_error(stream->input));
return -1;
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
/* disconnected */
return -1;
}
i_assert(stream->input->v_offset == stream->size);
/* finished with the stream */
i_stream_unref(&stream->input);
array_pop_front(&cmd->streams);
i_assert(cmd->send_pos != cmd->data->used);
return 1;
}
static void imapc_connection_set_selecting(struct imapc_client_mailbox *box)
{
struct imapc_connection *conn = box->conn;
i_assert(conn->qresync_selecting_box == NULL);
if (conn->selected_on_server &&
(conn->capabilities & IMAPC_CAPABILITY_QRESYNC) != 0) {
/* server will send a [CLOSED] once selected mailbox is
closed */
conn->qresync_selecting_box = box;
} else {
/* we'll have to assume that all the future untagged messages
are for the mailbox we're selecting */
conn->selected_box = box;
conn->selected_on_server = TRUE;
}
conn->select_waiting_reply = TRUE;
}
static bool imapc_connection_is_throttled(struct imapc_connection *conn)
{
timeout_remove(&conn->to_throttle);
if (conn->throttle_msecs == 0) {
/* we haven't received [THROTTLED] recently */
return FALSE;
}
if (array_count(&conn->cmd_wait_list) > 0) {
/* wait until we have received the existing commands' tagged
replies to see if we're still throttled */
return TRUE;
}
if (timeval_cmp(&ioloop_timeval, &conn->throttle_end_timeval) >= 0) {
/* we reached the throttle timeout - send the next command */
conn->throttle_pending = FALSE;
return FALSE;
}
/* we're still being throttled - wait for it to end */
conn->to_throttle = timeout_add_absolute(&conn->throttle_end_timeval,
imapc_command_send_more, conn);
return TRUE;
}
static void imapc_command_send_more(struct imapc_connection *conn)
{
struct imapc_command *const *cmds, *cmd;
struct imapc_command_reply reply;
const unsigned char *p, *data;
unsigned int count, size;
size_t seek_pos, start_pos, end_pos;
int ret;
if (imapc_connection_is_throttled(conn))
return;
cmds = array_get(&conn->cmd_send_queue, &count);
if (count == 0)
return;
cmd = cmds[0];
if ((cmd->flags & IMAPC_COMMAND_FLAG_PRELOGIN) == 0 &&
conn->state != IMAPC_CONNECTION_STATE_DONE) {
/* wait until we're fully connected */
return;
}
if ((cmd->flags & IMAPC_COMMAND_FLAG_LOGOUT) != 0 &&
array_count(&conn->cmd_wait_list) > 0) {
/* wait until existing commands have finished */
return;
}
if (conn->select_waiting_reply) {
/* wait for SELECT to finish */
return;
}
if (cmd->wait_for_literal) {
/* wait until we received '+' */
return;
}
i_assert(cmd->send_pos < cmd->data->used);
if (cmd->box == NULL) {
/* non-mailbox command */
} else if (cmd->send_pos == 0 &&
(cmd->flags & IMAPC_COMMAND_FLAG_SELECT) != 0) {
/* SELECT/EXAMINE command */
imapc_connection_set_selecting(cmd->box);
} else if (!imapc_client_mailbox_is_opened(cmd->box)) {
if (cmd->box->reconnecting) {
/* wait for SELECT/EXAMINE */
return;
}
/* shouldn't normally happen */
i_zero(&reply);
reply.text_without_resp = reply.text_full = "Mailbox not open";
reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
array_pop_front(&conn->cmd_send_queue);
imapc_command_reply_free(cmd, &reply);
imapc_command_send_more(conn);
return;
}
/* add timeout for commands if there's not one yet
(pre-login has its own timeout) */
if ((cmd->flags & IMAPC_COMMAND_FLAG_LOGOUT) != 0) {
/* LOGOUT has a shorter timeout */
timeout_remove(&conn->to);
conn->to = timeout_add(IMAPC_LOGOUT_TIMEOUT_MSECS,
imapc_command_timeout, conn);
} else if (conn->to == NULL) {
conn->to = timeout_add(conn->client->set.cmd_timeout_msecs,
imapc_command_timeout, conn);
}
timeout_reset(conn->to_output);
if ((ret = imapc_command_try_send_stream(conn, cmd)) == 0)
return;
if (ret == -1) {
i_zero(&reply);
reply.text_without_resp = reply.text_full = "Mailbox not open";
reply.state = IMAPC_COMMAND_STATE_DISCONNECTED;
array_pop_front(&conn->cmd_send_queue);
imapc_command_reply_free(cmd, &reply);
imapc_command_send_more(conn);
return;
}
seek_pos = cmd->send_pos;
if (seek_pos != 0 && ret == -2) {
/* skip over the literal. we can also get here from
AUTHENTICATE command, which doesn't use a literal */
if (parse_sync_literal(cmd->data->data, seek_pos, &size)) {
seek_pos += size;
i_assert(seek_pos <= cmd->data->used);
}
}
do {
start_pos = seek_pos;
p = memchr(CONST_PTR_OFFSET(cmd->data->data, seek_pos), '\n',
cmd->data->used - seek_pos);
i_assert(p != NULL);
seek_pos = p - (const unsigned char *)cmd->data->data + 1;
/* keep going for LITERAL+ command */
} while (start_pos + 3 < seek_pos &&
p[-1] == '\r' && p[-2] == '}' && p[-3] == '+');
end_pos = seek_pos;
data = CONST_PTR_OFFSET(cmd->data->data, cmd->send_pos);
size = end_pos - cmd->send_pos;
o_stream_nsend(conn->output, data, size);
cmd->send_pos = end_pos;
if (cmd->send_pos == cmd->data->used) {
i_assert(!array_is_created(&cmd->streams) ||
array_count(&cmd->streams) == 0);
imapc_command_send_finished(conn, cmd);
} else {
cmd->wait_for_literal = TRUE;
}
}
static void imapc_connection_send_idle_done(struct imapc_connection *conn)
{
if ((conn->idling || conn->idle_plus_waiting) && !conn->idle_stopping) {
conn->idle_stopping = TRUE;
o_stream_nsend_str(conn->output, "DONE\r\n");
if (conn->to == NULL) {
conn->to = timeout_add(conn->client->set.cmd_timeout_msecs,
imapc_command_timeout, conn);
}
}
}
static void imapc_connection_cmd_send(struct imapc_command *cmd)
{
struct imapc_connection *conn = cmd->conn;
struct imapc_command *const *cmds;
unsigned int i, count;
imapc_connection_send_idle_done(conn);
i_assert((cmd->flags & IMAPC_COMMAND_FLAG_RECONNECTED) == 0);
if ((cmd->flags & IMAPC_COMMAND_FLAG_PRELOGIN) != 0 &&
conn->state == IMAPC_CONNECTION_STATE_AUTHENTICATING) {
/* pre-login commands get inserted before everything else */
array_push_front(&conn->cmd_send_queue, &cmd);
imapc_command_send_more(conn);
return;
}
/* add the command just before retried commands */
cmds = array_get(&conn->cmd_send_queue, &count);
for (i = count; i > 0; i--) {
if ((cmds[i-1]->flags & IMAPC_COMMAND_FLAG_RECONNECTED) == 0)
break;
}
array_insert(&conn->cmd_send_queue, i, &cmd, 1);
imapc_command_send_more(conn);
}
static int imapc_connection_output(struct imapc_connection *conn)
{
struct imapc_command *const *cmds;
unsigned int count;
int ret;
if (conn->to != NULL)
timeout_reset(conn->to);
if ((ret = o_stream_flush(conn->output)) < 0)
return 1;
imapc_connection_ref(conn);
cmds = array_get(&conn->cmd_send_queue, &count);
if (count > 0) {
if (imapc_command_get_sending_stream(cmds[0]) != NULL &&
!cmds[0]->wait_for_literal) {
/* we're sending a stream. send more. */
imapc_command_send_more(conn);
}
}
imapc_connection_unref(&conn);
return ret;
}
struct imapc_command *
imapc_connection_cmd(struct imapc_connection *conn,
imapc_command_callback_t *callback, void *context)
{
struct imapc_command *cmd;
cmd = imapc_command_begin(callback, context);
cmd->conn = conn;
return cmd;
}
void imapc_command_set_flags(struct imapc_command *cmd,
enum imapc_command_flags flags)
{
cmd->flags = flags;
}
void imapc_command_set_mailbox(struct imapc_command *cmd,
struct imapc_client_mailbox *box)
{
cmd->box = box;
}
bool imapc_command_connection_is_selected(struct imapc_command *cmd)
{
return cmd->conn->selected_box != NULL ||
cmd->conn->qresync_selecting_box != NULL;
}
void imapc_command_send(struct imapc_command *cmd, const char *cmd_str)
{
size_t len = strlen(cmd_str);
cmd->data = str_new(cmd->pool, 6 + len + 2);
str_printfa(cmd->data, "%u %s\r\n", cmd->tag, cmd_str);
imapc_connection_cmd_send(cmd);
}
void imapc_command_sendf(struct imapc_command *cmd, const char *cmd_fmt, ...)
{
va_list args;
va_start(args, cmd_fmt);
imapc_command_sendvf(cmd, cmd_fmt, args);
va_end(args);
}
void imapc_command_sendvf(struct imapc_command *cmd,
const char *cmd_fmt, va_list args)
{
unsigned int i;
cmd->data = str_new(cmd->pool, 128);
str_printfa(cmd->data, "%u ", cmd->tag);
for (i = 0; cmd_fmt[i] != '\0'; i++) {
if (cmd_fmt[i] != '%') {
str_append_c(cmd->data, cmd_fmt[i]);
continue;
}
switch (cmd_fmt[++i]) {
case '\0':
i_unreached();
case 'u': {
unsigned int arg = va_arg(args, unsigned int);
str_printfa(cmd->data, "%u", arg);
break;
}
case 'p': {
struct istream *input = va_arg(args, struct istream *);
struct imapc_command_stream *s;
uoff_t size;
if (!array_is_created(&cmd->streams))
p_array_init(&cmd->streams, cmd->pool, 2);
if (i_stream_get_size(input, TRUE, &size) < 0)
size = 0;
str_printfa(cmd->data, "{%"PRIuUOFF_T"}\r\n", size);
s = array_append_space(&cmd->streams);
s->pos = str_len(cmd->data);
s->size = size;
s->input = input;
i_stream_ref(input);
break;
}
case 's': {
const char *arg = va_arg(args, const char *);
if (!need_literal(arg))
imap_append_quoted(cmd->data, arg);
else if ((cmd->conn->capabilities &
IMAPC_CAPABILITY_LITERALPLUS) != 0) {
str_printfa(cmd->data, "{%zu+}\r\n%s",
strlen(arg), arg);
} else {
str_printfa(cmd->data, "{%zu}\r\n%s",
strlen(arg), arg);
}
break;
}
case '1': {
/* %1s - no quoting */
const char *arg = va_arg(args, const char *);
i++;
i_assert(cmd_fmt[i] == 's');
str_append(cmd->data, arg);
break;
}
}
}
str_append(cmd->data, "\r\n");
imapc_connection_cmd_send(cmd);
}
enum imapc_connection_state
imapc_connection_get_state(struct imapc_connection *conn)
{
return conn->state;
}
enum imapc_capability
imapc_connection_get_capabilities(struct imapc_connection *conn)
{
return conn->capabilities;
}
void imapc_connection_unselect(struct imapc_client_mailbox *box,
bool via_tagged_reply)
{
struct imapc_connection *conn = box->conn;
if (conn->select_waiting_reply) {
/* Mailbox closing was requested before SELECT/EXAMINE
replied. The connection state is now unknown and
shouldn't be used anymore. */
imapc_connection_disconnect(conn);
} else if (conn->qresync_selecting_box == NULL &&
conn->selected_box == NULL) {
/* There is no mailbox selected currently. */
i_assert(!via_tagged_reply);
} else {
/* Mailbox was closed in a known state. Either due to
SELECT/EXAMINE failing (via_tagged_reply) or by
imapc-storage after the mailbox was already fully
selected. */
i_assert(conn->qresync_selecting_box == box ||
conn->selected_box == box);
conn->qresync_selecting_box = NULL;
conn->selected_box = NULL;
if (via_tagged_reply)
conn->selected_on_server = FALSE;
else {
/* We didn't actually send UNSELECT command, so don't
touch selected_on_server state. */
}
}
imapc_connection_send_idle_done(conn);
imapc_connection_abort_commands(conn, box, FALSE);
}
struct imapc_client_mailbox *
imapc_connection_get_mailbox(struct imapc_connection *conn)
{
if (conn->qresync_selecting_box != NULL)
return conn->qresync_selecting_box;
return conn->selected_box;
}
static void
imapc_connection_idle_callback(const struct imapc_command_reply *reply ATTR_UNUSED,
void *context)
{
struct imapc_connection *conn = context;
conn->idling = FALSE;
conn->idle_plus_waiting = FALSE;
conn->idle_stopping = FALSE;
}
void imapc_connection_idle(struct imapc_connection *conn)
{
struct imapc_command *cmd;
if (array_count(&conn->cmd_send_queue) != 0 ||
array_count(&conn->cmd_wait_list) != 0 ||
conn->idling || conn->idle_plus_waiting ||
(conn->capabilities & IMAPC_CAPABILITY_IDLE) == 0)
return;
cmd = imapc_connection_cmd(conn, imapc_connection_idle_callback, conn);
cmd->idle = TRUE;
imapc_command_send(cmd, "IDLE");
}
dovecot-2.3.21.1/src/lib-imap-client/imapc-client.h 0000644 0000000 0000000 00000020607 14656633576 016575 0000000 0000000 #ifndef IMAPC_CLIENT_H
#define IMAPC_CLIENT_H
#include "net.h"
#include "iostream-ssl.h"
/* IMAP RFC defines this to be at least 30 minutes. */
#define IMAPC_DEFAULT_MAX_IDLE_TIME (60*29)
enum imapc_command_state {
IMAPC_COMMAND_STATE_OK = 0,
IMAPC_COMMAND_STATE_NO,
IMAPC_COMMAND_STATE_BAD,
/* Authentication to IMAP server failed (NO or BAD) */
IMAPC_COMMAND_STATE_AUTH_FAILED,
/* Client was unexpectedly disconnected. */
IMAPC_COMMAND_STATE_DISCONNECTED
};
extern const char *imapc_command_state_names[];
enum imapc_capability {
IMAPC_CAPABILITY_SASL_IR = 0x01,
IMAPC_CAPABILITY_LITERALPLUS = 0x02,
IMAPC_CAPABILITY_QRESYNC = 0x04,
IMAPC_CAPABILITY_IDLE = 0x08,
IMAPC_CAPABILITY_UIDPLUS = 0x10,
IMAPC_CAPABILITY_AUTH_PLAIN = 0x20,
IMAPC_CAPABILITY_STARTTLS = 0x40,
IMAPC_CAPABILITY_X_GM_EXT_1 = 0x80,
IMAPC_CAPABILITY_CONDSTORE = 0x100,
IMAPC_CAPABILITY_NAMESPACE = 0x200,
IMAPC_CAPABILITY_UNSELECT = 0x400,
IMAPC_CAPABILITY_ESEARCH = 0x800,
IMAPC_CAPABILITY_WITHIN = 0x1000,
IMAPC_CAPABILITY_QUOTA = 0x2000,
IMAPC_CAPABILITY_ID = 0x4000,
IMAPC_CAPABILITY_SAVEDATE = 0x8000,
IMAPC_CAPABILITY_IMAP4REV1 = 0x40000000
};
struct imapc_capability_name {
const char *name;
enum imapc_capability capability;
};
extern const struct imapc_capability_name imapc_capability_names[];
enum imapc_command_flags {
/* The command changes the selected mailbox (SELECT, EXAMINE) */
IMAPC_COMMAND_FLAG_SELECT = 0x01,
/* The command is sent to server before login (or is the login
command itself). Non-prelogin commands will be queued until login
is successful. */
IMAPC_COMMAND_FLAG_PRELOGIN = 0x02,
/* Allow command to be automatically retried if disconnected before it
finishes. */
IMAPC_COMMAND_FLAG_RETRIABLE = 0x04,
/* This is the LOGOUT command. Use a small timeout for it. */
IMAPC_COMMAND_FLAG_LOGOUT = 0x08,
/* Command is being resent after a reconnection. */
IMAPC_COMMAND_FLAG_RECONNECTED = 0x10
};
enum imapc_client_ssl_mode {
IMAPC_CLIENT_SSL_MODE_NONE,
IMAPC_CLIENT_SSL_MODE_IMMEDIATE,
IMAPC_CLIENT_SSL_MODE_STARTTLS
};
#define IMAPC_DEFAULT_CONNECT_TIMEOUT_MSECS (1000*30)
#define IMAPC_DEFAULT_COMMAND_TIMEOUT_MSECS (1000*60*5)
#define IMAPC_DEFAULT_MAX_LINE_LENGTH (SIZE_MAX)
struct imapc_throttling_settings {
unsigned int init_msecs;
unsigned int max_msecs;
unsigned int shrink_min_msecs;
};
struct imapc_client_settings {
const char *host;
in_port_t port;
const char *master_user;
const char *username;
const char *password;
/* Space-separated list of SASL mechanisms to try (in the specified
order). The default is to use only LOGIN command or SASL PLAIN. */
const char *sasl_mechanisms;
bool use_proxyauth; /* Use Sun/Oracle PROXYAUTH command */
unsigned int max_idle_time;
/* If ID capability is advertised, send a unique "x-session-ext-id",
which begins with this prefix. */
const char *session_id_prefix;
const char *dns_client_socket_path;
const char *temp_path_prefix;
struct ssl_iostream_settings ssl_set;
enum imapc_client_ssl_mode ssl_mode;
const char *rawlog_dir;
bool debug;
/* Timeout for logging in. 0 = default. */
unsigned int connect_timeout_msecs;
/* Number of retries, -1 = infinity */
unsigned int connect_retry_count;
/* Interval between retries, must be > 0 if retries > 0 */
unsigned int connect_retry_interval_msecs;
/* Timeout for IMAP commands. Reset every time more data is being
sent or received. 0 = default. */
unsigned int cmd_timeout_msecs;
/* Maximum allowed line length (not including literals read as
streams). 0 = unlimited. */
size_t max_line_length;
struct imapc_throttling_settings throttle_set;
};
struct imapc_command_reply {
enum imapc_command_state state;
/* "[RESP TEXT]" produces key=RESP, value=TEXT.
"[RESP]" produces key=RESP, value=NULL
otherwise both are NULL */
const char *resp_text_key, *resp_text_value;
/* The full tagged reply, including [RESP TEXT]. */
const char *text_full;
/* Tagged reply text without [RESP TEXT] */
const char *text_without_resp;
};
struct imapc_arg_file {
/* file descriptor containing the value */
int fd;
/* parent_arg.list[list_idx] points to the IMAP_ARG_LITERAL_SIZE
argument */
const struct imap_arg *parent_arg;
unsigned int list_idx;
};
struct imapc_untagged_reply {
/* name of the untagged reply, e.g. EXISTS */
const char *name;
/* number at the beginning of the reply, or 0 if there wasn't any.
Set for EXISTS, EXPUNGE, etc. */
uint32_t num;
/* the rest of the reply can be read from these args. */
const struct imap_arg *args;
/* arguments whose contents are stored into files. only
"FETCH (BODY[" arguments can be here. */
const struct imapc_arg_file *file_args;
unsigned int file_args_count;
/* "* OK [RESP TEXT]" produces key=RESP, value=TEXT.
"* OK [RESP]" produces key=RESP, value=NULL
otherwise both are NULL */
const char *resp_text_key, *resp_text_value;
/* If this reply occurred while a mailbox was selected, this contains
the mailbox's untagged_context. */
void *untagged_box_context;
};
enum imapc_state_change_event {
IMAPC_STATE_CHANGE_AUTH_OK,
IMAPC_STATE_CHANGE_AUTH_FAILED,
};
/* Called when tagged reply is received for command. */
typedef void imapc_command_callback_t(const struct imapc_command_reply *reply,
void *context);
/* Called each time untagged input is received. */
typedef void imapc_untagged_callback_t(const struct imapc_untagged_reply *reply,
void *context);
typedef void imapc_state_change_callback_t(void *context,
enum imapc_state_change_event event,
const char *error);
struct imapc_client *
imapc_client_init(const struct imapc_client_settings *set,
struct event *event_parent);
void imapc_client_disconnect(struct imapc_client *client);
void imapc_client_deinit(struct imapc_client **client);
/* Set login callback, must be set before calling other commands.
This is called only for the first login, not for any reconnects or if there
are multiple connections created. */
void
imapc_client_set_login_callback(struct imapc_client *client,
imapc_command_callback_t *callback, void *context);
/* Explicitly login to server (also done automatically). */
void imapc_client_login(struct imapc_client *client);
/* Send a LOGOUT and wait for disconnection. */
void imapc_client_logout(struct imapc_client *client);
struct imapc_command *
imapc_client_cmd(struct imapc_client *client,
imapc_command_callback_t *callback, void *context);
void imapc_command_set_flags(struct imapc_command *cmd,
enum imapc_command_flags flags);
bool imapc_command_connection_is_selected(struct imapc_command *cmd);
void imapc_command_send(struct imapc_command *cmd, const char *cmd_str);
void imapc_command_sendf(struct imapc_command *cmd, const char *cmd_fmt, ...)
ATTR_FORMAT(2, 3);
void imapc_command_sendvf(struct imapc_command *cmd,
const char *cmd_fmt, va_list args) ATTR_FORMAT(2, 0);
const char *imapc_command_get_tag(struct imapc_command *cmd);
void imapc_command_abort(struct imapc_command **cmd);
void imapc_client_register_untagged(struct imapc_client *client,
imapc_untagged_callback_t *callback,
void *context);
void imapc_client_run(struct imapc_client *client);
void imapc_client_stop(struct imapc_client *client);
bool imapc_client_is_running(struct imapc_client *client);
struct imapc_client_mailbox *
imapc_client_mailbox_open(struct imapc_client *client,
void *untagged_box_context);
void imapc_client_mailbox_set_reopen_cb(struct imapc_client_mailbox *box,
void (*callback)(void *context),
void *context);
void imapc_client_mailbox_close(struct imapc_client_mailbox **box);
bool imapc_client_mailbox_can_reconnect(struct imapc_client_mailbox *box);
void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box,
const char *errmsg);
struct imapc_command *
imapc_client_mailbox_cmd(struct imapc_client_mailbox *box,
imapc_command_callback_t *callback, void *context);
struct imapc_msgmap *
imapc_client_mailbox_get_msgmap(struct imapc_client_mailbox *box);
void imapc_client_mailbox_idle(struct imapc_client_mailbox *box);
bool imapc_client_mailbox_is_opened(struct imapc_client_mailbox *box);
int imapc_client_get_capabilities(struct imapc_client *client,
enum imapc_capability *capabilities_r);
int imapc_client_create_temp_fd(struct imapc_client *client,
const char **path_r);
void imapc_client_register_state_change_callback(struct imapc_client *client,
imapc_state_change_callback_t *cb,
void *context);
#endif
dovecot-2.3.21.1/src/lib-imap-client/test-imapc-client.c 0000644 0000000 0000000 00000060542 14656633576 017547 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "hostpid.h"
#include "net.h"
#include "istream.h"
#include "ostream.h"
#include "ioloop.h"
#include "unlink-directory.h"
#include "sleep.h"
#include "test-common.h"
#include "test-subprocess.h"
#include "imapc-client-private.h"
#include
#include
#define SERVER_KILL_TIMEOUT_SECS 20
#define IMAPC_COMMAND_STATE_INVALID (enum imapc_command_state)-1
typedef void test_server_init_t(void);
typedef void test_client_init_t(void);
struct test_server {
in_port_t port;
pid_t pid;
int fd_listen, fd;
struct istream *input;
struct ostream *output;
};
static struct ip_addr bind_ip;
static struct test_server server;
static struct imapc_client *imapc_client;
static enum imapc_command_state imapc_login_last_reply;
static ARRAY(enum imapc_command_state) imapc_cmd_last_replies;
static bool debug = FALSE;
static void main_deinit(void);
/*
* Test client
*/
static struct imapc_client_settings test_imapc_default_settings = {
.host = "127.0.0.1",
.username = "testuser",
.password = "testpass",
.dns_client_socket_path = "",
.temp_path_prefix = ".test-tmp/",
.rawlog_dir = "",
.connect_timeout_msecs = 5000,
.connect_retry_count = 3,
.connect_retry_interval_msecs = 10,
.max_idle_time = 10000,
};
static enum imapc_command_state test_imapc_cmd_last_reply_pop(void)
{
const enum imapc_command_state *replies;
enum imapc_command_state reply;
unsigned int count;
replies = array_get(&imapc_cmd_last_replies, &count);
if (count == 0)
return IMAPC_COMMAND_STATE_INVALID;
reply = replies[0];
array_pop_front(&imapc_cmd_last_replies);
return reply;
}
static bool test_imapc_cmd_last_reply_expect(enum imapc_command_state state)
{
if (array_count(&imapc_cmd_last_replies) == 0)
imapc_client_run(imapc_client);
return test_imapc_cmd_last_reply_pop() == state;
}
static void imapc_login_callback(const struct imapc_command_reply *reply,
void *context ATTR_UNUSED)
{
if (debug) {
i_debug("Login reply: %s %s",
imapc_command_state_names[reply->state],
reply->text_full);
}
imapc_login_last_reply = reply->state;
imapc_client_stop(imapc_client);
}
static void imapc_command_callback(const struct imapc_command_reply *reply,
void *context ATTR_UNUSED)
{
if (debug) {
i_debug("Command reply: %s %s",
imapc_command_state_names[reply->state],
reply->text_full);
}
array_push_back(&imapc_cmd_last_replies, &reply->state);
imapc_client_stop(imapc_client);
}
static void imapc_reopen_callback(void *context)
{
struct imapc_client_mailbox *box = context;
struct imapc_command *cmd;
cmd = imapc_client_mailbox_cmd(box, imapc_command_callback, NULL);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_SELECT);
imapc_command_send(cmd, "SELECT");
}
/*
* Test server
*/
static bool
test_imapc_server_expect_full(struct test_server *server,
const char *expected_line)
{
const char *line = i_stream_read_next_line(server->input);
if (debug)
i_debug("Received: %s", (line == NULL ? "" : line));
if (line == NULL) {
printf("imapc client disconnected unexpectedly: %s\n",
i_stream_get_error(server->input));
return FALSE;
} else if (strcmp(line, expected_line) != 0) {
printf("imapc client sent '%s' when expecting '%s'\n",
line, expected_line);
return FALSE;
} else {
return TRUE;
}
}
static bool test_imapc_server_expect(const char *expected_line)
{
return test_imapc_server_expect_full(&server, expected_line);
}
static void
test_server_wait_connection(struct test_server *server, bool send_banner)
{
if (debug)
i_debug("Waiting for connection");
server->fd = net_accept(server->fd_listen, NULL, NULL);
i_assert(server->fd >= 0);
if (debug)
i_debug("Client connected");
fd_set_nonblock(server->fd, FALSE);
server->input = i_stream_create_fd(server->fd, SIZE_MAX);
server->output = o_stream_create_fd(server->fd, SIZE_MAX);
o_stream_set_no_error_handling(server->output, TRUE);
if (send_banner) {
o_stream_nsend_str(server->output,
"* OK [CAPABILITY IMAP4rev1 UNSELECT QUOTA] ready\r\n");
}
}
static void test_server_disconnect(struct test_server *server)
{
if (debug)
i_debug("Disconnecting client");
i_stream_unref(&server->input);
o_stream_unref(&server->output);
i_close_fd(&server->fd);
}
static void test_server_disconnect_and_wait(bool send_banner)
{
test_server_disconnect(&server);
test_server_wait_connection(&server, send_banner);
}
/*
* Test processes
*/
static int test_open_server_fd(in_port_t *bind_port)
{
int fd = net_listen(&bind_ip, bind_port, 128);
if (debug)
i_debug("server listening on %u", *bind_port);
if (fd == -1) {
i_fatal("listen(%s:%u) failed: %m",
net_ip2addr(&bind_ip), *bind_port);
}
fd_set_nonblock(fd, FALSE);
return fd;
}
static int test_run_server(test_server_init_t *server_test)
{
struct ioloop *ioloop;
i_set_failure_prefix("SERVER: ");
if (debug)
i_debug("PID=%s", my_pid);
ioloop = io_loop_create();
if (server_test != NULL)
server_test();
test_server_disconnect(&server);
io_loop_destroy(&ioloop);
if (debug)
i_debug("Terminated");
i_close_fd(&server.fd_listen);
main_deinit();
return 0;
}
static void
test_run_client(const struct imapc_client_settings *client_set,
test_client_init_t *client_test)
{
struct ioloop *ioloop;
i_set_failure_prefix("CLIENT: ");
if (debug)
i_debug("PID=%s", my_pid);
i_sleep_msecs(100); /* wait a little for server setup */
ioloop = io_loop_create();
imapc_client = imapc_client_init(client_set, NULL);
client_test();
imapc_client_logout(imapc_client);
test_assert(array_count(&imapc_cmd_last_replies) == 0);
if (imapc_client != NULL)
imapc_client_deinit(&imapc_client);
io_loop_destroy(&ioloop);
if (debug)
i_debug("Terminated");
}
static void
test_run_client_server(const struct imapc_client_settings *client_set,
test_client_init_t *client_test,
test_server_init_t *server_test)
{
struct imapc_client_settings client_set_copy = *client_set;
const char *error;
imapc_client_cmd_tag_counter = 0;
imapc_login_last_reply = IMAPC_COMMAND_STATE_INVALID;
t_array_init(&imapc_cmd_last_replies, 4);
i_zero(&server);
server.pid = (pid_t)-1;
server.fd = -1;
server.fd_listen = test_open_server_fd(&server.port);
client_set_copy.port = server.port;
if (mkdir(client_set->temp_path_prefix, 0700) < 0 && errno != EEXIST)
i_fatal("mkdir(%s) failed: %m", client_set->temp_path_prefix);
if (server_test != NULL) {
/* Fork server */
test_subprocess_fork(test_run_server, server_test, TRUE);
}
i_close_fd(&server.fd_listen);
/* Run client */
test_run_client(&client_set_copy, client_test);
i_unset_failure_prefix();
test_subprocess_kill_all(SERVER_KILL_TIMEOUT_SECS);
if (unlink_directory(client_set->temp_path_prefix,
UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
i_fatal("%s", error);
}
/*
* imapc connect failed
*/
static void test_imapc_connect_failed_client(void)
{
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
/* connection refused & one reconnect */
test_expect_errors(2);
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_DISCONNECTED);
}
static void test_imapc_connect_failed(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc connect failed");
test_run_client_server(&set, test_imapc_connect_failed_client, NULL);
test_end();
}
/*
* imapc banner hang
*/
static void test_imapc_banner_hangs_client(void)
{
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
test_expect_errors(2);
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_DISCONNECTED);
}
static void test_imapc_banner_hangs_server(void)
{
struct test_server server2 = { .fd_listen = server.fd_listen };
test_server_wait_connection(&server, FALSE);
test_server_wait_connection(&server2, FALSE);
test_assert(i_stream_read_next_line(server2.input) == NULL);
test_server_disconnect(&server2);
}
static void test_imapc_banner_hangs(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
set.connect_timeout_msecs = 500;
test_begin("imapc banner hangs");
test_run_client_server(&set, test_imapc_banner_hangs_client,
test_imapc_banner_hangs_server);
test_end();
}
/*
* imapc login hangs
*/
static void test_imapc_login_hangs_client(void)
{
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
/* run the first login */
test_expect_error_string("Authentication timed out");
imapc_client_run(imapc_client);
test_expect_no_more_errors();
/* imapc_login_callback() has stopped us. run the second reconnect
login. */
test_expect_error_string("Authentication timed out");
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_DISCONNECTED);
}
static void test_imapc_login_hangs_server(void)
{
struct test_server server2 = { .fd_listen = server.fd_listen };
test_server_wait_connection(&server, TRUE);
test_assert(test_imapc_server_expect(
"1 LOGIN \"testuser\" \"testpass\""));
test_server_wait_connection(&server2, TRUE);
test_assert(test_imapc_server_expect_full(
&server2, "2 LOGIN \"testuser\" \"testpass\""));
test_assert(i_stream_read_next_line(server2.input) == NULL);
test_server_disconnect(&server2);
}
static void test_imapc_login_hangs(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
set.connect_timeout_msecs = 500;
test_begin("imapc login hangs");
test_run_client_server(&set, test_imapc_login_hangs_client,
test_imapc_login_hangs_server);
test_end();
}
/*
* imapc login fails
*/
static void test_imapc_login_fails_client(void)
{
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
test_expect_error_string("Authentication failed: Test login failed");
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_AUTH_FAILED);
}
static void test_imapc_login_fails_server(void)
{
test_server_wait_connection(&server, TRUE);
test_assert(test_imapc_server_expect(
"1 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "1 NO Test login failed\r\n");
}
static void test_imapc_login_fails(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc login fails");
test_run_client_server(&set, test_imapc_login_fails_client,
test_imapc_login_fails_server);
test_end();
}
/*
* imapc reconnect
*/
static void test_imapc_reconnect_client(void)
{
struct imapc_command *cmd;
/* login to server */
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
imapc_client_run(imapc_client);
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_OK);
imapc_login_last_reply = IMAPC_COMMAND_STATE_INVALID;
/* disconnect */
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_send(cmd, "DISCONNECT");
test_expect_error_string("reconnecting");
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(test_imapc_cmd_last_reply_pop() ==
IMAPC_COMMAND_STATE_DISCONNECTED);
/* we should be reconnected now. try a command. */
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_send(cmd, "NOOP");
imapc_client_run(imapc_client);
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_INVALID);
test_assert(test_imapc_cmd_last_reply_pop() == IMAPC_COMMAND_STATE_OK);
}
static void test_imapc_reconnect_server(void)
{
test_server_wait_connection(&server, TRUE);
test_assert(test_imapc_server_expect(
"1 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "1 OK \r\n");
test_assert(test_imapc_server_expect("2 DISCONNECT"));
test_server_disconnect_and_wait(TRUE);
test_assert(test_imapc_server_expect(
"4 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "4 OK \r\n");
test_assert(test_imapc_server_expect("3 NOOP"));
o_stream_nsend_str(server.output, "3 OK \r\n");
test_assert(test_imapc_server_expect("5 LOGOUT"));
o_stream_nsend_str(server.output, "5 OK \r\n");
test_assert(i_stream_read_next_line(server.input) == NULL);
}
static void test_imapc_reconnect(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc reconnect");
test_run_client_server(&set, test_imapc_reconnect_client,
test_imapc_reconnect_server);
test_end();
}
/*
* imapc reconnect resend commands
*/
static void test_imapc_reconnect_resend_cmds_client(void)
{
struct imapc_command *cmd;
/* login to server */
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
imapc_client_run(imapc_client);
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_OK);
imapc_login_last_reply = IMAPC_COMMAND_STATE_INVALID;
/* send two commands */
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
imapc_command_send(cmd, "RETRY1");
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
imapc_command_send(cmd, "RETRY2");
/* disconnect & reconnect automatically */
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_send(cmd, "DISCONNECT");
test_expect_error_string("reconnecting");
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(test_imapc_cmd_last_reply_expect(
IMAPC_COMMAND_STATE_DISCONNECTED));
/* continue reconnection */
test_assert(test_imapc_cmd_last_reply_expect(IMAPC_COMMAND_STATE_OK));
test_assert(test_imapc_cmd_last_reply_expect(IMAPC_COMMAND_STATE_OK));
}
static void test_imapc_reconnect_resend_cmds_server(void)
{
test_server_wait_connection(&server, TRUE);
test_assert(test_imapc_server_expect(
"1 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "1 OK \r\n");
test_assert(test_imapc_server_expect("2 RETRY1"));
test_assert(test_imapc_server_expect("3 RETRY2"));
test_assert(test_imapc_server_expect("4 DISCONNECT"));
test_server_disconnect_and_wait(TRUE);
test_assert(test_imapc_server_expect(
"5 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "5 OK \r\n");
test_assert(test_imapc_server_expect("2 RETRY1"));
o_stream_nsend_str(server.output, "2 OK \r\n");
test_assert(test_imapc_server_expect("3 RETRY2"));
o_stream_nsend_str(server.output, "3 OK \r\n");
test_assert(test_imapc_server_expect("6 LOGOUT"));
o_stream_nsend_str(server.output, "6 OK \r\n");
test_assert(i_stream_read_next_line(server.input) == NULL);
}
static void test_imapc_reconnect_resend_commands(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc reconnect resend commands");
test_run_client_server(&set, test_imapc_reconnect_resend_cmds_client,
test_imapc_reconnect_resend_cmds_server);
test_end();
}
/*
* imapc reconnect resend commands failed
*/
static void test_imapc_reconnect_resend_cmds_failed_client(void)
{
struct imapc_command *cmd;
/* login to server */
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
imapc_client_run(imapc_client);
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_OK);
imapc_login_last_reply = IMAPC_COMMAND_STATE_INVALID;
/* send two commands */
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
imapc_command_send(cmd, "RETRY1");
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
imapc_command_send(cmd, "RETRY2");
/* disconnect & try to reconnect automatically */
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_send(cmd, "DISCONNECT");
test_expect_error_string("reconnecting");
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(test_imapc_cmd_last_reply_expect(
IMAPC_COMMAND_STATE_DISCONNECTED));
test_expect_error_string("timed out");
test_assert(test_imapc_cmd_last_reply_expect(
IMAPC_COMMAND_STATE_DISCONNECTED));
test_expect_no_more_errors();
test_assert(test_imapc_cmd_last_reply_expect(
IMAPC_COMMAND_STATE_DISCONNECTED));
}
static void test_imapc_reconnect_resend_cmds_failed_server(void)
{
test_server_wait_connection(&server, TRUE);
test_assert(test_imapc_server_expect(
"1 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "1 OK \r\n");
test_assert(test_imapc_server_expect("2 RETRY1"));
test_assert(test_imapc_server_expect("3 RETRY2"));
test_assert(test_imapc_server_expect("4 DISCONNECT"));
test_server_disconnect(&server);
i_sleep_intr_secs(60);
}
static void test_imapc_reconnect_resend_commands_failed(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
set.connect_timeout_msecs = 500;
test_begin("imapc reconnect resend commands failed");
test_run_client_server(&set,
test_imapc_reconnect_resend_cmds_failed_client,
test_imapc_reconnect_resend_cmds_failed_server);
test_end();
}
/*
* imapc reconnect mailbox
*/
static void test_imapc_reconnect_mailbox_client(void)
{
struct imapc_command *cmd;
struct imapc_client_mailbox *box;
/* login to server */
imapc_client_set_login_callback(imapc_client,
imapc_login_callback, NULL);
imapc_client_login(imapc_client);
imapc_client_run(imapc_client);
test_assert(imapc_login_last_reply == IMAPC_COMMAND_STATE_OK);
imapc_login_last_reply = IMAPC_COMMAND_STATE_INVALID;
/* select a mailbox */
box = imapc_client_mailbox_open(imapc_client, NULL);
imapc_client_mailbox_set_reopen_cb(box, imapc_reopen_callback, box);
cmd = imapc_client_mailbox_cmd(box, imapc_command_callback, NULL);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_SELECT);
imapc_command_send(cmd, "SELECT");
imapc_client_run(imapc_client);
test_assert(test_imapc_cmd_last_reply_expect(IMAPC_COMMAND_STATE_OK));
/* send a command */
cmd = imapc_client_mailbox_cmd(box, imapc_command_callback, NULL);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_RETRIABLE);
imapc_command_send(cmd, "RETRY");
/* disconnect & reconnect automatically */
cmd = imapc_client_cmd(imapc_client, imapc_command_callback, NULL);
imapc_command_send(cmd, "DISCONNECT");
test_expect_error_string("reconnecting");
imapc_client_run(imapc_client);
test_expect_no_more_errors();
test_assert(test_imapc_cmd_last_reply_expect(
IMAPC_COMMAND_STATE_DISCONNECTED));
/* continue reconnection */
test_assert(test_imapc_cmd_last_reply_expect(IMAPC_COMMAND_STATE_OK));
test_assert(test_imapc_cmd_last_reply_expect(IMAPC_COMMAND_STATE_OK));
imapc_client_mailbox_close(&box);
}
static void test_imapc_reconnect_mailbox_server(void)
{
test_server_wait_connection(&server, TRUE);
test_assert(test_imapc_server_expect(
"1 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "1 OK \r\n");
test_assert(test_imapc_server_expect("2 SELECT"));
o_stream_nsend_str(server.output, "2 OK \r\n");
test_assert(test_imapc_server_expect("3 RETRY"));
test_assert(test_imapc_server_expect("4 DISCONNECT"));
test_server_disconnect_and_wait(TRUE);
test_assert(test_imapc_server_expect(
"5 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "5 OK \r\n");
test_assert(test_imapc_server_expect("6 SELECT"));
o_stream_nsend_str(server.output, "6 OK \r\n");
test_assert(test_imapc_server_expect("3 RETRY"));
o_stream_nsend_str(server.output, "3 OK \r\n");
test_assert(test_imapc_server_expect("7 LOGOUT"));
o_stream_nsend_str(server.output, "7 OK \r\n");
test_assert(i_stream_read_next_line(server.input) == NULL);
}
static void test_imapc_reconnect_mailbox(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc reconnect mailbox");
test_run_client_server(&set, test_imapc_reconnect_mailbox_client,
test_imapc_reconnect_mailbox_server);
test_end();
}
/*
* imapc_client_get_capabilities()
*/
static void test_imapc_client_get_capabilities_client(void)
{
enum imapc_capability capabilities;
test_assert(imapc_client_get_capabilities(imapc_client, &capabilities) == 0);
test_assert(capabilities == (IMAPC_CAPABILITY_IMAP4REV1 |
IMAPC_CAPABILITY_UNSELECT |
IMAPC_CAPABILITY_QUOTA));
}
static void test_imapc_client_get_capabilities_server(void)
{
test_server_wait_connection(&server, TRUE);
test_assert(test_imapc_server_expect(
"1 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "1 OK \r\n");
test_assert(test_imapc_server_expect("2 LOGOUT"));
o_stream_nsend_str(server.output, "2 OK \r\n");
test_assert(i_stream_read_next_line(server.input) == NULL);
}
static void test_imapc_client_get_capabilities(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc_client_get_capabilities()");
test_run_client_server(&set, test_imapc_client_get_capabilities_client,
test_imapc_client_get_capabilities_server);
test_end();
}
/*
* imapc_client_get_capabilities() reconnected
*/
static void test_imapc_client_get_capabilities_reconnected_client(void)
{
enum imapc_capability capabilities;
test_expect_error_string("Server disconnected unexpectedly");
test_assert(imapc_client_get_capabilities(imapc_client,
&capabilities) == 0);
test_assert(capabilities == (IMAPC_CAPABILITY_IMAP4REV1 |
IMAPC_CAPABILITY_UNSELECT |
IMAPC_CAPABILITY_QUOTA));
test_expect_no_more_errors();
}
static void test_imapc_client_get_capabilities_reconnected_server(void)
{
test_server_wait_connection(&server, TRUE);
test_server_disconnect_and_wait(TRUE);
test_assert(test_imapc_server_expect(
"2 LOGIN \"testuser\" \"testpass\""));
o_stream_nsend_str(server.output, "2 OK \r\n");
test_assert(test_imapc_server_expect("3 LOGOUT"));
o_stream_nsend_str(server.output, "3 OK \r\n");
test_assert(i_stream_read_next_line(server.input) == NULL);
}
static void test_imapc_client_get_capabilities_reconnected(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc_client_get_capabilities() reconnected");
test_run_client_server(
&set, test_imapc_client_get_capabilities_reconnected_client,
test_imapc_client_get_capabilities_reconnected_server);
test_end();
}
/*
* imapc_client_get_capabilities() disconnected
*/
static void test_imapc_client_get_capabilities_disconnected_client(void)
{
enum imapc_capability capabilities;
test_expect_errors(2);
test_assert(imapc_client_get_capabilities(imapc_client,
&capabilities) < 0);
test_expect_no_more_errors();
}
static void test_imapc_client_get_capabilities_disconnected_server(void)
{
test_server_wait_connection(&server, TRUE);
test_server_disconnect_and_wait(TRUE);
}
static void test_imapc_client_get_capabilities_disconnected(void)
{
struct imapc_client_settings set = test_imapc_default_settings;
test_begin("imapc_client_get_capabilities() disconnected");
test_run_client_server(
&set, test_imapc_client_get_capabilities_disconnected_client,
test_imapc_client_get_capabilities_disconnected_server);
test_end();
}
/*
* Main
*/
static void main_init(void)
{
/* nothing yet */
}
static void main_deinit(void)
{
/* nothing yet; also called from sub-processes */
}
int main(int argc ATTR_UNUSED, char *argv[])
{
int c;
int ret;
static void (*const test_functions[])(void) = {
test_imapc_connect_failed,
test_imapc_banner_hangs,
test_imapc_login_hangs,
test_imapc_login_fails,
test_imapc_reconnect,
test_imapc_reconnect_resend_commands,
test_imapc_reconnect_resend_commands_failed,
test_imapc_reconnect_mailbox,
test_imapc_client_get_capabilities,
test_imapc_client_get_capabilities_reconnected,
test_imapc_client_get_capabilities_disconnected,
NULL
};
lib_init();
main_init();
while ((c = getopt(argc, argv, "D")) > 0) {
switch (c) {
case 'D':
debug = TRUE;
break;
default:
i_fatal("Usage: %s [-D]", argv[0]);
}
}
test_subprocesses_init(debug);
test_imapc_default_settings.debug = debug;
/* listen on localhost */
i_zero(&bind_ip);
bind_ip.family = AF_INET;
bind_ip.u.ip4.s_addr = htonl(INADDR_LOOPBACK);
ret = test_run(test_functions);
test_subprocesses_deinit();
main_deinit();
lib_deinit();
return ret;
}
dovecot-2.3.21.1/src/lib-imap-client/imapc-client-private.h 0000644 0000000 0000000 00000002574 14656633576 020250 0000000 0000000 #ifndef IMAPC_CLIENT_PRIVATE_H
#define IMAPC_CLIENT_PRIVATE_H
#include "imapc-client.h"
#define IMAPC_CLIENT_IDLE_SEND_DELAY_MSECS 100
struct imapc_client_connection {
struct imapc_connection *conn;
struct imapc_client *client;
struct imapc_client_mailbox *box;
};
struct imapc_client {
pool_t pool;
int refcount;
struct event *event;
struct imapc_client_settings set;
struct ssl_iostream_context *ssl_ctx;
imapc_untagged_callback_t *untagged_callback;
void *untagged_context;
imapc_state_change_callback_t *state_change_callback;
void *state_change_context;
imapc_command_callback_t *login_callback;
void *login_context;
ARRAY(struct imapc_client_connection *) conns;
bool logging_out;
struct ioloop *ioloop;
bool stop_on_state_finish;
};
struct imapc_client_mailbox {
struct imapc_client *client;
struct imapc_connection *conn;
struct imapc_msgmap *msgmap;
struct timeout *to_send_idle;
void (*reopen_callback)(void *context);
void *reopen_context;
void *untagged_box_context;
bool reconnect_ok;
bool reconnecting;
bool closing;
};
extern unsigned int imapc_client_cmd_tag_counter;
void imapc_client_ref(struct imapc_client *client);
void imapc_client_unref(struct imapc_client **client);
void imapc_command_set_mailbox(struct imapc_command *cmd,
struct imapc_client_mailbox *box);
void imapc_client_try_stop(struct imapc_client *client);
#endif
dovecot-2.3.21.1/src/lib-imap-client/Makefile.in 0000644 0000000 0000000 00000067627 14656633610 016126 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
noinst_PROGRAMS = $(am__EXEEXT_1)
subdir = src/lib-imap-client
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(pkginc_lib_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = test-imapc-client$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
LTLIBRARIES = $(noinst_LTLIBRARIES)
libimap_client_la_LIBADD =
am_libimap_client_la_OBJECTS = imapc-client.lo imapc-connection.lo \
imapc-msgmap.lo
libimap_client_la_OBJECTS = $(am_libimap_client_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am_test_imapc_client_OBJECTS = test-imapc-client.$(OBJEXT)
test_imapc_client_OBJECTS = $(am_test_imapc_client_OBJECTS)
am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = $(test_deps) $(am__DEPENDENCIES_1)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/imapc-client.Plo \
./$(DEPDIR)/imapc-connection.Plo ./$(DEPDIR)/imapc-msgmap.Plo \
./$(DEPDIR)/test-imapc-client.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libimap_client_la_SOURCES) $(test_imapc_client_SOURCES)
DIST_SOURCES = $(libimap_client_la_SOURCES) \
$(test_imapc_client_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
HEADERS = $(pkginc_lib_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
noinst_LTLIBRARIES = libimap_client.la
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-dns \
-I$(top_srcdir)/src/lib-sasl \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap
libimap_client_la_SOURCES = \
imapc-client.c \
imapc-connection.c \
imapc-msgmap.c
headers = \
imapc-client.h \
imapc-client-private.h \
imapc-connection.h \
imapc-msgmap.h
pkginc_libdir = $(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
test_programs = \
test-imapc-client
test_deps = \
$(noinst_LTLIBRARIES) \
../lib-ssl-iostream/libssl_iostream.la \
../lib-sasl/libsasl.la \
../lib-imap/libimap.la \
../lib-mail/libmail.la \
../lib-charset/libcharset.la \
../lib-dns/libdns.la \
../lib-test/libtest.la \
../lib/liblib.la
test_libs = \
$(test_deps) \
$(MODULE_LIBS)
test_imapc_client_SOURCES = test-imapc-client.c
test_imapc_client_LDADD = $(test_libs)
test_imapc_client_DEPENDENCIES = $(test_deps)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-imap-client/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/lib-imap-client/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libimap_client.la: $(libimap_client_la_OBJECTS) $(libimap_client_la_DEPENDENCIES) $(EXTRA_libimap_client_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(libimap_client_la_OBJECTS) $(libimap_client_la_LIBADD) $(LIBS)
test-imapc-client$(EXEEXT): $(test_imapc_client_OBJECTS) $(test_imapc_client_DEPENDENCIES) $(EXTRA_test_imapc_client_DEPENDENCIES)
@rm -f test-imapc-client$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_imapc_client_OBJECTS) $(test_imapc_client_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imapc-client.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imapc-connection.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imapc-msgmap.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-imapc-client.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
done
uninstall-pkginc_libHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-local
check: check-am
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/imapc-client.Plo
-rm -f ./$(DEPDIR)/imapc-connection.Plo
-rm -f ./$(DEPDIR)/imapc-msgmap.Plo
-rm -f ./$(DEPDIR)/test-imapc-client.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkginc_libHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/imapc-client.Plo
-rm -f ./$(DEPDIR)/imapc-connection.Plo
-rm -f ./$(DEPDIR)/imapc-msgmap.Plo
-rm -f ./$(DEPDIR)/test-imapc-client.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkginc_libHEADERS
.MAKE: check-am install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \
check-local clean clean-generic clean-libtool \
clean-noinstLTLIBRARIES clean-noinstPROGRAMS cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-pkginc_libHEADERS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-pkginc_libHEADERS
.PRECIOUS: Makefile
check-local:
for bin in $(test_programs); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/lib-imap-client/imapc-client.c 0000644 0000000 0000000 00000037537 14656633576 016602 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "ioloop.h"
#include "safe-mkstemp.h"
#include "iostream-ssl.h"
#include "imapc-msgmap.h"
#include "imapc-connection.h"
#include "imapc-client-private.h"
#include
const char *imapc_command_state_names[] = {
"OK", "NO", "BAD", "(auth failed)", "(disconnected)"
};
const struct imapc_capability_name imapc_capability_names[] = {
{ "SASL-IR", IMAPC_CAPABILITY_SASL_IR },
{ "LITERAL+", IMAPC_CAPABILITY_LITERALPLUS },
{ "QRESYNC", IMAPC_CAPABILITY_QRESYNC },
{ "IDLE", IMAPC_CAPABILITY_IDLE },
{ "UIDPLUS", IMAPC_CAPABILITY_UIDPLUS },
{ "AUTH=PLAIN", IMAPC_CAPABILITY_AUTH_PLAIN },
{ "STARTTLS", IMAPC_CAPABILITY_STARTTLS },
{ "X-GM-EXT-1", IMAPC_CAPABILITY_X_GM_EXT_1 },
{ "CONDSTORE", IMAPC_CAPABILITY_CONDSTORE },
{ "NAMESPACE", IMAPC_CAPABILITY_NAMESPACE },
{ "UNSELECT", IMAPC_CAPABILITY_UNSELECT },
{ "ESEARCH", IMAPC_CAPABILITY_ESEARCH },
{ "WITHIN", IMAPC_CAPABILITY_WITHIN },
{ "QUOTA", IMAPC_CAPABILITY_QUOTA },
{ "ID", IMAPC_CAPABILITY_ID },
{ "SAVEDATE", IMAPC_CAPABILITY_SAVEDATE },
{ "IMAP4REV1", IMAPC_CAPABILITY_IMAP4REV1 },
{ NULL, 0 }
};
unsigned int imapc_client_cmd_tag_counter = 0;
static void
default_untagged_callback(const struct imapc_untagged_reply *reply ATTR_UNUSED,
void *context ATTR_UNUSED)
{
}
struct imapc_client *
imapc_client_init(const struct imapc_client_settings *set,
struct event *event_parent)
{
struct imapc_client *client;
const char *error;
pool_t pool;
i_assert(set->connect_retry_count == 0 ||
set->connect_retry_interval_msecs > 0);
pool = pool_alloconly_create("imapc client", 1024);
client = p_new(pool, struct imapc_client, 1);
client->pool = pool;
client->refcount = 1;
client->event = event_create(event_parent);
client->set.debug = set->debug;
client->set.host = p_strdup(pool, set->host);
client->set.port = set->port;
client->set.master_user = p_strdup_empty(pool, set->master_user);
client->set.username = p_strdup(pool, set->username);
client->set.password = p_strdup(pool, set->password);
client->set.sasl_mechanisms = p_strdup(pool, set->sasl_mechanisms);
client->set.session_id_prefix = p_strdup(pool, set->session_id_prefix);
client->set.use_proxyauth = set->use_proxyauth;
client->set.dns_client_socket_path =
p_strdup(pool, set->dns_client_socket_path);
client->set.temp_path_prefix =
p_strdup(pool, set->temp_path_prefix);
client->set.rawlog_dir = p_strdup(pool, set->rawlog_dir);
client->set.max_idle_time = set->max_idle_time;
client->set.connect_timeout_msecs = set->connect_timeout_msecs != 0 ?
set->connect_timeout_msecs :
IMAPC_DEFAULT_CONNECT_TIMEOUT_MSECS;
client->set.connect_retry_count = set->connect_retry_count;
client->set.connect_retry_interval_msecs = set->connect_retry_interval_msecs;
client->set.cmd_timeout_msecs = set->cmd_timeout_msecs != 0 ?
set->cmd_timeout_msecs : IMAPC_DEFAULT_COMMAND_TIMEOUT_MSECS;
client->set.max_line_length = set->max_line_length != 0 ?
set->max_line_length : IMAPC_DEFAULT_MAX_LINE_LENGTH;
client->set.throttle_set = set->throttle_set;
if (client->set.throttle_set.init_msecs == 0)
client->set.throttle_set.init_msecs = IMAPC_THROTTLE_DEFAULT_INIT_MSECS;
if (client->set.throttle_set.max_msecs == 0)
client->set.throttle_set.max_msecs = IMAPC_THROTTLE_DEFAULT_MAX_MSECS;
if (client->set.throttle_set.shrink_min_msecs == 0)
client->set.throttle_set.shrink_min_msecs = IMAPC_THROTTLE_DEFAULT_SHRINK_MIN_MSECS;
if (set->ssl_mode != IMAPC_CLIENT_SSL_MODE_NONE) {
client->set.ssl_mode = set->ssl_mode;
ssl_iostream_settings_init_from(pool, &client->set.ssl_set, &set->ssl_set);
client->set.ssl_set.verbose_invalid_cert = !client->set.ssl_set.allow_invalid_cert;
if (ssl_iostream_client_context_cache_get(&client->set.ssl_set,
&client->ssl_ctx,
&error) < 0) {
i_error("imapc(%s:%u): Couldn't initialize SSL context: %s",
set->host, set->port, error);
}
}
client->untagged_callback = default_untagged_callback;
p_array_init(&client->conns, pool, 8);
return client;
}
void imapc_client_ref(struct imapc_client *client)
{
i_assert(client->refcount > 0);
client->refcount++;
}
void imapc_client_unref(struct imapc_client **_client)
{
struct imapc_client *client = *_client;
*_client = NULL;
i_assert(client->refcount > 0);
if (--client->refcount > 0)
return;
if (client->ssl_ctx != NULL)
ssl_iostream_context_unref(&client->ssl_ctx);
event_unref(&client->event);
pool_unref(&client->pool);
}
void imapc_client_disconnect(struct imapc_client *client)
{
struct imapc_client_connection *const *conns, *conn;
unsigned int i, count;
conns = array_get(&client->conns, &count);
for (i = count; i > 0; i--) {
conn = conns[i-1];
array_delete(&client->conns, i-1, 1);
i_assert(imapc_connection_get_mailbox(conn->conn) == NULL);
imapc_connection_deinit(&conn->conn);
i_free(conn);
}
}
void imapc_client_deinit(struct imapc_client **_client)
{
struct imapc_client *client = *_client;
imapc_client_disconnect(client);
imapc_client_unref(_client);
}
void imapc_client_register_untagged(struct imapc_client *client,
imapc_untagged_callback_t *callback,
void *context)
{
client->untagged_callback = callback;
client->untagged_context = context;
}
static void imapc_client_run_pre(struct imapc_client *client)
{
struct imapc_client_connection *conn;
struct ioloop *prev_ioloop = current_ioloop;
i_assert(client->ioloop == NULL);
client->ioloop = io_loop_create();
io_loop_set_running(client->ioloop);
array_foreach_elem(&client->conns, conn) {
imapc_connection_ioloop_changed(conn->conn);
if (imapc_connection_get_state(conn->conn) == IMAPC_CONNECTION_STATE_DISCONNECTED)
imapc_connection_connect(conn->conn);
}
if (io_loop_is_running(client->ioloop))
io_loop_run(client->ioloop);
io_loop_set_current(prev_ioloop);
}
static void imapc_client_run_post(struct imapc_client *client)
{
struct imapc_client_connection *conn;
struct ioloop *ioloop = client->ioloop;
client->ioloop = NULL;
array_foreach_elem(&client->conns, conn)
imapc_connection_ioloop_changed(conn->conn);
io_loop_set_current(ioloop);
io_loop_destroy(&ioloop);
}
void imapc_client_run(struct imapc_client *client)
{
imapc_client_run_pre(client);
imapc_client_run_post(client);
}
void imapc_client_stop(struct imapc_client *client)
{
if (client->ioloop != NULL)
io_loop_stop(client->ioloop);
}
void imapc_client_try_stop(struct imapc_client *client)
{
struct imapc_client_connection *conn;
array_foreach_elem(&client->conns, conn)
if (imapc_connection_get_state(conn->conn) != IMAPC_CONNECTION_STATE_DISCONNECTED)
return;
imapc_client_stop(client);
}
bool imapc_client_is_running(struct imapc_client *client)
{
return client->ioloop != NULL;
}
static void imapc_client_login_callback(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_client_connection *conn = context;
struct imapc_client *client = conn->client;
struct imapc_client_mailbox *box = conn->box;
if (box != NULL && box->reconnecting) {
box->reconnecting = FALSE;
if (reply->state == IMAPC_COMMAND_STATE_OK) {
/* reopen the mailbox */
box->reopen_callback(box->reopen_context);
} else {
imapc_connection_abort_commands(box->conn, NULL, FALSE);
}
}
/* call the login callback only once */
if (client->login_callback != NULL) {
imapc_command_callback_t *callback = client->login_callback;
void *context = client->login_context;
client->login_callback = NULL;
client->login_context = NULL;
callback(reply, context);
}
}
static struct imapc_client_connection *
imapc_client_add_connection(struct imapc_client *client)
{
struct imapc_client_connection *conn;
conn = i_new(struct imapc_client_connection, 1);
conn->client = client;
conn->conn = imapc_connection_init(client, imapc_client_login_callback,
conn);
array_push_back(&client->conns, &conn);
return conn;
}
static struct imapc_connection *
imapc_client_find_connection(struct imapc_client *client)
{
struct imapc_client_connection *const *connp;
/* FIXME: stupid algorithm */
if (array_count(&client->conns) == 0)
return imapc_client_add_connection(client)->conn;
connp = array_front(&client->conns);
return (*connp)->conn;
}
struct imapc_command *
imapc_client_cmd(struct imapc_client *client,
imapc_command_callback_t *callback, void *context)
{
struct imapc_connection *conn;
conn = imapc_client_find_connection(client);
return imapc_connection_cmd(conn, callback, context);
}
static struct imapc_client_connection *
imapc_client_get_unboxed_connection(struct imapc_client *client)
{
struct imapc_client_connection *const *conns;
unsigned int i, count;
conns = array_get(&client->conns, &count);
for (i = 0; i < count; i++) {
if (conns[i]->box == NULL)
return conns[i];
}
return imapc_client_add_connection(client);
}
void imapc_client_login(struct imapc_client *client)
{
struct imapc_client_connection *conn;
i_assert(client->login_callback != NULL);
i_assert(array_count(&client->conns) == 0);
conn = imapc_client_add_connection(client);
imapc_connection_connect(conn->conn);
}
struct imapc_logout_ctx {
struct imapc_client *client;
unsigned int logout_count;
};
static void
imapc_client_logout_callback(const struct imapc_command_reply *reply ATTR_UNUSED,
void *context)
{
struct imapc_logout_ctx *ctx = context;
i_assert(ctx->logout_count > 0);
if (--ctx->logout_count == 0)
imapc_client_stop(ctx->client);
}
void imapc_client_logout(struct imapc_client *client)
{
struct imapc_logout_ctx ctx = { .client = client };
struct imapc_client_connection *conn;
struct imapc_command *cmd;
client->logging_out = TRUE;
/* send LOGOUT to all connections */
array_foreach_elem(&client->conns, conn) {
if (imapc_connection_get_state(conn->conn) == IMAPC_CONNECTION_STATE_DISCONNECTED)
continue;
imapc_connection_set_no_reconnect(conn->conn);
ctx.logout_count++;
cmd = imapc_connection_cmd(conn->conn,
imapc_client_logout_callback, &ctx);
imapc_command_set_flags(cmd, IMAPC_COMMAND_FLAG_PRELOGIN |
IMAPC_COMMAND_FLAG_LOGOUT);
imapc_command_send(cmd, "LOGOUT");
}
/* wait for LOGOUT to finish */
while (ctx.logout_count > 0)
imapc_client_run(client);
/* we should have disconnected all clients already, but if there were
any timeouts there may be some clients left. */
imapc_client_disconnect(client);
}
struct imapc_client_mailbox *
imapc_client_mailbox_open(struct imapc_client *client,
void *untagged_box_context)
{
struct imapc_client_mailbox *box;
struct imapc_client_connection *conn;
box = i_new(struct imapc_client_mailbox, 1);
box->client = client;
box->untagged_box_context = untagged_box_context;
conn = imapc_client_get_unboxed_connection(client);
conn->box = box;
box->conn = conn->conn;
box->msgmap = imapc_msgmap_init();
/* if we get disconnected before the SELECT is finished, allow
one reconnect retry. */
box->reconnect_ok = TRUE;
return box;
}
void imapc_client_mailbox_set_reopen_cb(struct imapc_client_mailbox *box,
void (*callback)(void *context),
void *context)
{
box->reopen_callback = callback;
box->reopen_context = context;
}
bool imapc_client_mailbox_can_reconnect(struct imapc_client_mailbox *box)
{
/* the reconnect_ok flag attempts to avoid infinite reconnection loops
to a server that keeps disconnecting us (e.g. some of the commands
we send keeps crashing it always) */
return box->reopen_callback != NULL && box->reconnect_ok;
}
void imapc_client_mailbox_reconnect(struct imapc_client_mailbox *box,
const char *errmsg)
{
imapc_connection_try_reconnect(box->conn, errmsg, 0, FALSE);
}
void imapc_client_mailbox_close(struct imapc_client_mailbox **_box)
{
struct imapc_client_mailbox *box = *_box;
struct imapc_client_connection *conn;
box->closing = TRUE;
/* cancel any pending commands */
imapc_connection_unselect(box, FALSE);
if (box->reconnecting) {
/* need to abort the reconnection so it won't try to access
the box */
imapc_connection_disconnect(box->conn);
}
/* set this only after unselect, which may cancel some commands that
reference this box */
*_box = NULL;
array_foreach_elem(&box->client->conns, conn) {
if (conn->box == box) {
conn->box = NULL;
break;
}
}
imapc_msgmap_deinit(&box->msgmap);
timeout_remove(&box->to_send_idle);
i_free(box);
}
struct imapc_command *
imapc_client_mailbox_cmd(struct imapc_client_mailbox *box,
imapc_command_callback_t *callback, void *context)
{
struct imapc_command *cmd;
i_assert(!box->closing);
cmd = imapc_connection_cmd(box->conn, callback, context);
imapc_command_set_mailbox(cmd, box);
return cmd;
}
struct imapc_msgmap *
imapc_client_mailbox_get_msgmap(struct imapc_client_mailbox *box)
{
return box->msgmap;
}
static void imapc_client_mailbox_idle_send(struct imapc_client_mailbox *box)
{
timeout_remove(&box->to_send_idle);
if (imapc_client_mailbox_is_opened(box))
imapc_connection_idle(box->conn);
}
void imapc_client_mailbox_idle(struct imapc_client_mailbox *box)
{
/* send the IDLE with a delay to avoid unnecessary IDLEs that are
immediately aborted */
if (box->to_send_idle == NULL && imapc_client_mailbox_is_opened(box)) {
box->to_send_idle =
timeout_add_short(IMAPC_CLIENT_IDLE_SEND_DELAY_MSECS,
imapc_client_mailbox_idle_send, box);
}
/* we're done with all work at this point. */
box->reconnect_ok = TRUE;
}
bool imapc_client_mailbox_is_opened(struct imapc_client_mailbox *box)
{
struct imapc_client_mailbox *selected_box;
if (box->closing ||
imapc_connection_get_state(box->conn) != IMAPC_CONNECTION_STATE_DONE)
return FALSE;
selected_box = imapc_connection_get_mailbox(box->conn);
if (selected_box != box) {
if (selected_box != NULL)
i_error("imapc: Selected mailbox changed unexpectedly");
return FALSE;
}
return TRUE;
}
static bool
imapc_client_get_any_capabilities(struct imapc_client *client,
enum imapc_capability *capabilities_r)
{
struct imapc_client_connection *conn;
array_foreach_elem(&client->conns, conn) {
if (imapc_connection_get_state(conn->conn) == IMAPC_CONNECTION_STATE_DONE) {
*capabilities_r = imapc_connection_get_capabilities(conn->conn);
return TRUE;
}
}
return FALSE;
}
int imapc_client_get_capabilities(struct imapc_client *client,
enum imapc_capability *capabilities_r)
{
/* try to find a connection that is already logged in */
if (imapc_client_get_any_capabilities(client, capabilities_r))
return 0;
/* if there are no connections yet, create one */
if (array_count(&client->conns) == 0)
(void)imapc_client_add_connection(client);
/* wait for any of the connections to login */
client->stop_on_state_finish = TRUE;
imapc_client_run(client);
client->stop_on_state_finish = FALSE;
if (imapc_client_get_any_capabilities(client, capabilities_r))
return 0;
/* failed */
return -1;
}
int imapc_client_create_temp_fd(struct imapc_client *client,
const char **path_r)
{
string_t *path;
int fd;
if (client->set.temp_path_prefix == NULL) {
i_error("imapc: temp_path_prefix not set, "
"can't create temp file");
return -1;
}
path = t_str_new(128);
str_append(path, client->set.temp_path_prefix);
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
if (fd == -1) {
i_error("safe_mkstemp(%s) failed: %m", str_c(path));
return -1;
}
/* we just want the fd, unlink it */
if (i_unlink(str_c(path)) < 0) {
/* shouldn't happen.. */
i_close_fd(&fd);
return -1;
}
*path_r = str_c(path);
return fd;
}
void imapc_client_register_state_change_callback(struct imapc_client *client,
imapc_state_change_callback_t *cb,
void *context)
{
i_assert(client->state_change_callback == NULL);
i_assert(client->state_change_context == NULL);
client->state_change_callback = cb;
client->state_change_context = context;
}
void
imapc_client_set_login_callback(struct imapc_client *client,
imapc_command_callback_t *callback, void *context)
{
client->login_callback = callback;
client->login_context = context;
}
dovecot-2.3.21.1/src/lib-imap-client/imapc-msgmap.c 0000644 0000000 0000000 00000003421 14656633576 016571 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "imapc-msgmap.h"
#include "sort.h"
struct imapc_msgmap {
ARRAY_TYPE(uint32_t) uids;
uint32_t uid_next;
};
struct imapc_msgmap *imapc_msgmap_init(void)
{
struct imapc_msgmap *msgmap;
msgmap = i_new(struct imapc_msgmap, 1);
i_array_init(&msgmap->uids, 128);
msgmap->uid_next = 1;
return msgmap;
}
void imapc_msgmap_deinit(struct imapc_msgmap **_msgmap)
{
struct imapc_msgmap *msgmap = *_msgmap;
*_msgmap = NULL;
array_free(&msgmap->uids);
i_free(msgmap);
}
uint32_t imapc_msgmap_count(struct imapc_msgmap *msgmap)
{
return array_count(&msgmap->uids);
}
uint32_t imapc_msgmap_uidnext(struct imapc_msgmap *msgmap)
{
return msgmap->uid_next;
}
uint32_t imapc_msgmap_rseq_to_uid(struct imapc_msgmap *msgmap, uint32_t rseq)
{
const uint32_t *uidp;
uidp = array_idx(&msgmap->uids, rseq-1);
return *uidp;
}
bool imapc_msgmap_uid_to_rseq(struct imapc_msgmap *msgmap,
uint32_t uid, uint32_t *rseq_r)
{
const uint32_t *p, *first;
p = array_bsearch(&msgmap->uids, &uid, uint32_cmp);
if (p == NULL) {
*rseq_r = 0;
return FALSE;
}
first = array_front(&msgmap->uids);
*rseq_r = (p - first) + 1;
return TRUE;
}
void imapc_msgmap_append(struct imapc_msgmap *msgmap,
uint32_t rseq, uint32_t uid)
{
i_assert(rseq == imapc_msgmap_count(msgmap) + 1);
i_assert(uid >= msgmap->uid_next);
msgmap->uid_next = uid + 1;
array_push_back(&msgmap->uids, &uid);
}
void imapc_msgmap_expunge(struct imapc_msgmap *msgmap, uint32_t rseq)
{
i_assert(rseq > 0);
i_assert(rseq <= imapc_msgmap_count(msgmap));
array_delete(&msgmap->uids, rseq-1, 1);
}
void imapc_msgmap_reset(struct imapc_msgmap *msgmap)
{
array_clear(&msgmap->uids);
msgmap->uid_next = 1;
}
dovecot-2.3.21.1/src/lib-imap-client/imapc-connection.h 0000644 0000000 0000000 00000004212 14656633576 017450 0000000 0000000 #ifndef IMAPC_CONNECTION_H
#define IMAPC_CONNECTION_H
#include "imapc-client.h"
/* [THROTTLED] handling behavior */
#define IMAPC_THROTTLE_DEFAULT_INIT_MSECS 50
#define IMAPC_THROTTLE_DEFAULT_MAX_MSECS (16*1000)
#define IMAPC_THROTTLE_DEFAULT_SHRINK_MIN_MSECS 500
struct imapc_client;
struct imapc_connection;
enum imapc_connection_state {
/* No connection */
IMAPC_CONNECTION_STATE_DISCONNECTED = 0,
/* Trying to connect */
IMAPC_CONNECTION_STATE_CONNECTING,
/* Connected, trying to authenticate */
IMAPC_CONNECTION_STATE_AUTHENTICATING,
/* Authenticated, ready to accept commands */
IMAPC_CONNECTION_STATE_DONE
};
struct imapc_connection *
imapc_connection_init(struct imapc_client *client,
imapc_command_callback_t *login_callback,
void *login_context);
void imapc_connection_deinit(struct imapc_connection **conn);
void imapc_connection_connect(struct imapc_connection *conn);
void imapc_connection_set_no_reconnect(struct imapc_connection *conn);
void imapc_connection_disconnect(struct imapc_connection *conn);
void imapc_connection_disconnect_full(struct imapc_connection *conn,
bool reconnecting);
void imapc_connection_try_reconnect(struct imapc_connection *conn,
const char *errstr,
unsigned int delay_msecs,
bool connect_error);
void imapc_connection_abort_commands(struct imapc_connection *conn,
struct imapc_client_mailbox *only_box,
bool keep_retriable) ATTR_NULL(2);
void imapc_connection_ioloop_changed(struct imapc_connection *conn);
void imapc_connection_input_pending(struct imapc_connection *conn);
struct imapc_command *
imapc_connection_cmd(struct imapc_connection *conn,
imapc_command_callback_t *callback, void *context)
ATTR_NULL(3);
void imapc_connection_unselect(struct imapc_client_mailbox *box,
bool via_tagged_reply);
enum imapc_connection_state
imapc_connection_get_state(struct imapc_connection *conn);
enum imapc_capability
imapc_connection_get_capabilities(struct imapc_connection *conn);
struct imapc_client_mailbox *
imapc_connection_get_mailbox(struct imapc_connection *conn);
void imapc_connection_idle(struct imapc_connection *conn);
#endif
dovecot-2.3.21.1/src/lib-imap-client/imapc-msgmap.h 0000644 0000000 0000000 00000001236 14656633576 016600 0000000 0000000 #ifndef IMAPC_MSGMAP_H
#define IMAPC_MSGMAP_H
struct imapc_msgmap *imapc_msgmap_init(void);
void imapc_msgmap_deinit(struct imapc_msgmap **msgmap);
uint32_t imapc_msgmap_count(struct imapc_msgmap *msgmap);
uint32_t imapc_msgmap_uidnext(struct imapc_msgmap *msgmap);
uint32_t imapc_msgmap_rseq_to_uid(struct imapc_msgmap *msgmap, uint32_t rseq);
bool imapc_msgmap_uid_to_rseq(struct imapc_msgmap *msgmap,
uint32_t uid, uint32_t *rseq_r);
void imapc_msgmap_append(struct imapc_msgmap *msgmap,
uint32_t rseq, uint32_t uid);
void imapc_msgmap_expunge(struct imapc_msgmap *msgmap, uint32_t rseq);
void imapc_msgmap_reset(struct imapc_msgmap *msgmap);
#endif
dovecot-2.3.21.1/src/lib-imap-client/Makefile.am 0000644 0000000 0000000 00000002170 14656633576 016106 0000000 0000000 noinst_LTLIBRARIES = libimap_client.la
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-dns \
-I$(top_srcdir)/src/lib-sasl \
-I$(top_srcdir)/src/lib-ssl-iostream \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap
libimap_client_la_SOURCES = \
imapc-client.c \
imapc-connection.c \
imapc-msgmap.c
headers = \
imapc-client.h \
imapc-client-private.h \
imapc-connection.h \
imapc-msgmap.h
pkginc_libdir=$(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
test_programs = \
test-imapc-client
noinst_PROGRAMS = $(test_programs)
test_deps = \
$(noinst_LTLIBRARIES) \
../lib-ssl-iostream/libssl_iostream.la \
../lib-sasl/libsasl.la \
../lib-imap/libimap.la \
../lib-mail/libmail.la \
../lib-charset/libcharset.la \
../lib-dns/libdns.la \
../lib-test/libtest.la \
../lib/liblib.la
test_libs = \
$(test_deps) \
$(MODULE_LIBS)
test_imapc_client_SOURCES = test-imapc-client.c
test_imapc_client_LDADD = $(test_libs)
test_imapc_client_DEPENDENCIES = $(test_deps)
check-local:
for bin in $(test_programs); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
dovecot-2.3.21.1/src/pop3/ 0000755 0000000 0000000 00000000000 14656633640 012035 5 0000000 0000000 dovecot-2.3.21.1/src/pop3/pop3-commands.h 0000644 0000000 0000000 00000000510 14656633576 014612 0000000 0000000 #ifndef POP3_COMMANDS_H
#define POP3_COMMANDS_H
struct pop3_command {
const char *name;
int (*func)(struct client *client, const char *args);
};
const struct pop3_command *pop3_command_find(const char *name);
int client_command_execute(struct client *client,
const struct pop3_command *cmd, const char *args);
#endif
dovecot-2.3.21.1/src/pop3/pop3-client.c 0000644 0000000 0000000 00000057734 14656633576 014306 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "pop3-common.h"
#include "array.h"
#include "ioloop.h"
#include "net.h"
#include "iostream.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-rawlog.h"
#include "crc32.h"
#include "str.h"
#include "llist.h"
#include "hostpid.h"
#include "file-dotlock.h"
#include "var-expand.h"
#include "master-service.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "mail-autoexpunge.h"
#include "pop3-commands.h"
#include "mail-search-build.h"
#include "mail-namespace.h"
#include
/* max. length of input command line (spec says 512) */
#define MAX_INBUF_SIZE 2048
/* Disconnect client when it sends too many bad commands in a row */
#define CLIENT_MAX_BAD_COMMANDS 20
/* Disconnect client after idling this many milliseconds */
#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
/* If client starts idling for this many milliseconds, commit the current
transaction. This allows the mailbox to become unlocked. */
#define CLIENT_COMMIT_TIMEOUT_MSECS (10*1000)
#define POP3_LOCK_FNAME "dovecot-pop3-session.lock"
#define POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS (60*5)
extern struct pop3_client_vfuncs pop3_client_vfuncs;
struct pop3_module_register pop3_module_register = { 0 };
struct client *pop3_clients;
unsigned int pop3_client_count;
static enum mail_sort_type pop3_sort_program[] = {
MAIL_SORT_POP3_ORDER,
MAIL_SORT_END
};
static const struct dotlock_settings session_dotlock_set = {
.timeout = 10,
.stale_timeout = POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS,
.lock_suffix = "",
.use_io_notify = TRUE
};
static void client_input(struct client *client);
static int client_output(struct client *client);
static void client_commit_timeout(struct client *client)
{
if (client->cmd != NULL) {
/* Can't commit while commands are running */
return;
}
(void)mailbox_transaction_commit(&client->trans);
client->trans = mailbox_transaction_begin(client->mailbox, 0, __func__);
}
static void client_idle_timeout(struct client *client)
{
if (client->cmd != NULL) {
client_destroy(client, t_strdup_printf(
"Client has not read server output for for %"PRIdTIME_T" secs",
ioloop_time - client->last_output));
} else {
client_send_line(client, "-ERR Disconnected for inactivity.");
client_destroy(client, t_strdup_printf(
"Inactivity - no input for %"PRIdTIME_T" secs",
ioloop_time - client->last_input));
}
}
static int
pop3_mail_get_size(struct client *client, struct mail *mail, uoff_t *size_r)
{
int ret;
if (!client->set->pop3_fast_size_lookups)
return mail_get_virtual_size(mail, size_r);
/* first try to get the virtual size */
mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL;
ret = mail_get_virtual_size(mail, size_r);
mail->lookup_abort = MAIL_LOOKUP_ABORT_NEVER;
if (ret == 0)
return 0;
if (mailbox_get_last_mail_error(mail->box) != MAIL_ERROR_LOOKUP_ABORTED)
return -1;
/* virtual size not available with a fast lookup.
fallback to trying the physical size */
mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL;
ret = mail_get_physical_size(mail, size_r);
mail->lookup_abort = MAIL_LOOKUP_ABORT_NEVER;
if (ret == 0)
return 0;
if (mailbox_get_last_mail_error(mail->box) != MAIL_ERROR_LOOKUP_ABORTED)
return -1;
/* no way to quickly get the size. fallback to doing a slow virtual
size lookup */
return mail_get_virtual_size(mail, size_r);
}
static void
msgnum_to_seq_map_add(ARRAY_TYPE(uint32_t) *msgnum_to_seq_map,
struct client *client, struct mail *mail,
unsigned int msgnum)
{
uint32_t seq;
if (mail->seq == msgnum+1)
return;
if (!array_is_created(msgnum_to_seq_map))
i_array_init(msgnum_to_seq_map, client->messages_count);
/* add any messages between this and the previous one that had
a POP3 order defined */
seq = array_count(msgnum_to_seq_map) + 1;
for (; seq <= msgnum; seq++)
array_push_back(msgnum_to_seq_map, &seq);
array_push_back(msgnum_to_seq_map, &mail->seq);
}
static int read_mailbox(struct client *client, uint32_t *failed_uid_r)
{
struct mailbox_status status;
struct mailbox_transaction_context *t;
struct mail_search_args *search_args;
struct mail_search_arg *sarg;
struct mail_search_context *ctx;
struct mail *mail;
uoff_t size;
ARRAY(uoff_t) message_sizes;
ARRAY_TYPE(uint32_t) msgnum_to_seq_map = ARRAY_INIT;
unsigned int msgnum;
int ret = 1;
*failed_uid_r = 0;
mailbox_get_open_status(client->mailbox, STATUS_UIDVALIDITY, &status);
client->uid_validity = status.uidvalidity;
client->messages_count = status.messages;
t = mailbox_transaction_begin(client->mailbox, 0, __func__);
search_args = mail_search_build_init();
if (client->deleted_kw != NULL) {
sarg = mail_search_build_add(search_args, SEARCH_KEYWORDS);
sarg->match_not = TRUE;
sarg->value.str = p_strdup(search_args->pool,
client->set->pop3_deleted_flag);
i_array_init(&client->all_seqs, 32);
} else {
mail_search_build_add_all(search_args);
}
mail_search_args_init(search_args, client->mailbox, TRUE, NULL);
ctx = mailbox_search_init(t, search_args, pop3_sort_program,
client->set->pop3_fast_size_lookups ? 0 :
MAIL_FETCH_VIRTUAL_SIZE, NULL);
mail_search_args_unref(&search_args);
client->last_seen_pop3_msn = 0;
client->total_size = 0;
i_array_init(&message_sizes, client->messages_count);
msgnum = 0;
while (mailbox_search_next(ctx, &mail)) {
if (pop3_mail_get_size(client, mail, &size) < 0) {
ret = mail->expunged ? 0 : -1;
*failed_uid_r = mail->uid;
break;
}
if (array_is_created(&client->all_seqs))
seq_range_array_add(&client->all_seqs, mail->seq);
msgnum_to_seq_map_add(&msgnum_to_seq_map, client, mail, msgnum);
if ((mail_get_flags(mail) & MAIL_SEEN) != 0)
client->last_seen_pop3_msn = msgnum + 1;
client->total_size += size;
if (client->highest_seq < mail->seq)
client->highest_seq = mail->seq;
array_push_back(&message_sizes, &size);
msgnum++;
}
if (mailbox_search_deinit(&ctx) < 0)
ret = -1;
if (ret <= 0) {
/* commit the transaction instead of rolling back to make sure
we don't lose data (virtual sizes) added to cache file */
(void)mailbox_transaction_commit(&t);
array_free(&message_sizes);
if (array_is_created(&msgnum_to_seq_map))
array_free(&msgnum_to_seq_map);
return ret;
}
i_assert(msgnum <= client->messages_count);
client->messages_count = msgnum;
if (!array_is_created(&client->all_seqs)) {
i_array_init(&client->all_seqs, 1);
seq_range_array_add_range(&client->all_seqs, 1, msgnum);
}
client->trans = t;
client->message_sizes =
array_free_without_data(&message_sizes);
if (array_is_created(&msgnum_to_seq_map)) {
client->msgnum_to_seq_map_count =
array_count(&msgnum_to_seq_map);
client->msgnum_to_seq_map =
array_free_without_data(&msgnum_to_seq_map);
}
return 1;
}
static int init_pop3_deleted_flag(struct client *client, const char **error_r)
{
const char *deleted_keywords[2];
if (client->set->pop3_deleted_flag[0] == '\0')
return 0;
deleted_keywords[0] = client->set->pop3_deleted_flag;
deleted_keywords[1] = NULL;
if (mailbox_keywords_create(client->mailbox, deleted_keywords,
&client->deleted_kw) < 0) {
*error_r = t_strdup_printf(
"pop3_deleted_flags: Invalid keyword '%s': %s",
client->set->pop3_deleted_flag,
mailbox_get_last_internal_error(client->mailbox, NULL));
return -1;
}
return 0;
}
static int init_mailbox(struct client *client, const char **error_r)
{
uint32_t failed_uid = 0, last_failed_uid = 0;
int i, ret = -1;
for (i = 0;; i++) {
if (mailbox_sync(client->mailbox,
MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
ret = -1;
break;
}
ret = read_mailbox(client, &failed_uid);
if (ret > 0)
return 0;
if (i == 2)
break;
/* well, sync and try again. maybe it works the second time. */
last_failed_uid = failed_uid;
failed_uid = 0;
}
if (ret < 0) {
*error_r = mailbox_get_last_internal_error(client->mailbox, NULL);
client_send_storage_error(client);
} else {
if (failed_uid == last_failed_uid && failed_uid != 0) {
/* failed twice in same message */
*error_r = t_strdup_printf(
"Getting size of message UID=%u failed",
failed_uid);
} else {
*error_r = "Can't sync mailbox: "
"Messages keep getting expunged";
}
client_send_line(client, "-ERR [SYS/TEMP] Couldn't sync mailbox.");
}
return -1;
}
static enum uidl_keys parse_uidl_keymask(const char *format)
{
enum uidl_keys mask = 0;
for (; *format != '\0'; format++) {
if (format[0] == '%' && format[1] != '\0') {
switch (var_get_key(++format)) {
case 'v':
mask |= UIDL_UIDVALIDITY;
break;
case 'u':
mask |= UIDL_UID;
break;
case 'm':
mask |= UIDL_MD5;
break;
case 'f':
mask |= UIDL_FILE_NAME;
break;
case 'g':
mask |= UIDL_GUID;
break;
}
}
}
return mask;
}
static void pop3_lock_session_refresh(struct client *client)
{
if (file_dotlock_touch(client->session_dotlock) < 0) {
client_send_line(client,
"-ERR [SYS/TEMP] Couldn't update POP3 session lock.");
client_destroy(client, "Couldn't lock POP3 session");
}
}
int pop3_lock_session(struct client *client)
{
const struct mail_storage_settings *mail_set =
mail_storage_service_user_get_mail_set(client->service_user);
struct dotlock_settings dotlock_set;
enum mailbox_list_path_type type;
const char *dir, *path;
int ret;
if (mailbox_list_get_root_path(client->inbox_ns->list,
MAILBOX_LIST_PATH_TYPE_INDEX, &dir)) {
type = MAILBOX_LIST_PATH_TYPE_INDEX;
} else if (mailbox_list_get_root_path(client->inbox_ns->list,
MAILBOX_LIST_PATH_TYPE_DIR, &dir)) {
type = MAILBOX_LIST_PATH_TYPE_DIR;
} else {
i_error("pop3_lock_session: Storage has no root/index directory, "
"can't create a POP3 session lock file");
return -1;
}
if (mailbox_list_mkdir_root(client->inbox_ns->list, dir, type) < 0) {
i_error("pop3_lock_session: Couldn't create root directory %s: %s",
dir, mailbox_list_get_last_internal_error(client->inbox_ns->list, NULL));
return -1;
}
path = t_strdup_printf("%s/"POP3_LOCK_FNAME, dir);
dotlock_set = session_dotlock_set;
dotlock_set.use_excl_lock = mail_set->dotlock_use_excl;
dotlock_set.nfs_flush = mail_set->mail_nfs_storage;
ret = file_dotlock_create(&dotlock_set, path, 0,
&client->session_dotlock);
if (ret < 0)
i_error("file_dotlock_create(%s) failed: %m", path);
else if (ret > 0) {
client->to_session_dotlock_refresh =
timeout_add(POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS*1000,
pop3_lock_session_refresh, client);
}
return ret;
}
struct client *client_create(int fd_in, int fd_out,
struct mail_user *user,
struct mail_storage_service_user *service_user,
const struct pop3_settings *set)
{
struct client *client;
pool_t pool;
/* always use nonblocking I/O */
net_set_nonblock(fd_in, TRUE);
net_set_nonblock(fd_out, TRUE);
pool = pool_alloconly_create("pop3 client", 256);
client = p_new(pool, struct client, 1);
client->pool = pool;
client->service_user = service_user;
client->v = pop3_client_vfuncs;
client->set = set;
client->fd_in = fd_in;
client->fd_out = fd_out;
client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE);
client->output = o_stream_create_fd(fd_out, SIZE_MAX);
o_stream_set_no_error_handling(client->output, TRUE);
o_stream_set_flush_callback(client->output, client_output, client);
p_array_init(&client->module_contexts, client->pool, 5);
client->last_input = ioloop_time;
client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
client_idle_timeout, client);
client->to_commit = timeout_add(CLIENT_COMMIT_TIMEOUT_MSECS,
client_commit_timeout, client);
client->user = user;
client->mail_set = mail_user_set_get_storage_set(user);
client->uidl_keymask =
parse_uidl_keymask(client->mail_set->pop3_uidl_format);
if (client->uidl_keymask == 0)
i_fatal("Invalid pop3_uidl_format");
if (var_has_key(set->pop3_logout_format, 'u', "uidl_change")) {
/* logging uidl_change. we need hashes of the UIDLs */
client->message_uidls_save = TRUE;
} else if (strcmp(set->pop3_uidl_duplicates, "allow") != 0) {
/* UIDL duplicates aren't allowed, so we'll need to
keep track of them */
client->message_uidls_save = TRUE;
}
pop3_client_count++;
DLLIST_PREPEND(&pop3_clients, client);
if (hook_client_created != NULL)
hook_client_created(&client);
return client;
}
void client_create_finish(struct client *client)
{
if (client->set->rawlog_dir[0] != '\0') {
(void)iostream_rawlog_create(client->set->rawlog_dir,
&client->input, &client->output);
}
client->io = io_add_istream(client->input, client_input, client);
}
int client_init_mailbox(struct client *client, const char **error_r)
{
enum mailbox_flags flags;
const char *ident, *errmsg;
/* refresh proctitle before a potentially long-running init_mailbox() */
pop3_refresh_proctitle();
flags = MAILBOX_FLAG_POP3_SESSION;
if (!client->set->pop3_no_flag_updates)
flags |= MAILBOX_FLAG_DROP_RECENT;
client->mailbox = mailbox_alloc(client->inbox_ns->list, "INBOX", flags);
if (mailbox_open(client->mailbox) < 0) {
*error_r = t_strdup_printf("Couldn't open INBOX: %s",
mailbox_get_last_internal_error(client->mailbox, NULL));
client_send_storage_error(client);
return -1;
}
if (init_pop3_deleted_flag(client, &errmsg) < 0 ||
init_mailbox(client, &errmsg) < 0) {
*error_r = t_strdup_printf("Couldn't init INBOX: %s", errmsg);
return -1;
}
if (!client->set->pop3_no_flag_updates && client->messages_count > 0)
client->seen_bitmask = i_malloc(MSGS_BITMASK_SIZE(client));
ident = mail_user_get_anvil_userip_ident(client->user);
if (ident != NULL) {
master_service_anvil_send(master_service, t_strconcat(
"CONNECT\t", my_pid, "\tpop3/", ident, "\n", NULL));
client->anvil_sent = TRUE;
}
return 0;
}
static const char *client_build_uidl_change_string(struct client *client)
{
uint32_t i, old_hash, new_hash;
unsigned int old_msg_count, new_msg_count;
if (client->message_uidls == NULL) {
/* UIDL command not given */
return "";
}
/* 1..new-1 were probably left to mailbox by previous POP3 session */
old_msg_count = client->lowest_retr_pop3_msn > 0 ?
client->lowest_retr_pop3_msn - 1 : client->messages_count;
for (i = 0, old_hash = 0; i < old_msg_count; i++)
old_hash ^= crc32_str(client->message_uidls[i]);
/* assume all except deleted messages were sent to POP3 client */
if (!client->deleted) {
for (i = 0, new_hash = 0; i < client->messages_count; i++)
new_hash ^= crc32_str(client->message_uidls[i]);
} else {
for (i = 0, new_hash = 0; i < client->messages_count; i++) {
if ((client->deleted_bitmask[i / CHAR_BIT] &
(1 << (i % CHAR_BIT))) != 0)
continue;
new_hash ^= crc32_str(client->message_uidls[i]);
}
}
new_msg_count = client->messages_count - client->deleted_count;
if (old_hash == new_hash && old_msg_count == new_msg_count)
return t_strdup_printf("%u/%08x", old_msg_count, old_hash);
else {
return t_strdup_printf("%u/%08x -> %u/%08x",
old_msg_count, old_hash,
new_msg_count, new_hash);
}
}
static const char *client_stats(struct client *client)
{
const char *uidl_change = "";
if (var_has_key(client->set->pop3_logout_format,
'o', "uidl_change"))
uidl_change = client_build_uidl_change_string(client);
const struct var_expand_table logout_tab[] = {
{ 'p', dec2str(client->top_bytes), "top_bytes" },
{ 't', dec2str(client->top_count), "top_count" },
{ 'b', dec2str(client->retr_bytes), "retr_bytes" },
{ 'r', dec2str(client->retr_count), "retr_count" },
{ 'd', !client->delete_success ? "0" :
dec2str(client->deleted_count), "deleted_count" },
{ 'm', dec2str(client->messages_count), "message_count" },
{ 's', dec2str(client->total_size), "message_bytes" },
{ 'i', dec2str(client->input->v_offset), "input" },
{ 'o', dec2str(client->output->offset), "output" },
{ 'u', uidl_change, "uidl_change" },
{ '\0', !client->delete_success ? "0" :
dec2str(client->deleted_size), "deleted_bytes" },
{ '\0', NULL, NULL }
};
const struct var_expand_table *user_tab =
mail_user_var_expand_table(client->user);
const struct var_expand_table *tab =
t_var_expand_merge_tables(logout_tab, user_tab);
string_t *str;
const char *error;
str = t_str_new(128);
if (var_expand_with_funcs(str, client->set->pop3_logout_format,
tab, mail_user_var_expand_func_table,
client->user, &error) < 0) {
i_error("Failed to expand pop3_logout_format=%s: %s",
client->set->pop3_logout_format, error);
}
return str_c(str);
}
void client_destroy(struct client *client, const char *reason)
{
client->v.destroy(client, reason);
}
static void client_default_destroy(struct client *client, const char *reason)
{
i_assert(!client->destroyed);
client->destroyed = TRUE;
if (client->seen_change_count > 0)
(void)client_update_mails(client);
if (!client->disconnected) {
if (reason == NULL) {
reason = io_stream_get_disconnect_reason(client->input,
client->output);
}
i_info("Disconnected: %s %s", reason, client_stats(client));
}
if (client->cmd != NULL) {
/* deinitialize command */
i_stream_close(client->input);
o_stream_close(client->output);
client->cmd(client);
i_assert(client->cmd == NULL);
}
if (client->trans != NULL) {
/* client didn't QUIT, but we still want to save any changes
done in this transaction. especially the cached virtual
message sizes. */
(void)mailbox_transaction_commit(&client->trans);
}
if (array_is_created(&client->all_seqs))
array_free(&client->all_seqs);
if (client->deleted_kw != NULL)
mailbox_keywords_unref(&client->deleted_kw);
if (client->mailbox != NULL)
mailbox_free(&client->mailbox);
if (client->anvil_sent) {
master_service_anvil_send(master_service, t_strconcat(
"DISCONNECT\t", my_pid, "\tpop3/",
mail_user_get_anvil_userip_ident(client->user),
"\n", NULL));
}
if (client->session_dotlock != NULL)
file_dotlock_delete(&client->session_dotlock);
timeout_remove(&client->to_session_dotlock_refresh);
pool_unref(&client->uidl_pool);
i_free(client->message_sizes);
i_free(client->deleted_bitmask);
i_free(client->seen_bitmask);
i_free(client->msgnum_to_seq_map);
io_remove(&client->io);
timeout_remove(&client->to_idle);
timeout_remove(&client->to_commit);
i_stream_destroy(&client->input);
o_stream_destroy(&client->output);
fd_close_maybe_stdio(&client->fd_in, &client->fd_out);
/* Autoexpunging might run for a long time. Disconnect the client
before it starts, and refresh proctitle so it's clear that it's
doing autoexpunging. We've also sent DISCONNECT to anvil already,
because this is background work and shouldn't really be counted
as an active POP3 session for the user. */
pop3_refresh_proctitle();
mail_user_autoexpunge(client->user);
mail_user_deinit(&client->user);
mail_storage_service_user_unref(&client->service_user);
pop3_client_count--;
DLLIST_REMOVE(&pop3_clients, client);
pool_unref(&client->pool);
master_service_client_connection_destroyed(master_service);
pop3_refresh_proctitle();
}
static void client_destroy_timeout(struct client *client)
{
client_destroy(client, NULL);
}
void client_disconnect(struct client *client, const char *reason)
{
if (client->disconnected)
return;
client->disconnected = TRUE;
i_info("Disconnected: %s %s", reason, client_stats(client));
(void)o_stream_flush(client->output);
i_stream_close(client->input);
o_stream_close(client->output);
timeout_remove(&client->to_idle);
client->to_idle = timeout_add(0, client_destroy_timeout, client);
}
void client_send_line(struct client *client, const char *fmt, ...)
{
va_list va;
ssize_t ret;
if (client->output->closed)
return;
va_start(va, fmt);
T_BEGIN {
string_t *str;
str = t_str_new(256);
str_vprintfa(str, fmt, va);
str_append(str, "\r\n");
ret = o_stream_send(client->output,
str_data(str), str_len(str));
i_assert(ret < 0 || (size_t)ret == str_len(str));
} T_END;
if (ret >= 0) {
if (!POP3_CLIENT_OUTPUT_FULL(client))
client->last_output = ioloop_time;
else if (client->io != NULL) {
/* no more input until client has read
our output */
io_remove(&client->io);
/* If someone happens to flush output, we want to get
our IO handler back in flush callback */
o_stream_set_flush_pending(client->output, TRUE);
}
}
va_end(va);
}
void client_send_storage_error(struct client *client)
{
const char *errstr;
enum mail_error error;
if (mailbox_is_inconsistent(client->mailbox)) {
client_send_line(client, "-ERR [SYS/TEMP] Mailbox is in inconsistent "
"state, please relogin.");
client_disconnect(client, "Mailbox is in inconsistent state.");
return;
}
errstr = mailbox_get_last_error(client->mailbox, &error);
switch (error) {
case MAIL_ERROR_TEMP:
case MAIL_ERROR_NOQUOTA:
case MAIL_ERROR_INUSE:
client_send_line(client, "-ERR [SYS/TEMP] %s", errstr);
break;
default:
client_send_line(client, "-ERR [SYS/PERM] %s", errstr);
break;
}
}
bool client_handle_input(struct client *client)
{
char *line, *args;
int ret;
o_stream_cork(client->output);
while (!client->output->closed &&
(line = i_stream_next_line(client->input)) != NULL) {
args = strchr(line, ' ');
if (args != NULL)
*args++ = '\0';
const struct pop3_command *cmd = pop3_command_find(line);
if (cmd == NULL) {
client_send_line(client, "-ERR Unknown command: %s", line);
ret = -1;
} else T_BEGIN {
const char *reason_code =
event_reason_code_prefix("pop3", "cmd_",
cmd->name);
struct event_reason *reason =
event_reason_begin(reason_code);
ret = client_command_execute(client, cmd,
args != NULL ? args : "");
event_reason_end(&reason);
} T_END;
if (ret >= 0) {
client->bad_counter = 0;
if (client->cmd != NULL) {
o_stream_set_flush_pending(client->output,
TRUE);
client->waiting_input = TRUE;
break;
}
} else if (++client->bad_counter > CLIENT_MAX_BAD_COMMANDS) {
client_send_line(client, "-ERR Too many bad commands.");
client_disconnect(client, "Too many bad commands.");
}
}
o_stream_uncork(client->output);
if (client->output->closed) {
client_destroy(client, NULL);
return FALSE;
}
return TRUE;
}
static void client_input(struct client *client)
{
if (client->cmd != NULL) {
/* we're still processing a command. wait until it's
finished. */
io_remove(&client->io);
client->waiting_input = TRUE;
return;
}
client->waiting_input = FALSE;
client->last_input = ioloop_time;
timeout_reset(client->to_idle);
if (client->to_commit != NULL)
timeout_reset(client->to_commit);
switch (i_stream_read(client->input)) {
case -1:
/* disconnected */
client_destroy(client, NULL);
return;
case -2:
/* line too long, kill it */
client_send_line(client, "-ERR Input line too long.");
client_destroy(client, "Input line too long");
return;
}
(void)client_handle_input(client);
}
static int client_output(struct client *client)
{
if (o_stream_flush(client->output) < 0) {
client_destroy(client, NULL);
return 1;
}
client->last_output = ioloop_time;
timeout_reset(client->to_idle);
if (client->to_commit != NULL)
timeout_reset(client->to_commit);
if (client->cmd != NULL)
client->cmd(client);
if (client->cmd == NULL) {
if (o_stream_get_buffer_used_size(client->output) <
POP3_OUTBUF_THROTTLE_SIZE/2 && client->io == NULL &&
!client->input->closed) {
/* enable input again */
client->io = io_add_istream(client->input, client_input,
client);
}
if (client->io != NULL && client->waiting_input) {
if (!client_handle_input(client)) {
/* client got destroyed */
return 1;
}
}
}
if (client->cmd != NULL) {
/* command not finished yet */
return 0;
} else if (client->io == NULL) {
/* data still in output buffer, get back here to add IO */
return 0;
} else {
return 1;
}
}
void clients_destroy_all(void)
{
while (pop3_clients != NULL) {
mail_storage_service_io_activate_user(pop3_clients->service_user);
if (pop3_clients->cmd == NULL) {
client_send_line(pop3_clients,
"-ERR [SYS/TEMP] Server shutting down.");
}
client_destroy(pop3_clients, "Server shutting down.");
}
}
struct pop3_client_vfuncs pop3_client_vfuncs = {
client_default_destroy
};
dovecot-2.3.21.1/src/pop3/pop3-commands.c 0000644 0000000 0000000 00000060300 14656633576 014610 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "pop3-common.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "hash.h"
#include "str.h"
#include "var-expand.h"
#include "message-size.h"
#include "mail-storage.h"
#include "mail-storage-settings.h"
#include "mail-search-build.h"
#include "pop3-capability.h"
#include "pop3-commands.h"
static enum mail_sort_type pop3_sort_program[] = {
MAIL_SORT_POP3_ORDER,
MAIL_SORT_END
};
static uint32_t msgnum_to_seq(struct client *client, uint32_t msgnum)
{
return msgnum < client->msgnum_to_seq_map_count ?
client->msgnum_to_seq_map[msgnum] : msgnum+1;
}
static const char *get_msgnum(struct client *client, const char *args,
unsigned int *msgnum, bool thenspace)
{
unsigned int num;
if (*args < '0' || *args > '9') {
client_send_line(client,
"-ERR Invalid message number: %s", args);
return NULL;
}
if (str_parse_uint(args, &num, &args) < 0) {
client_send_line(client,
"-ERR Message number too large: %s", args);
return NULL;
}
if (*args != (thenspace ? ' ' : '\0')) {
client_send_line(client,
"-ERR Noise after message number: %s", args);
return NULL;
}
if (num == 0 || num > client->messages_count) {
client_send_line(client,
"-ERR There's no message %u.", num);
return NULL;
}
num--;
if (client->deleted) {
if ((client->deleted_bitmask[num / CHAR_BIT] &
(1 << (num % CHAR_BIT))) != 0) {
client_send_line(client, "-ERR Message is deleted.");
return NULL;
}
}
while (*args == ' ') args++;
*msgnum = num;
return args;
}
static const char *get_size(struct client *client, const char *args,
uoff_t *size, bool thenspace)
{
uoff_t num;
if (*args < '0' || *args > '9') {
client_send_line(client, "-ERR Invalid size: %s",
args);
return NULL;
}
if (str_parse_uoff(args, &num, &args) < 0) {
client_send_line(client, "-ERR Size too large: %s",
args);
return NULL;
}
if (*args != (thenspace ? ' ' : '\0')) {
client_send_line(client, "-ERR Noise after size: %s", args);
return NULL;
}
while (*args == ' ') args++;
*size = num;
return args;
}
static int cmd_capa(struct client *client, const char *args ATTR_UNUSED)
{
client_send_line(client, "+OK\r\n"POP3_CAPABILITY_REPLY".");
return 1;
}
static int cmd_dele(struct client *client, const char *args)
{
unsigned int msgnum;
if (get_msgnum(client, args, &msgnum, FALSE) == NULL)
return -1;
if (!client->deleted) {
client->deleted_bitmask = i_malloc(MSGS_BITMASK_SIZE(client));
client->deleted = TRUE;
}
client->deleted_bitmask[msgnum / CHAR_BIT] |= 1 << (msgnum % CHAR_BIT);
client->deleted_count++;
client->deleted_size += client->message_sizes[msgnum];
client_send_line(client, "+OK Marked to be deleted.");
return 1;
}
struct cmd_list_context {
unsigned int msgnum;
};
static void cmd_list_callback(struct client *client)
{
struct cmd_list_context *ctx = client->cmd_context;
for (; ctx->msgnum != client->messages_count; ctx->msgnum++) {
if (client->output->closed)
break;
if (POP3_CLIENT_OUTPUT_FULL(client)) {
/* buffer full */
return;
}
if (client->deleted) {
if ((client->deleted_bitmask[ctx->msgnum / CHAR_BIT] &
(1 << (ctx->msgnum % CHAR_BIT))) != 0)
continue;
}
client_send_line(client, "%u %"PRIuUOFF_T, ctx->msgnum+1,
client->message_sizes[ctx->msgnum]);
}
client_send_line(client, ".");
i_free(ctx);
client->cmd = NULL;
}
static int cmd_list(struct client *client, const char *args)
{
struct cmd_list_context *ctx;
if (*args == '\0') {
ctx = i_new(struct cmd_list_context, 1);
client_send_line(client, "+OK %u messages:",
client->messages_count - client->deleted_count);
client->cmd = cmd_list_callback;
client->cmd_context = ctx;
cmd_list_callback(client);
} else {
unsigned int msgnum;
if (get_msgnum(client, args, &msgnum, FALSE) == NULL)
return -1;
client_send_line(client, "+OK %u %"PRIuUOFF_T, msgnum+1,
client->message_sizes[msgnum]);
}
return 1;
}
static int cmd_last(struct client *client, const char *args ATTR_UNUSED)
{
if (client->set->pop3_enable_last)
client_send_line(client, "+OK %u", client->last_seen_pop3_msn);
else
client_send_line(client, "-ERR LAST command not enabled");
return 1;
}
static int cmd_noop(struct client *client, const char *args ATTR_UNUSED)
{
client_send_line(client, "+OK");
return 1;
}
static struct mail_search_args *
pop3_search_build_seqset(ARRAY_TYPE(seq_range) *seqset)
{
struct mail_search_args *search_args;
struct mail_search_arg *sarg;
search_args = mail_search_build_init();
sarg = mail_search_build_add(search_args, SEARCH_SEQSET);
sarg->value.seqset = *seqset;
return search_args;
}
static struct mail_search_args *
pop3_search_build(struct client *client, uint32_t seq)
{
struct mail_search_args *search_args;
if (seq == 0)
return pop3_search_build_seqset(&client->all_seqs);
search_args = mail_search_build_init();
mail_search_build_add_seqset(search_args, seq, seq);
return search_args;
}
static int client_verify_ordering(struct client *client,
struct mail *mail, uint32_t msgnum)
{
uint32_t seq;
seq = msgnum_to_seq(client, msgnum);
if (seq != mail->seq) {
i_error("Message ordering changed unexpectedly "
"(msg #%u: storage seq %u -> %u)",
msgnum+1, seq, mail->seq);
return -1;
}
return 0;
}
static void client_expunge(struct client *client, struct mail *mail)
{
switch (client->set->parsed_delete_type) {
case POP3_DELETE_TYPE_EXPUNGE:
mail_expunge(mail);
break;
case POP3_DELETE_TYPE_FLAG:
i_assert(client->deleted_kw != NULL);
mail_update_keywords(mail, MODIFY_ADD, client->deleted_kw);
break;
}
}
bool client_update_mails(struct client *client)
{
struct mail_search_args *search_args;
struct mail_search_context *ctx;
struct mail *mail;
ARRAY_TYPE(seq_range) deleted_msgs, seen_msgs;
uint32_t msgnum, bit;
bool ret = TRUE;
if (mailbox_is_readonly(client->mailbox)) {
/* silently ignore */
return TRUE;
}
/* translate msgnums to sequences (in case POP3 ordering is
different) */
t_array_init(&deleted_msgs, 8);
if (client->deleted_bitmask != NULL && client->quit_seen) {
for (msgnum = 0; msgnum < client->messages_count; msgnum++) {
bit = 1 << (msgnum % CHAR_BIT);
if ((client->deleted_bitmask[msgnum / CHAR_BIT] & bit) != 0)
seq_range_array_add(&deleted_msgs, msgnum_to_seq(client, msgnum));
}
}
t_array_init(&seen_msgs, 8);
if (client->seen_bitmask != NULL) {
for (msgnum = 0; msgnum < client->messages_count; msgnum++) {
bit = 1 << (msgnum % CHAR_BIT);
if ((client->seen_bitmask[msgnum / CHAR_BIT] & bit) != 0)
seq_range_array_add(&seen_msgs, msgnum_to_seq(client, msgnum));
}
}
if (array_count(&deleted_msgs) > 0) {
/* expunge DELEted mails */
search_args = pop3_search_build_seqset(&deleted_msgs);
ctx = mailbox_search_init(client->trans, search_args, NULL, 0, NULL);
mail_search_args_unref(&search_args);
while (mailbox_search_next(ctx, &mail))
client_expunge(client, mail);
if (mailbox_search_deinit(&ctx) < 0)
ret = FALSE;
/* don't bother setting \Seen flags for deleted messages */
seq_range_array_invert(&deleted_msgs, 1, client->highest_seq);
seq_range_array_intersect(&seen_msgs, &deleted_msgs);
}
if (array_count(&seen_msgs) > 0) {
/* add \Seen flags for RETRed mails */
search_args = pop3_search_build_seqset(&seen_msgs);
ctx = mailbox_search_init(client->trans, search_args, NULL, 0, NULL);
mail_search_args_unref(&search_args);
while (mailbox_search_next(ctx, &mail))
mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
if (mailbox_search_deinit(&ctx) < 0)
ret = FALSE;
}
client->seen_change_count = 0;
return ret;
}
static int cmd_quit(struct client *client, const char *args ATTR_UNUSED)
{
client->quit_seen = TRUE;
if (client->deleted || client->seen_bitmask != NULL) {
if (!client_update_mails(client)) {
client_send_storage_error(client);
client_disconnect(client,
"Storage error during logout.");
return 1;
}
}
if (mailbox_transaction_commit(&client->trans) < 0 ||
mailbox_sync(client->mailbox, MAILBOX_SYNC_FLAG_FULL_WRITE) < 0) {
client_send_storage_error(client);
client_disconnect(client, "Storage error during logout.");
return 1;
} else {
client->delete_success = TRUE;
}
if (!client->deleted)
client_send_line(client, "+OK Logging out.");
else
client_send_line(client, "+OK Logging out, messages deleted.");
client_disconnect(client, "Logged out");
return 1;
}
struct fetch_context {
struct mail *mail;
struct istream *stream;
uoff_t body_lines;
uoff_t *byte_counter;
uoff_t byte_counter_offset;
unsigned char last;
bool cr_skipped, in_body;
};
static void fetch_deinit(struct fetch_context *ctx)
{
mail_free(&ctx->mail);
i_free(ctx);
}
static void fetch_callback(struct client *client)
{
struct fetch_context *ctx = client->cmd_context;
const unsigned char *data;
unsigned char add;
size_t i, size;
int ret;
while ((ctx->body_lines > 0 || !ctx->in_body) &&
i_stream_read_more(ctx->stream, &data, &size) > 0) {
if (size > 4096)
size = 4096;
add = '\0';
for (i = 0; i < size; i++) {
if ((data[i] == '\r' || data[i] == '\n') &&
!ctx->in_body) {
if (i == 0 && (ctx->last == '\0' ||
ctx->last == '\n'))
ctx->in_body = TRUE;
else if (i > 0 && data[i-1] == '\n')
ctx->in_body = TRUE;
}
if (data[i] == '\n') {
if ((i == 0 && ctx->last != '\r') ||
(i > 0 && data[i-1] != '\r')) {
/* missing CR */
add = '\r';
break;
}
if (ctx->in_body) {
if (--ctx->body_lines == 0) {
i++;
break;
}
}
} else if (data[i] == '.' &&
((i == 0 && ctx->last == '\n') ||
(i > 0 && data[i-1] == '\n'))) {
/* escape the dot */
add = '.';
break;
} else if (data[i] == '\0' &&
(client->set->parsed_workarounds &
WORKAROUND_OUTLOOK_NO_NULS) != 0) {
add = 0x80;
break;
}
}
if (i > 0) {
if (o_stream_send(client->output, data, i) < 0)
break;
ctx->last = data[i-1];
i_stream_skip(ctx->stream, i);
}
if (o_stream_get_buffer_used_size(client->output) >= 4096) {
if ((ret = o_stream_flush(client->output)) < 0)
break;
if (ret == 0) {
/* continue later */
return;
}
}
if (add != '\0') {
if (o_stream_send(client->output, &add, 1) < 0)
break;
ctx->last = add;
if (add == 0x80)
i_stream_skip(ctx->stream, 1);
}
}
if (ctx->last != '\n') {
/* didn't end with CRLF */
o_stream_nsend(client->output, "\r\n", 2);
}
if (!ctx->in_body &&
(client->set->parsed_workarounds & WORKAROUND_OE_NS_EOH) != 0) {
/* Add the missing end of headers line. */
o_stream_nsend(client->output, "\r\n", 2);
}
*ctx->byte_counter +=
client->output->offset - ctx->byte_counter_offset;
client_send_line(client, ".");
fetch_deinit(ctx);
client->cmd = NULL;
}
static int client_reply_msg_expunged(struct client *client, unsigned int msgnum)
{
client_send_line(client, "-ERR Message %u expunged.", msgnum + 1);
if (msgnum <= client->highest_expunged_fetch_msgnum) {
/* client tried to fetch an expunged message again.
treat this as error so we'll eventually disconnect the
client instead of letting it loop forever. */
return -1;
}
client->highest_expunged_fetch_msgnum = msgnum;
return 1;
}
static int fetch(struct client *client, unsigned int msgnum, uoff_t body_lines,
const char *reason, uoff_t *byte_counter)
{
struct fetch_context *ctx;
int ret;
ctx = i_new(struct fetch_context, 1);
ctx->byte_counter = byte_counter;
ctx->byte_counter_offset = client->output->offset;
ctx->mail = mail_alloc(client->trans,
MAIL_FETCH_STREAM_HEADER |
MAIL_FETCH_STREAM_BODY, NULL);
mail_set_seq(ctx->mail, msgnum_to_seq(client, msgnum));
if (mail_get_stream_because(ctx->mail, NULL, NULL, reason, &ctx->stream) < 0) {
ret = client_reply_msg_expunged(client, msgnum);
fetch_deinit(ctx);
return ret;
}
if (body_lines == UOFF_T_MAX && client->seen_bitmask != NULL) {
if ((mail_get_flags(ctx->mail) & MAIL_SEEN) == 0) {
/* mark the message seen with RETR command */
client->seen_bitmask[msgnum / CHAR_BIT] |=
1 << (msgnum % CHAR_BIT);
client->seen_change_count++;
}
}
ctx->body_lines = body_lines;
if (body_lines == UOFF_T_MAX) {
client_send_line(client, "+OK %"PRIuUOFF_T" octets",
client->message_sizes[msgnum]);
} else {
client_send_line(client, "+OK");
ctx->body_lines++; /* internally we count the empty line too */
}
client->cmd = fetch_callback;
client->cmd_context = ctx;
fetch_callback(client);
return 1;
}
static int cmd_retr(struct client *client, const char *args)
{
unsigned int msgnum;
if (get_msgnum(client, args, &msgnum, FALSE) == NULL)
return -1;
if (client->lowest_retr_pop3_msn > msgnum+1 ||
client->lowest_retr_pop3_msn == 0)
client->lowest_retr_pop3_msn = msgnum+1;
if (client->last_seen_pop3_msn < msgnum+1)
client->last_seen_pop3_msn = msgnum+1;
client->retr_count++;
return fetch(client, msgnum, UOFF_T_MAX, "RETR", &client->retr_bytes);
}
static int cmd_rset(struct client *client, const char *args ATTR_UNUSED)
{
struct mail_search_context *search_ctx;
struct mail *mail;
struct mail_search_args *search_args;
client->last_seen_pop3_msn = 0;
if (client->deleted) {
client->deleted = FALSE;
memset(client->deleted_bitmask, 0, MSGS_BITMASK_SIZE(client));
client->deleted_count = 0;
client->deleted_size = 0;
}
if (client->seen_change_count > 0) {
memset(client->seen_bitmask, 0, MSGS_BITMASK_SIZE(client));
client->seen_change_count = 0;
}
if (client->set->pop3_enable_last) {
/* remove all \Seen flags (as specified by RFC 1460) */
search_args = pop3_search_build(client, 0);
search_ctx = mailbox_search_init(client->trans,
search_args, NULL, 0, NULL);
mail_search_args_unref(&search_args);
while (mailbox_search_next(search_ctx, &mail))
mail_update_flags(mail, MODIFY_REMOVE, MAIL_SEEN);
(void)mailbox_search_deinit(&search_ctx);
(void)mailbox_transaction_commit(&client->trans);
client->trans = mailbox_transaction_begin(client->mailbox, 0,
__func__);
}
client_send_line(client, "+OK");
return 1;
}
static int cmd_stat(struct client *client, const char *args ATTR_UNUSED)
{
client_send_line(client, "+OK %u %"PRIuUOFF_T,
client->messages_count - client->deleted_count,
client->total_size - client->deleted_size);
return 1;
}
static int cmd_top(struct client *client, const char *args)
{
unsigned int msgnum;
uoff_t max_lines;
args = get_msgnum(client, args, &msgnum, TRUE);
if (args == NULL)
return -1;
if (get_size(client, args, &max_lines, FALSE) == NULL)
return -1;
client->top_count++;
return fetch(client, msgnum, max_lines, "TOP", &client->top_bytes);
}
struct cmd_uidl_context {
struct mail_search_context *search_ctx;
struct mail *mail;
uint32_t msgnum;
bool list_all;
};
static int
pop3_get_uid(struct client *client, struct mail *mail, string_t *str,
bool *permanent_uidl_r)
{
char uid_str[MAX_INT_STRLEN] = { 0 };
const char *uidl;
const char *hdr_md5 = NULL, *filename = NULL, *guid = NULL;
if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &uidl) == 0 &&
*uidl != '\0') {
str_append(str, uidl);
/* UIDL is already permanent */
*permanent_uidl_r = TRUE;
return 0;
}
*permanent_uidl_r = FALSE;
if (client->set->pop3_reuse_xuidl &&
mail_get_first_header(mail, "X-UIDL", &uidl) > 0) {
str_append(str, uidl);
return 0;
}
if ((client->uidl_keymask & UIDL_UID) != 0) {
if (i_snprintf(uid_str, sizeof(uid_str), "%u", mail->uid) < 0)
i_unreached();
}
if ((client->uidl_keymask & UIDL_MD5) != 0) {
if (mail_get_special(mail, MAIL_FETCH_HEADER_MD5,
&hdr_md5) < 0) {
i_error("UIDL: Header MD5 lookup failed: %s",
mailbox_get_last_internal_error(mail->box, NULL));
return -1;
} else if (hdr_md5[0] == '\0') {
i_error("UIDL: Header MD5 not found "
"(pop3_uidl_format=%%m not supported by storage?)");
return -1;
}
}
if ((client->uidl_keymask & UIDL_FILE_NAME) != 0) {
if (mail_get_special(mail, MAIL_FETCH_STORAGE_ID,
&filename) < 0) {
i_error("UIDL: File name lookup failed: %s",
mailbox_get_last_internal_error(mail->box, NULL));
return -1;
} else if (filename[0] == '\0') {
i_error("UIDL: File name not found "
"(pop3_uidl_format=%%f not supported by storage?)");
return -1;
}
}
if ((client->uidl_keymask & UIDL_GUID) != 0) {
if (mail_get_special(mail, MAIL_FETCH_GUID,
&guid) < 0) {
i_error("UIDL: Message GUID lookup failed: %s",
mailbox_get_last_internal_error(mail->box, NULL));
return -1;
} else if (guid[0] == '\0') {
i_error("UIDL: Message GUID not found "
"(pop3_uidl_format=%%g not supported by storage?)");
return -1;
}
}
const struct var_expand_table tab[] = {
{ 'v', dec2str(client->uid_validity), "uidvalidity" },
{ 'u', uid_str, "uid" },
{ 'm', hdr_md5, "md5" },
{ 'f', filename, "filename" },
{ 'g', guid, "guid" },
{ '\0', NULL, NULL }
};
const char *error;
if (var_expand(str, client->mail_set->pop3_uidl_format,
tab, &error) <= 0) {
i_error("UIDL: Failed to expand pop3_uidl_format=%s: %s",
client->mail_set->pop3_uidl_format, error);
return -1;
}
return 0;
}
static bool
list_uidls_saved_iter(struct client *client, struct cmd_uidl_context *ctx)
{
bool found = FALSE;
while (ctx->msgnum < client->messages_count) {
uint32_t msgnum = ctx->msgnum++;
if (client->deleted) {
if ((client->deleted_bitmask[msgnum / CHAR_BIT] &
(1 << (msgnum % CHAR_BIT))) != 0)
continue;
}
found = TRUE;
client_send_line(client,
ctx->list_all ? "%u %s" : "+OK %u %s",
msgnum+1, client->message_uidls[msgnum]);
if (client->output->closed || !ctx->list_all)
break;
if (POP3_CLIENT_OUTPUT_FULL(client)) {
/* output is being buffered, continue when there's
more space */
return FALSE;
}
}
/* finished */
client->cmd = NULL;
if (ctx->list_all)
client_send_line(client, ".");
i_free(ctx);
return found;
}
static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
{
string_t *str;
bool permanent_uidl, found = FALSE;
bool failed = FALSE;
if (client->message_uidls != NULL)
return list_uidls_saved_iter(client, ctx);
str = t_str_new(128);
while (mailbox_search_next(ctx->search_ctx, &ctx->mail)) {
uint32_t msgnum = ctx->msgnum++;
if (client_verify_ordering(client, ctx->mail, msgnum) < 0) {
failed = TRUE;
break;
}
if (client->deleted) {
if ((client->deleted_bitmask[msgnum / CHAR_BIT] &
(1 << (msgnum % CHAR_BIT))) != 0)
continue;
}
found = TRUE;
str_truncate(str, 0);
if (pop3_get_uid(client, ctx->mail, str, &permanent_uidl) < 0) {
failed = TRUE;
break;
}
if (client->set->pop3_save_uidl && !permanent_uidl)
mail_update_pop3_uidl(ctx->mail, str_c(str));
client_send_line(client, ctx->list_all ? "%u %s" : "+OK %u %s",
msgnum+1, str_c(str));
if (client->output->closed)
break;
if (POP3_CLIENT_OUTPUT_FULL(client) && ctx->list_all) {
/* output is being buffered, continue when there's
more space */
return FALSE;
}
}
/* finished */
(void)mailbox_search_deinit(&ctx->search_ctx);
client->cmd = NULL;
if (ctx->list_all && !failed)
client_send_line(client, ".");
i_free(ctx);
if (failed)
client_disconnect(client, "POP3 UIDLs couldn't be listed");
return found || failed;
}
static void cmd_uidl_callback(struct client *client)
{
struct cmd_uidl_context *ctx = client->cmd_context;
(void)list_uids_iter(client, ctx);
}
HASH_TABLE_DEFINE_TYPE(uidl_counter, char *, void *);
static void
uidl_rename_duplicate(string_t *uidl, HASH_TABLE_TYPE(uidl_counter) prev_uidls)
{
char *key;
void *value;
unsigned int counter;
while (hash_table_lookup_full(prev_uidls, str_c(uidl), &key, &value)) {
/* duplicate. the value contains the number of duplicates. */
counter = POINTER_CAST_TO(value, unsigned int) + 1;
hash_table_update(prev_uidls, key, POINTER_CAST(counter));
str_printfa(uidl, "-%u", counter);
/* the second lookup really should return NULL, but just in
case of some weird UIDLs do this as many times as needed */
}
}
static void client_uidls_save(struct client *client)
{
struct mail_search_context *search_ctx;
struct mail_search_args *search_args;
struct mail *mail;
HASH_TABLE_TYPE(uidl_counter) prev_uidls;
const char **seq_uidls;
string_t *str;
char *uidl;
enum mail_fetch_field wanted_fields;
uint32_t msgnum;
bool permanent_uidl, uidl_duplicates_rename, failed = FALSE;
i_assert(client->message_uidls == NULL);
search_args = pop3_search_build(client, 0);
wanted_fields = 0;
if ((client->uidl_keymask & UIDL_MD5) != 0)
wanted_fields |= MAIL_FETCH_HEADER_MD5;
search_ctx = mailbox_search_init(client->trans, search_args,
NULL, wanted_fields, NULL);
mail_search_args_unref(&search_args);
uidl_duplicates_rename =
strcmp(client->set->pop3_uidl_duplicates, "rename") == 0;
if (uidl_duplicates_rename)
hash_table_create(&prev_uidls, default_pool, 0, str_hash,
strcmp);
client->uidl_pool = pool_alloconly_create("message uidls", 1024);
/* first read all the UIDLs into a temporary [seq] array */
seq_uidls = i_new(const char *, client->highest_seq);
str = t_str_new(128);
while (mailbox_search_next(search_ctx, &mail)) {
str_truncate(str, 0);
if (pop3_get_uid(client, mail, str, &permanent_uidl) < 0) {
failed = TRUE;
break;
}
if (uidl_duplicates_rename)
uidl_rename_duplicate(str, prev_uidls);
uidl = p_strdup(client->uidl_pool, str_c(str));
if (client->set->pop3_save_uidl && !permanent_uidl)
mail_update_pop3_uidl(mail, uidl);
i_assert(mail->seq <= client->highest_seq);
seq_uidls[mail->seq-1] = uidl;
if (uidl_duplicates_rename)
hash_table_update(prev_uidls, uidl, POINTER_CAST(1));
}
(void)mailbox_search_deinit(&search_ctx);
if (uidl_duplicates_rename)
hash_table_destroy(&prev_uidls);
if (failed) {
pool_unref(&client->uidl_pool);
i_free(seq_uidls);
return;
}
/* map UIDLs to msgnums (in case POP3 sort ordering is different) */
client->message_uidls = p_new(client->uidl_pool, const char *,
MALLOC_ADD(client->messages_count, 1));
for (msgnum = 0; msgnum < client->messages_count; msgnum++) {
client->message_uidls[msgnum] =
seq_uidls[msgnum_to_seq(client, msgnum) - 1];
}
i_free(seq_uidls);
}
static struct cmd_uidl_context *
cmd_uidl_init(struct client *client, uint32_t seq)
{
struct cmd_uidl_context *ctx;
struct mail_search_args *search_args;
enum mail_fetch_field wanted_fields;
if (client->message_uidls_save && client->message_uidls == NULL &&
client->messages_count > 0)
client_uidls_save(client);
ctx = i_new(struct cmd_uidl_context, 1);
ctx->list_all = seq == 0;
if (client->message_uidls == NULL) {
wanted_fields = 0;
if ((client->uidl_keymask & UIDL_MD5) != 0)
wanted_fields |= MAIL_FETCH_HEADER_MD5;
search_args = pop3_search_build(client, seq);
ctx->search_ctx = mailbox_search_init(client->trans, search_args,
pop3_sort_program,
wanted_fields, NULL);
mail_search_args_unref(&search_args);
}
if (seq == 0) {
client->cmd = cmd_uidl_callback;
client->cmd_context = ctx;
}
return ctx;
}
static int cmd_uidl(struct client *client, const char *args)
{
struct cmd_uidl_context *ctx;
uint32_t seq;
if (*args == '\0') {
client_send_line(client, "+OK");
ctx = cmd_uidl_init(client, 0);
(void)list_uids_iter(client, ctx);
} else {
unsigned int msgnum;
if (get_msgnum(client, args, &msgnum, FALSE) == NULL)
return -1;
seq = msgnum_to_seq(client, msgnum);
ctx = cmd_uidl_init(client, seq);
ctx->msgnum = msgnum;
if (!list_uids_iter(client, ctx))
return client_reply_msg_expunged(client, msgnum);
}
return 1;
}
static const struct pop3_command pop3_commands[] = {
{ "capa", cmd_capa },
{ "dele", cmd_dele },
{ "list", cmd_list },
{ "last", cmd_last },
{ "noop", cmd_noop },
{ "quit", cmd_quit },
{ "retr", cmd_retr },
{ "rset", cmd_rset },
{ "stat", cmd_stat },
{ "top", cmd_top },
{ "uidl", cmd_uidl },
};
const struct pop3_command *pop3_command_find(const char *name)
{
for (unsigned int i = 0; i < N_ELEMENTS(pop3_commands); i++) {
if (strcasecmp(pop3_commands[i].name, name) == 0)
return &pop3_commands[i];
}
return NULL;
}
int client_command_execute(struct client *client,
const struct pop3_command *cmd, const char *args)
{
while (*args == ' ') args++;
return cmd->func(client, args);
}
dovecot-2.3.21.1/src/pop3/pop3-client.h 0000644 0000000 0000000 00000007537 14656633576 014307 0000000 0000000 #ifndef POP3_CLIENT_H
#define POP3_CLIENT_H
#include "seq-range-array.h"
struct client;
struct mail_storage;
struct mail_storage_service_ctx;
typedef void command_func_t(struct client *client);
#define MSGS_BITMASK_SIZE(client) \
(MALLOC_ADD((client)->messages_count, (CHAR_BIT-1)) / CHAR_BIT)
/* Stop reading input when output buffer has this many bytes. Once the buffer
size has dropped to half of it, start reading input again. */
#define POP3_OUTBUF_THROTTLE_SIZE 4096
#define POP3_CLIENT_OUTPUT_FULL(client) \
(o_stream_get_buffer_used_size((client)->output) >= POP3_OUTBUF_THROTTLE_SIZE)
struct pop3_client_vfuncs {
void (*destroy)(struct client *client, const char *reason);
};
/*
pop3_msn = 1..n in the POP3 protocol
msgnum = 0..n-1 = pop3_msn-1
seq = 1..n = mail's sequence number in lib-storage. when pop3 sort ordering
is used, msgnum_to_seq_map[] can be used for translation.
*/
struct client {
struct client *prev, *next;
struct pop3_client_vfuncs v;
int fd_in, fd_out;
struct io *io;
struct istream *input;
struct ostream *output;
struct timeout *to_idle, *to_commit;
command_func_t *cmd;
void *cmd_context;
pool_t pool;
struct mail_storage_service_user *service_user;
struct mail_user *user;
struct mail_namespace *inbox_ns;
struct mailbox *mailbox;
struct mailbox_transaction_context *trans;
struct mail_keywords *deleted_kw;
struct timeout *to_session_dotlock_refresh;
struct dotlock *session_dotlock;
time_t last_input, last_output;
unsigned int bad_counter;
unsigned int highest_expunged_fetch_msgnum;
unsigned int uid_validity;
unsigned int messages_count;
unsigned int deleted_count, seen_change_count;
uoff_t total_size;
uoff_t deleted_size;
uint32_t last_seen_pop3_msn, lowest_retr_pop3_msn;
/* All sequences currently visible in the mailbox. */
ARRAY_TYPE(seq_range) all_seqs;
uint32_t highest_seq;
/* [msgnum] contains mail seq. anything after it has seq = msgnum+1 */
uint32_t *msgnum_to_seq_map;
uint32_t msgnum_to_seq_map_count;
uoff_t top_bytes;
uoff_t retr_bytes;
unsigned int top_count;
unsigned int retr_count;
/* [msgnum] */
const char **message_uidls;
uoff_t *message_sizes;
/* [msgnum/8] & msgnum%8 */
unsigned char *deleted_bitmask;
unsigned char *seen_bitmask;
/* settings: */
const struct pop3_settings *set;
const struct mail_storage_settings *mail_set;
pool_t uidl_pool;
enum uidl_keys uidl_keymask;
/* Module-specific contexts. */
ARRAY(union pop3_module_context *) module_contexts;
bool destroyed:1;
bool disconnected:1;
bool deleted:1;
bool waiting_input:1;
bool anvil_sent:1;
bool message_uidls_save:1;
bool delete_success:1;
bool quit_seen:1;
};
struct pop3_module_register {
unsigned int id;
};
union pop3_module_context {
struct pop3_client_vfuncs super;
struct pop3_module_register *reg;
};
extern struct pop3_module_register pop3_module_register;
extern struct client *pop3_clients;
extern unsigned int pop3_client_count;
/* Create new client with specified input/output handles. socket specifies
if the handle is a socket. */
struct client *client_create(int fd_in, int fd_out,
struct mail_user *user,
struct mail_storage_service_user *service_user,
const struct pop3_settings *set);
void client_create_finish(struct client *client);
int client_init_mailbox(struct client *client, const char **error_r);
void client_destroy(struct client *client, const char *reason) ATTR_NULL(2);
/* Disconnect client connection */
void client_disconnect(struct client *client, const char *reason);
/* Send a line of data to client */
void client_send_line(struct client *client, const char *fmt, ...)
ATTR_FORMAT(2, 3);
void client_send_storage_error(struct client *client);
bool client_handle_input(struct client *client);
bool client_update_mails(struct client *client);
void clients_destroy_all(void);
int pop3_lock_session(struct client *client);
#endif
dovecot-2.3.21.1/src/pop3/Makefile.in 0000644 0000000 0000000 00000070561 14656633613 014033 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
pkglibexec_PROGRAMS = pop3$(EXEEXT)
subdir = src/pop3
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(pkginc_lib_HEADERS) \
$(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(pkglibexecdir)" \
"$(DESTDIR)$(pkginc_libdir)"
PROGRAMS = $(pkglibexec_PROGRAMS)
am_pop3_OBJECTS = main.$(OBJEXT) pop3-client.$(OBJEXT) \
pop3-commands.$(OBJEXT) pop3-settings.$(OBJEXT)
pop3_OBJECTS = $(am_pop3_OBJECTS)
am__DEPENDENCIES_1 =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
pop3_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(pop3_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/main.Po ./$(DEPDIR)/pop3-client.Po \
./$(DEPDIR)/pop3-commands.Po ./$(DEPDIR)/pop3-settings.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(pop3_SOURCES)
DIST_SOURCES = $(pop3_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
HEADERS = $(pkginc_lib_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkglibexecdir = $(libexecdir)/dovecot
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage \
$(BINARY_CFLAGS)
pop3_LDFLAGS = -export-dynamic \
$(BINARY_LDFLAGS)
pop3_LDADD = \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT)
pop3_DEPENDENCIES = \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
pop3_SOURCES = \
main.c \
pop3-client.c \
pop3-commands.c \
pop3-settings.c
headers = \
pop3-capability.h \
pop3-client.h \
pop3-commands.h \
pop3-common.h \
pop3-settings.h
pkginc_libdir = $(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/pop3/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/pop3/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
} \
; done
uninstall-pkglibexecPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
clean-pkglibexecPROGRAMS:
@list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
pop3$(EXEEXT): $(pop3_OBJECTS) $(pop3_DEPENDENCIES) $(EXTRA_pop3_DEPENDENCIES)
@rm -f pop3$(EXEEXT)
$(AM_V_CCLD)$(pop3_LINK) $(pop3_OBJECTS) $(pop3_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pop3-client.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pop3-commands.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pop3-settings.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
done
uninstall-pkginc_libHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(pkginc_libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/pop3-client.Po
-rm -f ./$(DEPDIR)/pop3-commands.Po
-rm -f ./$(DEPDIR)/pop3-settings.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkginc_libHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-pkglibexecPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/main.Po
-rm -f ./$(DEPDIR)/pop3-client.Po
-rm -f ./$(DEPDIR)/pop3-commands.Po
-rm -f ./$(DEPDIR)/pop3-settings.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libtool clean-pkglibexecPROGRAMS \
cscopelist-am ctags ctags-am distclean distclean-compile \
distclean-generic distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-pkginc_libHEADERS \
install-pkglibexecPROGRAMS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/pop3/pop3-capability.h 0000644 0000000 0000000 00000000322 14656633576 015133 0000000 0000000 #ifndef POP3_CAPABILITY_H
#define POP3_CAPABILITY_H
#define POP3_CAPABILITY_REPLY \
"CAPA\r\n" \
"TOP\r\n" \
"UIDL\r\n" \
"RESP-CODES\r\n" \
"PIPELINING\r\n" \
"AUTH-RESP-CODE\r\n"
/* + SASL */
#endif
dovecot-2.3.21.1/src/pop3/pop3-settings.h 0000644 0000000 0000000 00000001574 14656633576 014664 0000000 0000000 #ifndef POP3_SETTINGS_H
#define POP3_SETTINGS_H
struct mail_user_settings;
/* */
enum pop3_client_workarounds {
WORKAROUND_OUTLOOK_NO_NULS = 0x01,
WORKAROUND_OE_NS_EOH = 0x02
};
enum pop3_delete_type {
POP3_DELETE_TYPE_EXPUNGE = 0,
POP3_DELETE_TYPE_FLAG,
};
/* */
struct pop3_settings {
bool verbose_proctitle;
const char *rawlog_dir;
/* pop3: */
bool pop3_no_flag_updates;
bool pop3_enable_last;
bool pop3_reuse_xuidl;
bool pop3_save_uidl;
bool pop3_lock_session;
bool pop3_fast_size_lookups;
const char *pop3_client_workarounds;
const char *pop3_logout_format;
const char *pop3_uidl_duplicates;
const char *pop3_deleted_flag;
const char *pop3_delete_type;
enum pop3_client_workarounds parsed_workarounds;
enum pop3_delete_type parsed_delete_type;
};
extern const struct setting_parser_info pop3_setting_parser_info;
#endif
dovecot-2.3.21.1/src/pop3/pop3-settings.c 0000644 0000000 0000000 00000011600 14656633576 014646 0000000 0000000 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "settings-parser.h"
#include "service-settings.h"
#include "mail-storage-settings.h"
#include "pop3-settings.h"
#include
#include
static bool pop3_settings_verify(void *_set, pool_t pool,
const char **error_r);
/* */
static struct file_listener_settings pop3_unix_listeners_array[] = {
{ "login/pop3", 0666, "", "" }
};
static struct file_listener_settings *pop3_unix_listeners[] = {
&pop3_unix_listeners_array[0]
};
static buffer_t pop3_unix_listeners_buf = {
{ { pop3_unix_listeners, sizeof(pop3_unix_listeners) } }
};
/* */
struct service_settings pop3_service_settings = {
.name = "pop3",
.protocol = "pop3",
.type = "",
.executable = "pop3",
.user = "",
.group = "",
.privileged_group = "",
.extra_groups = "$default_internal_group",
.chroot = "",
.drop_priv_before_exec = FALSE,
.process_min_avail = 0,
.process_limit = 1024,
.client_limit = 1,
.service_count = 1,
.idle_kill = 0,
.vsz_limit = UOFF_T_MAX,
.unix_listeners = { { &pop3_unix_listeners_buf,
sizeof(pop3_unix_listeners[0]) } },
.fifo_listeners = ARRAY_INIT,
.inet_listeners = ARRAY_INIT
};
#undef DEF
#undef DEFLIST
#define DEF(type, name) \
SETTING_DEFINE_STRUCT_##type(#name, name, struct pop3_settings)
#define DEFLIST(field, name, defines) \
{ .type = SET_DEFLIST, .key = name, \
.offset = offsetof(struct pop3_settings, field), \
.list_info = defines }
static const struct setting_define pop3_setting_defines[] = {
DEF(BOOL, verbose_proctitle),
DEF(STR_VARS, rawlog_dir),
DEF(BOOL, pop3_no_flag_updates),
DEF(BOOL, pop3_enable_last),
DEF(BOOL, pop3_reuse_xuidl),
DEF(BOOL, pop3_save_uidl),
DEF(BOOL, pop3_lock_session),
DEF(BOOL, pop3_fast_size_lookups),
DEF(STR, pop3_client_workarounds),
DEF(STR, pop3_logout_format),
DEF(ENUM, pop3_uidl_duplicates),
DEF(STR, pop3_deleted_flag),
DEF(ENUM, pop3_delete_type),
SETTING_DEFINE_LIST_END
};
static const struct pop3_settings pop3_default_settings = {
.verbose_proctitle = FALSE,
.rawlog_dir = "",
.pop3_no_flag_updates = FALSE,
.pop3_enable_last = FALSE,
.pop3_reuse_xuidl = FALSE,
.pop3_save_uidl = FALSE,
.pop3_lock_session = FALSE,
.pop3_fast_size_lookups = FALSE,
.pop3_client_workarounds = "",
.pop3_logout_format = "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s",
.pop3_uidl_duplicates = "allow:rename",
.pop3_deleted_flag = "",
.pop3_delete_type = "default:expunge:flag"
};
static const struct setting_parser_info *pop3_setting_dependencies[] = {
&mail_user_setting_parser_info,
NULL
};
const struct setting_parser_info pop3_setting_parser_info = {
.module_name = "pop3",
.defines = pop3_setting_defines,
.defaults = &pop3_default_settings,
.type_offset = SIZE_MAX,
.struct_size = sizeof(struct pop3_settings),
.parent_offset = SIZE_MAX,
.check_func = pop3_settings_verify,
.dependencies = pop3_setting_dependencies
};
/* */
struct pop3_client_workaround_list {
const char *name;
enum pop3_client_workarounds num;
};
static const struct pop3_client_workaround_list pop3_client_workaround_list[] = {
{ "outlook-no-nuls", WORKAROUND_OUTLOOK_NO_NULS },
{ "oe-ns-eoh", WORKAROUND_OE_NS_EOH },
{ NULL, 0 }
};
static int
pop3_settings_parse_workarounds(struct pop3_settings *set,
const char **error_r)
{
enum pop3_client_workarounds client_workarounds = 0;
const struct pop3_client_workaround_list *list;
const char *const *str;
str = t_strsplit_spaces(set->pop3_client_workarounds, " ,");
for (; *str != NULL; str++) {
list = pop3_client_workaround_list;
for (; list->name != NULL; list++) {
if (strcasecmp(*str, list->name) == 0) {
client_workarounds |= list->num;
break;
}
}
if (list->name == NULL) {
*error_r = t_strdup_printf("pop3_client_workarounds: "
"Unknown workaround: %s", *str);
return -1;
}
}
set->parsed_workarounds = client_workarounds;
return 0;
}
static bool
pop3_settings_verify(void *_set, pool_t pool ATTR_UNUSED, const char **error_r)
{
struct pop3_settings *set = _set;
if (pop3_settings_parse_workarounds(set, error_r) < 0)
return FALSE;
if (strcmp(set->pop3_delete_type, "default") == 0) {
if (set->pop3_deleted_flag[0] == '\0')
set->parsed_delete_type = POP3_DELETE_TYPE_EXPUNGE;
else
set->parsed_delete_type = POP3_DELETE_TYPE_FLAG;
} else if (strcmp(set->pop3_delete_type, "expunge") == 0) {
set->parsed_delete_type = POP3_DELETE_TYPE_EXPUNGE;
} else if (strcmp(set->pop3_delete_type, "flag") == 0) {
if (set->pop3_deleted_flag[0] == '\0') {
*error_r = "pop3_delete_type=flag, but pop3_deleted_flag not set";
return FALSE;
}
set->parsed_delete_type = POP3_DELETE_TYPE_FLAG;
} else {
*error_r = t_strdup_printf("pop3_delete_type: Unknown value '%s'",
set->pop3_delete_type);
return FALSE;
}
return TRUE;
}
/* */
dovecot-2.3.21.1/src/pop3/main.c 0000644 0000000 0000000 00000030011 14656633576 013050 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "pop3-common.h"
#include "ioloop.h"
#include "buffer.h"
#include "istream.h"
#include "istream-concat.h"
#include "ostream.h"
#include "path-util.h"
#include "base64.h"
#include "str.h"
#include "process-title.h"
#include "restrict-access.h"
#include "settings-parser.h"
#include "master-service.h"
#include "master-login.h"
#include "master-interface.h"
#include "var-expand.h"
#include "mail-error.h"
#include "mail-user.h"
#include "mail-namespace.h"
#include "mail-storage-service.h"
#include
#include
#define IS_STANDALONE() \
(getenv(MASTER_IS_PARENT_ENV) == NULL)
static bool verbose_proctitle = FALSE;
static struct mail_storage_service_ctx *storage_service;
static struct master_login *master_login = NULL;
pop3_client_created_func_t *hook_client_created = NULL;
pop3_client_created_func_t *
pop3_client_created_hook_set(pop3_client_created_func_t *new_hook)
{
pop3_client_created_func_t *old_hook = hook_client_created;
hook_client_created = new_hook;
return old_hook;
}
void pop3_refresh_proctitle(void)
{
struct client *client;
string_t *title = t_str_new(128);
if (!verbose_proctitle)
return;
str_append_c(title, '[');
switch (pop3_client_count) {
case 0:
str_append(title, "idling");
break;
case 1:
client = pop3_clients;
str_append(title, client->user->username);
if (client->user->conn.remote_ip != NULL) {
str_append_c(title, ' ');
str_append(title,
net_ip2addr(client->user->conn.remote_ip));
}
if (client->destroyed)
str_append(title, " (deinit)");
break;
default:
str_printfa(title, "%u connections", pop3_client_count);
break;
}
str_append_c(title, ']');
process_title_set(str_c(title));
}
static void pop3_die(void)
{
/* do nothing. pop3 connections typically die pretty quick anyway. */
}
static void client_add_input(struct client *client, const buffer_t *buf)
{
struct ostream *output;
if (buf != NULL && buf->used > 0) {
struct istream *inputs[] = {
i_stream_create_copy_from_data(buf->data, buf->used),
client->input,
NULL
};
client->input = i_stream_create_concat(inputs);
i_stream_copy_fd(client->input, inputs[1]);
i_stream_unref(&inputs[0]);
i_stream_unref(&inputs[1]);
i_stream_set_input_pending(client->input, TRUE);
}
output = client->output;
o_stream_ref(output);
o_stream_cork(output);
(void)client_handle_input(client);
o_stream_uncork(output);
o_stream_unref(&output);
}
static int
client_create_from_input(const struct mail_storage_service_input *input,
int fd_in, int fd_out, struct client **client_r,
const char **error_r)
{
const char *lookup_error_str =
"-ERR [SYS/TEMP] "MAIL_ERRSTR_CRITICAL_MSG"\r\n";
struct mail_storage_service_user *user;
struct mail_user *mail_user;
struct pop3_settings *set;
const char *errstr;
if (mail_storage_service_lookup_next(storage_service, input,
&user, &mail_user, error_r) <= 0) {
if (write(fd_out, lookup_error_str, strlen(lookup_error_str)) < 0) {
/* ignored */
}
return -1;
}
restrict_access_allow_coredumps(TRUE);
set = mail_storage_service_user_get_set(user)[1];
if (set->verbose_proctitle)
verbose_proctitle = TRUE;
if (settings_var_expand(&pop3_setting_parser_info, set,
mail_user->pool, mail_user_var_expand_table(mail_user),
&errstr) <= 0) {
*error_r = t_strdup_printf("Failed to expand settings: %s", errstr);
mail_user_deinit(&mail_user);
mail_storage_service_user_unref(&user);
return -1;
}
*client_r = client_create(fd_in, fd_out, mail_user, user, set);
return 0;
}
static int lock_session(struct client *client)
{
int ret;
i_assert(client->user->namespaces != NULL);
i_assert(client->set->pop3_lock_session);
if ((ret = pop3_lock_session(client)) <= 0) {
client_send_line(client, ret < 0 ?
"-ERR [SYS/TEMP] Failed to create POP3 session lock." :
"-ERR [IN-USE] Mailbox is locked by another POP3 session.");
client_destroy(client, "Couldn't lock POP3 session");
return -1;
}
return 0;
}
#define MSG_BYE_INTERNAL_ERROR "-ERR "MAIL_ERRSTR_CRITICAL_MSG
static int init_namespaces(struct client *client, bool already_logged_in)
{
const char *error;
/* finish initializing the user (see comment in main()) */
if (mail_namespaces_init(client->user, &error) < 0) {
if (!already_logged_in)
client_send_line(client, MSG_BYE_INTERNAL_ERROR);
i_error("%s", error);
client_destroy(client, error);
return -1;
}
i_assert(client->inbox_ns == NULL);
client->inbox_ns = mail_namespace_find_inbox(client->user->namespaces);
i_assert(client->inbox_ns != NULL);
return 0;
}
static void client_init_session(struct client *client)
{
const char *error;
/*
* RFC 1939 requires that the session lock gets acquired before the
* positive response is sent to the client indicating a transition
* to the TRANSACTION state.
*
* Since the session lock is stored under the INBOX's storage
* directory, the locking code requires that the namespaces are
* initialized first.
*
* If the system administrator configured dovecot to not use session
* locks, we can send back the positive response before the
* potentially long-running namespace initialization occurs. This
* avoids the client possibly timing out during authentication due
* to storage initialization taking too long.
*/
if (client->set->pop3_lock_session) {
if (init_namespaces(client, FALSE) < 0)
return; /* no need to propagate an error */
if (lock_session(client) < 0)
return; /* no need to propagate an error */
if (!IS_STANDALONE())
client_send_line(client, "+OK Logged in.");
} else {
if (!IS_STANDALONE())
client_send_line(client, "+OK Logged in.");
if (init_namespaces(client, TRUE) < 0)
return; /* no need to propagate an error */
}
struct event_reason *reason = event_reason_begin("pop3:initialize");
int ret = client_init_mailbox(client, &error);
event_reason_end(&reason);
if (ret < 0) {
i_error("%s", error);
client_destroy(client, error);
}
}
static void main_stdio_run(const char *username)
{
struct client *client;
struct mail_storage_service_input input;
buffer_t *input_buf;
const char *value, *error, *input_base64;
i_zero(&input);
input.module = input.service = "pop3";
input.username = username != NULL ? username : getenv("USER");
if (input.username == NULL && IS_STANDALONE())
input.username = getlogin();
if (input.username == NULL)
i_fatal("USER environment missing");
if ((value = getenv("IP")) != NULL)
(void)net_addr2ip(value, &input.remote_ip);
if ((value = getenv("LOCAL_IP")) != NULL)
(void)net_addr2ip(value, &input.local_ip);
input_base64 = getenv("CLIENT_INPUT");
input_buf = input_base64 == NULL ? NULL :
t_base64_decode_str(input_base64);
if (client_create_from_input(&input, STDIN_FILENO, STDOUT_FILENO,
&client, &error) < 0)
i_fatal("%s", error);
client_add_input(client, input_buf);
client_create_finish(client);
client_init_session(client);
/* client may be destroyed now */
}
static void
login_client_connected(const struct master_login_client *login_client,
const char *username, const char *const *extra_fields)
{
struct client *client;
struct mail_storage_service_input input;
enum mail_auth_request_flags flags = login_client->auth_req.flags;
const char *error;
buffer_t input_buf;
i_zero(&input);
input.module = input.service = "pop3";
input.local_ip = login_client->auth_req.local_ip;
input.remote_ip = login_client->auth_req.remote_ip;
input.local_port = login_client->auth_req.local_port;
input.remote_port = login_client->auth_req.remote_port;
input.username = username;
input.userdb_fields = extra_fields;
input.session_id = login_client->session_id;
if ((flags & MAIL_AUTH_REQUEST_FLAG_CONN_SECURED) != 0)
input.conn_secured = TRUE;
if ((flags & MAIL_AUTH_REQUEST_FLAG_CONN_SSL_SECURED) != 0)
input.conn_ssl_secured = TRUE;
buffer_create_from_const_data(&input_buf, login_client->data,
login_client->auth_req.data_size);
if (client_create_from_input(&input, login_client->fd, login_client->fd,
&client, &error) < 0) {
int fd = login_client->fd;
i_error("%s", error);
i_close_fd(&fd);
master_service_client_connection_destroyed(master_service);
return;
}
client_add_input(client, &input_buf);
client_create_finish(client);
client_init_session(client);
/* client may be destroyed now */
}
static void login_client_failed(const struct master_login_client *client,
const char *errormsg)
{
const char *msg;
msg = t_strdup_printf("-ERR [SYS/TEMP] %s\r\n", errormsg);
if (write(client->fd, msg, strlen(msg)) < 0) {
/* ignored */
}
}
static void client_connected(struct master_service_connection *conn)
{
/* when running standalone, we shouldn't even get here */
i_assert(master_login != NULL);
master_service_client_connection_accept(conn);
master_login_add(master_login, conn->fd);
}
int main(int argc, char *argv[])
{
static const struct setting_parser_info *set_roots[] = {
&pop3_setting_parser_info,
NULL
};
struct master_login_settings login_set;
enum master_service_flags service_flags = 0;
enum mail_storage_service_flags storage_service_flags =
MAIL_STORAGE_SERVICE_FLAG_NO_SSL_CA;
const char *username = NULL, *auth_socket_path = "auth-master";
int c;
i_zero(&login_set);
login_set.postlogin_timeout_secs = MASTER_POSTLOGIN_TIMEOUT_DEFAULT;
if (IS_STANDALONE() && getuid() == 0 &&
net_getpeername(1, NULL, NULL) == 0) {
printf("-ERR [SYS/PERM] pop3 binary must not be started from "
"inetd, use pop3-login instead.\n");
return 1;
}
if (IS_STANDALONE()) {
service_flags |= MASTER_SERVICE_FLAG_STANDALONE |
MASTER_SERVICE_FLAG_STD_CLIENT;
} else {
service_flags |= MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN;
}
/*
* We include MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES so that the
* mail_user initialization is fast and we can quickly send back the
* OK response to LOGIN/AUTHENTICATE. Otherwise we risk a very slow
* namespace initialization to cause client timeouts on login.
*/
storage_service_flags |= MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES;
master_service = master_service_init("pop3", service_flags,
&argc, &argv, "a:t:u:");
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'a':
auth_socket_path = optarg;
break;
case 't':
if (str_to_uint(optarg, &login_set.postlogin_timeout_secs) < 0 ||
login_set.postlogin_timeout_secs == 0)
i_fatal("Invalid -t parameter: %s", optarg);
break;
case 'u':
storage_service_flags |=
MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
username = optarg;
break;
default:
return FATAL_DEFAULT;
}
}
const char *error;
if (t_abspath(auth_socket_path, &login_set.auth_socket_path, &error) < 0) {
i_fatal("t_abspath(%s) failed: %s", auth_socket_path, error);
}
if (argv[optind] != NULL) {
if (t_abspath(argv[optind], &login_set.postlogin_socket_path, &error) < 0) {
i_fatal("t_abspath(%s) failed: %s", argv[optind], error);
}
}
login_set.callback = login_client_connected;
login_set.failure_callback = login_client_failed;
login_set.update_proctitle =
getenv(MASTER_VERBOSE_PROCTITLE_ENV) != NULL &&
master_service_get_client_limit(master_service) == 1;
if (!IS_STANDALONE())
master_login = master_login_init(master_service, &login_set);
master_service_set_die_callback(master_service, pop3_die);
storage_service =
mail_storage_service_init(master_service,
set_roots, storage_service_flags);
master_service_init_finish(master_service);
/* NOTE: login_set.*_socket_path are now invalid due to data stack
having been freed */
/* fake that we're running, so we know if client was destroyed
while handling its initial input */
io_loop_set_running(current_ioloop);
if (IS_STANDALONE()) {
T_BEGIN {
main_stdio_run(username);
} T_END;
} else {
io_loop_set_running(current_ioloop);
}
if (io_loop_is_running(current_ioloop))
master_service_run(master_service, client_connected);
clients_destroy_all();
if (master_login != NULL)
master_login_deinit(&master_login);
mail_storage_service_deinit(&storage_service);
master_service_deinit(&master_service);
return 0;
}
dovecot-2.3.21.1/src/pop3/Makefile.am 0000644 0000000 0000000 00000001370 14656633576 014022 0000000 0000000 pkglibexecdir = $(libexecdir)/dovecot
pkglibexec_PROGRAMS = pop3
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage \
$(BINARY_CFLAGS)
pop3_LDFLAGS = -export-dynamic \
$(BINARY_LDFLAGS)
pop3_LDADD = \
$(LIBDOVECOT_STORAGE) \
$(LIBDOVECOT)
pop3_DEPENDENCIES = \
$(LIBDOVECOT_STORAGE_DEPS) \
$(LIBDOVECOT_DEPS)
pop3_SOURCES = \
main.c \
pop3-client.c \
pop3-commands.c \
pop3-settings.c
headers = \
pop3-capability.h \
pop3-client.h \
pop3-commands.h \
pop3-common.h \
pop3-settings.h
pkginc_libdir=$(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
dovecot-2.3.21.1/src/pop3/pop3-common.h 0000644 0000000 0000000 00000001162 14656633576 014305 0000000 0000000 #ifndef POP3_COMMON_H
#define POP3_COMMON_H
enum uidl_keys {
UIDL_UIDVALIDITY = 0x01,
UIDL_UID = 0x02,
UIDL_MD5 = 0x04,
UIDL_FILE_NAME = 0x08,
UIDL_GUID = 0x10
};
#include "lib.h"
#include "pop3-client.h"
#include "pop3-settings.h"
typedef void pop3_client_created_func_t(struct client **client);
extern pop3_client_created_func_t *hook_client_created;
/* Sets the hook_client_created and returns the previous hook,
which the new_hook should call if it's non-NULL. */
pop3_client_created_func_t *
pop3_client_created_hook_set(pop3_client_created_func_t *new_hook);
void pop3_refresh_proctitle(void);
#endif
dovecot-2.3.21.1/src/lib/ 0000755 0000000 0000000 00000000000 14656633635 011726 5 0000000 0000000 dovecot-2.3.21.1/src/lib/ostream-rawlog.c 0000644 0000000 0000000 00000004670 14656633576 014770 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "iostream-rawlog-private.h"
#include "ostream-private.h"
#include "ostream-rawlog.h"
struct rawlog_ostream {
struct ostream_private ostream;
struct rawlog_iostream riostream;
};
static void o_stream_rawlog_close(struct iostream_private *stream,
bool close_parent)
{
struct rawlog_ostream *rstream =
container_of(stream, struct rawlog_ostream, ostream.iostream);
iostream_rawlog_close(&rstream->riostream);
if (close_parent)
o_stream_close(rstream->ostream.parent);
}
static ssize_t
o_stream_rawlog_sendv(struct ostream_private *stream,
const struct const_iovec *iov, unsigned int iov_count)
{
struct rawlog_ostream *rstream =
container_of(stream, struct rawlog_ostream, ostream);
unsigned int i;
ssize_t ret, bytes;
if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
o_stream_copy_error_from_parent(stream);
return -1;
}
bytes = ret;
for (i = 0; i < iov_count && bytes > 0; i++) {
if (iov[i].iov_len < (size_t)bytes) {
iostream_rawlog_write(&rstream->riostream,
iov[i].iov_base, iov[i].iov_len);
bytes -= iov[i].iov_len;
} else {
iostream_rawlog_write(&rstream->riostream,
iov[i].iov_base, bytes);
break;
}
}
stream->ostream.offset += ret;
return ret;
}
struct ostream *
o_stream_create_rawlog(struct ostream *output, const char *rawlog_path,
int rawlog_fd, enum iostream_rawlog_flags flags)
{
struct ostream *rawlog_output;
bool autoclose_fd = (flags & IOSTREAM_RAWLOG_FLAG_AUTOCLOSE) != 0;
i_assert(rawlog_path != NULL);
i_assert(rawlog_fd != -1);
rawlog_output = autoclose_fd ?
o_stream_create_fd_autoclose(&rawlog_fd, 0):
o_stream_create_fd(rawlog_fd, 0);
o_stream_set_name(rawlog_output,
t_strdup_printf("rawlog(%s)", rawlog_path));
return o_stream_create_rawlog_from_stream(output, rawlog_output, flags);
}
struct ostream *
o_stream_create_rawlog_from_stream(struct ostream *output,
struct ostream *rawlog_output,
enum iostream_rawlog_flags flags)
{
struct rawlog_ostream *rstream;
rstream = i_new(struct rawlog_ostream, 1);
rstream->ostream.sendv = o_stream_rawlog_sendv;
rstream->ostream.iostream.close = o_stream_rawlog_close;
rstream->riostream.rawlog_output = rawlog_output;
iostream_rawlog_init(&rstream->riostream, flags, FALSE);
return o_stream_create(&rstream->ostream, output,
o_stream_get_fd(output));
}
dovecot-2.3.21.1/src/lib/file-create-locked.h 0000644 0000000 0000000 00000003040 14656633576 015437 0000000 0000000 #ifndef FILE_CREATE_LOCKED_H
#define FILE_CREATE_LOCKED_H
#include "file-lock.h"
struct file_create_settings {
/* 0 = try locking without waiting */
unsigned int lock_timeout_secs;
struct file_lock_settings lock_settings;
/* 0 = 0600 */
int mode;
/* 0 = default */
uid_t uid;
/* 0 = default */
gid_t gid;
const char *gid_origin;
/* If parent directory doesn't exist, mkdir() it with this mode.
0 = don't mkdir(). The parent directories are assumed to be
potentially rmdir() simultaneously, so the mkdir()+locking may be
attempted multiple times. */
int mkdir_mode;
/* 0 = default */
uid_t mkdir_uid;
/* 0 = default */
gid_t mkdir_gid;
const char *mkdir_gid_origin;
};
/* Either open an existing file and lock it, or create the file locked.
The creation is done by creating a temp file and link()ing it to path.
If link() fails, opening is retried again. Returns fd on success,
-1 on error. errno is preserved for the last failed syscall, so most
importantly ENOENT could mean that the directory doesn't exist and EAGAIN
means locking timed out.
If this function is used to create lock files, file_lock_set_unlink_on_free()
should be used for the resulting lock. It attempts to avoid unlinking the
file if there are already other processes using the lock. That can help to
avoid "Creating a locked file ... keeps failing" errors */
int file_create_locked(const char *path, const struct file_create_settings *set,
struct file_lock **lock_r, bool *created_r,
const char **error_r);
#endif
dovecot-2.3.21.1/src/lib/llist.h 0000644 0000000 0000000 00000005331 14656633576 013154 0000000 0000000 #ifndef LLIST_H
#define LLIST_H
/* Doubly linked list */
#define DLLIST_PREPEND_FULL(list, item, prev, next) STMT_START { \
(item)->prev = NULL; \
(item)->next = *(list); \
if (*(list) != NULL) (*(list))->prev = (item); \
*(list) = (item); \
} STMT_END
#define DLLIST_PREPEND(list, item) \
DLLIST_PREPEND_FULL(list, item, prev, next)
#define DLLIST_REMOVE_FULL(list, item, prev, next) STMT_START { \
if ((item)->prev != NULL) \
(item)->prev->next = (item)->next; \
else if ((*list) == item) \
*(list) = (item)->next; \
if ((item)->next != NULL) { \
(item)->next->prev = (item)->prev; \
(item)->next = NULL; \
} \
(item)->prev = NULL; \
} STMT_END
#define DLLIST_REMOVE(list, item) \
DLLIST_REMOVE_FULL(list, item, prev, next)
/* Doubly linked list with head and tail */
#define DLLIST2_PREPEND_FULL(head, tail, item, prev, next) STMT_START { \
(item)->prev = NULL; \
(item)->next = *(head); \
if (*(head) != NULL) (*(head))->prev = (item); else (*tail) = (item); \
*(head) = (item); \
} STMT_END
#define DLLIST2_PREPEND(head, tail, item) \
DLLIST2_PREPEND_FULL(head, tail, item, prev, next)
#define DLLIST2_APPEND_FULL(head, tail, item, prev, next) STMT_START { \
(item)->prev = *(tail); \
(item)->next = NULL; \
if (*(tail) != NULL) (*(tail))->next = (item); else (*head) = (item); \
*(tail) = (item); \
} STMT_END
#define DLLIST2_APPEND(head, tail, item) \
DLLIST2_APPEND_FULL(head, tail, item, prev, next)
#define DLLIST2_INSERT_AFTER_FULL(head, tail, after, item, prev, next) \
STMT_START { \
(item)->prev = (after); \
(item)->next = (after)->next; \
if ((after)->next != NULL) \
(after)->next->prev = (item); \
(after)->next = (item); \
if (*(tail) == (after)) \
*(tail) = (item); \
} STMT_END
#define DLLIST2_INSERT_AFTER(head, tail, after, item) \
DLLIST2_INSERT_AFTER_FULL(head, tail, after, item, prev, next)
#define DLLIST2_REMOVE_FULL(head, tail, item, prev, next) STMT_START { \
if ((item)->prev != NULL) \
(item)->prev->next = (item)->next; \
else if (*(head) == item) \
*(head) = (item)->next; \
if ((item)->next != NULL) { \
(item)->next->prev = (item)->prev; \
(item)->next = NULL; \
} else if ((*tail) == item) \
*(tail) = (item)->prev; \
(item)->prev = NULL; \
} STMT_END
#define DLLIST2_REMOVE(head, tail, item) \
DLLIST2_REMOVE_FULL(head, tail, item, prev, next)
#define DLLIST2_JOIN_FULL(head1, tail1, head2, tail2, prev, next) STMT_START { \
if (*(head1) == NULL) { \
*(head1) = *(head2); \
*(tail1) = *(tail2); \
} else if (*(head2) != NULL) { \
(*(tail1))->next = *(head2); \
(*(head2))->prev = *(tail1); \
(*tail1) = (*tail2); \
} \
} STMT_END
#define DLLIST2_JOIN(head1, tail1, head2, tail2) \
DLLIST2_JOIN_FULL(head1, tail1, head2, tail2, prev, next)
#endif
dovecot-2.3.21.1/src/lib/test-hash.c 0000644 0000000 0000000 00000002214 14656633576 013715 0000000 0000000 /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "hash.h"
static void test_hash_random_pool(pool_t pool)
{
#define KEYMAX 100000
HASH_TABLE(void *, void *) hash;
unsigned int *keys;
unsigned int i, key, keyidx, delidx;
keys = i_new(unsigned int, KEYMAX); keyidx = 0;
hash_table_create_direct(&hash, pool, 0);
for (i = 0; i < KEYMAX; i++) {
key = (i_rand_limit(KEYMAX)) + 1;
if (i_rand_limit(5) > 0) {
if (hash_table_lookup(hash, POINTER_CAST(key)) == NULL) {
hash_table_insert(hash, POINTER_CAST(key),
POINTER_CAST(1));
keys[keyidx++] = key;
}
} else if (keyidx > 0) {
delidx = i_rand_limit(keyidx);
hash_table_remove(hash, POINTER_CAST(keys[delidx]));
memmove(&keys[delidx], &keys[delidx+1],
(keyidx-delidx-1) * sizeof(*keys));
keyidx--;
}
}
for (i = 0; i < keyidx; i++)
hash_table_remove(hash, POINTER_CAST(keys[i]));
hash_table_destroy(&hash);
i_free(keys);
}
void test_hash(void)
{
pool_t pool;
test_hash_random_pool(default_pool);
pool = pool_alloconly_create("test hash", 1024);
test_hash_random_pool(pool);
pool_unref(&pool);
}
dovecot-2.3.21.1/src/lib/test-pkcs5.c 0000644 0000000 0000000 00000003755 14656633576 014032 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "buffer.h"
#include "hash-method.h"
#include "pkcs5.h"
struct test_vector {
const char *prf;
unsigned char *p;
size_t pLen;
unsigned char *s;
size_t sLen;
unsigned int i;
unsigned char *dk;
size_t dkLen;
};
#define TEST_BUF(x) (unsigned char*)x, sizeof(x)-1
/* RFC 6070 test vectors */
static const struct test_vector test_vectors_v2[] = {
{ "sha1", TEST_BUF("password"), TEST_BUF("salt"), 1, TEST_BUF("\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6") },
{ "sha1", TEST_BUF("password"), TEST_BUF("salt"), 2, TEST_BUF("\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57") },
{ "sha1", TEST_BUF("password"), TEST_BUF("salt"), 4096, TEST_BUF("\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1") },
/* enable the next test only when you need it, it takes quite long time */
/* { "sha1", TEST_BUF("password"), TEST_BUF("salt"), 16777216, TEST_BUF("\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84") }, */
{ "sha1", TEST_BUF("passwordPASSWORDpassword"), TEST_BUF("saltSALTsaltSALTsaltSALTsaltSALTsalt"), 4096, TEST_BUF("\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38") },
{ "sha1", TEST_BUF("pass\0word"), TEST_BUF("sa\0lt"), 4096, TEST_BUF("\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34\x25\xe0\xc3") }
};
void test_pkcs5_pbkdf2(void)
{
buffer_t *res = buffer_create_dynamic(default_pool, 25);
test_begin("pkcs5_pbkdf2");
for(size_t i = 0; i < N_ELEMENTS(test_vectors_v2); i++) {
buffer_set_used_size(res, 0);
const struct test_vector *vec = &(test_vectors_v2[i]);
pkcs5_pbkdf(PKCS5_PBKDF2, hash_method_lookup(vec->prf), vec->p, vec->pLen, vec->s, vec->sLen, vec->i, vec->dkLen, res);
test_assert_idx(memcmp(res->data, vec->dk, vec->dkLen) == 0, i);
}
buffer_free(&res);
test_end();
}
dovecot-2.3.21.1/src/lib/fdatasync-path.c 0000644 0000000 0000000 00000001221 14656633576 014720 0000000 0000000 /* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "fdatasync-path.h"
#include
#include
int fdatasync_path(const char *path)
{
int fd, ret = 0;
/* Directories need to be opened as read-only.
fsync() doesn't appear to care about it. */
fd = open(path, O_RDONLY);
if (fd == -1)
return -1;
if (fdatasync(fd) < 0) {
/* Some OSes/FSes don't allow fsyncing directories. Silently
ignore the problem. */
if (errno == EBADF) {
/* e.g. NetBSD */
} else if (errno == EINVAL) {
/* e.g. Linux+CIFS */
} else {
ret = -1;
}
}
i_close_fd(&fd);
return ret;
}
dovecot-2.3.21.1/src/lib/failures.h 0000644 0000000 0000000 00000013177 14656633576 013646 0000000 0000000 #ifndef FAILURES_H
#define FAILURES_H
struct ip_addr;
/* Default exit status codes that we could use. */
enum fatal_exit_status {
FATAL_LOGOPEN = 80, /* Can't open log file */
FATAL_LOGWRITE = 81, /* Can't write to log file */
FATAL_LOGERROR = 82, /* Internal logging error */
FATAL_OUTOFMEM = 83, /* Out of memory */
FATAL_EXEC = 84, /* exec() failed */
FATAL_DEFAULT = 89
};
enum log_type {
LOG_TYPE_DEBUG,
LOG_TYPE_INFO,
LOG_TYPE_WARNING,
LOG_TYPE_ERROR,
LOG_TYPE_FATAL,
LOG_TYPE_PANIC,
LOG_TYPE_COUNT,
/* special case */
LOG_TYPE_OPTION
};
struct failure_line {
pid_t pid;
enum log_type log_type;
/* If non-zero, the first log_prefix_len bytes in text indicate
the log prefix. This implies disable_log_prefix=TRUE. */
unsigned int log_prefix_len;
/* Disable the global log prefix. */
bool disable_log_prefix;
const char *text;
};
struct failure_context {
enum log_type type;
int exit_status; /* for LOG_TYPE_FATAL */
const struct tm *timestamp; /* NULL = use time() + localtime() */
unsigned int timestamp_usecs;
const char *log_prefix; /* override the default log prefix */
/* If non-0, insert the log type text (e.g. "Info: ") at this position
in the log_prefix instead of appending it. */
unsigned int log_prefix_type_pos;
};
#define DEFAULT_FAILURE_STAMP_FORMAT "%b %d %H:%M:%S "
typedef void failure_callback_t(const struct failure_context *ctx,
const char *format, va_list args);
extern const char *failure_log_type_prefixes[];
extern const char *failure_log_type_names[];
void i_log_type(const struct failure_context *ctx, const char *format, ...)
ATTR_FORMAT(2, 3);
void i_log_typev(const struct failure_context *ctx, const char *format,
va_list args) ATTR_FORMAT(2, 0);
void i_panic(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_NORETURN ATTR_COLD;
void i_unreached(const char *source_filename, int source_linenum)
ATTR_NORETURN ATTR_COLD;
#define i_unreached() \
i_unreached(__FILE__, __LINE__)
void i_fatal(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_NORETURN ATTR_COLD;
void i_error(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_COLD;
void i_warning(const char *format, ...) ATTR_FORMAT(1, 2);
void i_info(const char *format, ...) ATTR_FORMAT(1, 2);
void i_debug(const char *format, ...) ATTR_FORMAT(1, 2);
void i_fatal_status(int status, const char *format, ...)
ATTR_FORMAT(2, 3) ATTR_NORETURN ATTR_COLD;
/* Change failure handlers. */
#ifndef __cplusplus
void i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN);
#else
/* Older g++ doesn't like attributes in parameters */
void i_set_fatal_handler(failure_callback_t *callback);
#endif
void i_set_error_handler(failure_callback_t *callback);
void i_set_info_handler(failure_callback_t *callback);
void i_set_debug_handler(failure_callback_t *callback);
void i_get_failure_handlers(failure_callback_t **fatal_callback_r,
failure_callback_t **error_callback_r,
failure_callback_t **info_callback_r,
failure_callback_t **debug_callback_r);
/* Send failures to file. */
void default_fatal_handler(const struct failure_context *ctx,
const char *format, va_list args)
ATTR_NORETURN ATTR_FORMAT(2, 0);
void default_error_handler(const struct failure_context *ctx,
const char *format, va_list args)
ATTR_FORMAT(2, 0);
/* Send failures to syslog() */
void i_syslog_fatal_handler(const struct failure_context *ctx,
const char *format, va_list args)
ATTR_NORETURN ATTR_FORMAT(2, 0);
void i_syslog_error_handler(const struct failure_context *ctx,
const char *format, va_list args)
ATTR_FORMAT(2, 0);
/* Open syslog and set failure/info/debug handlers to use it. */
void i_set_failure_syslog(const char *ident, int options, int facility);
/* Send failures to specified log file instead of stderr. */
void i_set_failure_file(const char *path, const char *prefix);
/* Send errors to stderr using internal error protocol. */
void i_set_failure_internal(void);
/* Returns TRUE if the given callback handler was set via
i_set_failure_internal(). */
bool i_failure_handler_is_internal(failure_callback_t *const callback);
/* If writing to log fails, ignore it instead of existing with
FATAL_LOGWRITE or FATAL_LOGERROR. */
void i_set_failure_ignore_errors(bool ignore);
/* Send informational messages to specified log file. i_set_failure_*()
functions modify the info file too, so call this function after them. */
void i_set_info_file(const char *path);
/* Send debug-level message to the given log file. The i_set_info_file()
function modifies also the debug log file, so call this function after it. */
void i_set_debug_file(const char *path);
/* Set the failure prefix. */
void i_set_failure_prefix(const char *prefix_fmt, ...) ATTR_FORMAT(1, 2);
/* Set prefix to "". */
void i_unset_failure_prefix(void);
/* Returns the current failure prefix (never NULL). */
const char *i_get_failure_prefix(void);
/* Prefix failures with a timestamp. fmt is in strftime() format. */
void i_set_failure_timestamp_format(const char *fmt);
/* When logging with internal error protocol, update the process's current
IP address / log prefix by sending it to log process. This is mainly used to
improve the error message if the process crashes. */
void i_set_failure_send_ip(const struct ip_addr *ip);
void i_set_failure_send_prefix(const char *prefix);
/* Call the callback before exit()ing. The callback may update the status. */
void i_set_failure_exit_callback(void (*callback)(int *status));
/* Call the exit callback and exit() */
void failure_exit(int status) ATTR_NORETURN ATTR_COLD;
/* Parse a line logged using internal failure handler */
void i_failure_parse_line(const char *line, struct failure_line *failure);
void failures_deinit(void);
#endif
dovecot-2.3.21.1/src/lib/home-expand.c 0000644 0000000 0000000 00000002345 14656633576 014227 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ipwd.h"
#include "home-expand.h"
int home_try_expand(const char **_path)
{
const char *path = *_path;
const char *name, *home, *p;
struct passwd pw;
if (path == NULL || *path != '~')
return 0;
path++;
if (*path == '/' || *path == '\0') {
home = getenv("HOME");
if (*path != '\0') path++;
} else {
p = strchr(path, '/');
if (p == NULL) {
name = path;
path = "";
} else {
name = t_strdup_until(path, p);
path = p+1;
}
switch (i_getpwnam(name, &pw)) {
case -1:
i_error("getpwnam(%s) failed: %m", name);
home = NULL;
break;
case 0:
home = NULL;
break;
default:
home = pw.pw_dir;
break;
}
}
if (home == NULL)
return -1;
if (*path == '\0')
*_path = t_strdup(home);
else
*_path = t_strconcat(home, "/", path, NULL);
return 0;
}
const char *home_expand(const char *path)
{
(void)home_try_expand(&path);
return path;
}
const char *home_expand_tilde(const char *path, const char *home)
{
if (path == NULL || *path != '~')
return path;
if (path[1] == '\0')
return home;
if (path[1] != '/')
return path;
/* ~/ used */
return t_strconcat(home, path + 1, NULL);
}
dovecot-2.3.21.1/src/lib/imem.h 0000644 0000000 0000000 00000003001 14656633576 012744 0000000 0000000 #ifndef IMEM_H
#define IMEM_H
/* For easy allocation of memory from default memory pool. */
extern pool_t default_pool;
#define i_new(type, count) p_new(default_pool, type, count)
#define i_realloc_type(mem, type, old_count, new_count) \
p_realloc_type(default_pool, mem, type, old_count, new_count)
void *i_malloc(size_t size) ATTR_MALLOC ATTR_RETURNS_NONNULL;
void *i_realloc(void *mem, size_t old_size, size_t new_size)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
/* i_free() and i_free_and_null() are now guaranteed to both set mem=NULL,
so either one of them can be used. */
#ifndef STATIC_CHECKER
# define i_free(mem) p_free_and_null(default_pool, mem)
#else
# define i_free(mem) \
STMT_START { \
pool_system_free(default_pool, mem); \
(mem) = NULL; \
} STMT_END
#endif
#define i_free_and_null(mem) i_free(mem)
/* string functions */
char *i_strdup(const char *str) ATTR_MALLOC;
void *i_memdup(const void *data, size_t size) ATTR_MALLOC;
/* like i_strdup(), but if str == "", return NULL */
char *i_strdup_empty(const char *str) ATTR_MALLOC;
/* *end isn't included */
char *i_strdup_until(const void *str, const void *end)
ATTR_MALLOC ATTR_RETURNS_NONNULL;
char *i_strndup(const void *str, size_t max_chars) ATTR_MALLOC;
char *i_strdup_printf(const char *format, ...)
ATTR_FORMAT(1, 2) ATTR_MALLOC ATTR_RETURNS_NONNULL;
char *i_strdup_vprintf(const char *format, va_list args)
ATTR_FORMAT(1, 0) ATTR_MALLOC ATTR_RETURNS_NONNULL;
char *i_strconcat(const char *str1, ...) ATTR_SENTINEL ATTR_MALLOC;
#endif
dovecot-2.3.21.1/src/lib/safe-mkdir.h 0000644 0000000 0000000 00000000573 14656633576 014052 0000000 0000000 #ifndef SAFE_MKDIR_H
#define SAFE_MKDIR_H
/* Either create a directory or make sure that it already exists with given
permissions. If anything fails, the i_fatal() is called. Returns 1 if
directory was created, 2 if it already existed with correct permissions,
0 if we changed permissions. */
int safe_mkdir(const char *dir, mode_t mode, uid_t uid, gid_t gid);
#endif
dovecot-2.3.21.1/src/lib/net.c 0000644 0000000 0000000 00000064520 14656633576 012613 0000000 0000000 /* Copyright (c) 1999-2018 Dovecot authors, see the included COPYING file */
#define _GNU_SOURCE /* For Linux's struct ucred */
#include "lib.h"
#include "time-util.h"
#include "net.h"
#include
#include
#include
#include
#include
#if defined(HAVE_UCRED_H)
# include /* for getpeerucred() */
#elif defined(HAVE_SYS_UCRED_H)
# include /* for FreeBSD struct xucred */
#endif
union sockaddr_union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
union sockaddr_union_unix {
struct sockaddr sa;
struct sockaddr_un un;
};
#define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
sizeof(so.sin6) : sizeof(so.sin))
#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEERUCRED) && defined(MSG_WAITALL) && defined(LOCAL_CREDS)
# define NEEDS_LOCAL_CREDS 1
#else
# undef NEEDS_LOCAL_CREDS
#endif
/* If connect() fails with EADDRNOTAVAIL (or some others on FreeBSD), retry it
this many times.
This is needed on busy systems kernel may assign the same source port to two
sockets at bind() stage, which is what we generally want to allow more than
64k outgoing connections to different destinations. However, at bind() stage
the kernel doesn't know the destination yet. So it's possible that it
assigns the same source port to two (or more) sockets that have the same
destination IP+port as well. In this case connect() will fail with
EADDRNOTAVAIL. We'll need to retry this and hope that the next attempt won't
conflict. */
#define MAX_CONNECT_RETRIES 20
bool net_ip_compare(const struct ip_addr *ip1, const struct ip_addr *ip2)
{
return net_ip_cmp(ip1, ip2) == 0;
}
int net_ip_cmp(const struct ip_addr *ip1, const struct ip_addr *ip2)
{
if (ip1->family != ip2->family)
return ip1->family - ip2->family;
switch (ip1->family) {
case AF_INET6:
return memcmp(&ip1->u.ip6, &ip2->u.ip6, sizeof(ip1->u.ip6));
case AF_INET:
return memcmp(&ip1->u.ip4, &ip2->u.ip4, sizeof(ip1->u.ip4));
default:
break;
}
return 0;
}
unsigned int net_ip_hash(const struct ip_addr *ip)
{
const unsigned char *p;
unsigned int len, g, h = 0;
if (ip->family == AF_INET6) {
p = ip->u.ip6.s6_addr;
len = sizeof(ip->u.ip6);
} else
{
return ip->u.ip4.s_addr;
}
for (; len > 0; len--, p++) {
h = (h << 4) + *p;
if ((g = h & 0xf0000000UL) != 0) {
h = h ^ (g >> 24);
h = h ^ g;
}
}
return h;
}
/* copy IP to sockaddr */
static inline void
sin_set_ip(union sockaddr_union *so, const struct ip_addr *ip)
{
if (ip == NULL) {
so->sin6.sin6_family = AF_INET6;
so->sin6.sin6_addr = in6addr_any;
return;
}
so->sin.sin_family = ip->family;
if (ip->family == AF_INET6)
memcpy(&so->sin6.sin6_addr, &ip->u.ip6, sizeof(ip->u.ip6));
else
memcpy(&so->sin.sin_addr, &ip->u.ip4, sizeof(ip->u.ip4));
}
static inline void
sin_get_ip(const union sockaddr_union *so, struct ip_addr *ip)
{
/* IP structs may be sent across processes. Clear the whole struct
first to make sure it won't leak any data across processes. */
i_zero(ip);
ip->family = so->sin.sin_family;
if (ip->family == AF_INET6)
memcpy(&ip->u.ip6, &so->sin6.sin6_addr, sizeof(ip->u.ip6));
else
if (ip->family == AF_INET)
memcpy(&ip->u.ip4, &so->sin.sin_addr, sizeof(ip->u.ip4));
else
i_zero(&ip->u);
}
static inline void sin_set_port(union sockaddr_union *so, in_port_t port)
{
if (so->sin.sin_family == AF_INET6)
so->sin6.sin6_port = htons(port);
else
so->sin.sin_port = htons(port);
}
static inline in_port_t sin_get_port(union sockaddr_union *so)
{
if (so->sin.sin_family == AF_INET6)
return ntohs(so->sin6.sin6_port);
if (so->sin.sin_family == AF_INET)
return ntohs(so->sin.sin_port);
return 0;
}
static int net_connect_ip_once(const struct ip_addr *ip, in_port_t port,
const struct ip_addr *my_ip, int sock_type, bool blocking)
{
union sockaddr_union so;
int fd, ret, opt = 1;
if (my_ip != NULL && ip->family != my_ip->family) {
i_warning("net_connect_ip(): ip->family != my_ip->family");
my_ip = NULL;
}
/* create the socket */
i_zero(&so);
so.sin.sin_family = ip->family;
fd = socket(ip->family, sock_type, 0);
if (fd == -1) {
i_error("socket() failed: %m");
return -1;
}
/* set socket options */
(void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (sock_type == SOCK_STREAM)
(void)setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
if (!blocking)
net_set_nonblock(fd, TRUE);
/* set our own address */
if (my_ip != NULL) {
sin_set_ip(&so, my_ip);
if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
i_error("bind(%s) failed: %m", net_ip2addr(my_ip));
i_close_fd(&fd);
return -1;
}
}
/* connect */
sin_set_ip(&so, ip);
sin_set_port(&so, port);
ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so));
#ifndef WIN32
if (ret < 0 && errno != EINPROGRESS)
#else
if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
#endif
{
i_close_fd(&fd);
return -1;
}
return fd;
}
static int net_connect_ip_full(const struct ip_addr *ip, in_port_t port,
const struct ip_addr *my_ip, int sock_type,
bool blocking)
{
int fd, try;
for (try = 0;;) {
fd = net_connect_ip_once(ip, port, my_ip, sock_type, blocking);
if (fd != -1 || try++ >= MAX_CONNECT_RETRIES ||
(errno != EADDRNOTAVAIL
#ifdef __FreeBSD__
/* busy */
&& errno != EADDRINUSE
/* pf may cause this if another connection used
the same port recently */
&& errno != EACCES
#endif
))
break;
}
return fd;
}
int net_connect_ip(const struct ip_addr *ip, in_port_t port,
const struct ip_addr *my_ip)
{
return net_connect_ip_full(ip, port, my_ip, SOCK_STREAM, FALSE);
}
int net_connect_ip_blocking(const struct ip_addr *ip, in_port_t port,
const struct ip_addr *my_ip)
{
return net_connect_ip_full(ip, port, my_ip, SOCK_STREAM, TRUE);
}
int net_connect_udp(const struct ip_addr *ip, in_port_t port,
const struct ip_addr *my_ip)
{
return net_connect_ip_full(ip, port, my_ip, SOCK_DGRAM, FALSE);
}
int net_try_bind(const struct ip_addr *ip)
{
union sockaddr_union so;
int fd;
/* create the socket */
i_zero(&so);
so.sin.sin_family = ip->family;
fd = socket(ip->family, SOCK_STREAM, 0);
if (fd == -1) {
i_error("socket() failed: %m");
return -1;
}
sin_set_ip(&so, ip);
if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
i_close_fd(&fd);
return -1;
}
i_close_fd(&fd);
return 0;
}
int net_connect_unix(const char *path)
{
union sockaddr_union_unix sa;
int fd, ret;
i_zero(&sa);
sa.un.sun_family = AF_UNIX;
if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
/* too long path */
#ifdef ENAMETOOLONG
errno = ENAMETOOLONG;
#else
errno = EOVERFLOW;
#endif
return -1;
}
/* create the socket */
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
i_error("socket(%s) failed: %m", path);
return -1;
}
net_set_nonblock(fd, TRUE);
/* connect */
ret = connect(fd, &sa.sa, sizeof(sa));
if (ret < 0 && errno != EINPROGRESS) {
i_close_fd(&fd);
return -1;
}
#ifdef NEEDS_LOCAL_CREDS
{
int on = 1;
if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
i_error("setsockopt(LOCAL_CREDS) failed: %m");
return -1;
}
}
#endif
return fd;
}
int net_connect_unix_with_retries(const char *path, unsigned int msecs)
{
struct timeval start, now;
int fd;
i_gettimeofday(&start);
do {
fd = net_connect_unix(path);
if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
break;
/* busy. wait for a while. */
usleep(i_rand_minmax(1, 10) * 10000);
i_gettimeofday(&now);
} while (timeval_diff_msecs(&now, &start) < (int)msecs);
return fd;
}
void net_disconnect(int fd)
{
/* FreeBSD's close() fails with ECONNRESET if socket still has unsent
data in transmit buffer. We don't care. */
if (close(fd) < 0 && errno != ECONNRESET)
i_error("net_disconnect() failed: %m");
}
void net_set_nonblock(int fd, bool nonblock)
{
fd_set_nonblock(fd, nonblock);
}
int net_set_cork(int fd ATTR_UNUSED, bool cork ATTR_UNUSED)
{
#ifdef TCP_CORK
int val = cork;
return setsockopt(fd, IPPROTO_TCP, TCP_CORK, &val, sizeof(val));
#else
errno = ENOPROTOOPT;
return -1;
#endif
}
int net_set_tcp_nodelay(int fd, bool nodelay)
{
int val = nodelay;
return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
}
int net_set_tcp_quickack(int fd ATTR_UNUSED, bool quickack ATTR_UNUSED)
{
#ifdef TCP_QUICKACK
int val = quickack;
return setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &val, sizeof(val));
#else
errno = ENOPROTOOPT;
return -1;
#endif
}
int net_set_send_buffer_size(int fd, size_t size)
{
int opt;
if (size > INT_MAX) {
errno = EINVAL;
return -1;
}
opt = (int)size;
return setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
}
int net_set_recv_buffer_size(int fd, size_t size)
{
int opt;
if (size > INT_MAX) {
errno = EINVAL;
return -1;
}
opt = (int)size;
return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
}
const struct ip_addr net_ip4_any = {
.family = AF_INET,
.u.ip4.s_addr = INADDR_ANY
};
const struct ip_addr net_ip6_any = {
.family = AF_INET6,
.u.ip6 = IN6ADDR_ANY_INIT
};
const struct ip_addr net_ip4_loopback = {
.family = AF_INET,
.u.ip4.s_addr = INADDR_LOOPBACK
};
const struct ip_addr net_ip6_loopback = {
.family = AF_INET6,
.u.ip6 = IN6ADDR_LOOPBACK_INIT
};
int net_listen(const struct ip_addr *my_ip, in_port_t *port, int backlog)
{
enum net_listen_flags flags = 0;
return net_listen_full(my_ip, port, &flags, backlog);
}
int net_listen_full(const struct ip_addr *my_ip, in_port_t *port,
enum net_listen_flags *flags, int backlog)
{
union sockaddr_union so;
int ret, fd, opt = 1;
socklen_t len;
i_zero(&so);
sin_set_port(&so, *port);
sin_set_ip(&so, my_ip);
/* create the socket */
fd = socket(so.sin.sin_family, SOCK_STREAM, 0);
if (fd == -1 && my_ip == NULL &&
(errno == EINVAL || errno == EAFNOSUPPORT)) {
/* IPv6 is not supported by OS */
so.sin.sin_family = AF_INET;
so.sin.sin_addr.s_addr = INADDR_ANY;
fd = socket(AF_INET, SOCK_STREAM, 0);
}
if (fd == -1) {
i_error("socket() failed: %m");
return -1;
}
/* set socket options */
(void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
(void)setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
if ((*flags & NET_LISTEN_FLAG_REUSEPORT) != 0) {
#ifdef SO_REUSEPORT
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
&opt, sizeof(opt)) < 0)
#endif
*flags &= ENUM_NEGATE(NET_LISTEN_FLAG_REUSEPORT);
}
/* If using IPv6, bind only to IPv6 if possible. This avoids
ambiguities with IPv4-mapped IPv6 addresses. */
#ifdef IPV6_V6ONLY
if (so.sin.sin_family == AF_INET6) {
opt = 1;
(void)setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
}
#endif
/* specify the address/port we want to listen in */
ret = bind(fd, &so.sa, SIZEOF_SOCKADDR(so));
if (ret < 0) {
if (errno != EADDRINUSE) {
i_error("bind(%s, %u) failed: %m",
my_ip == NULL ? "" : net_ip2addr(my_ip), *port);
}
} else {
/* get the actual port we started listen */
len = SIZEOF_SOCKADDR(so);
ret = getsockname(fd, &so.sa, &len);
if (ret >= 0) {
*port = sin_get_port(&so);
/* start listening */
if (listen(fd, backlog) >= 0)
return fd;
if (errno != EADDRINUSE)
i_error("listen() failed: %m");
}
}
/* error */
i_close_fd(&fd);
return -1;
}
int net_listen_unix(const char *path, int backlog)
{
union {
struct sockaddr sa;
struct sockaddr_un un;
} sa;
int fd;
i_zero(&sa);
sa.un.sun_family = AF_UNIX;
if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
/* too long path */
#ifdef ENAMETOOLONG
errno = ENAMETOOLONG;
#else
errno = EOVERFLOW;
#endif
return -1;
}
/* create the socket */
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
i_error("socket() failed: %m");
return -1;
}
#ifdef NEEDS_LOCAL_CREDS
{
int on = 1;
if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
i_error("setsockopt(LOCAL_CREDS) failed: %m");
return -1;
}
}
#endif
/* bind */
if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
if (errno != EADDRINUSE)
i_error("bind(%s) failed: %m", path);
} else {
/* start listening */
if (listen(fd, backlog) == 0)
return fd;
if (errno != EADDRINUSE)
i_error("listen() failed: %m");
}
i_close_fd(&fd);
return -1;
}
int net_listen_unix_unlink_stale(const char *path, int backlog)
{
unsigned int i = 0;
int fd;
while ((fd = net_listen_unix(path, backlog)) == -1) {
if (errno != EADDRINUSE || ++i == 2)
return -1;
/* see if it really exists */
fd = net_connect_unix(path);
if (fd != -1 || errno != ECONNREFUSED) {
i_close_fd(&fd);
errno = EADDRINUSE;
return -1;
}
/* delete and try again */
if (i_unlink_if_exists(path) < 0) {
errno = EADDRINUSE;
return -1;
}
}
return fd;
}
int net_accept(int fd, struct ip_addr *addr_r, in_port_t *port_r)
{
union sockaddr_union so;
int ret;
socklen_t addrlen;
i_assert(fd >= 0);
i_zero(&so);
addrlen = sizeof(so);
ret = accept(fd, &so.sa, &addrlen);
if (ret < 0) {
if (errno == EAGAIN || errno == ECONNABORTED)
return -1;
else
return -2;
}
if (so.sin.sin_family == AF_UNIX) {
if (addr_r != NULL)
i_zero(addr_r);
if (port_r != NULL) *port_r = 0;
} else {
if (addr_r != NULL) sin_get_ip(&so, addr_r);
if (port_r != NULL) *port_r = sin_get_port(&so);
}
return ret;
}
ssize_t net_receive(int fd, void *buf, size_t len)
{
ssize_t ret;
i_assert(fd >= 0);
i_assert(len <= SSIZE_T_MAX);
ret = read(fd, buf, len);
if (ret == 0) {
/* disconnected */
errno = 0;
return -2;
}
if (unlikely(ret < 0)) {
if (errno == EINTR || errno == EAGAIN)
return 0;
if (errno == ECONNRESET || errno == ETIMEDOUT) {
/* treat as disconnection */
return -2;
}
}
return ret;
}
int net_gethostbyname(const char *addr, struct ip_addr **ips,
unsigned int *ips_count)
{
/* @UNSAFE */
union sockaddr_union *so;
struct addrinfo hints, *ai, *origai;
struct ip_addr ip;
int host_error;
int count;
*ips = NULL;
*ips_count = 0;
/* support [ipv6] style addresses here so they work globally */
if (addr[0] == '[' && net_addr2ip(addr, &ip) == 0) {
*ips_count = 1;
*ips = t_new(struct ip_addr, 1);
**ips = ip;
return 0;
}
i_zero(&hints);
hints.ai_socktype = SOCK_STREAM;
/* save error to host_error for later use */
host_error = getaddrinfo(addr, NULL, &hints, &ai);
if (host_error != 0)
return host_error;
/* get number of IPs */
origai = ai;
for (count = 0; ai != NULL; ai = ai->ai_next)
count++;
*ips_count = count;
*ips = t_new(struct ip_addr, count);
count = 0;
for (ai = origai; ai != NULL; ai = ai->ai_next, count++) {
so = (union sockaddr_union *) ai->ai_addr;
sin_get_ip(so, &(*ips)[count]);
}
freeaddrinfo(origai);
return 0;
}
int net_gethostbyaddr(const struct ip_addr *ip, const char **name_r)
{
union sockaddr_union so;
socklen_t addrlen = sizeof(so);
char hbuf[NI_MAXHOST];
int ret;
i_zero(&so);
sin_set_ip(&so, ip);
ret = getnameinfo(&so.sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
NI_NAMEREQD);
if (ret != 0)
return ret;
*name_r = t_strdup(hbuf);
return 0;
}
int net_getsockname(int fd, struct ip_addr *addr, in_port_t *port)
{
union sockaddr_union so;
socklen_t addrlen;
i_assert(fd >= 0);
i_zero(&so);
addrlen = sizeof(so);
if (getsockname(fd, &so.sa, &addrlen) == -1)
return -1;
if (so.sin.sin_family == AF_UNIX) {
if (addr != NULL)
i_zero(addr);
if (port != NULL) *port = 0;
} else {
if (addr != NULL) sin_get_ip(&so, addr);
if (port != NULL) *port = sin_get_port(&so);
}
return 0;
}
int net_getpeername(int fd, struct ip_addr *addr, in_port_t *port)
{
union sockaddr_union so;
socklen_t addrlen;
i_assert(fd >= 0);
i_zero(&so);
addrlen = sizeof(so);
if (getpeername(fd, &so.sa, &addrlen) == -1)
return -1;
if (so.sin.sin_family == AF_UNIX) {
if (addr != NULL)
i_zero(addr);
if (port != NULL) *port = 0;
} else {
if (addr != NULL) sin_get_ip(&so, addr);
if (port != NULL) *port = sin_get_port(&so);
}
return 0;
}
int net_getunixname(int fd, const char **name_r)
{
union sockaddr_union_unix so;
socklen_t addrlen = sizeof(so);
i_zero(&so);
if (getsockname(fd, &so.sa, &addrlen) < 0)
return -1;
if (so.un.sun_family != AF_UNIX) {
errno = ENOTSOCK;
return -1;
}
*name_r = t_strdup(so.un.sun_path);
return 0;
}
int net_getunixcred(int fd, struct net_unix_cred *cred_r)
{
#if defined(SO_PEERCRED)
# if defined(HAVE_STRUCT_SOCKPEERCRED)
/* OpenBSD (may also provide getpeereid, but we also want pid) */
struct sockpeercred ucred;
# else
/* Linux */
struct ucred ucred;
# endif
socklen_t len = sizeof(ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
i_error("getsockopt(SO_PEERCRED) failed: %m");
return -1;
}
cred_r->uid = ucred.uid;
cred_r->gid = ucred.gid;
cred_r->pid = ucred.pid;
return 0;
#elif defined(LOCAL_PEEREID)
/* NetBSD (may also provide getpeereid, but we also want pid) */
struct unpcbid ucred;
socklen_t len = sizeof(ucred);
if (getsockopt(fd, 0, LOCAL_PEEREID, &ucred, &len) < 0) {
i_error("getsockopt(LOCAL_PEEREID) failed: %m");
return -1;
}
cred_r->uid = ucred.unp_euid;
cred_r->gid = ucred.unp_egid;
cred_r->pid = ucred.unp_pid;
return 0;
#elif defined(HAVE_GETPEEREID)
/* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
i_error("getpeereid() failed: %m");
return -1;
}
cred_r->pid = (pid_t)-1;
return 0;
#elif defined(LOCAL_PEERCRED)
/* Older FreeBSD */
struct xucred ucred;
socklen_t len = sizeof(ucred);
if (getsockopt(fd, 0, LOCAL_PEERCRED, &ucred, &len) < 0) {
i_error("getsockopt(LOCAL_PEERCRED) failed: %m");
return -1;
}
if (ucred.cr_version != XUCRED_VERSION) {
errno = EINVAL;
return -1;
}
cred_r->uid = ucred.cr_uid;
cred_r->gid = ucred.cr_gid;
cred_r->pid = (pid_t)-1;
return 0;
#elif defined(HAVE_GETPEERUCRED)
/* Solaris */
ucred_t *ucred = NULL;
if (getpeerucred(fd, &ucred) < 0) {
i_error("getpeerucred() failed: %m");
return -1;
}
cred_r->uid = ucred_geteuid(ucred);
cred_r->gid = ucred_getrgid(ucred);
cred_r->pid = ucred_getpid(ucred);
ucred_free(ucred);
if (cred_r->uid == (uid_t)-1 ||
cred_r->gid == (gid_t)-1) {
errno = EINVAL;
return -1;
}
return 0;
#elif defined(NEEDS_LOCAL_CREDS)
/* NetBSD < 5 */
int i, n, on;
struct iovec iov;
struct msghdr msg;
struct {
struct cmsghdr ch;
char buf[110];
} cdata;
struct sockcred *sc;
iov.iov_base = (char *)&on;
iov.iov_len = 1;
sc = (struct sockcred *)cdata.buf;
sc->sc_uid = sc->sc_euid = sc->sc_gid = sc->sc_egid = -1;
i_zero(&cdata.ch);
i_zero(&msg);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &cdata;
msg.msg_controllen = sizeof(cdata.ch) + sizeof(cdata.buf);
for (i = 0; i < 10; i++) {
n = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK);
if (n >= 0 || errno != EAGAIN)
break;
usleep(100);
}
if (n < 0) {
i_error("recvmsg() failed: %m");
return -1;
}
cred_r->uid = sc->sc_euid;
cred_r->gid = sc->sc_egid;
cred_r->pid = (pid_t)-1;
return 0;
#else
errno = EINVAL;
return -1;
#endif
}
const char *net_ip2addr(const struct ip_addr *ip)
{
char *addr = t_malloc_no0(MAX_IP_LEN+1);
if (inet_ntop(ip->family, &ip->u.ip6, addr, MAX_IP_LEN) == NULL)
return "";
return addr;
}
static bool net_addr2ip_inet4_fast(const char *addr, struct ip_addr *ip)
{
uint8_t *saddr = (void *)&ip->u.ip4.s_addr;
unsigned int i, num;
if (str_parse_uint(addr, &num, &addr) < 0)
return FALSE;
if (*addr == '\0' && num <= 0xffffffff) {
/* single-number IPv4 address */
ip->u.ip4.s_addr = htonl(num);
ip->family = AF_INET;
return TRUE;
}
/* try to parse as a.b.c.d */
i = 0;
for (;;) {
if (num >= 256)
return FALSE;
saddr[i] = num;
if (i == 3)
break;
i++;
if (*addr != '.')
return FALSE;
addr++;
if (str_parse_uint(addr, &num, &addr) < 0)
return FALSE;
}
if (*addr != '\0')
return FALSE;
ip->family = AF_INET;
return TRUE;
}
int net_addr2ip(const char *addr, struct ip_addr *ip)
{
int ret;
if (net_addr2ip_inet4_fast(addr, ip))
return 0;
if (strchr(addr, ':') != NULL) {
/* IPv6 */
T_BEGIN {
if (addr[0] == '[') {
/* allow [ipv6 addr] */
size_t len = strlen(addr);
if (addr[len-1] == ']')
addr = t_strndup(addr+1, len-2);
}
ret = inet_pton(AF_INET6, addr, &ip->u.ip6);
} T_END;
if (ret == 0)
return -1;
ip->family = AF_INET6;
} else {
/* IPv4 */
if (inet_aton(addr, &ip->u.ip4) == 0)
return -1;
ip->family = AF_INET;
}
return 0;
}
int net_str2port(const char *str, in_port_t *port_r)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return -1;
if (l == 0 || l > (in_port_t)-1)
return -1;
*port_r = (in_port_t)l;
return 0;
}
int net_str2port_zero(const char *str, in_port_t *port_r)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return -1;
if (l > (in_port_t)-1)
return -1;
*port_r = (in_port_t)l;
return 0;
}
int net_str2hostport(const char *str, in_port_t default_port,
const char **host_r, in_port_t *port_r)
{
const char *p, *host;
in_port_t port;
if (str[0] == '[') {
/* [IPv6] address, possibly followed by :port */
p = strchr(str, ']');
if (p == NULL)
return -1;
host = t_strdup_until(str+1, p++);
} else {
p = strchr(str, ':');
if (p == NULL || strchr(p+1, ':') != NULL) {
/* host or IPv6 address */
*host_r = str;
*port_r = default_port;
return 0;
}
host = t_strdup_until(str, p);
}
if (p[0] == '\0') {
*host_r = host;
*port_r = default_port;
return 0;
}
if (p[0] != ':')
return -1;
if (net_str2port(p+1, &port) < 0)
return -1;
*host_r = host;
*port_r = port;
return 0;
}
int net_ipport2str(const struct ip_addr *ip, in_port_t port, const char **str_r)
{
if (!IPADDR_IS_V4(ip) && !IPADDR_IS_V6(ip)) return -1;
*str_r = t_strdup_printf("%s%s%s:%u",
IPADDR_IS_V6(ip) ? "[" : "",
net_ip2addr(ip),
IPADDR_IS_V6(ip) ? "]" : "",
port);
return 0;
}
int net_ipv6_mapped_ipv4_convert(const struct ip_addr *src,
struct ip_addr *dest)
{
static uint8_t v4_prefix[] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
if (!IPADDR_IS_V6(src))
return -1;
if (memcmp(src->u.ip6.s6_addr, v4_prefix, sizeof(v4_prefix)) != 0)
return -1;
i_zero(dest);
dest->family = AF_INET;
memcpy(&dest->u.ip6, &src->u.ip6.s6_addr[3*4], 4);
return 0;
}
int net_geterror(int fd)
{
int data;
socklen_t len = sizeof(data);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &data, &len) == -1) {
/* we're now really returning the getsockopt()'s error code
instead of the socket's, but normally we should never get
here anyway. */
return errno;
}
return data;
}
const char *net_gethosterror(int error)
{
i_assert(error != 0);
return gai_strerror(error);
}
enum net_hosterror_type net_get_hosterror_type(int error)
{
const struct {
int error;
enum net_hosterror_type type;
} error_map[] = {
#ifdef EAI_ADDRFAMILY /* Obsoleted by RFC 2553bis-02 */
{ EAI_ADDRFAMILY, NET_HOSTERROR_TYPE_NOT_FOUND },
#endif
{ EAI_AGAIN, NET_HOSTERROR_TYPE_NAMESERVER },
{ EAI_BADFLAGS, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
{ EAI_FAIL, NET_HOSTERROR_TYPE_NAMESERVER },
{ EAI_FAMILY, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
{ EAI_MEMORY, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
#ifdef EAI_NODATA /* Obsoleted by RFC 2553bis-02 */
{ EAI_NODATA, NET_HOSTERROR_TYPE_NOT_FOUND },
#endif
{ EAI_NONAME, NET_HOSTERROR_TYPE_NOT_FOUND },
{ EAI_SERVICE, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
{ EAI_SOCKTYPE, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
{ EAI_SYSTEM, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
};
for (unsigned int i = 0; i < N_ELEMENTS(error_map); i++) {
if (error_map[i].error == error)
return error_map[i].type;
}
/* shouldn't happen? assume internal error */
return NET_HOSTERROR_TYPE_INTERNAL_ERROR;
}
int net_hosterror_notfound(int error)
{
#ifdef EAI_NODATA /* NODATA is depricated */
return (error != 1 && (error == EAI_NONAME || error == EAI_NODATA)) ? 1 : 0;
#else
return (error != 1 && (error == EAI_NONAME)) ? 1 : 0;
#endif
}
const char *net_getservbyport(in_port_t port)
{
struct servent *entry;
entry = getservbyport(htons(port), "tcp");
return entry == NULL ? NULL : entry->s_name;
}
bool is_ipv4_address(const char *addr)
{
while (*addr != '\0') {
if (*addr != '.' && !i_isdigit(*addr))
return FALSE;
addr++;
}
return TRUE;
}
bool is_ipv6_address(const char *addr)
{
bool have_prefix = FALSE;
if (*addr == '[') {
have_prefix = TRUE;
addr++;
}
while (*addr != '\0') {
if (*addr != ':' && !i_isxdigit(*addr)) {
if (have_prefix && *addr == ']' && addr[1] == '\0')
break;
return FALSE;
}
addr++;
}
return TRUE;
}
int net_parse_range(const char *network, struct ip_addr *ip_r,
unsigned int *bits_r)
{
const char *p;
unsigned int bits, max_bits;
p = strchr(network, '/');
if (p != NULL)
network = t_strdup_until(network, p++);
if (net_addr2ip(network, ip_r) < 0)
return -1;
max_bits = IPADDR_BITS(ip_r);
if (p == NULL) {
/* full IP address must match */
bits = max_bits;
} else {
/* get the network mask */
if (str_to_uint(p, &bits) < 0 || bits > max_bits)
return -1;
}
*bits_r = bits;
return 0;
}
bool net_is_in_network(const struct ip_addr *ip,
const struct ip_addr *net_ip, unsigned int bits)
{
struct ip_addr tmp_ip;
const uint32_t *ip1, *ip2;
uint32_t mask, i1, i2;
unsigned int pos, i;
if (net_ipv6_mapped_ipv4_convert(ip, &tmp_ip) == 0) {
/* IPv4 address mapped disguised as IPv6 address */
ip = &tmp_ip;
}
if (ip->family == 0 || net_ip->family == 0) {
/* non-IPv4/IPv6 address (e.g. UNIX socket) never matches
anything */
return FALSE;
}
if (IPADDR_IS_V4(ip) != IPADDR_IS_V4(net_ip)) {
/* one is IPv6 and one is IPv4 */
return FALSE;
}
i_assert(IPADDR_IS_V6(ip) == IPADDR_IS_V6(net_ip));
if (IPADDR_IS_V4(ip)) {
ip1 = &ip->u.ip4.s_addr;
ip2 = &net_ip->u.ip4.s_addr;
} else {
ip1 = (const void *)&ip->u.ip6;
ip2 = (const void *)&net_ip->u.ip6;
}
/* check first the full 32bit ints */
for (pos = 0, i = 0; pos + 32 <= bits; pos += 32, i++) {
if (ip1[i] != ip2[i])
return FALSE;
}
i1 = htonl(ip1[i]);
i2 = htonl(ip2[i]);
/* check the last full bytes */
for (mask = 0xff000000; pos + 8 <= bits; pos += 8, mask >>= 8) {
if ((i1 & mask) != (i2 & mask))
return FALSE;
}
/* check the last bits, they're reversed in bytes */
bits -= pos;
for (mask = 0x80000000 >> (pos % 32); bits > 0; bits--, mask >>= 1) {
if ((i1 & mask) != (i2 & mask))
return FALSE;
}
return TRUE;
}
dovecot-2.3.21.1/src/lib/backtrace-string.c 0000644 0000000 0000000 00000006666 14656633576 015257 0000000 0000000 /* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "backtrace-string.h"
#define MAX_STACK_SIZE 30
#define BACKTRACE_SKIP_PREFIX "backtrace_"
#if defined(HAVE_LIBUNWIND)
#include
static int backtrace_append_unwind(string_t *str)
{
size_t str_orig_size = str_len(str);
char proc_name[256];
int ret;
unsigned int fp = 0;
unw_cursor_t c;
unw_context_t ctx;
unw_proc_info_t pip;
bool success = FALSE;
if ((ret = unw_getcontext(&ctx)) != 0) {
str_printfa(str, "unw_getcontext() failed: %d", ret);
return -1;
}
if ((ret = unw_init_local(&c, &ctx)) != 0) {
str_printfa(str, "unw_init_local() failed: %d", ret);
return -1;
}
do {
str_printfa(str, "#%d ", fp);
if ((ret = unw_get_proc_info(&c, &pip)) != 0) {
str_printfa(str, "[unw_get_proc_info_failed(): %d]", ret);
} else if (pip.start_ip == 0 || pip.end_ip == 0) {
str_append(str, "[no start/end information]");
} else if ((ret = unw_get_proc_name(&c, proc_name, sizeof(proc_name), 0)) != 0 &&
ret != UNW_ENOMEM) {
str_printfa(str, "[unw_get_proc_name() failed: %d]", ret);
} else if (!success && str_begins(proc_name, BACKTRACE_SKIP_PREFIX)) {
str_truncate(str, str_orig_size);
continue;
} else {
str_append_max(str, proc_name, sizeof(proc_name));
str_printfa(str, "[0x%08zx]", pip.start_ip);
success = TRUE;
}
str_append(str, " -> ");
fp++;
} while ((ret = unw_step(&c)) > 0);
/* remove ' -> ' */
if (str->used > 4)
str_truncate(str, str->used - 4);
return ret == 0 && success ? 0 : -1;
}
#endif
#if defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_EXECINFO_H)
/* Linux */
#include
static int backtrace_append_libc(string_t *str)
{
size_t str_orig_size = str_len(str);
void *stack[MAX_STACK_SIZE];
char **strings;
int ret, i;
ret = backtrace(stack, N_ELEMENTS(stack));
if (ret <= 0)
return -1;
strings = backtrace_symbols(stack, ret);
for (i = 0; i < ret; i++) {
if (str_len(str) > str_orig_size)
str_append(str, " -> ");
if (strings == NULL) {
/* out of memory case */
str_printfa(str, "0x%p", stack[i]);
} else if (str_len(str) != str_orig_size ||
!str_begins(strings[i], BACKTRACE_SKIP_PREFIX))
str_append(str, strings[i]);
}
free(strings);
return 0;
}
#elif defined(HAVE_WALKCONTEXT) && defined(HAVE_UCONTEXT_H)
/* Solaris */
#include
struct walk_context {
string_t *str;
unsigned int pos;
};
static int walk_callback(uintptr_t ptr, int signo ATTR_UNUSED,
void *context)
{
struct walk_context *ctx = context;
if (ctx->pos > 0)
str_append(ctx->str, " -> ");
str_printfa(ctx->str, "0x%p", (void *)ptr);
ctx->pos++;
return 0;
}
static int backtrace_append_libc(string_t *str)
{
ucontext_t uc;
struct walk_context ctx;
if (getcontext(&uc) < 0)
return -1;
ctx.str = str;
ctx.pos = 0;
walkcontext(&uc, walk_callback, &ctx);
return 0;
}
#else
static int backtrace_append_libc(string_t *str ATTR_UNUSED)
{
return -1;
}
#endif
int backtrace_append(string_t *str)
{
#if defined(HAVE_LIBUNWIND)
size_t orig_len = str_len(str);
if (backtrace_append_unwind(str) == 0)
return 0;
/* failed to get useful backtrace. libc's own method is likely
better. */
str_truncate(str, orig_len);
#endif
return backtrace_append_libc(str);
}
int backtrace_get(const char **backtrace_r)
{
string_t *str;
str = t_str_new(512);
if (backtrace_append(str) < 0)
return -1;
*backtrace_r = str_c(str);
return 0;
}
dovecot-2.3.21.1/src/lib/ioloop.c 0000644 0000000 0000000 00000106724 14656633576 013331 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "backtrace-string.h"
#include "llist.h"
#include "time-util.h"
#include "istream-private.h"
#include "ioloop-private.h"
#include
/* Dovecot attempts to detect also when time suddenly jumps forwards.
This is done by getting the minimum timeout wait in epoll() (or similar)
and then seeing if the current time after epoll() is past the timeout.
This can't be very exact, so likely the difference is always at least
1 microsecond. In high load situations it can be somewhat higher.
Dovecot generally doesn't have very important short timeouts, so to avoid
logging many warnings about this, use a rather high value. */
#define IOLOOP_TIME_MOVED_FORWARDS_MIN_USECS (100000)
time_t ioloop_time = 0;
struct timeval ioloop_timeval;
struct ioloop *current_ioloop = NULL;
uint64_t ioloop_global_wait_usecs = 0;
static ARRAY(io_switch_callback_t *) io_switch_callbacks = ARRAY_INIT;
static ARRAY(io_destroy_callback_t *) io_destroy_callbacks = ARRAY_INIT;
static bool panic_on_leak = FALSE, panic_on_leak_set = FALSE;
static time_t data_stack_last_free_unused = 0;
static void io_loop_initialize_handler(struct ioloop *ioloop)
{
unsigned int initial_fd_count;
initial_fd_count = ioloop->max_fd_count > 0 &&
ioloop->max_fd_count < IOLOOP_INITIAL_FD_COUNT ?
ioloop->max_fd_count : IOLOOP_INITIAL_FD_COUNT;
io_loop_handler_init(ioloop, initial_fd_count);
}
static struct io_file *
io_add_file(struct ioloop *ioloop, int fd, enum io_condition condition,
const char *source_filename,
unsigned int source_linenum,
io_callback_t *callback, void *context)
{
struct io_file *io;
i_assert(callback != NULL);
i_assert((condition & IO_NOTIFY) == 0);
io = i_new(struct io_file, 1);
io->io.condition = condition;
io->io.callback = callback;
io->io.context = context;
io->io.ioloop = ioloop;
io->io.source_filename = source_filename;
io->io.source_linenum = source_linenum;
io->refcount = 1;
io->fd = fd;
if (io->io.ioloop->cur_ctx != NULL) {
io->io.ctx = io->io.ioloop->cur_ctx;
io_loop_context_ref(io->io.ctx);
}
if (io->io.ioloop->handler_context == NULL)
io_loop_initialize_handler(io->io.ioloop);
if (fd != -1)
io_loop_handle_add(io);
else {
/* we're adding an istream whose only way to get notified
is to call i_stream_set_input_pending() */
}
if (io->io.ioloop->io_files != NULL) {
io->io.ioloop->io_files->prev = io;
io->next = io->io.ioloop->io_files;
}
io->io.ioloop->io_files = io;
return io;
}
#undef io_add_to
struct io *io_add_to(struct ioloop *ioloop, int fd, enum io_condition condition,
const char *source_filename, unsigned int source_linenum,
io_callback_t *callback, void *context)
{
struct io_file *io;
i_assert(fd >= 0);
io = io_add_file(ioloop, fd, condition,
source_filename, source_linenum,
callback, context);
return &io->io;
}
#undef io_add
struct io *io_add(int fd, enum io_condition condition,
const char *source_filename,
unsigned int source_linenum,
io_callback_t *callback, void *context)
{
return io_add_to(current_ioloop, fd, condition,
source_filename, source_linenum,
callback, context);
}
#undef io_add_istream_to
struct io *io_add_istream_to(struct ioloop *ioloop, struct istream *input,
const char *source_filename,
unsigned int source_linenum,
io_callback_t *callback, void *context)
{
struct io_file *io;
io = io_add_file(ioloop, i_stream_get_fd(input), IO_READ,
source_filename, source_linenum, callback, context);
io->istream = input;
i_stream_ref(io->istream);
i_stream_set_io(io->istream, &io->io);
return &io->io;
}
#undef io_add_istream
struct io *io_add_istream(struct istream *input, const char *source_filename,
unsigned int source_linenum,
io_callback_t *callback, void *context)
{
return io_add_istream_to(current_ioloop, input,
source_filename, source_linenum,
callback, context);
}
static void io_file_unlink(struct io_file *io)
{
if (io->prev != NULL)
io->prev->next = io->next;
else
io->io.ioloop->io_files = io->next;
if (io->next != NULL)
io->next->prev = io->prev;
/* if we got here from an I/O handler callback, make sure we
don't try to handle this one next. */
if (io->io.ioloop->next_io_file == io)
io->io.ioloop->next_io_file = io->next;
}
static void io_remove_full(struct io **_io, bool closed)
{
struct io *io = *_io;
i_assert(io->callback != NULL);
*_io = NULL;
/* make sure the callback doesn't get called anymore.
kqueue code relies on this. */
io->callback = NULL;
if (io->pending) {
i_assert(io->ioloop->io_pending_count > 0);
io->ioloop->io_pending_count--;
}
if (io->ctx != NULL)
io_loop_context_unref(&io->ctx);
if ((io->condition & IO_NOTIFY) != 0)
io_loop_notify_remove(io);
else {
struct io_file *io_file = (struct io_file *)io;
struct istream *istream = io_file->istream;
if (istream != NULL) {
/* remove io before it's freed */
i_stream_unset_io(istream, io);
}
io_file_unlink(io_file);
if (io_file->fd != -1)
io_loop_handle_remove(io_file, closed);
else
i_free(io);
/* remove io from the ioloop before unreferencing the istream,
because a destroyed istream may automatically close the
fd. */
i_stream_unref(&istream);
}
}
void io_remove(struct io **io)
{
if (*io == NULL)
return;
io_remove_full(io, FALSE);
}
void io_remove_closed(struct io **io)
{
if (*io == NULL)
return;
i_assert(((*io)->condition & IO_NOTIFY) == 0);
io_remove_full(io, TRUE);
}
void io_set_pending(struct io *io)
{
i_assert((io->condition & IO_NOTIFY) == 0);
if (!io->pending) {
io->pending = TRUE;
io->ioloop->io_pending_count++;
}
}
bool io_is_pending(struct io *io)
{
return io->pending;
}
void io_set_never_wait_alone(struct io *io, bool set)
{
io->never_wait_alone = set;
}
static void timeout_update_next(struct timeout *timeout, struct timeval *tv_now)
{
if (tv_now == NULL)
i_gettimeofday(&timeout->next_run);
else {
timeout->next_run.tv_sec = tv_now->tv_sec;
timeout->next_run.tv_usec = tv_now->tv_usec;
}
/* we don't want microsecond accuracy or this function will be
called all the time - millisecond is more than enough */
timeout->next_run.tv_usec -= timeout->next_run.tv_usec % 1000;
timeout->next_run.tv_sec += timeout->msecs/1000;
timeout->next_run.tv_usec += (timeout->msecs%1000)*1000;
if (timeout->next_run.tv_usec >= 1000000) {
timeout->next_run.tv_sec++;
timeout->next_run.tv_usec -= 1000000;
}
}
static struct timeout *
timeout_add_common(struct ioloop *ioloop, const char *source_filename,
unsigned int source_linenum,
timeout_callback_t *callback, void *context)
{
struct timeout *timeout;
timeout = i_new(struct timeout, 1);
timeout->item.idx = UINT_MAX;
timeout->source_filename = source_filename;
timeout->source_linenum = source_linenum;
timeout->ioloop = ioloop;
timeout->callback = callback;
timeout->context = context;
if (timeout->ioloop->cur_ctx != NULL) {
timeout->ctx = timeout->ioloop->cur_ctx;
io_loop_context_ref(timeout->ctx);
}
return timeout;
}
#undef timeout_add_to
struct timeout *timeout_add_to(struct ioloop *ioloop, unsigned int msecs,
const char *source_filename,
unsigned int source_linenum,
timeout_callback_t *callback, void *context)
{
struct timeout *timeout;
timeout = timeout_add_common(ioloop, source_filename, source_linenum,
callback, context);
timeout->msecs = msecs;
if (msecs > 0) {
/* start this timeout in the next run cycle */
array_push_back(&timeout->ioloop->timeouts_new, &timeout);
} else {
/* Trigger zero timeouts as soon as possible. When ioloop is
running, refresh the timestamp to prevent infinite loops
in case a timeout callback keeps recreating the 0-timeout. */
timeout_update_next(timeout, timeout->ioloop->running ?
NULL : &ioloop_timeval);
priorityq_add(timeout->ioloop->timeouts, &timeout->item);
}
return timeout;
}
#undef timeout_add
struct timeout *timeout_add(unsigned int msecs, const char *source_filename,
unsigned int source_linenum,
timeout_callback_t *callback, void *context)
{
return timeout_add_to(current_ioloop, msecs,
source_filename, source_linenum,
callback, context);
}
#undef timeout_add_short_to
struct timeout *
timeout_add_short_to(struct ioloop *ioloop, unsigned int msecs,
const char *source_filename, unsigned int source_linenum,
timeout_callback_t *callback, void *context)
{
return timeout_add_to(ioloop, msecs,
source_filename, source_linenum,
callback, context);
}
#undef timeout_add_short
struct timeout *
timeout_add_short(unsigned int msecs, const char *source_filename,
unsigned int source_linenum,
timeout_callback_t *callback, void *context)
{
return timeout_add(msecs, source_filename, source_linenum,
callback, context);
}
#undef timeout_add_absolute_to
struct timeout *
timeout_add_absolute_to(struct ioloop *ioloop, const struct timeval *time,
const char *source_filename,
unsigned int source_linenum,
timeout_callback_t *callback, void *context)
{
struct timeout *timeout;
timeout = timeout_add_common(ioloop, source_filename, source_linenum,
callback, context);
timeout->one_shot = TRUE;
timeout->next_run = *time;
priorityq_add(timeout->ioloop->timeouts, &timeout->item);
return timeout;
}
#undef timeout_add_absolute
struct timeout *
timeout_add_absolute(const struct timeval *time,
const char *source_filename,
unsigned int source_linenum,
timeout_callback_t *callback, void *context)
{
return timeout_add_absolute_to(current_ioloop, time,
source_filename, source_linenum,
callback, context);
}
static struct timeout *
timeout_copy(const struct timeout *old_to, struct ioloop *ioloop)
{
struct timeout *new_to;
new_to = timeout_add_common(ioloop,
old_to->source_filename, old_to->source_linenum,
old_to->callback, old_to->context);
new_to->one_shot = old_to->one_shot;
new_to->msecs = old_to->msecs;
new_to->next_run = old_to->next_run;
if (old_to->item.idx != UINT_MAX)
priorityq_add(new_to->ioloop->timeouts, &new_to->item);
else if (!new_to->one_shot) {
i_assert(new_to->msecs > 0);
array_push_back(&new_to->ioloop->timeouts_new, &new_to);
}
return new_to;
}
static void timeout_free(struct timeout *timeout)
{
if (timeout->ctx != NULL)
io_loop_context_unref(&timeout->ctx);
i_free(timeout);
}
void timeout_remove(struct timeout **_timeout)
{
struct timeout *timeout = *_timeout;
struct ioloop *ioloop;
if (timeout == NULL)
return;
ioloop = timeout->ioloop;
*_timeout = NULL;
if (timeout->item.idx != UINT_MAX)
priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
else if (!timeout->one_shot && timeout->msecs > 0) {
struct timeout *const *to_idx;
array_foreach(&ioloop->timeouts_new, to_idx) {
if (*to_idx == timeout) {
array_delete(&ioloop->timeouts_new,
array_foreach_idx(&ioloop->timeouts_new, to_idx), 1);
break;
}
}
}
timeout_free(timeout);
}
static void ATTR_NULL(2)
timeout_reset_timeval(struct timeout *timeout, struct timeval *tv_now)
{
if (timeout->item.idx == UINT_MAX)
return;
timeout_update_next(timeout, tv_now);
/* If we came here from io_loop_handle_timeouts_real(), next_run must
be larger than tv_now or it can go to infinite loop. This would
mainly happen with 0 ms timeouts. Avoid this by making sure
next_run is at least 1 us higher than tv_now.
Note that some callers (like master process's process_min_avail
preforking timeout) really do want the 0 ms timeout to trigger
multiple times as rapidly as it can (but in separate ioloop runs).
So don't increase it more than by 1 us. */
if (tv_now != NULL && timeval_cmp(&timeout->next_run, tv_now) <= 0) {
timeout->next_run = *tv_now;
timeval_add_usecs(&timeout->next_run, 1);
}
priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
priorityq_add(timeout->ioloop->timeouts, &timeout->item);
}
void timeout_reset(struct timeout *timeout)
{
i_assert(!timeout->one_shot);
timeout_reset_timeval(timeout, NULL);
}
static int timeout_get_wait_time(struct timeout *timeout, struct timeval *tv_r,
struct timeval *tv_now, bool in_timeout_loop)
{
int ret;
if (tv_now->tv_sec == 0)
i_gettimeofday(tv_now);
tv_r->tv_sec = tv_now->tv_sec;
tv_r->tv_usec = tv_now->tv_usec;
i_assert(tv_r->tv_sec > 0);
i_assert(timeout->next_run.tv_sec > 0);
tv_r->tv_sec = timeout->next_run.tv_sec - tv_r->tv_sec;
tv_r->tv_usec = timeout->next_run.tv_usec - tv_r->tv_usec;
if (tv_r->tv_usec < 0) {
tv_r->tv_sec--;
tv_r->tv_usec += 1000000;
}
if (tv_r->tv_sec < 0) {
/* The timeout should have been called already */
tv_r->tv_sec = 0;
tv_r->tv_usec = 0;
return 0;
}
if (tv_r->tv_sec == 0 && tv_r->tv_usec == 1 && !in_timeout_loop) {
/* Possibly 0 ms timeout. Don't wait for a full millisecond
for it to trigger. */
tv_r->tv_usec = 0;
return 0;
}
if (tv_r->tv_sec > INT_MAX/1000-1)
tv_r->tv_sec = INT_MAX/1000-1;
/* round wait times up to next millisecond */
ret = tv_r->tv_sec * 1000 + (tv_r->tv_usec + 999) / 1000;
i_assert(ret >= 0 && tv_r->tv_sec >= 0 && tv_r->tv_usec >= 0);
return ret;
}
static int io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r)
{
struct timeval tv_now;
struct priorityq_item *item;
struct timeout *timeout;
int msecs;
item = priorityq_peek(ioloop->timeouts);
timeout = (struct timeout *)item;
/* we need to see if there are pending IO waiting,
if there is, we set msecs = 0 to ensure they are
processed without delay */
if (timeout == NULL && ioloop->io_pending_count == 0) {
/* no timeouts. use INT_MAX msecs for timeval and
return -1 for poll/epoll infinity. */
tv_r->tv_sec = INT_MAX / 1000;
tv_r->tv_usec = 0;
ioloop->next_max_time.tv_sec = (1ULL << (TIME_T_MAX_BITS-1)) - 1;
ioloop->next_max_time.tv_usec = 0;
return -1;
}
if (ioloop->io_pending_count > 0) {
i_gettimeofday(&tv_now);
msecs = 0;
tv_r->tv_sec = 0;
tv_r->tv_usec = 0;
} else {
tv_now.tv_sec = 0;
msecs = timeout_get_wait_time(timeout, tv_r, &tv_now, FALSE);
}
ioloop->next_max_time = tv_now;
timeval_add_msecs(&ioloop->next_max_time, msecs);
/* update ioloop_timeval - this is meant for io_loop_handle_timeouts()'s
ioloop_wait_usecs calculation. normally after this we go to the
ioloop and after that we update ioloop_timeval immediately again. */
ioloop_timeval = tv_now;
ioloop_time = tv_now.tv_sec;
i_assert(msecs == 0 || timeout->msecs > 0 || timeout->one_shot);
return msecs;
}
static bool io_loop_have_waitable_io_files(struct ioloop *ioloop)
{
struct io_file *io;
for (io = ioloop->io_files; io != NULL; io = io->next) {
if (io->io.callback != NULL && !io->io.never_wait_alone)
return TRUE;
}
return FALSE;
}
int io_loop_run_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r)
{
int msecs = io_loop_get_wait_time(ioloop, tv_r);
if (msecs < 0 && !io_loop_have_waitable_io_files(ioloop))
i_panic("BUG: No IOs or timeouts set. Not waiting for infinity.");
return msecs;
}
static int timeout_cmp(const void *p1, const void *p2)
{
const struct timeout *to1 = p1, *to2 = p2;
return timeval_cmp(&to1->next_run, &to2->next_run);
}
static void
io_loop_default_time_moved(const struct timeval *old_time,
const struct timeval *new_time)
{
long long diff = timeval_diff_usecs(old_time, new_time);
if (diff > 0) {
i_warning("Time moved backwards by %lld.%06lld seconds.",
diff / 1000000, diff % 1000000);
}
}
static void io_loop_timeouts_start_new(struct ioloop *ioloop)
{
struct timeout *timeout;
if (array_count(&ioloop->timeouts_new) == 0)
return;
io_loop_time_refresh();
array_foreach_elem(&ioloop->timeouts_new, timeout) {
i_assert(timeout->next_run.tv_sec == 0 &&
timeout->next_run.tv_usec == 0);
i_assert(!timeout->one_shot);
i_assert(timeout->msecs > 0);
timeout_update_next(timeout, &ioloop_timeval);
priorityq_add(ioloop->timeouts, &timeout->item);
}
array_clear(&ioloop->timeouts_new);
}
static void io_loop_timeouts_update(struct ioloop *ioloop, long long diff_usecs)
{
struct priorityq_item *const *items;
unsigned int i, count;
count = priorityq_count(ioloop->timeouts);
items = priorityq_items(ioloop->timeouts);
for (i = 0; i < count; i++) {
struct timeout *to = (struct timeout *)items[i];
if (diff_usecs > 0)
timeval_add_usecs(&to->next_run, diff_usecs);
else
timeval_sub_usecs(&to->next_run, -diff_usecs);
}
}
static void io_loops_timeouts_update(long long diff_usecs)
{
struct ioloop *ioloop;
for (ioloop = current_ioloop; ioloop != NULL; ioloop = ioloop->prev)
io_loop_timeouts_update(ioloop, diff_usecs);
}
static void ioloop_add_wait_time(struct ioloop *ioloop)
{
struct io_wait_timer *timer;
long long diff;
diff = timeval_diff_usecs(&ioloop_timeval, &ioloop->wait_started);
if (diff < 0) {
/* time moved backwards */
diff = 0;
}
ioloop->ioloop_wait_usecs += diff;
ioloop_global_wait_usecs += diff;
for (timer = ioloop->wait_timers; timer != NULL; timer = timer->next)
timer->usecs += diff;
}
static void io_loop_handle_timeouts_real(struct ioloop *ioloop)
{
struct priorityq_item *item;
struct timeval tv_old, tv, tv_call;
long long diff_usecs;
data_stack_frame_t t_id;
tv_old = ioloop_timeval;
i_gettimeofday(&ioloop_timeval);
diff_usecs = timeval_diff_usecs(&ioloop_timeval, &tv_old);
if (unlikely(diff_usecs < 0)) {
/* time moved backwards */
io_loops_timeouts_update(diff_usecs);
ioloop->time_moved_callback(&tv_old, &ioloop_timeval);
i_assert(ioloop == current_ioloop);
/* the callback may have slept, so check the time again. */
i_gettimeofday(&ioloop_timeval);
} else {
diff_usecs = timeval_diff_usecs(&ioloop->next_max_time,
&ioloop_timeval);
if (unlikely(-diff_usecs >= IOLOOP_TIME_MOVED_FORWARDS_MIN_USECS)) {
io_loops_timeouts_update(-diff_usecs);
/* time moved forwards */
ioloop->time_moved_callback(&ioloop->next_max_time,
&ioloop_timeval);
i_assert(ioloop == current_ioloop);
}
ioloop_add_wait_time(ioloop);
}
ioloop_time = ioloop_timeval.tv_sec;
tv_call = ioloop_timeval;
while (ioloop->running &&
(item = priorityq_peek(ioloop->timeouts)) != NULL) {
struct timeout *timeout = (struct timeout *)item;
/* use tv_call to make sure we don't get to infinite loop in
case callbacks update ioloop_timeval. */
if (timeout_get_wait_time(timeout, &tv, &tv_call, TRUE) > 0)
break;
if (timeout->one_shot) {
/* remove timeout from queue */
priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
} else {
/* update timeout's next_run and reposition it in the queue */
timeout_reset_timeval(timeout, &tv_call);
}
if (timeout->ctx != NULL)
io_loop_context_activate(timeout->ctx);
t_id = t_push_named("ioloop timeout handler %p",
(void *)timeout->callback);
timeout->callback(timeout->context);
if (!t_pop(&t_id)) {
i_panic("Leaked a t_pop() call in timeout handler %p",
(void *)timeout->callback);
}
if (ioloop->cur_ctx != NULL)
io_loop_context_deactivate(ioloop->cur_ctx);
i_assert(ioloop == current_ioloop);
}
}
void io_loop_handle_timeouts(struct ioloop *ioloop)
{
T_BEGIN {
io_loop_handle_timeouts_real(ioloop);
} T_END;
/* Free the unused memory in data stack once per second. This way if
the data stack has grown excessively large temporarily, it won't
permanently waste memory. And if the data stack grows back to the
same large size, re-allocating it once per second doesn't cause
performance problems. */
if (data_stack_last_free_unused != ioloop_time) {
if (data_stack_last_free_unused != 0)
data_stack_free_unused();
data_stack_last_free_unused = ioloop_time;
}
}
void io_loop_call_io(struct io *io)
{
struct ioloop *ioloop = io->ioloop;
data_stack_frame_t t_id;
if (io->pending) {
i_assert(ioloop->io_pending_count > 0);
ioloop->io_pending_count--;
io->pending = FALSE;
}
if (io->ctx != NULL)
io_loop_context_activate(io->ctx);
t_id = t_push_named("ioloop handler %p",
(void *)io->callback);
io->callback(io->context);
if (!t_pop(&t_id)) {
i_panic("Leaked a t_pop() call in I/O handler %p",
(void *)io->callback);
}
if (ioloop->cur_ctx != NULL)
io_loop_context_deactivate(ioloop->cur_ctx);
i_assert(ioloop == current_ioloop);
}
void io_loop_run(struct ioloop *ioloop)
{
if (ioloop->handler_context == NULL)
io_loop_initialize_handler(ioloop);
if (ioloop->cur_ctx != NULL)
io_loop_context_deactivate(ioloop->cur_ctx);
/* recursive io_loop_run() isn't allowed for the same ioloop.
it can break backends. */
i_assert(!ioloop->iolooping);
ioloop->iolooping = TRUE;
ioloop->running = TRUE;
while (ioloop->running)
io_loop_handler_run(ioloop);
ioloop->iolooping = FALSE;
}
static void io_loop_call_pending(struct ioloop *ioloop)
{
struct io_file *io;
while (ioloop->io_pending_count > 0) {
io = ioloop->io_files;
do {
ioloop->next_io_file = io->next;
if (io->io.pending)
io_loop_call_io(&io->io);
if (ioloop->io_pending_count == 0)
break;
io = ioloop->next_io_file;
} while (io != NULL);
}
}
void io_loop_handler_run(struct ioloop *ioloop)
{
i_assert(ioloop == current_ioloop);
io_loop_timeouts_start_new(ioloop);
ioloop->wait_started = ioloop_timeval;
io_loop_handler_run_internal(ioloop);
io_loop_call_pending(ioloop);
if (ioloop->stop_after_run_loop)
io_loop_stop(ioloop);
i_assert(ioloop == current_ioloop);
}
void io_loop_stop(struct ioloop *ioloop)
{
ioloop->running = FALSE;
ioloop->stop_after_run_loop = FALSE;
}
void io_loop_stop_delayed(struct ioloop *ioloop)
{
ioloop->stop_after_run_loop = TRUE;
}
void io_loop_set_running(struct ioloop *ioloop)
{
ioloop->running = TRUE;
}
void io_loop_set_max_fd_count(struct ioloop *ioloop, unsigned int max_fds)
{
ioloop->max_fd_count = max_fds;
}
bool io_loop_is_running(struct ioloop *ioloop)
{
return ioloop->running;
}
void io_loop_time_refresh(void)
{
i_gettimeofday(&ioloop_timeval);
ioloop_time = ioloop_timeval.tv_sec;
}
struct ioloop *io_loop_create(void)
{
struct ioloop *ioloop;
if (!panic_on_leak_set) {
panic_on_leak_set = TRUE;
panic_on_leak = getenv("CORE_IO_LEAK") != NULL;
}
/* initialize time */
i_gettimeofday(&ioloop_timeval);
ioloop_time = ioloop_timeval.tv_sec;
ioloop = i_new(struct ioloop, 1);
ioloop->timeouts = priorityq_init(timeout_cmp, 32);
i_array_init(&ioloop->timeouts_new, 8);
ioloop->time_moved_callback = current_ioloop != NULL ?
current_ioloop->time_moved_callback :
io_loop_default_time_moved;
ioloop->prev = current_ioloop;
io_loop_set_current(ioloop);
return ioloop;
}
void io_loop_destroy(struct ioloop **_ioloop)
{
struct ioloop *ioloop = *_ioloop;
struct timeout *to;
struct priorityq_item *item;
bool leaks = FALSE;
*_ioloop = NULL;
/* ->prev won't work unless loops are destroyed in create order */
i_assert(ioloop == current_ioloop);
if (array_is_created(&io_destroy_callbacks)) {
io_destroy_callback_t *callback;
array_foreach_elem(&io_destroy_callbacks, callback) T_BEGIN {
callback(current_ioloop);
} T_END;
}
io_loop_set_current(current_ioloop->prev);
if (ioloop->notify_handler_context != NULL)
io_loop_notify_handler_deinit(ioloop);
while (ioloop->io_files != NULL) {
struct io_file *io = ioloop->io_files;
struct io *_io = &io->io;
const char *error = t_strdup_printf(
"I/O leak: %p (%s:%u, fd %d)",
(void *)io->io.callback,
io->io.source_filename,
io->io.source_linenum, io->fd);
if (panic_on_leak)
i_panic("%s", error);
else
i_warning("%s", error);
io_remove(&_io);
leaks = TRUE;
}
i_assert(ioloop->io_pending_count == 0);
array_foreach_elem(&ioloop->timeouts_new, to) {
const char *error = t_strdup_printf(
"Timeout leak: %p (%s:%u)", (void *)to->callback,
to->source_filename,
to->source_linenum);
if (panic_on_leak)
i_panic("%s", error);
else
i_warning("%s", error);
timeout_free(to);
leaks = TRUE;
}
array_free(&ioloop->timeouts_new);
while ((item = priorityq_pop(ioloop->timeouts)) != NULL) {
struct timeout *to = (struct timeout *)item;
const char *error = t_strdup_printf(
"Timeout leak: %p (%s:%u)", (void *)to->callback,
to->source_filename,
to->source_linenum);
if (panic_on_leak)
i_panic("%s", error);
else
i_warning("%s", error);
timeout_free(to);
leaks = TRUE;
}
priorityq_deinit(&ioloop->timeouts);
while (ioloop->wait_timers != NULL) {
struct io_wait_timer *timer = ioloop->wait_timers;
const char *error = t_strdup_printf(
"IO wait timer leak: %s:%u",
timer->source_filename,
timer->source_linenum);
if (panic_on_leak)
i_panic("%s", error);
else
i_warning("%s", error);
io_wait_timer_remove(&timer);
leaks = TRUE;
}
if (leaks) {
const char *backtrace;
if (backtrace_get(&backtrace) == 0)
i_warning("Raw backtrace for leaks: %s", backtrace);
}
if (ioloop->handler_context != NULL)
io_loop_handler_deinit(ioloop);
if (ioloop->cur_ctx != NULL)
io_loop_context_unref(&ioloop->cur_ctx);
i_free(ioloop);
}
void io_loop_set_time_moved_callback(struct ioloop *ioloop,
io_loop_time_moved_callback_t *callback)
{
ioloop->time_moved_callback = callback;
}
static void io_switch_callbacks_free(void)
{
array_free(&io_switch_callbacks);
}
static void io_destroy_callbacks_free(void)
{
array_free(&io_destroy_callbacks);
}
void io_loop_set_current(struct ioloop *ioloop)
{
io_switch_callback_t *callback;
struct ioloop *prev_ioloop = current_ioloop;
if (ioloop == current_ioloop)
return;
current_ioloop = ioloop;
if (array_is_created(&io_switch_callbacks)) {
array_foreach_elem(&io_switch_callbacks, callback) T_BEGIN {
callback(prev_ioloop);
} T_END;
}
}
struct ioloop *io_loop_get_root(void)
{
struct ioloop *ioloop = current_ioloop;
while (ioloop->prev != NULL)
ioloop = ioloop->prev;
return ioloop;
}
void io_loop_add_switch_callback(io_switch_callback_t *callback)
{
if (!array_is_created(&io_switch_callbacks)) {
i_array_init(&io_switch_callbacks, 4);
lib_atexit_priority(io_switch_callbacks_free, LIB_ATEXIT_PRIORITY_LOW);
}
array_push_back(&io_switch_callbacks, &callback);
}
void io_loop_remove_switch_callback(io_switch_callback_t *callback)
{
io_switch_callback_t *const *callbackp;
unsigned int idx;
array_foreach(&io_switch_callbacks, callbackp) {
if (*callbackp == callback) {
idx = array_foreach_idx(&io_switch_callbacks, callbackp);
array_delete(&io_switch_callbacks, idx, 1);
return;
}
}
i_unreached();
}
void io_loop_add_destroy_callback(io_destroy_callback_t *callback)
{
if (!array_is_created(&io_destroy_callbacks)) {
i_array_init(&io_destroy_callbacks, 4);
lib_atexit_priority(io_destroy_callbacks_free, LIB_ATEXIT_PRIORITY_LOW);
}
array_push_back(&io_destroy_callbacks, &callback);
}
void io_loop_remove_destroy_callback(io_destroy_callback_t *callback)
{
io_destroy_callback_t *const *callbackp;
unsigned int idx;
array_foreach(&io_destroy_callbacks, callbackp) {
if (*callbackp == callback) {
idx = array_foreach_idx(&io_destroy_callbacks, callbackp);
array_delete(&io_destroy_callbacks, idx, 1);
return;
}
}
i_unreached();
}
struct ioloop_context *io_loop_context_new(struct ioloop *ioloop)
{
struct ioloop_context *ctx;
ctx = i_new(struct ioloop_context, 1);
ctx->refcount = 1;
ctx->ioloop = ioloop;
i_array_init(&ctx->callbacks, 4);
return ctx;
}
void io_loop_context_ref(struct ioloop_context *ctx)
{
i_assert(ctx->refcount > 0);
ctx->refcount++;
}
void io_loop_context_unref(struct ioloop_context **_ctx)
{
struct ioloop_context *ctx = *_ctx;
*_ctx = NULL;
i_assert(ctx->refcount > 0);
if (--ctx->refcount > 0)
return;
/* cur_ctx itself keeps a reference */
i_assert(ctx->ioloop->cur_ctx != ctx);
array_free(&ctx->callbacks);
array_free(&ctx->global_event_stack);
i_free(ctx);
}
#undef io_loop_context_add_callbacks
void io_loop_context_add_callbacks(struct ioloop_context *ctx,
io_callback_t *activate,
io_callback_t *deactivate, void *context)
{
struct ioloop_context_callback cb;
i_zero(&cb);
cb.activate = activate;
cb.deactivate = deactivate;
cb.context = context;
array_push_back(&ctx->callbacks, &cb);
}
#undef io_loop_context_remove_callbacks
void io_loop_context_remove_callbacks(struct ioloop_context *ctx,
io_callback_t *activate,
io_callback_t *deactivate, void *context)
{
struct ioloop_context_callback *cb;
array_foreach_modifiable(&ctx->callbacks, cb) {
if (cb->context == context &&
cb->activate == activate && cb->deactivate == deactivate) {
/* simply mark it as deleted, since we could get
here from activate/deactivate loop */
cb->activate = NULL;
cb->deactivate = NULL;
cb->context = NULL;
return;
}
}
i_panic("io_loop_context_remove_callbacks() context not found");
}
static void
io_loop_context_remove_deleted_callbacks(struct ioloop_context *ctx)
{
const struct ioloop_context_callback *cbs;
unsigned int i, count;
cbs = array_get(&ctx->callbacks, &count);
for (i = 0; i < count; ) {
if (cbs[i].activate != NULL)
i++;
else {
array_delete(&ctx->callbacks, i, 1);
cbs = array_get(&ctx->callbacks, &count);
}
}
}
static void io_loop_context_push_global_events(struct ioloop_context *ctx)
{
struct event *const *events;
unsigned int i, count;
ctx->root_global_event = event_get_global();
if (!array_is_created(&ctx->global_event_stack))
return;
/* push the global events from stack in reverse order */
events = array_get(&ctx->global_event_stack, &count);
if (count == 0)
return;
/* Remember the oldest global event. We're going to pop until that
event when deactivating the context. */
for (i = count; i > 0; i--)
event_push_global(events[i-1]);
array_clear(&ctx->global_event_stack);
}
static void io_loop_context_pop_global_events(struct ioloop_context *ctx)
{
struct event *event;
/* ioloop context is always global, so we can't push one ioloop context
on top of another one. We'll need to rewind the global event stack
until we've reached the event that started this context. We'll push
these global events back when the ioloop context is activated
again. (We'll assert-crash if the root event is freed before these
global events have been popped.) */
while ((event = event_get_global()) != ctx->root_global_event) {
i_assert(event != NULL);
if (!array_is_created(&ctx->global_event_stack))
i_array_init(&ctx->global_event_stack, 4);
array_push_back(&ctx->global_event_stack, &event);
event_pop_global(event);
}
ctx->root_global_event = NULL;
}
void io_loop_context_activate(struct ioloop_context *ctx)
{
struct ioloop_context_callback *cb;
i_assert(ctx->ioloop->cur_ctx == NULL);
ctx->ioloop->cur_ctx = ctx;
io_loop_context_push_global_events(ctx);
io_loop_context_ref(ctx);
array_foreach_modifiable(&ctx->callbacks, cb) {
i_assert(!cb->activated);
if (cb->activate != NULL) T_BEGIN {
cb->activate(cb->context);
} T_END;
cb->activated = TRUE;
}
}
void io_loop_context_deactivate(struct ioloop_context *ctx)
{
struct ioloop_context_callback *cb;
i_assert(ctx->ioloop->cur_ctx == ctx);
array_foreach_modifiable(&ctx->callbacks, cb) {
if (!cb->activated) {
/* we just added this callback. don't deactivate it
before it gets first activated. */
} else {
if (cb->deactivate != NULL) T_BEGIN {
cb->deactivate(cb->context);
} T_END;
cb->activated = FALSE;
}
}
ctx->ioloop->cur_ctx = NULL;
io_loop_context_pop_global_events(ctx);
io_loop_context_remove_deleted_callbacks(ctx);
io_loop_context_unref(&ctx);
}
void io_loop_context_switch(struct ioloop_context *ctx)
{
if (ctx->ioloop->cur_ctx != NULL) {
if (ctx->ioloop->cur_ctx == ctx)
return;
io_loop_context_deactivate(ctx->ioloop->cur_ctx);
/* deactivation may remove the cur_ctx */
if (ctx->ioloop->cur_ctx != NULL)
io_loop_context_unref(&ctx->ioloop->cur_ctx);
}
io_loop_context_activate(ctx);
}
struct ioloop_context *io_loop_get_current_context(struct ioloop *ioloop)
{
return ioloop->cur_ctx;
}
struct io *io_loop_move_io_to(struct ioloop *ioloop, struct io **_io)
{
struct io *old_io = *_io;
struct io_file *old_io_file, *new_io_file;
if (old_io == NULL)
return NULL;
i_assert((old_io->condition & IO_NOTIFY) == 0);
if (old_io->ioloop == ioloop)
return old_io;
old_io_file = (struct io_file *)old_io;
new_io_file = io_add_file(ioloop, old_io_file->fd,
old_io->condition, old_io->source_filename,
old_io->source_linenum,
old_io->callback, old_io->context);
if (old_io_file->istream != NULL) {
/* reference before io_remove() */
new_io_file->istream = old_io_file->istream;
i_stream_ref(new_io_file->istream);
}
if (old_io->pending)
io_set_pending(&new_io_file->io);
io_remove(_io);
if (new_io_file->istream != NULL) {
/* update istream io after it was removed with io_remove() */
i_stream_set_io(new_io_file->istream, &new_io_file->io);
}
return &new_io_file->io;
}
struct io *io_loop_move_io(struct io **_io)
{
return io_loop_move_io_to(current_ioloop, _io);
}
struct timeout *io_loop_move_timeout_to(struct ioloop *ioloop,
struct timeout **_timeout)
{
struct timeout *new_to, *old_to = *_timeout;
if (old_to == NULL || old_to->ioloop == ioloop)
return old_to;
new_to = timeout_copy(old_to, ioloop);
timeout_remove(_timeout);
return new_to;
}
struct timeout *io_loop_move_timeout(struct timeout **_timeout)
{
return io_loop_move_timeout_to(current_ioloop, _timeout);
}
bool io_loop_have_ios(struct ioloop *ioloop)
{
return ioloop->io_files != NULL;
}
bool io_loop_have_immediate_timeouts(struct ioloop *ioloop)
{
struct timeval tv;
return io_loop_get_wait_time(ioloop, &tv) == 0;
}
bool io_loop_is_empty(struct ioloop *ioloop)
{
return ioloop->io_files == NULL &&
priorityq_count(ioloop->timeouts) == 0 &&
array_count(&ioloop->timeouts_new) == 0;
}
uint64_t io_loop_get_wait_usecs(struct ioloop *ioloop)
{
return ioloop->ioloop_wait_usecs;
}
enum io_condition io_loop_find_fd_conditions(struct ioloop *ioloop, int fd)
{
enum io_condition conditions = 0;
struct io_file *io;
i_assert(fd >= 0);
for (io = ioloop->io_files; io != NULL; io = io->next) {
if (io->fd == fd)
conditions |= io->io.condition;
}
return conditions;
}
#undef io_wait_timer_add_to
struct io_wait_timer *
io_wait_timer_add_to(struct ioloop *ioloop, const char *source_filename,
unsigned int source_linenum)
{
struct io_wait_timer *timer;
timer = i_new(struct io_wait_timer, 1);
timer->ioloop = ioloop;
timer->source_filename = source_filename;
timer->source_linenum = source_linenum;
DLLIST_PREPEND(&ioloop->wait_timers, timer);
return timer;
}
#undef io_wait_timer_add
struct io_wait_timer *
io_wait_timer_add(const char *source_filename, unsigned int source_linenum)
{
return io_wait_timer_add_to(current_ioloop, source_filename,
source_linenum);
}
struct io_wait_timer *io_wait_timer_move_to(struct io_wait_timer **_timer,
struct ioloop *ioloop)
{
struct io_wait_timer *timer = *_timer;
*_timer = NULL;
DLLIST_REMOVE(&timer->ioloop->wait_timers, timer);
DLLIST_PREPEND(&ioloop->wait_timers, timer);
timer->ioloop = ioloop;
return timer;
}
struct io_wait_timer *io_wait_timer_move(struct io_wait_timer **_timer)
{
return io_wait_timer_move_to(_timer, current_ioloop);
}
void io_wait_timer_remove(struct io_wait_timer **_timer)
{
struct io_wait_timer *timer = *_timer;
*_timer = NULL;
DLLIST_REMOVE(&timer->ioloop->wait_timers, timer);
i_free(timer);
}
uint64_t io_wait_timer_get_usecs(struct io_wait_timer *timer)
{
return timer->usecs;
}
struct event *io_loop_get_active_global_root(void)
{
if (current_ioloop == NULL)
return NULL;
if (current_ioloop->cur_ctx == NULL)
return NULL;
return current_ioloop->cur_ctx->root_global_event;
}
dovecot-2.3.21.1/src/lib/imem.c 0000644 0000000 0000000 00000002654 14656633576 012754 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
pool_t default_pool = &static_system_pool;
void *i_malloc(size_t size)
{
return p_malloc(default_pool, size);
}
void *i_realloc(void *mem, size_t old_size, size_t new_size)
{
return p_realloc(default_pool, mem, old_size, new_size);
}
char *i_strdup(const char *str)
{
return p_strdup(default_pool, str);
}
void *i_memdup(const void *data, size_t size)
{
return p_memdup(default_pool, data, size);
}
char *i_strdup_empty(const char *str)
{
return p_strdup_empty(default_pool, str);
}
char *i_strdup_until(const void *str, const void *end)
{
return p_strdup_until(default_pool, str, end);
}
char *i_strndup(const void *str, size_t max_chars)
{
i_assert(str != NULL);
return p_strndup(default_pool, str, max_chars);
}
char *i_strdup_printf(const char *format, ...)
{
va_list args;
char *ret;
va_start(args, format);
ret = p_strdup_vprintf(default_pool, format, args);
va_end(args);
return ret;
}
char *i_strdup_vprintf(const char *format, va_list args)
{
return p_strdup_vprintf(default_pool, format, args);
}
char *i_strconcat(const char *str1, ...)
{
va_list args;
char *ret;
size_t len;
i_assert(str1 != NULL);
va_start(args, str1);
T_BEGIN {
const char *temp = vstrconcat(str1, args, &len);
t_buffer_alloc(len);
ret = p_malloc(default_pool, len);
memcpy(ret, temp, len);
} T_END;
va_end(args);
return ret;
}
dovecot-2.3.21.1/src/lib/test-lib.h 0000644 0000000 0000000 00000000303 14656633576 013542 0000000 0000000 #ifndef TEST_LIB
#define TEST_LIB
#include "lib.h"
#include "test-common.h"
#define TEST(x) TEST_DECL(x)
#define FATAL(x) FATAL_DECL(x)
#include "test-lib.inc"
#undef TEST
#undef FATAL
#endif
dovecot-2.3.21.1/src/lib/ostream-hash.c 0000644 0000000 0000000 00000002637 14656633576 014421 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "hash-method.h"
#include "ostream-private.h"
#include "ostream-hash.h"
struct hash_ostream {
struct ostream_private ostream;
const struct hash_method *method;
void *hash_context;
};
static ssize_t
o_stream_hash_sendv(struct ostream_private *stream,
const struct const_iovec *iov, unsigned int iov_count)
{
struct hash_ostream *hstream =
container_of(stream, struct hash_ostream, ostream);
unsigned int i;
size_t bytes_left, block_len;
ssize_t ret;
if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
o_stream_copy_error_from_parent(stream);
return -1;
}
if (ret > 0) {
bytes_left = ret;
for (i = 0; i < iov_count && bytes_left > 0; i++) {
block_len = iov[i].iov_len <= bytes_left ?
iov[i].iov_len : bytes_left;
hstream->method->loop(hstream->hash_context,
iov[i].iov_base, block_len);
bytes_left -= block_len;
}
}
stream->ostream.offset += ret;
return ret;
}
struct ostream *
o_stream_create_hash(struct ostream *output, const struct hash_method *method,
void *hash_context)
{
struct hash_ostream *hstream;
hstream = i_new(struct hash_ostream, 1);
hstream->ostream.sendv = o_stream_hash_sendv;
hstream->method = method;
hstream->hash_context = hash_context;
return o_stream_create(&hstream->ostream, output,
o_stream_get_fd(output));
}
dovecot-2.3.21.1/src/lib/istream-base64-decoder.c 0000644 0000000 0000000 00000010766 14656633576 016161 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "base64.h"
#include "hex-binary.h"
#include "istream-private.h"
#include "istream-base64.h"
struct base64_decoder_istream {
struct istream_private istream;
struct base64_decoder decoder;
};
static int i_stream_read_parent(struct istream_private *stream)
{
size_t size;
ssize_t ret;
size = i_stream_get_data_size(stream->parent);
if (size >= 4)
return 1;
/* we have less than one base64 block.
see if there is more data available. */
ret = i_stream_read_memarea(stream->parent);
if (ret <= 0) {
stream->istream.stream_errno = stream->parent->stream_errno;
return ret;
}
size = i_stream_get_data_size(stream->parent);
i_assert(size != 0);
return 1;
}
static int
i_stream_base64_try_decode_block(struct base64_decoder_istream *bstream)
{
struct istream_private *stream = &bstream->istream;
const unsigned char *data;
size_t size, avail, pos;
buffer_t buf;
data = i_stream_get_data(stream->parent, &size);
if (size == 0)
return 0;
if (!i_stream_try_alloc(stream, (size+3)/4*3, &avail))
return -2;
buffer_create_from_data(&buf, stream->w_buffer + stream->pos, avail);
if (base64_decode_more(&bstream->decoder, data, size, &pos, &buf) < 0) {
io_stream_set_error(&stream->iostream,
"Invalid base64 data: 0x%s",
binary_to_hex(data+pos, I_MIN(size-pos, 8)));
stream->istream.stream_errno = EINVAL;
return -1;
}
stream->pos += buf.used;
i_stream_skip(stream->parent, pos);
return pos > 0 ? 1 : 0;
}
static void
i_stream_base64_finish_decode(struct base64_decoder_istream *bstream)
{
struct istream_private *stream = &bstream->istream;
i_assert(i_stream_get_data_size(stream->parent) == 0);
if (base64_decode_finish(&bstream->decoder) < 0) {
io_stream_set_error(&stream->iostream,
"Base64 data ends prematurely");
stream->istream.stream_errno = EPIPE;
}
}
static ssize_t i_stream_base64_decoder_read(struct istream_private *stream)
{
struct base64_decoder_istream *bstream =
container_of(stream, struct base64_decoder_istream, istream);
size_t pre_count, post_count;
int ret;
if (base64_decode_is_finished(&bstream->decoder)) {
stream->istream.eof = TRUE;
return -1;
}
do {
ret = i_stream_read_parent(stream);
if (ret == 0)
return 0;
if (ret < 0 && ret != -2) {
if (stream->istream.stream_errno != 0)
return -1;
if (i_stream_get_data_size(stream->parent) == 0) {
i_stream_base64_finish_decode(bstream);
stream->istream.eof = TRUE;
return -1;
}
}
/* encode as many blocks as fits into destination buffer */
pre_count = stream->pos - stream->skip;
while ((ret = i_stream_base64_try_decode_block(bstream)) > 0) ;
post_count = stream->pos - stream->skip;
} while (ret == 0 && pre_count == post_count);
if (ret < 0 && pre_count == post_count)
return ret;
i_assert(post_count > pre_count);
return post_count - pre_count;
}
static void
i_stream_base64_decoder_seek(struct istream_private *stream,
uoff_t v_offset, bool mark)
{
struct base64_decoder_istream *bstream =
container_of(stream, struct base64_decoder_istream, istream);
if (v_offset < stream->istream.v_offset) {
/* seeking backwards - go back to beginning and seek
forward from there. */
stream->parent_expected_offset = stream->parent_start_offset;
stream->skip = stream->pos = 0;
stream->istream.v_offset = 0;
i_stream_seek(stream->parent, 0);
base64_decode_reset(&bstream->decoder);
}
i_stream_default_seek_nonseekable(stream, v_offset, mark);
}
static struct istream *
i_stream_create_base64_decoder_common(const struct base64_scheme *b64,
struct istream *input)
{
struct base64_decoder_istream *bstream;
bstream = i_new(struct base64_decoder_istream, 1);
bstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
bstream->istream.read = i_stream_base64_decoder_read;
bstream->istream.seek = i_stream_base64_decoder_seek;
bstream->istream.istream.readable_fd = FALSE;
bstream->istream.istream.blocking = input->blocking;
bstream->istream.istream.seekable = input->seekable;
base64_decode_init(&bstream->decoder, b64, 0);
return i_stream_create(&bstream->istream, input,
i_stream_get_fd(input), 0);
}
struct istream *
i_stream_create_base64_decoder(struct istream *input)
{
return i_stream_create_base64_decoder_common(&base64_scheme, input);
}
struct istream *
i_stream_create_base64url_decoder(struct istream *input)
{
return i_stream_create_base64_decoder_common(&base64url_scheme, input);
}
dovecot-2.3.21.1/src/lib/guid.h 0000644 0000000 0000000 00000003264 14656633576 012760 0000000 0000000 #ifndef GUID_H
#define GUID_H
#define GUID_128_SIZE 16
typedef uint8_t guid_128_t[GUID_128_SIZE];
#define GUID_128_HOST_HASH_SIZE 4
ARRAY_DEFINE_TYPE(guid_128_t, guid_128_t);
enum uuid_format {
FORMAT_RECORD,
FORMAT_COMPACT,
FORMAT_MICROSOFT,
};
/* Generate a GUID (contains host name) */
const char *guid_generate(void);
/* Generate 128 bit GUID */
void guid_128_generate(guid_128_t guid_r);
/* Returns TRUE if GUID is empty (not set / unknown). */
bool guid_128_is_empty(const guid_128_t guid) ATTR_PURE;
static inline void guid_128_empty(guid_128_t guid)
{
memset(guid, 0, GUID_128_SIZE);
}
/* Returns TRUE if two GUIDs are equal. */
bool guid_128_equals(const guid_128_t guid1, const guid_128_t guid2) ATTR_PURE;
/* Copy GUID */
static inline void guid_128_copy(guid_128_t dest, const guid_128_t src)
{
memcpy(dest, src, GUID_128_SIZE);
}
/* Returns GUID as a hex string. */
const char *guid_128_to_string(const guid_128_t guid);
/* Parse GUID from a string. Returns 0 if ok, -1 if GUID isn't valid. */
int guid_128_from_string(const char *str, guid_128_t guid_r);
/* Returns GUID as a UUID hex string. */
const char *guid_128_to_uuid_string(const guid_128_t guid, enum uuid_format format);
/* Parse GUID from a UUID string. Returns 0 if ok, -1 if UUID isn't valid. */
int guid_128_from_uuid_string(const char *str, guid_128_t guid_r);
/* guid_128 hash/cmp functions for hash.h */
unsigned int guid_128_hash(const guid_128_t guid) ATTR_PURE;
int guid_128_cmp(const guid_128_t guid1, const guid_128_t guid2) ATTR_PURE;
/* Return the hash of host used by guid_128_generate(). */
void guid_128_host_hash_get(const char *host,
unsigned char hash_r[STATIC_ARRAY GUID_128_HOST_HASH_SIZE]);
#endif
dovecot-2.3.21.1/src/lib/str-find.h 0000644 0000000 0000000 00000001404 14656633576 013550 0000000 0000000 #ifndef STR_FIND_H
#define STR_FIND_H
struct str_find_context;
struct str_find_context *str_find_init(pool_t pool, const char *key);
void str_find_deinit(struct str_find_context **ctx);
/* Returns TRUE if key is found. It's possible to send the data in arbitrary
blocks and have the key still match. */
bool str_find_more(struct str_find_context *ctx,
const unsigned char *data, size_t size);
/* After str_find_more() has returned TRUE, this function returns the end
position in the previous data block where the key had matched. */
size_t str_find_get_match_end_pos(struct str_find_context *ctx);
/* Reset input data. The next str_find_more() call won't try to match the key
to earlier data. */
void str_find_reset(struct str_find_context *ctx);
#endif
dovecot-2.3.21.1/src/lib/test-base32.c 0000644 0000000 0000000 00000011275 14656633576 014060 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "base32.h"
static void test_base32_encode(void)
{
static const char *input[] = {
"toedeledokie!!",
"bye bye world",
"hoeveel onzin kun je testen?????",
"c'est pas vrai! ",
"dit is het einde van deze test"
};
static const char *output[] = {
"ORXWKZDFNRSWI33LNFSSCII=",
"MJ4WKIDCPFSSA53POJWGI===",
"NBXWK5TFMVWCA33OPJUW4IDLOVXCA2TFEB2GK43UMVXD6PZ7H47Q====",
"MMTWK43UEBYGC4ZAOZZGC2JBEA======",
"MRUXIIDJOMQGQZLUEBSWS3TEMUQHMYLOEBSGK6TFEB2GK43U"
};
string_t *str;
unsigned int i;
test_begin("base32_encode() with padding");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(input); i++) {
str_truncate(str, 0);
base32_encode(TRUE, input[i], strlen(input[i]), str);
test_assert(strcmp(output[i], str_c(str)) == 0);
}
test_end();
test_begin("base32_encode() no padding");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(input); i++) {
const char *p = strchr(output[i], '=');
size_t len;
if (p == NULL)
len = strlen(output[i]);
else
len = (size_t)(p - output[i]);
str_truncate(str, 0);
base32_encode(FALSE, input[i], strlen(input[i]), str);
test_assert(strncmp(output[i], str_c(str), len) == 0);
}
test_end();
}
static void test_base32hex_encode(void)
{
static const char *input[] = {
"toedeledokie!!",
"bye bye world",
"hoeveel onzin kun je testen?????",
"c'est pas vrai! ",
"dit is het einde van deze test"
};
static const char *output[] = {
"EHNMAP35DHIM8RRBD5II288=",
"C9SMA832F5II0TRFE9M68===",
"D1NMATJ5CLM20RREF9KMS83BELN20QJ541Q6ASRKCLN3UFPV7SVG====",
"CCJMASRK41O62SP0EPP62Q9140======",
"CHKN8839ECG6GPBK41IMIRJ4CKG7COBE41I6AUJ541Q6ASRK"
};
string_t *str;
unsigned int i;
test_begin("base32hex_encode() with padding");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(input); i++) {
str_truncate(str, 0);
base32hex_encode(TRUE, input[i], strlen(input[i]), str);
test_assert(strcmp(output[i], str_c(str)) == 0);
}
test_end();
test_begin("base32hex_encode() no padding");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(input); i++) {
const char *p = strchr(output[i], '=');
size_t len;
if (p == NULL)
len = strlen(output[i]);
else
len = (size_t)(p - output[i]);
str_truncate(str, 0);
base32hex_encode(FALSE, input[i], strlen(input[i]), str);
test_assert(strncmp(output[i], str_c(str), len) == 0);
}
test_end();
}
struct test_base32_decode_output {
const char *text;
int ret;
unsigned int src_pos;
};
static void test_base32_decode(void)
{
static const char *input[] = {
"ORXWKZDFNRSWI33LNFSSCII=",
"MJ4WKIDCPFSSA53POJWGI===",
"NBXWK5TFMVWCA33OPJUW4IDLOVXCA2TFEB2GK43UMVXD6PZ7H47Q====",
"MMTWK43UEBYGC4ZAOZZGC2JBEA======",
"MRUXIIDJOMQGQZLUEBSWS3TEMUQHMYLOEBSGK6TFEB2GK43U"
};
static const struct test_base32_decode_output output[] = {
{ "toedeledokie!!", 0, 24 },
{ "bye bye world", 0, 24 },
{ "hoeveel onzin kun je testen?????", 0, 56 },
{ "c'est pas vrai! ", 0, 32 },
{ "dit is het einde van deze test", 1, 48 },
};
string_t *str;
unsigned int i;
size_t src_pos;
int ret;
test_begin("base32_decode()");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(input); i++) {
str_truncate(str, 0);
src_pos = 0;
ret = base32_decode(input[i], strlen(input[i]), &src_pos, str);
test_assert(output[i].ret == ret &&
strcmp(output[i].text, str_c(str)) == 0 &&
(src_pos == output[i].src_pos ||
(output[i].src_pos == UINT_MAX &&
src_pos == strlen(input[i]))));
}
test_end();
}
static void test_base32_random(void)
{
string_t *str, *dest;
unsigned char buf[10];
unsigned int i, j, max;
str = t_str_new(256);
dest = t_str_new(256);
test_begin("padded base32 encode/decode with random input");
for (i = 0; i < 1000; i++) {
max = i_rand_limit(sizeof(buf));
for (j = 0; j < max; j++)
buf[j] = i_rand_uchar();
str_truncate(str, 0);
str_truncate(dest, 0);
base32_encode(TRUE, buf, max, str);
test_assert(base32_decode(str_data(str), str_len(str), NULL, dest) >= 0);
test_assert(str_len(dest) == max &&
memcmp(buf, str_data(dest), max) == 0);
}
test_end();
test_begin("padded base32hex encode/decode with random input");
for (i = 0; i < 1000; i++) {
max = i_rand_limit(sizeof(buf));
for (j = 0; j < max; j++)
buf[j] = i_rand_uchar();
str_truncate(str, 0);
str_truncate(dest, 0);
base32hex_encode(TRUE, buf, max, str);
test_assert(base32hex_decode(str_data(str), str_len(str), NULL, dest) >= 0);
test_assert(str_len(dest) == max &&
memcmp(buf, str_data(dest), max) == 0);
}
test_end();
}
void test_base32(void)
{
test_base32_encode();
test_base32hex_encode();
test_base32_decode();
test_base32_random();
}
dovecot-2.3.21.1/src/lib/failures.c 0000644 0000000 0000000 00000061471 14656633576 013641 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "str.h"
#include "hostpid.h"
#include "net.h"
#include "process-title.h"
#include "lib-signals.h"
#include "backtrace-string.h"
#include "printf-format-fix.h"
#include "write-full.h"
#include "time-util.h"
#include "failures-private.h"
#include
#include
#include
#include
#include
#define LOG_TYPE_FLAG_PREFIX_LEN 0x40
#define LOG_TYPE_FLAG_DISABLE_LOG_PREFIX 0x80
const char *failure_log_type_prefixes[LOG_TYPE_COUNT] = {
"Debug: ",
"Info: ",
"Warning: ",
"Error: ",
"Fatal: ",
"Panic: "
};
const char *failure_log_type_names[LOG_TYPE_COUNT] = {
"debug", "info", "warning", "error", "fatal", "panic"
};
static int log_fd_write(int fd, const unsigned char *data, size_t len);
static void error_handler_real(const struct failure_context *ctx,
const char *format, va_list args);
/* Initialize working defaults */
static failure_callback_t *fatal_handler ATTR_NORETURN =
default_fatal_handler;
static failure_callback_t *error_handler = default_error_handler;
static failure_callback_t *info_handler = default_error_handler;
static failure_callback_t *debug_handler = default_error_handler;
static void (*failure_exit_callback)(int *) = NULL;
static struct failure_context failure_ctx_debug = { .type = LOG_TYPE_DEBUG };
static struct failure_context failure_ctx_info = { .type = LOG_TYPE_INFO };
static struct failure_context failure_ctx_warning = { .type = LOG_TYPE_WARNING };
static struct failure_context failure_ctx_error = { .type = LOG_TYPE_ERROR };
static int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO,
log_debug_fd = STDERR_FILENO;
static char *log_prefix = NULL;
static char *log_stamp_format = NULL, *log_stamp_format_suffix = NULL;
static bool failure_ignore_errors = FALSE, log_prefix_sent = FALSE;
static bool coredump_on_error = FALSE;
static void log_timestamp_add(const struct failure_context *ctx, string_t *str);
static void log_prefix_add(const struct failure_context *ctx, string_t *str);
static int i_failure_send_option_forced(const char *key, const char *value);
static int internal_send_split(string_t *full_str, size_t prefix_len);
static string_t * ATTR_FORMAT(3, 0) default_format(const struct failure_context *ctx,
size_t *prefix_len_r ATTR_UNUSED,
const char *format,
va_list args)
{
string_t *str = t_str_new(256);
log_timestamp_add(ctx, str);
log_prefix_add(ctx, str);
/* make sure there's no %n in there and fix %m */
str_vprintfa(str, printf_format_fix(format), args);
return str;
}
static int default_write(enum log_type type, string_t *data, size_t prefix_len ATTR_UNUSED)
{
int fd;
switch (type) {
case LOG_TYPE_DEBUG:
fd = log_debug_fd;
break;
case LOG_TYPE_INFO:
fd = log_info_fd;
break;
default:
fd = log_fd;
break;
}
str_append_c(data, '\n');
return log_fd_write(fd, str_data(data), str_len(data));
}
static void default_on_handler_failure(const struct failure_context *ctx)
{
const char *log_type = "info";
switch (ctx->type) {
case LOG_TYPE_DEBUG:
log_type = "debug";
/* fall through */
case LOG_TYPE_INFO:
/* we failed to log to info/debug log, try to log the
write error to error log - maybe that'll work. */
i_fatal_status(FATAL_LOGWRITE, "write() failed to %s log: %m",
log_type);
break;
default:
failure_exit(FATAL_LOGWRITE);
break;
}
}
static void default_post_handler(const struct failure_context *ctx)
{
if (ctx->type == LOG_TYPE_ERROR && coredump_on_error)
abort();
}
static string_t * ATTR_FORMAT(3, 0) syslog_format(const struct failure_context *ctx,
size_t *prefix_len_r ATTR_UNUSED,
const char *format,
va_list args)
{
string_t *str = t_str_new(128);
if (ctx->type == LOG_TYPE_INFO) {
if (ctx->log_prefix != NULL)
str_append(str, ctx->log_prefix);
else if (log_prefix != NULL)
str_append(str, log_prefix);
} else {
log_prefix_add(ctx, str);
}
str_vprintfa(str, format, args);
return str;
}
static int syslog_write(enum log_type type, string_t *data, size_t prefix_len ATTR_UNUSED)
{
int level = LOG_ERR;
switch (type) {
case LOG_TYPE_DEBUG:
level = LOG_DEBUG;
break;
case LOG_TYPE_INFO:
level = LOG_INFO;
break;
case LOG_TYPE_WARNING:
level = LOG_WARNING;
break;
case LOG_TYPE_ERROR:
level = LOG_ERR;
break;
case LOG_TYPE_FATAL:
case LOG_TYPE_PANIC:
level = LOG_CRIT;
break;
case LOG_TYPE_COUNT:
case LOG_TYPE_OPTION:
i_unreached();
}
syslog(level, "%s", str_c(data));
return 0;
}
static void syslog_on_handler_failure(const struct failure_context *ctx ATTR_UNUSED)
{
failure_exit(FATAL_LOGERROR);
}
static void syslog_post_handler(const struct failure_context *ctx ATTR_UNUSED)
{
}
static string_t * ATTR_FORMAT(3, 0) internal_format(const struct failure_context *ctx,
size_t *prefix_len_r,
const char *format,
va_list args)
{
string_t *str;
unsigned char log_type = ctx->type + 1;
if (ctx->log_prefix != NULL) {
log_type |= LOG_TYPE_FLAG_DISABLE_LOG_PREFIX;
if (ctx->log_prefix_type_pos != 0)
log_type |= LOG_TYPE_FLAG_PREFIX_LEN;
} else if (!log_prefix_sent && log_prefix != NULL) {
if (i_failure_send_option_forced("prefix", log_prefix) < 0) {
/* Failed to write log prefix. The log message writing
would likely fail as well, but don't even try since
the log prefix would be wrong. */
return NULL;
}
log_prefix_sent = TRUE;
}
str = t_str_new(128);
str_printfa(str, "\001%c%s ", log_type, my_pid);
if ((log_type & LOG_TYPE_FLAG_PREFIX_LEN) != 0)
str_printfa(str, "%u ", ctx->log_prefix_type_pos);
if (ctx->log_prefix != NULL)
str_append(str, ctx->log_prefix);
*prefix_len_r = str_len(str);
str_vprintfa(str, format, args);
return str;
}
static int internal_write(enum log_type type ATTR_UNUSED, string_t *data, size_t prefix_len)
{
if (str_len(data)+1 <= PIPE_BUF) {
str_append_c(data, '\n');
return log_fd_write(STDERR_FILENO,
str_data(data), str_len(data));
}
return internal_send_split(data, prefix_len);
}
static void internal_on_handler_failure(const struct failure_context *ctx ATTR_UNUSED)
{
failure_exit(FATAL_LOGERROR);
}
static void internal_post_handler(const struct failure_context *ctx ATTR_UNUSED)
{
}
static struct failure_handler_vfuncs default_handler_vfuncs = {
.write = &default_write,
.format = &default_format,
.on_handler_failure = &default_on_handler_failure,
.post_handler = &default_post_handler
};
static struct failure_handler_vfuncs syslog_handler_vfuncs = {
.write = &syslog_write,
.format = &syslog_format,
.on_handler_failure = &syslog_on_handler_failure,
.post_handler = &syslog_post_handler
};
static struct failure_handler_vfuncs internal_handler_vfuncs = {
.write = &internal_write,
.format = &internal_format,
.on_handler_failure = &internal_on_handler_failure,
.post_handler = &internal_post_handler
};
struct failure_handler_config failure_handler = { .fatal_err_reset = FATAL_LOGWRITE,
.v = &default_handler_vfuncs };
static int common_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
static int recursed = 0;
int ret;
size_t prefix_len = 0;
if (recursed >= 2) {
/* we're being called from some signal handler or we ran
out of memory */
return -1;
}
recursed++;
T_BEGIN {
string_t *str = failure_handler.v->format(ctx, &prefix_len, format, args);
ret = str == NULL ? -1 :
failure_handler.v->write(ctx->type, str, prefix_len);
} T_END;
if (ret < 0 && failure_ignore_errors)
ret = 0;
recursed--;
return ret;
}
static void error_handler_real(const struct failure_context *ctx,
const char *format, va_list args)
{
if (common_handler(ctx, format, args) < 0)
failure_handler.v->on_handler_failure(ctx);
failure_handler.v->post_handler(ctx);
}
static void ATTR_FORMAT(2, 0)
i_internal_error_handler(const struct failure_context *ctx,
const char *format, va_list args);
/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
static const char *
get_log_stamp_format(const char *format_arg, unsigned int timestamp_usecs)
ATTR_FORMAT_ARG(1);
static const char *get_log_stamp_format(const char *format_arg ATTR_UNUSED,
unsigned int timestamp_usecs)
{
if (log_stamp_format_suffix == NULL)
return log_stamp_format;
return t_strdup_printf("%s%06u%s", log_stamp_format,
timestamp_usecs, log_stamp_format_suffix);
}
void failure_exit(int status)
{
static bool recursed = FALSE;
if (failure_exit_callback != NULL && !recursed) {
recursed = TRUE;
failure_exit_callback(&status);
}
lib_exit(status);
}
static void log_timestamp_add(const struct failure_context *ctx, string_t *str)
{
const struct tm *tm = ctx->timestamp;
char buf[256];
struct timeval now;
if (log_stamp_format != NULL) {
if (tm == NULL) {
i_gettimeofday(&now);
tm = localtime(&now.tv_sec);
} else {
now.tv_usec = ctx->timestamp_usecs;
}
if (strftime(buf, sizeof(buf),
get_log_stamp_format("unused", now.tv_usec), tm) > 0)
str_append(str, buf);
}
}
static void log_prefix_add(const struct failure_context *ctx, string_t *str)
{
if (ctx->log_prefix == NULL) {
/* use global log prefix */
if (log_prefix != NULL)
str_append(str, log_prefix);
str_append(str, failure_log_type_prefixes[ctx->type]);
} else if (ctx->log_prefix_type_pos == 0) {
str_append(str, ctx->log_prefix);
str_append(str, failure_log_type_prefixes[ctx->type]);
} else {
i_assert(ctx->log_prefix_type_pos <= strlen(ctx->log_prefix));
str_append_data(str, ctx->log_prefix, ctx->log_prefix_type_pos);
str_append(str, failure_log_type_prefixes[ctx->type]);
str_append(str, ctx->log_prefix + ctx->log_prefix_type_pos);
}
}
static void fd_wait_writable(int fd)
{
struct pollfd pfd = {
.fd = fd,
.events = POLLOUT | POLLERR | POLLHUP | POLLNVAL,
};
/* Use poll() instead of ioloop, because we don't want to recurse back
to log writing in case something fails. */
if (poll(&pfd, 1, -1) < 0 && errno != EINTR) {
/* Unexpected error. We're already blocking on log writes,
so we can't log it. */
abort();
}
}
static int log_fd_write(int fd, const unsigned char *data, size_t len)
{
ssize_t ret;
unsigned int prev_signal_term_counter = signal_term_counter;
unsigned int terminal_eintr_count = 0;
const char *old_title = NULL;
bool failed = FALSE, process_title_changed = FALSE;
while (!failed &&
(ret = write(fd, data, len)) != (ssize_t)len) {
if (ret > 0) {
/* some was written, continue.. */
data += ret;
len -= ret;
continue;
}
if (ret == 0) {
/* out of disk space? */
errno = ENOSPC;
failed = TRUE;
break;
}
switch (errno) {
case EAGAIN: {
/* Log fd is nonblocking - wait until we can write more.
Indicate in process title that the process is waiting
because it's waiting on the log.
Remember that the log fd is shared across processes,
which also means the log fd flags are shared. So if
one process changes the O_NONBLOCK flag for a log fd,
all the processes see the change. To avoid problems,
we'll wait using poll() instead of changing the
O_NONBLOCK flag. */
if (!process_title_changed) {
const char *title;
process_title_changed = TRUE;
old_title = t_strdup(process_title_get());
if (old_title == NULL)
title = "[blocking on log write]";
else
title = t_strdup_printf("%s - [blocking on log write]",
old_title);
process_title_set(title);
}
fd_wait_writable(fd);
break;
}
case EINTR:
if (prev_signal_term_counter == signal_term_counter) {
/* non-terminal signal. ignore. */
} else if (terminal_eintr_count++ == 0) {
/* we'd rather not die in the middle of
writing to log. try again once more */
} else {
/* received two terminal signals.
someone wants us dead. */
failed = TRUE;
break;
}
break;
default:
failed = TRUE;
break;
}
prev_signal_term_counter = signal_term_counter;
}
if (process_title_changed)
process_title_set(old_title);
return failed ? -1 : 0;
}
static void ATTR_NORETURN
default_fatal_finish(enum log_type type, int status)
{
const char *backtrace;
static int recursed = 0;
recursed++;
if ((type == LOG_TYPE_PANIC || status == FATAL_OUTOFMEM) &&
recursed == 1) {
if (backtrace_get(&backtrace) == 0)
i_error("Raw backtrace: %s", backtrace);
}
recursed--;
if (type == LOG_TYPE_PANIC || getenv("CORE_ERROR") != NULL ||
(status == FATAL_OUTOFMEM && getenv("CORE_OUTOFMEM") != NULL))
abort();
else
failure_exit(status);
}
static void ATTR_NORETURN fatal_handler_real(const struct failure_context *ctx,
const char *format, va_list args)
{
int status = ctx->exit_status;
if (common_handler(ctx, format, args) < 0 &&
status == FATAL_DEFAULT)
status = failure_handler.fatal_err_reset;
default_fatal_finish(ctx->type, status);
}
void default_fatal_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
failure_handler.v = &default_handler_vfuncs;
failure_handler.fatal_err_reset = FATAL_LOGWRITE;
fatal_handler_real(ctx, format, args);
}
void default_error_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
failure_handler.v = &default_handler_vfuncs;
failure_handler.fatal_err_reset = FATAL_LOGWRITE;
error_handler_real(ctx, format, args);
}
void i_log_type(const struct failure_context *ctx, const char *format, ...)
{
va_list args;
va_start(args, format);
i_log_typev(ctx, format, args);
va_end(args);
}
void i_log_typev(const struct failure_context *ctx, const char *format,
va_list args)
{
switch (ctx->type) {
case LOG_TYPE_DEBUG:
debug_handler(ctx, format, args);
break;
case LOG_TYPE_INFO:
info_handler(ctx, format, args);
break;
default:
error_handler(ctx, format, args);
}
}
void i_panic(const char *format, ...)
{
struct failure_context ctx;
va_list args;
lib_set_clean_exit(TRUE);
i_zero(&ctx);
ctx.type = LOG_TYPE_PANIC;
va_start(args, format);
fatal_handler(&ctx, format, args);
i_unreached();
/*va_end(args);*/
}
void i_fatal(const char *format, ...)
{
struct failure_context ctx;
va_list args;
lib_set_clean_exit(TRUE);
i_zero(&ctx);
ctx.type = LOG_TYPE_FATAL;
ctx.exit_status = FATAL_DEFAULT;
va_start(args, format);
fatal_handler(&ctx, format, args);
i_unreached();
/*va_end(args);*/
}
void i_fatal_status(int status, const char *format, ...)
{
struct failure_context ctx;
va_list args;
lib_set_clean_exit(TRUE);
i_zero(&ctx);
ctx.type = LOG_TYPE_FATAL;
ctx.exit_status = status;
va_start(args, format);
fatal_handler(&ctx, format, args);
i_unreached();
/*va_end(args);*/
}
void i_error(const char *format, ...)
{
int old_errno = errno;
va_list args;
va_start(args, format);
error_handler(&failure_ctx_error, format, args);
va_end(args);
errno = old_errno;
}
void i_warning(const char *format, ...)
{
int old_errno = errno;
va_list args;
va_start(args, format);
error_handler(&failure_ctx_warning, format, args);
va_end(args);
errno = old_errno;
}
void i_info(const char *format, ...)
{
int old_errno = errno;
va_list args;
va_start(args, format);
info_handler(&failure_ctx_info, format, args);
va_end(args);
errno = old_errno;
}
void i_debug(const char *format, ...)
{
int old_errno = errno;
va_list args;
va_start(args, format);
debug_handler(&failure_ctx_debug, format, args);
va_end(args);
errno = old_errno;
}
void i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN)
{
fatal_handler = callback;
}
void i_set_error_handler(failure_callback_t *callback)
{
coredump_on_error = getenv("CORE_ERROR") != NULL;
error_handler = callback;
}
void i_set_info_handler(failure_callback_t *callback)
{
info_handler = callback;
}
void i_set_debug_handler(failure_callback_t *callback)
{
debug_handler = callback;
}
void i_get_failure_handlers(failure_callback_t **fatal_callback_r,
failure_callback_t **error_callback_r,
failure_callback_t **info_callback_r,
failure_callback_t **debug_callback_r)
{
*fatal_callback_r = fatal_handler;
*error_callback_r = error_handler;
*info_callback_r = info_handler;
*debug_callback_r = debug_handler;
}
void i_syslog_fatal_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
failure_handler.v = &syslog_handler_vfuncs;
failure_handler.fatal_err_reset = FATAL_LOGERROR;
fatal_handler_real(ctx, format, args);
}
void i_syslog_error_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
failure_handler.v = &syslog_handler_vfuncs;
failure_handler.fatal_err_reset = FATAL_LOGERROR;
error_handler_real(ctx, format, args);
}
void i_set_failure_syslog(const char *ident, int options, int facility)
{
openlog(ident, options, facility);
i_set_fatal_handler(i_syslog_fatal_handler);
i_set_error_handler(i_syslog_error_handler);
i_set_info_handler(i_syslog_error_handler);
i_set_debug_handler(i_syslog_error_handler);
}
static void open_log_file(int *fd, const char *path)
{
const char *str;
if (*fd != STDERR_FILENO) {
if (close(*fd) < 0) {
str = t_strdup_printf("close(%d) failed: %m\n", *fd);
(void)write_full(STDERR_FILENO, str, strlen(str));
}
}
if (path == NULL || strcmp(path, "/dev/stderr") == 0)
*fd = STDERR_FILENO;
else {
*fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600);
if (*fd == -1) {
*fd = STDERR_FILENO;
str = t_strdup_printf("Can't open log file %s: %m\n",
path);
(void)write_full(STDERR_FILENO, str, strlen(str));
if (fd == &log_fd)
failure_exit(FATAL_LOGOPEN);
else
i_fatal_status(FATAL_LOGOPEN, "%s", str);
}
fd_close_on_exec(*fd, TRUE);
}
}
void i_set_failure_file(const char *path, const char *prefix)
{
i_set_failure_prefix("%s", prefix);
if (log_info_fd != STDERR_FILENO && log_info_fd != log_fd) {
if (close(log_info_fd) < 0)
i_error("close(%d) failed: %m", log_info_fd);
}
if (log_debug_fd != STDERR_FILENO && log_debug_fd != log_info_fd &&
log_debug_fd != log_fd) {
if (close(log_debug_fd) < 0)
i_error("close(%d) failed: %m", log_debug_fd);
}
open_log_file(&log_fd, path);
/* if info/debug logs are elsewhere, i_set_info/debug_file()
overrides these later. */
log_info_fd = log_fd;
log_debug_fd = log_fd;
i_set_fatal_handler(default_fatal_handler);
i_set_error_handler(default_error_handler);
i_set_info_handler(default_error_handler);
i_set_debug_handler(default_error_handler);
}
static int i_failure_send_option_forced(const char *key, const char *value)
{
const char *str;
str = t_strdup_printf("\001%c%s %s=%s\n", LOG_TYPE_OPTION+1,
my_pid, key, value);
return log_fd_write(STDERR_FILENO, (const unsigned char *)str,
strlen(str));
}
static void i_failure_send_option(const char *key, const char *value)
{
if (error_handler == i_internal_error_handler)
(void)i_failure_send_option_forced(key, value);
}
void i_set_failure_prefix(const char *prefix_fmt, ...)
{
va_list args;
va_start(args, prefix_fmt);
i_free(log_prefix);
log_prefix = i_strdup_vprintf(prefix_fmt, args);
va_end(args);
log_prefix_sent = FALSE;
}
void i_unset_failure_prefix(void)
{
i_free(log_prefix);
log_prefix = i_strdup("");
log_prefix_sent = FALSE;
}
const char *i_get_failure_prefix(void)
{
return log_prefix != NULL ? log_prefix : "";
}
static int internal_send_split(string_t *full_str, size_t prefix_len)
{
/* This function splits the log line into PIPE_BUF sized blocks, so
the log process doesn't see partial lines. The log prefix is
repeated for each sent line. However, if the log prefix is
excessively long, we're still going to send the log lines even
if they are longer than PIPE_BUF. LINE_MIN_TEXT_LEN controls the
minimum number of bytes we're going to send of the actual log line
regardless of the log prefix length. (Alternative solution could be
to just forcibly split the line to PIPE_BUF length blocks without
repeating the log prefix for subsequent lines.) */
#define LINE_MIN_TEXT_LEN 128
#if LINE_MIN_TEXT_LEN >= PIPE_BUF
# error LINE_MIN_TEXT_LEN too large
#endif
string_t *str;
size_t max_text_len, pos = prefix_len;
str = t_str_new(PIPE_BUF);
str_append_data(str, str_data(full_str), prefix_len);
if (prefix_len < PIPE_BUF) {
max_text_len = I_MAX(PIPE_BUF - prefix_len - 1,
LINE_MIN_TEXT_LEN);
} else {
max_text_len = LINE_MIN_TEXT_LEN;
}
while (pos < str_len(full_str)) {
str_truncate(str, prefix_len);
str_append_max(str, str_c(full_str) + pos, max_text_len);
str_append_c(str, '\n');
if (log_fd_write(STDERR_FILENO,
str_data(str), str_len(str)) < 0)
return -1;
pos += max_text_len;
}
return 0;
}
static bool line_parse_prefix(const char *line, enum log_type *log_type_r,
bool *replace_prefix_r, bool *have_prefix_len_r)
{
if (*line != 1)
return FALSE;
unsigned char log_type = (line[1] & 0x3f);
if (log_type == '\0') {
i_warning("Broken log line follows (type=NUL)");
return FALSE;
}
log_type--;
if (log_type > LOG_TYPE_OPTION) {
i_warning("Broken log line follows (type=%d)", log_type);
return FALSE;
}
*log_type_r = log_type;
*replace_prefix_r = (line[1] & LOG_TYPE_FLAG_DISABLE_LOG_PREFIX) != 0;
*have_prefix_len_r = (line[1] & LOG_TYPE_FLAG_PREFIX_LEN) != 0;
return TRUE;
}
void i_failure_parse_line(const char *line, struct failure_line *failure)
{
bool have_prefix_len = FALSE;
i_zero(failure);
if (!line_parse_prefix(line, &failure->log_type,
&failure->disable_log_prefix,
&have_prefix_len)) {
failure->log_type = LOG_TYPE_ERROR;
failure->text = line;
return;
}
line += 2;
failure->text = line;
while (*line >= '0' && *line <= '9') {
failure->pid = failure->pid*10 + (*line - '0');
line++;
}
if (*line != ' ') {
/* some old protocol? */
failure->pid = 0;
return;
}
line++;
if (have_prefix_len) {
if (str_parse_uint(line, &failure->log_prefix_len, &line) < 0 ||
line[0] != ' ') {
/* unexpected, but ignore */
} else {
line++;
if (failure->log_prefix_len > strlen(line)) {
/* invalid */
failure->log_prefix_len = 0;
}
}
}
failure->text = line;
}
static void ATTR_NORETURN ATTR_FORMAT(2, 0)
i_internal_fatal_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
failure_handler.v = &internal_handler_vfuncs;
failure_handler.fatal_err_reset = FATAL_LOGERROR;
fatal_handler_real(ctx, format, args);
}
static void
i_internal_error_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
failure_handler.v = &internal_handler_vfuncs;
failure_handler.fatal_err_reset = FATAL_LOGERROR;
error_handler_real(ctx, format, args);
}
void i_set_failure_internal(void)
{
fd_set_nonblock(STDERR_FILENO, TRUE);
i_set_fatal_handler(i_internal_fatal_handler);
i_set_error_handler(i_internal_error_handler);
i_set_info_handler(i_internal_error_handler);
i_set_debug_handler(i_internal_error_handler);
}
bool i_failure_handler_is_internal(failure_callback_t *const callback)
{
return callback == i_internal_fatal_handler ||
callback == i_internal_error_handler;
}
void i_set_failure_ignore_errors(bool ignore)
{
failure_ignore_errors = ignore;
}
void i_set_info_file(const char *path)
{
if (log_info_fd == log_fd)
log_info_fd = STDERR_FILENO;
open_log_file(&log_info_fd, path);
info_handler = default_error_handler;
/* write debug-level messages to the info_log_path,
until i_set_debug_file() was called */
log_debug_fd = log_info_fd;
i_set_debug_handler(default_error_handler);
}
void i_set_debug_file(const char *path)
{
if (log_debug_fd == log_fd || log_debug_fd == log_info_fd)
log_debug_fd = STDERR_FILENO;
open_log_file(&log_debug_fd, path);
debug_handler = default_error_handler;
}
void i_set_failure_timestamp_format(const char *fmt)
{
const char *p;
i_free(log_stamp_format);
i_free_and_null(log_stamp_format_suffix);
p = strstr(fmt, "%{usecs}");
if (p == NULL)
log_stamp_format = i_strdup(fmt);
else {
log_stamp_format = i_strdup_until(fmt, p);
log_stamp_format_suffix = i_strdup(p + 8);
}
}
void i_set_failure_send_ip(const struct ip_addr *ip)
{
i_failure_send_option("ip", net_ip2addr(ip));
}
void i_set_failure_send_prefix(const char *prefix)
{
i_failure_send_option("prefix", prefix);
}
void i_set_failure_exit_callback(void (*callback)(int *status))
{
failure_exit_callback = callback;
}
void failures_deinit(void)
{
if (log_debug_fd == log_info_fd || log_debug_fd == log_fd)
log_debug_fd = STDERR_FILENO;
if (log_info_fd == log_fd)
log_info_fd = STDERR_FILENO;
if (log_fd != STDERR_FILENO) {
i_close_fd(&log_fd);
log_fd = STDERR_FILENO;
}
if (log_info_fd != STDERR_FILENO) {
i_close_fd(&log_info_fd);
log_info_fd = STDERR_FILENO;
}
if (log_debug_fd != STDERR_FILENO) {
i_close_fd(&log_debug_fd);
log_debug_fd = STDERR_FILENO;
}
i_free_and_null(log_prefix);
i_free_and_null(log_stamp_format);
i_free_and_null(log_stamp_format_suffix);
}
#undef i_unreached
void i_unreached(const char *source_filename, int source_linenum)
{
i_panic("file %s: line %d: unreached", source_filename, source_linenum);
}
dovecot-2.3.21.1/src/lib/bits.h 0000644 0000000 0000000 00000013373 14656633576 012773 0000000 0000000 #ifndef BITS_H
#define BITS_H
#define UINT64_SUM_OVERFLOWS(a, b) \
(a > (uint64_t)-1 - b)
#define BIT(n) (1u << (n))
/* These expressions make it easy to ensure that bit test expressions
are boolean in order to satisfy the in-house -Wstrict-bool. */
/* ((val & bits) == 0) is very common */
#define HAS_NO_BITS(val,bits) (((val) & (bits)) == 0)
/* ((val & bits) != 0) is even more common */
/* Note - illogical behaviour if bits==0, fixing that requires potential
multiple evaluation, but it's a corner case that should never occur. */
#define HAS_ANY_BITS(val,bits) (((val) & (bits)) != 0)
/* ((val & bits) == bits) is uncommon */
#define HAS_ALL_BITS(val,bits) ((~(val) & (bits)) == 0)
/* negation implemented without using the subtraction operator
~(x - 1) = 1 + ~x these are equivalent by -(-x) == ~(~(x)) == x */
#define UNSIGNED_MINUS(x) (1 + ~(x))
/* Returns x, such that x is the smallest power of 2 >= num. */
size_t nearest_power(size_t num) ATTR_CONST;
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
/* Returns TRUE if 2^x=num, i.e. if num has only a single bit set to 1. */
static inline bool ATTR_CONST
bits_is_power_of_two(uint64_t num)
{
return __builtin_popcountll(num) == 1;
}
static inline unsigned int ATTR_CONST
bits_required32(uint32_t num)
{
return num == 0 ? 0 : 32 - __builtin_clz(num);
}
static inline unsigned int ATTR_CONST
bits_required8(uint8_t num) { return bits_required32(num); }
static inline unsigned int ATTR_CONST
bits_required16(uint16_t num) { return bits_required32(num); }
static inline unsigned int ATTR_CONST
bits_required64(uint64_t num)
{
return num == 0 ? 0 : 64 - __builtin_clzll(num);
}
#else
/* Returns TRUE if 2^x=num, i.e. if num has only a single bit set to 1. */
static inline bool ATTR_CONST
bits_is_power_of_two(uint64_t num)
{
return num != 0 && (num & (num + ~0ULL)) == 0;
}
unsigned int bits_required8(uint8_t num) ATTR_CONST;
static inline
unsigned int bits_required16(uint16_t num)
{
return (num <= 0xff) ? bits_required8(num)
: 8 + bits_required8(num >> 8);
}
static inline
unsigned int bits_required32(uint32_t num)
{
return (num <= 0xffff) ? bits_required16(num)
: 16 + bits_required16(num >> 16);
}
static inline
unsigned int bits_required64(uint64_t num)
{
return (num <= 0xffffffff) ? bits_required32(num)
: 32 + bits_required32(num >> 32);
}
#endif
static inline uint64_t ATTR_NO_SANITIZE_INTEGER
ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
bits_rotl64(uint64_t num, unsigned int count)
{
const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
count &= mask;
return (num << count) | (num >> (UNSIGNED_MINUS(count) & mask));
}
static inline uint32_t ATTR_NO_SANITIZE_INTEGER
ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
bits_rotl32(uint32_t num, unsigned int count)
{
const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
count &= mask;
return (num << count) | (num >> (UNSIGNED_MINUS(count) & mask));
}
static inline uint64_t ATTR_NO_SANITIZE_INTEGER
ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
bits_rotr64(uint64_t num, unsigned int count)
{
const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
count &= mask;
return (num >> count) | (num << (UNSIGNED_MINUS(count) & mask));
}
static inline uint32_t ATTR_NO_SANITIZE_INTEGER
ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
bits_rotr32(uint32_t num, unsigned int count)
{
const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
count &= mask;
return (num >> count) | (num << (UNSIGNED_MINUS(count) & mask));
}
/* These functions look too big to be inline, but in almost all expected
uses, 'fracbits' will be a compile-time constant, and most of the
expressions will simplify greatly.
*/
/* Perform a piecewise-linear approximation to a log2, with fracbits "fractional" bits.
Best explained with examples:
With 2 fractional bits splitting each power of 2 into 4 bands:
00, 01, 10, 11 -> 00, 01, 10, 11 (small corner cases)
100, 101, 110, 111 -> 100, 101, 110, 111 ([4-8) split into 4 bands)
1000, 1001, 1010, 1011 -> 1000, 1000, 1001, 1001 ([8-15) split ...
1100, 1101, 1110, 1111 -> 1010, 1010, 1011, 1011 ... into 4 bands)
[16..31) -> 11bb
[32..63) -> 100bb
[64..127) -> 101bb
[128..255) -> 110bb
e.g. 236 = 11101100 -> ((8-2)<<2 == 11000) + (111.....>> 5 == 111) - 100 == 11011
*/
static inline unsigned int ATTR_CONST
bits_fraclog(unsigned int val, unsigned int fracbits)
{
unsigned bits = bits_required32(val);
if (bits <= fracbits + 1)
return val;
unsigned int bandnum = bits - fracbits;
unsigned int bandstart = bandnum << fracbits;
unsigned int fracoffsbad = val >> (bandnum - 1); /* has leading 1 still */
unsigned int bucket = bandstart + fracoffsbad - BIT(fracbits);
return bucket;
}
static inline unsigned int ATTR_CONST
bits_fraclog_bucket_start(unsigned int bucket, unsigned int fracbits)
{
unsigned int bandnum = bucket >> fracbits;
if (bandnum <= 1)
return bucket;
if (fracbits == 0)
return BIT(bucket - 1);
unsigned int fracoffs = bucket & (BIT(fracbits)-1);
unsigned int fracoffs1 = BIT(fracbits) + fracoffs;
unsigned int bandstart = fracoffs1 << (bandnum - 1);
return bandstart;
}
static inline unsigned int ATTR_CONST ATTR_NO_SANITIZE_INTEGER
ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
bits_fraclog_bucket_end(unsigned int bucket, unsigned int fracbits)
{
unsigned int bandnum = bucket >> fracbits;
if (bandnum <= 1)
return bucket;
if (fracbits == 0)
return BIT(bucket - 1) * 2 - 1;
unsigned int fracoffs = bucket & (BIT(fracbits)-1);
unsigned int nextfracoffs1 = 1 + BIT(fracbits) + fracoffs;
unsigned int nextbandstart = nextfracoffs1 << (bandnum - 1);
return nextbandstart - 1;
}
/* UNSAFE: multiple use of parameter (but expecting a constant in reality).
But a macro as it's most likely to be used to declare an array size.
*/
#define BITS_FRACLOG_BUCKETS(bits) ((33u - (bits)) << (bits))
#endif
dovecot-2.3.21.1/src/lib/test-strescape.c 0000644 0000000 0000000 00000014372 14656633576 014773 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "strescape.h"
struct strinput {
const char *input;
const char *output;
};
static const char tabescaped_input[] = "\0011\001t\001r\001nplip\001n";
static const char tabescaped_input_with_nul[] = "\0011\001t\001r\001nplip\001n\0010";
static const char tabunescaped_input[] = "\001\t\r\nplip\n";
static const char *wrong_tabescaped_input = "a\001\001b\001\nc\0011\001t\001r\001nplip\001n";
static const char *wrong_tabescaped_output = "a\001b\nc\001\t\r\nplip\n";
static struct {
const char *input;
const char *const *output;
} strsplit_tests[] = {
{ /*tabescaped_input3*/NULL, (const char *const []) {
tabunescaped_input,
tabunescaped_input,
tabunescaped_input,
"",
NULL
} },
{ "", (const char *const []) { NULL } },
{ "\t", (const char *const []) { "", "", NULL } },
{ tabescaped_input, (const char *const []) {
tabunescaped_input,
NULL
} },
};
static void test_str_escape(void)
{
static const struct strinput unesc[] = {
{ "foo", "foo" },
{ "\\\\\\\\\\\"\\\"\\\'\\\'", "\\\\\"\"\'\'" },
{ "\\a\\n\\r\\", "anr" }
};
static const struct strinput tabesc[] = {
{ "foo", "foo" },
{ "\001", "\0011" },
{ "\t", "\001t" },
{ "\r", "\001r" },
{ "\n", "\001n" },
{ "\001\001\t\t\r\r\n\n", "\0011\0011\001t\001t\001r\001r\001n\001n" }
};
unsigned char buf[1 << CHAR_BIT];
const char *escaped, *tabstr, *unesc_str;
string_t *str;
unsigned int i;
test_begin("str_escape");
for (i = 1; i < sizeof(buf); i++)
buf[i-1] = i;
buf[i-1] = '\0';
escaped = str_escape((char *)buf);
test_assert(strlen(escaped) == (1 << CHAR_BIT) - 1 + 3);
test_assert(escaped['\"'-1] == '\\'); /* 34 */
test_assert(escaped['\"'] == '\"');
test_assert(escaped['\''+1-1] == '\\'); /* 39 */
test_assert(escaped['\''+1] == '\'');
test_assert(escaped['\\'+2-1] == '\\'); /* 92 */
test_assert(escaped['\\'+2] == '\\');
test_assert(strcmp(str_escape("\\\\\"\"\'\'"),
"\\\\\\\\\\\"\\\"\\\'\\\'") == 0);
test_end();
test_begin("str_nescape");
escaped = str_nescape("\"escape only first but not 'this'", 10);
test_assert(strcmp(escaped, "\\\"escape on") == 0);
escaped = str_nescape("\"hello\"\0\"world\"", 15);
test_assert(memcmp(escaped, "\\\"hello\\\"\0\\\"world\\\"", 19) == 0);
test_end();
str = t_str_new(256);
test_begin("str_unescape");
for (i = 0; i < N_ELEMENTS(unesc); i++) {
test_assert(strcmp(str_unescape(t_strdup_noconst(unesc[i].input)),
unesc[i].output) == 0);
str_truncate(str, 0);
str_append_unescaped(str, unesc[i].input, strlen(unesc[i].input));
test_assert(strcmp(str_c(str), unesc[i].output) == 0);
}
test_end();
test_begin("str_unescape_next");
escaped = "foo\"bar\\\"b\\\\az\"plop";
test_assert(str_unescape_next(&escaped, &unesc_str) == 0);
test_assert(strcmp(unesc_str, "foo") == 0);
test_assert(str_unescape_next(&escaped, &unesc_str) == 0);
test_assert(strcmp(unesc_str, "bar\"b\\az") == 0);
test_assert(str_unescape_next(&escaped, &unesc_str) == -1);
escaped = "foo\\";
test_assert(str_unescape_next(&escaped, &unesc_str) == -1);
test_end();
test_begin("str_tabescape");
for (i = 0; i < N_ELEMENTS(tabesc); i++) {
test_assert(strcmp(t_str_tabunescape(tabesc[i].output),
tabesc[i].input) == 0);
test_assert(strcmp(str_tabunescape(t_strdup_noconst(tabesc[i].output)),
tabesc[i].input) == 0);
test_assert(strcmp(str_tabescape(tabesc[i].input),
tabesc[i].output) == 0);
str_truncate(str, 0);
str_append_tabunescaped(str, tabesc[i].output, strlen(tabesc[i].output));
test_assert(strcmp(str_c(str), tabesc[i].input) == 0);
}
str_truncate(str, 0);
tabstr = "\0012\001l\001";
str_append_tabunescaped(str, tabstr, strlen(tabstr));
test_assert(strcmp(str_c(str), "2l") == 0);
test_assert(strcmp(str_c(str), str_tabunescape(t_strdup_noconst(tabstr))) == 0);
test_end();
}
static void test_tabescape(void)
{
string_t *str = t_str_new(128);
test_begin("string tabescaping");
test_assert(strcmp(str_tabescape(tabunescaped_input), tabescaped_input) == 0);
str_append_tabescaped(str, tabunescaped_input);
test_assert(strcmp(str_c(str), tabescaped_input) == 0);
/* test escaping the trailing NUL as well */
str_truncate(str, 0);
str_append_tabescaped_n(str, (const unsigned char *)tabunescaped_input,
strlen(tabunescaped_input)+1);
test_assert_strcmp(str_c(str), tabescaped_input_with_nul);
/* unescaping */
str_truncate(str, 0);
str_append_tabunescaped(str, tabescaped_input, strlen(tabescaped_input));
test_assert(strcmp(str_c(str), tabunescaped_input) == 0);
test_assert(strcmp(str_tabunescape(t_strdup_noconst(tabescaped_input)), tabunescaped_input) == 0);
test_assert(strcmp(t_str_tabunescape(tabescaped_input), tabunescaped_input) == 0);
/* unescaping with wrongly written tabescape-input */
str_truncate(str, 0);
str_append_tabunescaped(str, wrong_tabescaped_input, strlen(wrong_tabescaped_input));
test_assert(strcmp(str_c(str), wrong_tabescaped_output) == 0);
test_assert(strcmp(str_tabunescape(t_strdup_noconst(wrong_tabescaped_input)), wrong_tabescaped_output) == 0);
test_assert(strcmp(t_str_tabunescape(wrong_tabescaped_input), wrong_tabescaped_output) == 0);
test_end();
}
static void test_strsplit_tabescaped(void)
{
const char *const *args;
test_begin("*_strsplit_tabescaped()");
for (unsigned int i = 0; i < N_ELEMENTS(strsplit_tests); i++) {
args = t_strsplit_tabescaped(strsplit_tests[i].input);
for (unsigned int j = 0; strsplit_tests[i].output[j] != NULL; j++)
test_assert_idx(null_strcmp(strsplit_tests[i].output[j], args[j]) == 0, i);
}
test_end();
}
static void test_strsplit_tabescaped_inplace(void)
{
const char *const *args;
test_begin("*_strsplit_tabescaped_inplace()");
for (unsigned int i = 0; i < N_ELEMENTS(strsplit_tests); i++) {
char *input = t_strdup_noconst(strsplit_tests[i].input);
args = t_strsplit_tabescaped_inplace(input);
for (unsigned int j = 0; strsplit_tests[i].output[j] != NULL; j++)
test_assert_idx(null_strcmp(strsplit_tests[i].output[j], args[j]) == 0, i);
}
test_end();
}
void test_strescape(void)
{
strsplit_tests[0].input = t_strdup_printf("%s\t%s\t%s\t",
tabescaped_input, tabescaped_input, tabescaped_input);
test_str_escape();
test_tabescape();
test_strsplit_tabescaped();
test_strsplit_tabescaped_inplace();
}
dovecot-2.3.21.1/src/lib/test-base64.c 0000644 0000000 0000000 00000102600 14656633576 014056 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "base64.h"
static void test_base64_encode(void)
{
const struct {
const char *input;
const char *output;
} tests[] = {
{ "hello world", "aGVsbG8gd29ybGQ=" },
{ "foo barits", "Zm9vIGJhcml0cw==" },
{ "just niin", "anVzdCBuaWlu" },
{ "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
"\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
"54y/44KC5pyo44GL44KJ6JC944Gh44KL" },
{ "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3\x81"
"\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81\x99",
"6KeS44KS55+v44KB44Gm54mb44KS5q6644GZ" },
};
string_t *str;
unsigned int i;
test_begin("base64_encode()");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(tests); i++) {
str_truncate(str, 0);
base64_encode(tests[i].input, strlen(tests[i].input), str);
test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
test_assert_idx(
str_len(str) == MAX_BASE64_ENCODED_SIZE(
strlen(tests[i].input)), i);
}
test_end();
}
struct test_base64_decode {
const char *input;
const char *output;
int ret;
};
static void test_base64_decode(void)
{
static const struct test_base64_decode tests[] = {
{ "", "", 0 },
{ "\taGVsbG8gd29ybGQ=",
"hello world", 0 },
{ "\nZm9v\n \tIGJh \t\ncml0cw==",
"foo barits", 0 },
{ " anVzdCBuaWlu \n",
"just niin", 0 },
{ "aGVsb",
"hel", -1 },
{ "aGVsb!!!!!",
"hel", -1 },
{ "aGVs!!!!!",
"hel", -1 },
{ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
"C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e", 0 },
};
string_t *str;
buffer_t buf;
unsigned int i;
int ret;
test_begin("base64_decode()");
for (i = 0; i < N_ELEMENTS(tests); i++) {
/* Some of the base64_decode() callers use fixed size buffers.
Use a fixed size buffer here as well to test that
base64_decode() can't allocate any extra space even
temporarily. */
size_t max_decoded_size =
MAX_BASE64_DECODED_SIZE(strlen(tests[i].input));
buffer_create_from_data(&buf,
(max_decoded_size == 0 ? "" :
t_malloc0(max_decoded_size)),
max_decoded_size);
str = &buf;
ret = base64_decode(tests[i].input, strlen(tests[i].input),
NULL, str);
test_assert_idx(tests[i].ret == ret, i);
test_assert_idx(strlen(tests[i].output) == str_len(str) &&
memcmp(tests[i].output, str_data(str),
str_len(str)) == 0, i);
if (ret >= 0) {
test_assert_idx(
str_len(str) <= MAX_BASE64_DECODED_SIZE(
strlen(tests[i].input)), i);
}
}
test_end();
}
static void test_base64_random(void)
{
string_t *str, *dest;
unsigned char buf[10];
unsigned int i, j, max;
str = t_str_new(256);
dest = t_str_new(256);
test_begin("base64 encode/decode with random input");
for (i = 0; i < 1000; i++) {
max = i_rand_limit(sizeof(buf));
for (j = 0; j < max; j++)
buf[j] = i_rand_uchar();
str_truncate(str, 0);
str_truncate(dest, 0);
base64_encode(buf, max, str);
test_assert_idx(base64_decode(str_data(str), str_len(str),
NULL, dest) >= 0, i);
test_assert_idx(str_len(dest) == max &&
memcmp(buf, str_data(dest), max) == 0, i);
}
test_end();
}
static void test_base64url_encode(void)
{
const struct {
const char *input;
const char *output;
} tests[] = {
{ "", "" },
{ "hello world", "aGVsbG8gd29ybGQ=" },
{ "foo barits", "Zm9vIGJhcml0cw==" },
{ "just niin", "anVzdCBuaWlu" },
{ "\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
"\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
"54y_44KC5pyo44GL44KJ6JC944Gh44KL" },
{ "\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3\x81"
"\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81\x99",
"6KeS44KS55-v44KB44Gm54mb44KS5q6644GZ" },
};
string_t *str;
unsigned int i;
test_begin("base64url_encode()");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(tests); i++) {
str_truncate(str, 0);
base64url_encode(0, 0, tests[i].input, strlen(tests[i].input),
str);
test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
test_assert_idx(
str_len(str) == MAX_BASE64_ENCODED_SIZE(
strlen(tests[i].input)), i);
}
test_end();
}
struct test_base64url_decode {
const char *input;
const char *output;
int ret;
};
static void test_base64url_decode(void)
{
static const struct test_base64url_decode tests[] = {
{ "", "", 0 },
{ "\taGVsbG8gd29ybGQ=",
"hello world", 0 },
{ "\nZm9v\n \tIGJh \t\ncml0cw==",
"foo barits", 0 },
{ " anVzdCBuaWlu \n",
"just niin", 0 },
{ "aGVsb",
"hel", -1 },
{ "aGVsb!!!!!",
"hel", -1 },
{ "aGVs!!!!!",
"hel", -1 },
{ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
"C-INC60YPRgCDQtNC-0Y_MgdGCLg==",
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e", 0 },
};
string_t *str;
buffer_t buf;
unsigned int i;
int ret;
test_begin("base64url_decode()");
for (i = 0; i < N_ELEMENTS(tests); i++) {
/* Some of the base64_decode() callers use fixed size buffers.
Use a fixed size buffer here as well to test that
base64_decode() can't allocate any extra space even
temporarily. */
size_t max_decoded_size =
MAX_BASE64_DECODED_SIZE(strlen(tests[i].input));
buffer_create_from_data(&buf,
(max_decoded_size == 0 ? "" :
t_malloc0(max_decoded_size)),
max_decoded_size);
str = &buf;
ret = base64url_decode(0, tests[i].input,
strlen(tests[i].input), str);
test_assert_idx(tests[i].ret == ret, i);
test_assert_idx(strlen(tests[i].output) == str_len(str) &&
memcmp(tests[i].output, str_data(str),
str_len(str)) == 0, i);
if (ret >= 0) {
test_assert_idx(
str_len(str) <= MAX_BASE64_DECODED_SIZE(
strlen(tests[i].input)), i);
}
}
test_end();
}
static void test_base64url_random(void)
{
string_t *str, *dest;
unsigned char buf[10];
unsigned int i, j, max;
str = t_str_new(256);
dest = t_str_new(256);
test_begin("base64url encode/decode with random input");
for (i = 0; i < 1000; i++) {
max = i_rand_limit(sizeof(buf));
for (j = 0; j < max; j++)
buf[j] = i_rand_uchar();
str_truncate(str, 0);
str_truncate(dest, 0);
base64url_encode(0, 0, buf, max, str);
test_assert_idx(base64url_decode(0, str_data(str), str_len(str),
dest) >= 0, i);
test_assert_idx(str_len(dest) == max &&
memcmp(buf, str_data(dest), max) == 0, i);
}
test_end();
}
struct test_base64_encode_lowlevel {
const struct base64_scheme *scheme;
enum base64_encode_flags flags;
size_t max_line_len;
const char *input;
const char *output;
};
static const struct test_base64_encode_lowlevel
tests_base64_encode_lowlevel[] = {
{
.scheme = &base64_scheme,
.input = "",
.output = "",
},
{
.scheme = &base64_scheme,
.max_line_len = 2,
.input = "",
.output = "",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_CRLF,
.max_line_len = 2,
.input = "",
.output = "",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_NO_PADDING,
.input = "",
.output = "",
},
{
.scheme = &base64_scheme,
.input = "hello world",
.output = "aGVsbG8gd29ybGQ=",
},
{
.scheme = &base64url_scheme,
.input = "hello world",
.output = "aGVsbG8gd29ybGQ=",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_NO_PADDING,
.input = "hello world",
.output = "aGVsbG8gd29ybGQ",
},
{
.scheme = &base64_scheme,
.input = "foo barits",
.output = "Zm9vIGJhcml0cw==",
},
{
.scheme = &base64url_scheme,
.input = "foo barits",
.output = "Zm9vIGJhcml0cw==",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_NO_PADDING,
.input = "foo barits",
.output = "Zm9vIGJhcml0cw",
},
{
.scheme = &base64_scheme,
.input = "just niin",
.output = "anVzdCBuaWlu",
},
{
.scheme = &base64url_scheme,
.input = "just niin",
.output = "anVzdCBuaWlu",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_NO_PADDING,
.input = "just niin",
.output = "anVzdCBuaWlu",
},
{
.scheme = &base64_scheme,
.input =
"\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
"\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
.output = "54y/44KC5pyo44GL44KJ6JC944Gh44KL",
},
{
.scheme = &base64url_scheme,
.input =
"\xe7\x8c\xbf\xe3\x82\x82\xe6\x9c\xa8\xe3\x81\x8b"
"\xe3\x82\x89\xe8\x90\xbd\xe3\x81\xa1\xe3\x82\x8b",
.output = "54y_44KC5pyo44GL44KJ6JC944Gh44KL",
},
{
.scheme = &base64_scheme,
.input =
"\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3"
"\x81\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81"
"\x99",
.output = "6KeS44KS55+v44KB44Gm54mb44KS5q6644GZ",
},
{
.scheme = &base64url_scheme,
.input =
"\xe8\xa7\x92\xe3\x82\x92\xe7\x9f\xaf\xe3\x82\x81\xe3"
"\x81\xa6\xe7\x89\x9b\xe3\x82\x92\xe6\xae\xba\xe3\x81"
"\x99",
.output = "6KeS44KS55-v44KB44Gm54mb44KS5q6644GZ",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_CRLF,
.input = "just niin",
.output = "anVzdCBuaWlu",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_CRLF,
.max_line_len = 80,
.input = "just niin",
.output = "anVzdCBuaWlu",
},
{
.scheme = &base64_scheme,
.flags = BASE64_ENCODE_FLAG_CRLF,
.max_line_len = 48,
.input =
"Passer, deliciae meae puellae,\n"
"quicum ludere, quem in sinu tenere,\n"
"cui primum digitum dare appetenti\n"
"et acris solet incitare morsus,\n"
"cum desiderio meo nitenti\n"
"carum nescio quid lubet iocari,\n"
"credo ut, cum gravis acquiescet ardor,\n"
"sit solaciolum sui doloris,\n"
"tecum ludere sicut ipsa possem\n"
"et tristis animi levare curas!\n",
.output =
"UGFzc2VyLCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUsCnF1aWN1\r\n"
"bSBsdWRlcmUsIHF1ZW0gaW4gc2ludSB0ZW5lcmUsCmN1aSBw\r\n"
"cmltdW0gZGlnaXR1bSBkYXJlIGFwcGV0ZW50aQpldCBhY3Jp\r\n"
"cyBzb2xldCBpbmNpdGFyZSBtb3JzdXMsCmN1bSBkZXNpZGVy\r\n"
"aW8gbWVvIG5pdGVudGkKY2FydW0gbmVzY2lvIHF1aWQgbHVi\r\n"
"ZXQgaW9jYXJpLApjcmVkbyB1dCwgY3VtIGdyYXZpcyBhY3F1\r\n"
"aWVzY2V0IGFyZG9yLApzaXQgc29sYWNpb2x1bSBzdWkgZG9s\r\n"
"b3JpcywKdGVjdW0gbHVkZXJlIHNpY3V0IGlwc2EgcG9zc2Vt\r\n"
"CmV0IHRyaXN0aXMgYW5pbWkgbGV2YXJlIGN1cmFzIQo=",
},
{
.scheme = &base64_scheme,
.max_line_len = 48,
.input =
"Lugete, o Veneres Cupidinesque,\n"
"et quantum est hominum venustiorum:\n"
"passer mortuus est meae puellae, \n"
"passer, deliciae meae puellae\n"
"quem plus amat illa oculis suis amabat.\n"
"Nam mellitus erat suamque norat\n"
"ipsam tam bene quam puella matrem,\n"
"nec sese a gremio illius movebat,\n"
"sed circumsiliens modo huc modo illuc\n"
"ad solam dominam usque pipiabat;\n"
"qui nunc it per iter tenebricosum\n"
"illuc, unde negant redire quemquam.\n"
"At vobis male sint, malae tenebrae\n"
"Orci, quae omnia bella devoratis:\n"
"tam bellum mihi passerem abstulistis.\n"
"O factum male! O miselle passer!\n"
"Tua nunc opera meae puellae\n"
"flendo turgiduli rubent ocelli.\n",
.output =
"THVnZXRlLCBvIFZlbmVyZXMgQ3VwaWRpbmVzcXVlLApldCBx\n"
"dWFudHVtIGVzdCBob21pbnVtIHZlbnVzdGlvcnVtOgpwYXNz\n"
"ZXIgbW9ydHV1cyBlc3QgbWVhZSBwdWVsbGFlLCAKcGFzc2Vy\n"
"LCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUKcXVlbSBwbHVzIGFt\n"
"YXQgaWxsYSBvY3VsaXMgc3VpcyBhbWFiYXQuCk5hbSBtZWxs\n"
"aXR1cyBlcmF0IHN1YW1xdWUgbm9yYXQKaXBzYW0gdGFtIGJl\n"
"bmUgcXVhbSBwdWVsbGEgbWF0cmVtLApuZWMgc2VzZSBhIGdy\n"
"ZW1pbyBpbGxpdXMgbW92ZWJhdCwKc2VkIGNpcmN1bXNpbGll\n"
"bnMgbW9kbyBodWMgbW9kbyBpbGx1YwphZCBzb2xhbSBkb21p\n"
"bmFtIHVzcXVlIHBpcGlhYmF0OwpxdWkgbnVuYyBpdCBwZXIg\n"
"aXRlciB0ZW5lYnJpY29zdW0KaWxsdWMsIHVuZGUgbmVnYW50\n"
"IHJlZGlyZSBxdWVtcXVhbS4KQXQgdm9iaXMgbWFsZSBzaW50\n"
"LCBtYWxhZSB0ZW5lYnJhZQpPcmNpLCBxdWFlIG9tbmlhIGJl\n"
"bGxhIGRldm9yYXRpczoKdGFtIGJlbGx1bSBtaWhpIHBhc3Nl\n"
"cmVtIGFic3R1bGlzdGlzLgpPIGZhY3R1bSBtYWxlISBPIG1p\n"
"c2VsbGUgcGFzc2VyIQpUdWEgbnVuYyBvcGVyYSBtZWFlIHB1\n"
"ZWxsYWUKZmxlbmRvIHR1cmdpZHVsaSBydWJlbnQgb2NlbGxp\n"
"Lgo=",
},
};
static void test_base64_encode_lowlevel(void)
{
string_t *str;
unsigned int i;
test_begin("base64 encode low-level");
str = t_str_new(256);
for (i = 0; i < N_ELEMENTS(tests_base64_encode_lowlevel); i++) {
const struct test_base64_encode_lowlevel *test =
&tests_base64_encode_lowlevel[i];
struct base64_encoder enc;
uoff_t out_size;
str_truncate(str, 0);
base64_encode_init(&enc, test->scheme, test->flags,
test->max_line_len);
out_size = base64_get_full_encoded_size(
&enc, strlen(test->input));
test_assert_idx(base64_encode_more(&enc, test->input,
strlen(test->input),
NULL, str), i);
test_assert_idx(base64_encode_finish(&enc, str), i);
test_assert_idx(strcmp(test->output, str_c(str)) == 0, i);
test_assert_idx(test->flags != 0 || test->max_line_len != 0 ||
str_len(str) == MAX_BASE64_ENCODED_SIZE(
strlen(test->input)), i);
test_assert_idx(str_len(str) == out_size, i);
}
test_end();
}
struct test_base64_decode_lowlevel {
const struct base64_scheme *scheme;
enum base64_decode_flags flags;
const char *input;
const char *output;
int ret;
unsigned int src_pos;
};
static const struct test_base64_decode_lowlevel
tests_base64_decode_lowlevel[] = {
{
.scheme = &base64_scheme,
.input = "",
.output = "",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = " ",
.output = "",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "",
.output = "",
.ret = 0,
.src_pos = UINT_MAX,
.flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
},
{
.scheme = &base64_scheme,
.input = "",
.output = "",
.ret = 0,
.src_pos = UINT_MAX,
.flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
},
{
.scheme = &base64_scheme,
.input = " ",
.output = "",
.ret = -1,
.src_pos = 0,
.flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
},
{
.scheme = &base64_scheme,
.input = "",
.output = "",
.ret = 0,
.src_pos = UINT_MAX,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
},
{
.scheme = &base64_scheme,
.input = "",
.output = "",
.ret = 0,
.src_pos = UINT_MAX,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
},
{
.scheme = &base64_scheme,
.input = "\taGVsbG8gd29ybGQ=",
.output = "hello world",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64url_scheme,
.input = "\taGVsbG8gd29ybGQ=",
.output = "hello world",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "aGVsbG8gd29ybGQ=\t",
.output = "hello world",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "\taGVsbG8gd29ybGQ=\t",
.output = "hello world",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "aGVsbG8gd29ybGQ=:frop",
.output = "hello world",
.ret = 0,
.src_pos = 16,
.flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
},
{
.scheme = &base64_scheme,
.input = "\taGVsbG8gd29ybGQ=\t:frop",
.output = "hello world",
.ret = 0,
.src_pos = 18,
.flags = BASE64_DECODE_FLAG_EXPECT_BOUNDARY,
},
{
.scheme = &base64_scheme,
.input = "aGVsbG8gd29ybGQ=\t",
.output = "hello world",
.ret = -1,
.src_pos = 16,
.flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
},
{
.scheme = &base64_scheme,
.input = "\taGVsbG8gd29ybGQ=\t",
.output = "",
.ret = -1,
.src_pos = 0,
.flags = BASE64_DECODE_FLAG_NO_WHITESPACE,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
.input = "\taGVsbG8gd29ybGQ=",
.output = "hello world",
.ret = -1,
.src_pos = 16,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
.input = "\taGVsbG8gd29ybGQ",
.output = "hello world",
.ret = 0,
.src_pos = 16,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input = "\taGVsbG8gd29ybGQ=",
.output = "hello world",
.ret = 0,
.src_pos = 17,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input = "\taGVsbG8gd29ybGQ",
.output = "hello world",
.ret = 0,
.src_pos = 16,
},
{
.scheme = &base64_scheme,
.input = "\nZm9v\n \tIGJh \t\ncml0cw==",
.output = "foo barits",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64url_scheme,
.input = "\nZm9v\n \tIGJh \t\ncml0cw==",
.output = "foo barits",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "\nZm9v\n \tIGJh \t\ncml0cw==\n ",
.output = "foo barits",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "\nZm9v\n \tIGJh \t\ncml0cw= =\n ",
.output = "foo barits",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "\nZm9v\n \tIGJh \t\ncml0cw\n= =\n ",
.output = "foo barits",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
.input = "\nZm9v\n \tIGJh \t\ncml0cw==",
.output = "foo barits",
.ret = -1,
.src_pos = 22,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
.input = "\nZm9v\n \tIGJh \t\ncml0cw",
.output = "foo barits",
.ret = 0,
.src_pos = 22,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input = "\nZm9v\n \tIGJh \t\ncml0cw==",
.output = "foo barits",
.ret = 0,
.src_pos = 24,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input = "\nZm9v\n \tIGJh \t\ncml0cw",
.output = "foo barits",
.ret = 0,
.src_pos = 22,
},
{
.scheme = &base64_scheme,
.input = " anVzdCBuaWlu \n",
.output = "just niin",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64url_scheme,
.input = " anVzdCBuaWlu \n",
.output = "just niin",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
.input = " anVzdCBuaWlu \n",
.output = "just niin",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input = " anVzdCBuaWlu \n",
.output = "just niin",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.input = "aGVsb",
.output = "hel",
.ret = -1,
.src_pos = 5,
},
{
.scheme = &base64url_scheme,
.input = "aGVsb",
.output = "hel",
.ret = -1,
.src_pos = 5,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
.input = "aGVsb",
.output = "hel",
.ret = 0,
.src_pos = 5,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input = "aGVsb",
.output = "hel",
.ret = 0,
.src_pos = 5,
},
{
.scheme = &base64_scheme,
.input = "aGVsb!!!!!",
.output = "hel",
.ret = -1,
.src_pos = 5,
},
{
.scheme = &base64url_scheme,
.input = "aGVsb!!!!!",
.output = "hel",
.ret = -1,
.src_pos = 5,
},
{
.scheme = &base64_scheme,
.input = "aGVs!!!!!",
.output = "hel",
.ret = -1,
.src_pos = 4,
},
{
.scheme = &base64url_scheme,
.input = "aGVs!!!!!",
.output = "hel",
.ret = -1,
.src_pos = 4,
},
{
.scheme = &base64_scheme,
.input =
"0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
"C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
.output =
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64url_scheme,
.input =
"0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
"C-INC60YPRgCDQtNC-0Y_MgdGCLg==",
.output =
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_NO_PADDING,
.input =
"0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
"C+INC60YPRgCDQtNC+0Y/MgdGCLg",
.output =
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input =
"0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
"C+INC60YPRgCDQtNC+0Y/MgdGCLg",
.output =
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e",
.ret = 0,
.src_pos = UINT_MAX,
},
{
.scheme = &base64_scheme,
.flags = BASE64_DECODE_FLAG_IGNORE_PADDING,
.input =
"0JPQvtCy0L7RgNGPzIHRgiwg0YfRgt"
"C+INC60YPRgCDQtNC+0Y/MgdGCLg==",
.output =
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e",
.ret = 0,
.src_pos = UINT_MAX,
},
};
static void test_base64_decode_lowlevel(void)
{
string_t *str;
buffer_t buf;
unsigned int i;
test_begin("base64 decode low-level");
for (i = 0; i < N_ELEMENTS(tests_base64_decode_lowlevel); i++) {
const struct test_base64_decode_lowlevel *test =
&tests_base64_decode_lowlevel[i];
struct base64_decoder dec;
size_t src_pos;
int ret;
/* Some of the base64_decode() callers use fixed size buffers.
Use a fixed size buffer here as well to test that
base64_decode() can't allocate any extra space even
temporarily. */
size_t max_decoded_size =
MAX_BASE64_DECODED_SIZE(strlen(test->input));
buffer_create_from_data(&buf,
(max_decoded_size == 0 ? "" :
t_malloc0(max_decoded_size)),
max_decoded_size);
str = &buf;
base64_decode_init(&dec, test->scheme, test->flags);
ret = base64_decode_more(&dec, test->input, strlen(test->input),
&src_pos, str);
if (ret >= 0)
ret = base64_decode_finish(&dec);
test_assert_idx(ret == test->ret, i);
test_assert_idx(strlen(test->output) == str_len(str) &&
memcmp(test->output, str_data(str),
str_len(str)) == 0, i);
test_assert_idx(src_pos == test->src_pos ||
(test->src_pos == UINT_MAX &&
src_pos == strlen(test->input)), i);
if (ret >= 0) {
test_assert_idx(
str_len(str) <= MAX_BASE64_DECODED_SIZE(
strlen(test->input)), i);
}
}
test_end();
}
static void
test_base64_random_lowlevel_one_block(const struct base64_scheme *b64,
enum base64_encode_flags enc_flags,
enum base64_decode_flags dec_flags,
size_t max_line_len,
unsigned int test_idx,
const unsigned char *in_buf,
size_t in_buf_size,
buffer_t *buf1, buffer_t *buf2)
{
struct base64_encoder enc;
struct base64_decoder dec;
void *space;
size_t enc_size;
buffer_t buf;
int ret;
buffer_set_used_size(buf1, 0);
buffer_set_used_size(buf2, 0);
base64_encode_init(&enc, b64, enc_flags, max_line_len);
enc_size = base64_get_full_encoded_size(&enc, in_buf_size);
space = buffer_append_space_unsafe(buf1, enc_size);
buffer_create_from_data(&buf, space, enc_size);
if (!base64_encode_more(&enc, in_buf, in_buf_size, NULL, &buf))
test_assert_idx(FALSE, test_idx);
if (!base64_encode_finish(&enc, &buf))
test_assert_idx(FALSE, test_idx);
test_assert(base64_get_full_encoded_size(&enc, in_buf_size) ==
buf1->used);
base64_decode_init(&dec, b64, dec_flags);
space = buffer_append_space_unsafe(buf2, in_buf_size);
buffer_create_from_data(&buf, space, in_buf_size);
ret = base64_decode_more(&dec, buf1->data, buf1->used, NULL, &buf);
if (ret >= 0)
ret = base64_decode_finish(&dec);
test_assert_idx(ret >= 0, test_idx);
test_assert_idx(buf2->used == in_buf_size &&
memcmp(in_buf, buf2->data, in_buf_size) == 0, test_idx);
}
static void
test_base64_random_lowlevel_stream(const struct base64_scheme *b64,
enum base64_encode_flags enc_flags,
enum base64_decode_flags dec_flags,
size_t max_line_len, unsigned int test_idx,
const unsigned char *in_buf,
size_t in_buf_size,
buffer_t *buf1, buffer_t *buf2,
size_t chunk_size)
{
struct base64_encoder enc;
struct base64_decoder dec;
const unsigned char *buf_p, *buf_begin, *buf_end;
int ret;
size_t out_space, out_full_size;
void *out_data;
buffer_t out;
/* Encode */
buffer_set_used_size(buf1, 0);
buf_begin = in_buf;
buf_end = buf_begin + in_buf_size;
base64_encode_init(&enc, b64, enc_flags, max_line_len);
out_full_size = base64_get_full_encoded_size(&enc, in_buf_size);
out_space = 0;
for (buf_p = buf_begin; buf_p < buf_end; ) {
size_t buf_ch, out_ch;
size_t left = (buf_end - buf_p);
size_t used = buf1->used;
size_t src_pos, out_size, src_full_space;
bool eres;
if (chunk_size == 0) {
buf_ch = i_rand_limit(32);
out_ch = i_rand_limit(32);
} else {
buf_ch = chunk_size;
out_ch = chunk_size;
}
out_space += out_ch;
out_data = buffer_append_space_unsafe(buf1, out_space);
buffer_create_from_data(&out, out_data, out_space);
if (buf_ch > left)
buf_ch = left;
src_full_space = base64_encode_get_full_space(
&enc, out_full_size - used);
test_assert_idx(src_full_space >= (size_t)(buf_end - buf_p),
test_idx);
out_size = base64_encode_get_size(&enc, buf_ch);
eres = base64_encode_more(&enc, buf_p, buf_ch, &src_pos, &out);
test_assert_idx((eres && src_pos == buf_ch) ||
(!eres && src_pos < buf_ch), test_idx);
test_assert_idx(out.used <= out_size, test_idx);
buf_p += src_pos;
i_assert(out_space >= out.used);
out_space -= out.used;
buffer_set_used_size(buf1, used + out.used);
}
test_assert_idx(base64_encode_finish(&enc, buf1), test_idx);
/* Verify encode */
test_assert(out_full_size == buf1->used);
buffer_set_used_size(buf2, 0);
base64_encode_init(&enc, b64, enc_flags, max_line_len);
test_assert_idx(base64_encode_more(&enc, in_buf, in_buf_size,
NULL, buf2), test_idx);
test_assert_idx(base64_encode_finish(&enc, buf2), test_idx);
test_assert_idx(buffer_cmp(buf1, buf2), test_idx);
/* Decode */
buffer_set_used_size(buf2, 0);
buf_begin = buf1->data;
buf_end = buf_begin + buf1->used;
base64_decode_init(&dec, b64, dec_flags);
ret = 1;
out_space = 0;
for (buf_p = buf_begin; buf_p < buf_end; ) {
size_t buf_ch, out_ch;
size_t left = (buf_end - buf_p);
size_t used = buf2->used;
size_t src_pos;
if (chunk_size == 0) {
buf_ch = i_rand_limit(32);
out_ch = i_rand_limit(32);
} else {
buf_ch = chunk_size;
out_ch = chunk_size;
}
out_space += out_ch;
out_data = buffer_append_space_unsafe(buf2, out_space);
buffer_create_from_data(&out, out_data, out_space);
if (buf_ch > left)
buf_ch = left;
ret = base64_decode_more(&dec, buf_p, buf_ch,
&src_pos, &out);
test_assert_idx(ret >= 0, test_idx);
if (ret < 0) {
break;
}
buf_p += src_pos;
i_assert(out_space >= out.used);
out_space -= out.used;
buffer_set_used_size(buf2, used + out.used);
}
test_assert_idx(ret >= 0, test_idx);
/* Verify decode */
if (ret > 0) {
ret = base64_decode_finish(&dec);
test_assert_idx(ret == 0, test_idx);
test_assert_idx(buf2->used == in_buf_size &&
memcmp(in_buf, buf2->data, in_buf_size) == 0,
test_idx);
}
}
static void
test_base64_random_lowlevel_case(const struct base64_scheme *b64,
enum base64_encode_flags enc_flags,
enum base64_decode_flags dec_flags,
size_t max_line_len)
{
unsigned char in_buf[512];
size_t in_buf_size;
buffer_t *buf1, *buf2;
unsigned int i, j;
if (test_has_failed())
return;
buf1 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(sizeof(in_buf)));
buf2 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(sizeof(in_buf)));
/* one block */
for (i = 0; i < 1000; i++) {
in_buf_size = i_rand_limit(sizeof(in_buf));
for (j = 0; j < in_buf_size; j++)
in_buf[j] = i_rand_uchar();
test_base64_random_lowlevel_one_block(b64, enc_flags, dec_flags,
max_line_len, i,
in_buf, in_buf_size,
buf1, buf2);
if (test_has_failed()) {
i_info("One block test failed ("
"enc_flags=%02x dec_flags=%02x "
"max_line_len=%zu size=%zu)",
enc_flags, dec_flags, max_line_len,
in_buf_size);
return;
}
}
/* streaming; single-byte trickle */
for (i = 0; i < 1000; i++) {
in_buf_size = i_rand_limit(sizeof(in_buf));
for (j = 0; j < in_buf_size; j++)
in_buf[j] = i_rand_uchar();
test_base64_random_lowlevel_stream(b64, enc_flags, dec_flags,
max_line_len, i,
in_buf, in_buf_size,
buf1, buf2, 1);
if (test_has_failed()) {
i_info("Streaming single-byte trickle test failed ("
"enc_flags=%02x dec_flags=%02x "
"max_line_len=%zu size=%zu)",
enc_flags, dec_flags, max_line_len,
in_buf_size);
return;
}
}
/* streaming; random chunks */
for (i = 0; i < 1000; i++) {
in_buf_size = i_rand_limit(sizeof(in_buf));
for (j = 0; j < in_buf_size; j++)
in_buf[j] = i_rand_uchar();
test_base64_random_lowlevel_stream(b64, enc_flags, dec_flags,
max_line_len, i,
in_buf, in_buf_size,
buf1, buf2, 0);
if (test_has_failed()) {
i_info("Streaming random chunks test failed ("
"enc_flags=%02x dec_flags=%02x "
"max_line_len=%zu size=%zu)",
enc_flags, dec_flags, max_line_len,
in_buf_size);
return;
}
}
}
static void
test_base64_random_lowlevel(void)
{
test_begin("base64 encode/decode low-level with random input");
test_base64_random_lowlevel_case(&base64_scheme, 0, 0, 0);
test_base64_random_lowlevel_case(&base64url_scheme, 0, 0, 0);
test_base64_random_lowlevel_case(&base64_scheme, 0,
BASE64_DECODE_FLAG_EXPECT_BOUNDARY, 0);
test_base64_random_lowlevel_case(&base64url_scheme, 0,
BASE64_DECODE_FLAG_EXPECT_BOUNDARY, 0);
test_base64_random_lowlevel_case(&base64_scheme, 0,
BASE64_DECODE_FLAG_NO_WHITESPACE, 0);
test_base64_random_lowlevel_case(&base64url_scheme, 0,
BASE64_DECODE_FLAG_NO_WHITESPACE, 0);
test_base64_random_lowlevel_case(&base64_scheme, 0, 0, 10);
test_base64_random_lowlevel_case(&base64url_scheme, 0, 0, 10);
test_base64_random_lowlevel_case(&base64_scheme,
BASE64_ENCODE_FLAG_CRLF, 0, 10);
test_base64_random_lowlevel_case(&base64url_scheme,
BASE64_ENCODE_FLAG_CRLF, 0, 10);
test_base64_random_lowlevel_case(&base64_scheme,
BASE64_ENCODE_FLAG_NO_PADDING,
BASE64_DECODE_FLAG_NO_PADDING, 0);
test_base64_random_lowlevel_case(&base64url_scheme,
BASE64_ENCODE_FLAG_NO_PADDING,
BASE64_DECODE_FLAG_NO_PADDING, 0);
test_base64_random_lowlevel_case(&base64_scheme,
BASE64_ENCODE_FLAG_NO_PADDING |
BASE64_ENCODE_FLAG_CRLF,
BASE64_DECODE_FLAG_NO_PADDING, 15);
test_base64_random_lowlevel_case(&base64url_scheme,
BASE64_ENCODE_FLAG_NO_PADDING |
BASE64_ENCODE_FLAG_CRLF,
BASE64_DECODE_FLAG_NO_PADDING, 15);
test_base64_random_lowlevel_case(&base64_scheme,
BASE64_ENCODE_FLAG_NO_PADDING |
BASE64_ENCODE_FLAG_CRLF,
BASE64_DECODE_FLAG_NO_PADDING, 1);
test_end();
}
static void
_add_lines(const char *in, size_t max_line_len, bool crlf, string_t *out)
{
size_t in_len = strlen(in);
while (max_line_len > 0 && in_len > max_line_len) {
str_append_data(out, in, max_line_len);
if (crlf)
str_append(out, "\r\n");
else
str_append_c(out, '\n');
in += max_line_len;
in_len -= max_line_len;
}
str_append_data(out, in, in_len);
}
static void test_base64_encode_lines(void)
{
static const char *input[] = {
"Passer, deliciae meae puellae,\n"
"quicum ludere, quem in sinu tenere,\n"
"cui primum digitum dare appetenti\n"
"et acris solet incitare morsus,\n"
"cum desiderio meo nitenti\n"
"carum nescio quid lubet iocari,\n"
"credo ut, cum gravis acquiescet ardor,\n"
"sit solaciolum sui doloris,\n"
"tecum ludere sicut ipsa possem\n"
"et tristis animi levare curas!\n"
};
static const char *output[] = {
"UGFzc2VyLCBkZWxpY2lhZSBtZWFlIHB1ZWxsYWUsCnF1aWN1"
"bSBsdWRlcmUsIHF1ZW0gaW4gc2ludSB0ZW5lcmUsCmN1aSBw"
"cmltdW0gZGlnaXR1bSBkYXJlIGFwcGV0ZW50aQpldCBhY3Jp"
"cyBzb2xldCBpbmNpdGFyZSBtb3JzdXMsCmN1bSBkZXNpZGVy"
"aW8gbWVvIG5pdGVudGkKY2FydW0gbmVzY2lvIHF1aWQgbHVi"
"ZXQgaW9jYXJpLApjcmVkbyB1dCwgY3VtIGdyYXZpcyBhY3F1"
"aWVzY2V0IGFyZG9yLApzaXQgc29sYWNpb2x1bSBzdWkgZG9s"
"b3JpcywKdGVjdW0gbHVkZXJlIHNpY3V0IGlwc2EgcG9zc2Vt"
"CmV0IHRyaXN0aXMgYW5pbWkgbGV2YXJlIGN1cmFzIQo=",
};
string_t *out_test, *out_ref;
unsigned int i, n;
out_test = t_str_new(256);
out_ref = t_str_new(256);
test_begin("base64 encode lines (LF)");
for (i = 0; i < N_ELEMENTS(input); i++) {
struct base64_encoder b64enc;
for (n = 0; n <= 80; n++) {
str_truncate(out_test, 0);
base64_encode_init(&b64enc, &base64_scheme, 0, n);
base64_encode_more(&b64enc, input[i], strlen(input[i]),
NULL, out_test);
base64_encode_finish(&b64enc, out_test);
str_truncate(out_ref, 0);
_add_lines(output[i], n, FALSE, out_ref);
test_assert(strcmp(str_c(out_ref),
str_c(out_test)) == 0);
}
}
test_end();
test_begin("base64 encode lines (CRLF)");
for (i = 0; i < N_ELEMENTS(input); i++) {
struct base64_encoder b64enc;
for (n = 0; n <= 80; n++) {
str_truncate(out_test, 0);
base64_encode_init(&b64enc, &base64_scheme,
BASE64_ENCODE_FLAG_CRLF, n);
base64_encode_more(&b64enc, input[i], strlen(input[i]),
NULL, out_test);
base64_encode_finish(&b64enc, out_test);
str_truncate(out_ref, 0);
_add_lines(output[i], n, TRUE, out_ref);
test_assert(strcmp(str_c(out_ref),
str_c(out_test)) == 0);
}
}
test_end();
}
void test_base64(void)
{
test_base64_encode();
test_base64_decode();
test_base64_random();
test_base64url_encode();
test_base64url_decode();
test_base64url_random();
test_base64_encode_lowlevel();
test_base64_decode_lowlevel();
test_base64_random_lowlevel();
test_base64_encode_lines();
}
dovecot-2.3.21.1/src/lib/test-iso8601-date.c 0000644 0000000 0000000 00000007570 14656633576 015030 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "test-common.h"
#include "iso8601-date.h"
#include
struct iso8601_date_test {
const char *date_in;
const char *date_out;
struct tm tm;
int zone_offset;
};
/* Valid date tests */
struct iso8601_date_test valid_date_tests[] = {
{
.date_in = "2007-11-07T23:05:34+00:00",
.tm = {
.tm_year = 107, .tm_mon = 10, .tm_mday = 7,
.tm_hour = 23, .tm_min = 5, .tm_sec = 34 },
},{
.date_in = "2011-01-07T21:03:31+00:30",
.tm = {
.tm_year = 111, .tm_mon = 0, .tm_mday = 7,
.tm_hour = 21, .tm_min = 3, .tm_sec = 31 },
.zone_offset = 30
},{
.date_in = "2006-05-09T18:04:12+05:30",
.tm = {
.tm_year = 106, .tm_mon = 4, .tm_mday = 9,
.tm_hour = 18, .tm_min = 4, .tm_sec = 12 },
.zone_offset = 5*60+30
},{
.date_in = "1975-10-30T06:33:29Z",
.date_out = "1975-10-30T06:33:29+00:00",
.tm = {
.tm_year = 75, .tm_mon = 9, .tm_mday = 30,
.tm_hour = 6, .tm_min = 33, .tm_sec = 29 },
},{
.date_in = "1988-04-24t15:02:12z",
.date_out = "1988-04-24T15:02:12+00:00",
.tm = {
.tm_year = 88, .tm_mon = 3, .tm_mday = 24,
.tm_hour = 15, .tm_min = 2, .tm_sec = 12 },
},{
.date_in = "2012-02-29T08:12:34.23198Z",
.date_out = "2012-02-29T08:12:34+00:00",
.tm = {
.tm_year = 112, .tm_mon = 1, .tm_mday = 29,
.tm_hour = 8, .tm_min = 12, .tm_sec = 34 },
}
};
unsigned int valid_date_test_count = N_ELEMENTS(valid_date_tests);
static void test_iso8601_date_valid(void)
{
unsigned int i;
for (i = 0; i < valid_date_test_count; i++) T_BEGIN {
const char *date_in, *date_out, *pdate_out;
struct tm *tm = &valid_date_tests[i].tm, ptm;
int zone_offset = valid_date_tests[i].zone_offset, pzone_offset;
bool result;
date_in = valid_date_tests[i].date_in;
date_out = valid_date_tests[i].date_out == NULL ?
date_in : valid_date_tests[i].date_out;
test_begin(t_strdup_printf("iso8601 date valid [%d]", i));
result = iso8601_date_parse_tm
((const unsigned char *)date_in, strlen(date_in), &ptm, &pzone_offset);
test_out(t_strdup_printf("parse %s", date_in), result);
if (result) {
bool equal = tm->tm_year == ptm.tm_year && tm->tm_mon == ptm.tm_mon &&
tm->tm_mday == ptm.tm_mday && tm->tm_hour == ptm.tm_hour &&
tm->tm_min == ptm.tm_min && tm->tm_sec == ptm.tm_sec;
test_out("valid timestamp", equal);
test_out_reason("valid timezone", zone_offset == pzone_offset,
t_strdup_printf("%d", pzone_offset));
pdate_out = iso8601_date_create_tm(tm, zone_offset);
test_out_reason("valid create", strcmp(date_out, pdate_out) == 0,
pdate_out);
}
test_end();
} T_END;
}
/* Invalid date tests */
const char *invalid_date_tests[] = {
"200-11-17T23:05:34+00:00",
"2007:11-17T23:05:34+00:00",
"2007-11?17T23:05:34+00:00",
"2007-49-17T23:05:34+00:00",
"2007-11-77T23:05:34+00:00",
"2007-11-17K23:05:34+00:00",
"2007-11-13T59:05:34+00:00",
"2007-112-13T12:15:34+00:00",
"2007-11-133T12:15:34+00:00",
"2007-11-13T12J15:34+00:00",
"2007-11-13T12:15*34+00:00",
"2007-11-13T12:15:34/00:00",
"2007-11-13T12:15:34+00-00",
"2007-11-13T123:15:34+00:00",
"2007-11-13T12:157:34+00:00",
"2007-11-13T12:15:342+00:00",
"2007-11-13T12:15:34+001:00",
"2007-11-13T12:15:32+00:006",
"2007-02-29T15:13:21Z"
};
unsigned int invalid_date_test_count = N_ELEMENTS(invalid_date_tests);
static void test_iso8601_date_invalid(void)
{
unsigned int i;
for (i = 0; i < invalid_date_test_count; i++) T_BEGIN {
const char *date_in;
struct tm tm;
int tz;
bool result;
date_in = invalid_date_tests[i];
test_begin(t_strdup_printf("iso8601 date invalid [%d]", i));
result = iso8601_date_parse_tm
((const unsigned char *)date_in, strlen(date_in), &tm, &tz);
test_out(t_strdup_printf("parse %s", date_in), !result);
test_end();
} T_END;
}
void test_iso8601_date(void)
{
test_iso8601_date_valid();
test_iso8601_date_invalid();
}
dovecot-2.3.21.1/src/lib/test-istream-tee.c 0000644 0000000 0000000 00000010174 14656633576 015215 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "istream-private.h"
#include "istream-tee.h"
#define TEST_BUF_SIZE I_STREAM_MIN_SIZE
#define TEST_STR_LEN (TEST_BUF_SIZE*3)
#define CHILD_COUNT 5
static void test_istream_tee_tailing(const char *str)
{
struct istream *test_input, *child_input[CHILD_COUNT];
struct tee_istream *tee;
unsigned int i, len, delta;
test_input = test_istream_create(str);
test_istream_set_max_buffer_size(test_input, TEST_BUF_SIZE);
test_begin("istream tee tailing");
tee = tee_i_stream_create(test_input);
for (i = 0; i < CHILD_COUNT; i++)
child_input[i] = tee_i_stream_create_child(tee);
test_istream_set_allow_eof(test_input, FALSE);
delta = 1;
for (len = 1; len < TEST_BUF_SIZE; len += delta) {
test_istream_set_size(test_input, len);
for (i = 0; i < CHILD_COUNT; i++) {
test_assert_idx(i_stream_read(child_input[i]) == (int)delta, len);
test_assert_idx(!tee_i_stream_child_is_waiting(child_input[i]), len);
test_assert_idx(i_stream_read(child_input[i]) == 0, len);
test_assert_idx(!tee_i_stream_child_is_waiting(child_input[i]), len);
}
delta = i_rand_limit(32); /* may stand still */
if(delta > TEST_BUF_SIZE - len)
delta = 1;
}
test_istream_set_size(test_input, len);
for (i = 0; i < CHILD_COUNT; i++) {
test_assert(i_stream_read(child_input[i]) == (int)delta);
test_assert(i_stream_read(child_input[i]) == -2);
test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
}
delta = 1;
while ((len += delta) <= TEST_STR_LEN) {
unsigned int lagger = i_rand_limit(CHILD_COUNT);
test_istream_set_size(test_input, len);
for (i = 0; i < CHILD_COUNT; i++) {
test_assert(i_stream_read(child_input[i]) == -2);
test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
}
for (i = 0; i < CHILD_COUNT; i++) {
if (i == lagger)
continue;
i_stream_skip(child_input[i], delta);
test_assert(i_stream_read(child_input[i]) == 0);
test_assert(tee_i_stream_child_is_waiting(child_input[i]));
}
i_stream_skip(child_input[lagger], delta);
for (i = 0; i < CHILD_COUNT; i++) {
test_assert(i_stream_read(child_input[i]) == (int)delta);
test_assert(i_stream_read(child_input[i]) == -2);
test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
}
delta = i_rand_minmax(1, 31); /* mustn't stand still */
if(delta > TEST_STR_LEN - len)
delta = 1;
}
for (i = 0; i < CHILD_COUNT-1; i++) {
i_stream_skip(child_input[i], 1);
test_assert(i_stream_read(child_input[i]) == 0);
test_assert(tee_i_stream_child_is_waiting(child_input[i]));
}
i_stream_skip(child_input[i], 1);
test_assert(i_stream_read(child_input[i]) == 0);
test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
test_istream_set_allow_eof(test_input, TRUE);
for (i = 0; i < CHILD_COUNT; i++) {
test_assert(i_stream_read(child_input[i]) == -1);
i_stream_unref(&child_input[i]);
}
i_stream_unref(&test_input);
test_end();
}
static void test_istream_tee_blocks(const char *str)
{
struct istream *test_input, *child_input[CHILD_COUNT];
struct tee_istream *tee;
unsigned int i, j;
test_input = test_istream_create(str);
test_istream_set_max_buffer_size(test_input, TEST_BUF_SIZE);
test_begin("istream tee blocks");
tee = tee_i_stream_create(test_input);
for (i = 0; i < CHILD_COUNT; i++)
child_input[i] = tee_i_stream_create_child(tee);
test_istream_set_allow_eof(test_input, FALSE);
for (j = 1; j <= 3; j++) {
test_istream_set_size(test_input, TEST_BUF_SIZE*j);
for (i = 0; i < CHILD_COUNT; i++) {
test_assert(i_stream_read(child_input[i]) == TEST_BUF_SIZE);
i_stream_skip(child_input[i], TEST_BUF_SIZE);
}
}
test_istream_set_allow_eof(test_input, TRUE);
for (i = 0; i < CHILD_COUNT; i++) {
test_assert(i_stream_read(child_input[i]) == -1);
i_stream_unref(&child_input[i]);
}
i_stream_unref(&test_input);
test_end();
}
void test_istream_tee(void)
{
string_t *str;
unsigned int i;
str = str_new(default_pool, TEST_STR_LEN);
for (i = 0; i < TEST_STR_LEN; i++)
str_append_c(str, 'a' + i%26);
test_istream_tee_tailing(str_c(str));
test_istream_tee_blocks(str_c(str));
str_free(&str);
}
dovecot-2.3.21.1/src/lib/istream-hash.h 0000644 0000000 0000000 00000000543 14656633576 014412 0000000 0000000 #ifndef ISTREAM_HASH_H
#define ISTREAM_HASH_H
struct hash_method;
/* hash_context must be allocated and initialized by caller. This istream will
simply call method->loop() for all the data going through the istream. */
struct istream *
i_stream_create_hash(struct istream *input, const struct hash_method *method,
void *hash_context);
#endif
dovecot-2.3.21.1/src/lib/time-util.h 0000644 0000000 0000000 00000006123 14656633576 013736 0000000 0000000 #ifndef TIME_UTIL_H
#define TIME_UTIL_H
#include /* for struct timeval */
/* Same as gettimeofday(), but call i_fatal() if the call fails. */
void i_gettimeofday(struct timeval *tv_r);
/* Return nanoseconds since UNIX epoch (1970-01-01). */
uint64_t i_nanoseconds(void);
/* Return microseconds since UNIX epoch (1970-01-01). */
static inline uint64_t i_microseconds(void) {
return i_nanoseconds() / 1000;
}
/* Returns -1 if tv1tv2, 0 if they're equal. */
int timeval_cmp(const struct timeval *tv1, const struct timeval *tv2);
/* Same as timeval_cmp, but tv->usecs must differ by at least usec_margin */
int timeval_cmp_margin(const struct timeval *tv1, const struct timeval *tv2,
unsigned int usec_margin);
/* Returns tv1-tv2 in milliseconds. */
int timeval_diff_msecs(const struct timeval *tv1, const struct timeval *tv2);
/* Returns tv1-tv2 in microseconds. */
long long timeval_diff_usecs(const struct timeval *tv1,
const struct timeval *tv2);
static inline void
timeval_add_usecs(struct timeval *tv, long long usecs)
{
i_assert(usecs >= 0);
tv->tv_sec += usecs / 1000000;
tv->tv_usec += (usecs % 1000000);
if (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
static inline void
timeval_sub_usecs(struct timeval *tv, long long usecs)
{
i_assert(usecs >= 0);
tv->tv_sec -= usecs / 1000000;
tv->tv_usec -= (usecs % 1000000);
if (tv->tv_usec < 0) {
tv->tv_sec--;
tv->tv_usec += 1000000;
}
}
static inline void
timeval_add_msecs(struct timeval *tv, unsigned int msecs)
{
tv->tv_sec += msecs / 1000;
tv->tv_usec += (msecs % 1000) * 1000;
if (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
static inline void
timeval_sub_msecs(struct timeval *tv, unsigned int msecs)
{
tv->tv_sec -= msecs / 1000;
tv->tv_usec -= (msecs % 1000) * 1000;
if (tv->tv_usec < 0) {
tv->tv_sec--;
tv->tv_usec += 1000000;
}
}
static inline unsigned long long timeval_to_usecs(const struct timeval *tv)
{
return (tv->tv_sec * 1000000ULL + tv->tv_usec);
}
static inline void timeval_add(struct timeval *tv, const struct timeval *val)
{
i_assert(val->tv_usec < 1000000);
tv->tv_sec += val->tv_sec;
tv->tv_usec += val->tv_usec;
if (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
static inline time_t timeval_round(struct timeval *tv)
{
return (tv->tv_usec < 500000 ? tv->tv_sec : tv->tv_sec + 1);
}
/* Convert t to local time and return timestamp on that day at 00:00:00. */
time_t time_to_local_day_start(time_t t);
/* Wrappers to strftime() */
const char *t_strftime(const char *fmt, const struct tm *tm) ATTR_STRFTIME(1);
const char *t_strflocaltime(const char *fmt, time_t t) ATTR_STRFTIME(1);
const char *t_strfgmtime(const char *fmt, time_t t) ATTR_STRFTIME(1);
/* Parse string as [.] into timeval. must not
have higher precision time, i.e. a maximum of 6 digits is allowed. Note that
".1" is handled as ".1000000" so the string should have been written using
"%06u" printf format. */
int str_to_timeval(const char *str, struct timeval *tv_r)
ATTR_WARN_UNUSED_RESULT;
#endif
dovecot-2.3.21.1/src/lib/eacces-error.c 0000644 0000000 0000000 00000016675 14656633576 014407 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "path-util.h"
#include "ipwd.h"
#include "restrict-access.h"
#include "eacces-error.h"
#include
#include
static bool is_in_group(gid_t gid)
{
const gid_t *gids;
unsigned int i, count;
if (getegid() == gid)
return TRUE;
gids = restrict_get_groups_list(&count);
for (i = 0; i < count; i++) {
if (gids[i] == gid)
return TRUE;
}
return FALSE;
}
static void write_eacces_error(string_t *errmsg, const char *path, int mode)
{
char c;
switch (mode) {
case R_OK:
c = 'r';
break;
case W_OK:
c = 'w';
break;
case X_OK:
c = 'x';
break;
default:
i_unreached();
}
str_printfa(errmsg, " missing +%c perm: %s", c, path);
}
static int
test_manual_access(const char *path, int access_mode, bool write_eacces,
string_t *errmsg)
{
const struct group *group;
bool user_not_in_group = FALSE;
struct stat st;
int mode;
if (stat(path, &st) < 0) {
str_printfa(errmsg, " stat(%s) failed: %m", path);
return -1;
}
switch (access_mode) {
case R_OK:
mode = 04;
break;
case W_OK:
mode = 02;
break;
case X_OK:
mode = 01;
break;
default:
i_unreached();
}
if (st.st_uid == geteuid())
st.st_mode = (st.st_mode & 0700) >> 6;
else if (is_in_group(st.st_gid))
st.st_mode = (st.st_mode & 0070) >> 3;
else {
if ((((st.st_mode & 0070) >> 3) & mode) != 0)
user_not_in_group = TRUE;
st.st_mode = (st.st_mode & 0007);
}
if ((st.st_mode & mode) != 0)
return 0;
if (write_eacces)
write_eacces_error(errmsg, path, access_mode);
if (user_not_in_group) {
/* group would have had enough permissions,
but we don't belong to the group */
str_printfa(errmsg, ", we're not in group %s",
dec2str(st.st_gid));
group = getgrgid(st.st_gid);
if (group != NULL)
str_printfa(errmsg, "(%s)", group->gr_name);
}
errno = EACCES;
return -1;
}
static int test_access(const char *path, int access_mode, string_t *errmsg)
{
struct stat st;
if (getuid() == geteuid()) {
if (access(path, access_mode) == 0)
return 0;
if (errno == EACCES) {
write_eacces_error(errmsg, path, access_mode);
if (test_manual_access(path, access_mode,
FALSE, errmsg) == 0) {
str_append(errmsg, ", UNIX perms appear ok "
"(ACL/MAC wrong?)");
}
errno = EACCES;
} else {
str_printfa(errmsg, ", access(%s, %d) failed: %m",
path, access_mode);
}
return -1;
}
/* access() uses real uid, not effective uid.
we'll have to do these checks manually. */
switch (access_mode) {
case X_OK:
if (stat(t_strconcat(path, "/test", NULL), &st) == 0)
return 0;
if (errno == ENOENT || errno == ENOTDIR)
return 0;
if (errno == EACCES)
write_eacces_error(errmsg, path, access_mode);
else
str_printfa(errmsg, ", stat(%s/test) failed: %m", path);
return -1;
case R_OK:
case W_OK:
break;
default:
i_unreached();
}
return test_manual_access(path, access_mode, TRUE, errmsg);
}
static const char *
eacces_error_get_full(const char *func, const char *path, bool creating)
{
const char *prev_path, *dir = NULL, *p;
const char *pw_name = NULL, *gr_name = NULL;
struct passwd pw;
struct group group;
string_t *errmsg;
struct stat st;
int orig_errno, ret, missing_mode = 0;
orig_errno = errno;
errmsg = t_str_new(256);
str_printfa(errmsg, "%s(%s)", func, path);
if (*path != '/') {
const char *error;
if (t_get_working_dir(&dir, &error) < 0) {
i_error("eacces_error_get_full: %s", error);
str_printfa(errmsg, " in an unknown directory");
} else {
str_printfa(errmsg, " in directory %s", dir);
path = t_strconcat(dir, "/", path, NULL);
}
}
str_printfa(errmsg, " failed: Permission denied (euid=%s",
dec2str(geteuid()));
switch (i_getpwuid(geteuid(), &pw)) {
case -1:
str_append(errmsg, "()");
break;
case 0:
str_append(errmsg, "()");
break;
default:
pw_name = t_strdup(pw.pw_name);
str_printfa(errmsg, "(%s)", pw_name);
break;
}
str_printfa(errmsg, " egid=%s", dec2str(getegid()));
switch (i_getgrgid(getegid(), &group)) {
case -1:
str_append(errmsg, "()");
break;
case 0:
str_append(errmsg, "()");
break;
default:
gr_name = t_strdup(group.gr_name);
str_printfa(errmsg, "(%s)", gr_name);
break;
}
prev_path = path; ret = -1;
while (strcmp(prev_path, "/") != 0) {
if ((p = strrchr(prev_path, '/')) == NULL)
break;
dir = t_strdup_until(prev_path, p);
ret = stat(dir, &st);
if (ret == 0)
break;
if (errno == EACCES && strcmp(dir, "/") != 0) {
/* see if we have access to parent directory */
} else if (errno == ENOENT && creating &&
strcmp(dir, "/") != 0) {
/* probably mkdir_parents() failed here, find the first
parent directory we couldn't create */
} else {
/* some other error, can't handle it */
str_printfa(errmsg, " stat(%s) failed: %m", dir);
break;
}
prev_path = dir;
}
if (ret == 0) {
/* dir is the first parent directory we can stat() */
if (test_access(dir, X_OK, errmsg) < 0) {
if (errno == EACCES)
missing_mode = 1;
} else if (creating && test_access(dir, W_OK, errmsg) < 0) {
if (errno == EACCES)
missing_mode = 2;
} else if (prev_path == path &&
test_access(path, R_OK, errmsg) < 0) {
} else if (!creating && test_access(path, W_OK, errmsg) < 0) {
/* this produces a wrong error if the operation didn't
actually need write permissions, but we don't know
it here.. */
if (errno == EACCES)
missing_mode = 4;
} else {
str_append(errmsg, " UNIX perms appear ok "
"(ACL/MAC wrong?)");
}
}
if (ret < 0)
;
else if (st.st_uid != geteuid()) {
if (pw_name != NULL && i_getpwuid(st.st_uid, &pw) > 0 &&
strcmp(pw.pw_name, pw_name) == 0) {
str_printfa(errmsg, ", conflicting dir uid=%s(%s)",
dec2str(st.st_uid), pw_name);
} else {
str_printfa(errmsg, ", dir owned by %s:%s mode=0%o",
dec2str(st.st_uid), dec2str(st.st_gid),
(unsigned int)(st.st_mode & 0777));
}
} else if (missing_mode != 0 &&
(((st.st_mode & 0700) >> 6) & missing_mode) == 0) {
str_append(errmsg, ", dir owner missing perms");
}
if (ret == 0 && gr_name != NULL && st.st_gid != getegid()) {
if (i_getgrgid(st.st_gid, &group) > 0 &&
strcmp(group.gr_name, gr_name) == 0) {
str_printfa(errmsg, ", conflicting dir gid=%s(%s)",
dec2str(st.st_gid), gr_name);
}
}
str_append_c(errmsg, ')');
errno = orig_errno;
return str_c(errmsg);
}
const char *eacces_error_get(const char *func, const char *path)
{
return eacces_error_get_full(func, path, FALSE);
}
const char *eacces_error_get_creating(const char *func, const char *path)
{
return eacces_error_get_full(func, path, TRUE);
}
const char *eperm_error_get_chgrp(const char *func, const char *path,
gid_t gid, const char *gid_origin)
{
string_t *errmsg;
const struct group *group;
int orig_errno = errno;
errmsg = t_str_new(256);
str_printfa(errmsg, "%s(%s, group=%s", func, path, dec2str(gid));
group = getgrgid(gid);
if (group != NULL)
str_printfa(errmsg, "(%s)", group->gr_name);
str_printfa(errmsg, ") failed: Operation not permitted (egid=%s",
dec2str(getegid()));
group = getgrgid(getegid());
if (group != NULL)
str_printfa(errmsg, "(%s)", group->gr_name);
if (gid_origin != NULL)
str_printfa(errmsg, ", group based on %s", gid_origin);
str_append(errmsg, " - see http://wiki2.dovecot.org/Errors/ChgrpNoPerm)");
errno = orig_errno;
return str_c(errmsg);
}
dovecot-2.3.21.1/src/lib/str-table.h 0000644 0000000 0000000 00000001231 14656633576 013715 0000000 0000000 #ifndef STR_TABLE_H
#define STR_TABLE_H
/* Hash table containing string -> refcount. */
struct str_table *str_table_init(void);
void str_table_deinit(struct str_table **table);
/* Returns TRUE if there are no referenced strings in the table. */
bool str_table_is_empty(struct str_table *table);
/* Return string allocated from the strtable and increase its reference
count. */
const char *str_table_ref(struct str_table *table, const char *str);
/* Decrease string's reference count, freeing it if it reaches zero.
The str pointer must have been returned by the str_table_ref(). */
void str_table_unref(struct str_table *table, const char **str);
#endif
dovecot-2.3.21.1/src/lib/module-context.h 0000644 0000000 0000000 00000007247 14656633576 015004 0000000 0000000 #ifndef MODULE_CONTEXT_H
#define MODULE_CONTEXT_H
#include "array.h"
/*
This is a bit complex to use, but it prevents using wrong module IDs
in module_contexts arrays.
---------
The main structure is implemented like this:
struct STRUCT_NAME_module_register {
unsigned int id;
};
union STRUCT_NAME_module_context {
struct STRUCT_NAME_module_register *reg;
// it's allowed to have some structure here so it won't waste space.
// for example: struct STRUCT_NAME_vfuncs super;
};
struct STRUCT_NAME {
ARRAY(union STRUCT_NAME_module_context *) module_contexts;
};
extern struct STRUCT_NAME_module_register STRUCT_NAME_module_register;
---------
The usage in modules goes like:
static MODULE_CONTEXT_DEFINE(mymodule_STRUCT_NAME_module,
&STRUCT_NAME_module_register);
struct mymodule_STRUCT_NAME {
union STRUCT_NAME_module_context module_ctx;
// module-specific data
};
struct mymodule_STRUCT_NAME *ctx = i_new(...);
MODULE_CONTEXT_SET(obj, mymodule_STRUCT_NAME_module, ctx);
struct mymodule_STRUCT_NAME *ctx =
MODULE_CONTEXT(obj, mymodule_STRUCT_NAME_module);
*/
#define OBJ_REGISTER(obj) \
((**(obj)->module_contexts.v)->reg)
#define OBJ_REGISTER_COMPATIBLE(obj, id_ctx) \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(OBJ_REGISTER(obj), (id_ctx).reg)
#define MODULE_CONTEXT(obj, id_ctx) \
(module_get_context_id(&(id_ctx).id) < array_count(&(obj)->module_contexts) ? \
(*((void **)array_idx_modifiable(&(obj)->module_contexts, \
module_get_context_id(&(id_ctx).id)) + \
OBJ_REGISTER_COMPATIBLE(obj, id_ctx))) : NULL)
/* Will crash if context is missing. This is mainly used to simplify code and
keep static analyzers happy. This syntax discards result of i_panic and
returns NULL instead to keep compilers happy. */
#define MODULE_CONTEXT_REQUIRE(obj, id_ctx) \
(module_get_context_id(&(id_ctx).id) < array_count(&(obj)->module_contexts) ? \
(*((void **)array_idx_modifiable(&(obj)->module_contexts, \
module_get_context_id(&(id_ctx).id)) + \
OBJ_REGISTER_COMPATIBLE(obj, id_ctx))) : (i_panic("Module context " #id_ctx " missing"), NULL))
#ifdef HAVE_TYPEOF
# define MODULE_CONTEXT_DEFINE(_name, _reg) \
struct _name { \
struct module_context_id id; \
typeof(_reg) reg; \
} _name
# define MODULE_CONTEXT_INIT(_reg) \
{ { &(_reg)->id, 0, FALSE }, NULL }
#else
# define MODULE_CONTEXT_DEFINE(_name, _reg) \
struct _name { \
struct module_context_id id; \
} _name
# define MODULE_CONTEXT_INIT(_reg) \
{ { &(_reg)->id, 0, FALSE } }
#endif
#define MODULE_CONTEXT_DEFINE_INIT(_name, _reg) \
MODULE_CONTEXT_DEFINE(_name, _reg) = MODULE_CONTEXT_INIT(_reg)
struct module_context_id {
unsigned int *module_id_register;
unsigned int module_id;
bool module_id_set;
};
static inline unsigned int module_get_context_id(struct module_context_id *id)
{
if (!id->module_id_set) {
id->module_id = *id->module_id_register;
id->module_id_set = TRUE;
*id->module_id_register += 1;
}
return id->module_id;
}
#define MODULE_CONTEXT_SET_FULL(obj, id_ctx, ctx, module_ctx) STMT_START { \
(void)COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(module_ctx, \
(**(obj)->module_contexts.v)); \
(void)OBJ_REGISTER_COMPATIBLE(obj, id_ctx); \
void *_module_tmp = ctx; \
array_idx_set_i(&(obj)->module_contexts.arr, \
module_get_context_id(&(id_ctx).id), &_module_tmp); \
} STMT_END
#define MODULE_CONTEXT_SET(obj, id_ctx, context) \
MODULE_CONTEXT_SET_FULL(obj, id_ctx, context, &(context)->module_ctx)
#define MODULE_CONTEXT_SET_SELF(obj, id_ctx, context) \
MODULE_CONTEXT_SET_FULL(obj, id_ctx, context, context)
#define MODULE_CONTEXT_UNSET(obj, id_ctx) \
array_idx_clear(&(obj)->module_contexts, (id_ctx).id.module_id)
#endif
dovecot-2.3.21.1/src/lib/lib-signals.c 0000644 0000000 0000000 00000041753 14656633576 014234 0000000 0000000 /* Copyright (c) 2001-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "write-full.h"
#include "llist.h"
#include "lib-signals.h"
#include
#include
#include
#define MAX_SIGNAL_VALUE 63
#define SIGNAL_IS_TERMINAL(signo) \
((signo) == SIGINT || (signo) == SIGQUIT || (signo) == SIGTERM)
#if !defined(SA_SIGINFO) && !defined(SI_NOINFO)
/* without SA_SIGINFO we don't know what the real code is. we need SI_NOINFO
to make sure lib_signal_code_to_str() returns "". */
# define SI_NOINFO -1
#endif
struct signal_ioloop {
struct signal_ioloop *prev, *next;
int refcount;
struct ioloop *ioloop;
struct io *io;
};
struct signal_handler {
signal_handler_t *handler;
void *context;
enum libsig_flags flags;
struct signal_handler *next;
struct signal_ioloop *sig_ioloop;
bool expected:1;
bool shadowed:1;
};
volatile unsigned int signal_term_counter = 0;
/* Remember that these are accessed inside signal handler which may be called
even while we're initializing/deinitializing. Try hard to keep everything
in consistent state. */
static struct signal_handler *signal_handlers[MAX_SIGNAL_VALUE+1] = { NULL, };
static int sig_pipe_fd[2] = { -1, -1 };
static bool signals_initialized = FALSE;
static unsigned int signals_expected = 0;
static struct signal_ioloop *signal_ioloops = NULL;
static siginfo_t pending_signals[MAX_SIGNAL_VALUE+1];
static ARRAY(siginfo_t) pending_shadowed_signals;
static bool have_pending_signals = FALSE;
static bool have_missing_ioloops = FALSE;
static bool ioloop_switched = FALSE;
static void signal_read(void *context);
const char *lib_signal_code_to_str(int signo, int sicode)
{
/* common */
switch (sicode) {
#ifdef SI_NOINFO
case SI_NOINFO:
return "";
#endif
case SI_USER:
return "kill";
#ifdef SI_KERNEL
case SI_KERNEL:
return "kernel";
#endif
case SI_TIMER:
return "timer";
}
/* If SEGV_MAPERR is supported, the rest of them must be too.
FreeBSD 6 at least doesn't support these. */
#ifdef SEGV_MAPERR
switch (signo) {
case SIGSEGV:
switch (sicode) {
case SEGV_MAPERR:
return "address not mapped";
case SEGV_ACCERR:
return "invalid permissions";
}
break;
case SIGBUS:
switch (sicode) {
case BUS_ADRALN:
return "invalid address alignment";
#ifdef BUS_ADRERR /* for OSX 10.3 */
case BUS_ADRERR:
return "nonexistent physical address";
#endif
#ifdef BUS_OBJERR /* for OSX 10.3 */
case BUS_OBJERR:
return "object-specific hardware error";
#endif
}
}
#endif
return t_strdup_printf("unknown %d", sicode);
}
#ifdef SA_SIGINFO
static void sig_handler(int signo, siginfo_t *si, void *context ATTR_UNUSED)
#else
static void sig_handler(int signo)
#endif
{
struct signal_handler *h;
int saved_errno;
char c = 0;
#if defined(SI_NOINFO) || !defined(SA_SIGINFO)
#ifndef SA_SIGINFO
siginfo_t *si = NULL;
#endif
siginfo_t tmp_si;
if (si == NULL) {
/* Solaris can leave this to NULL */
i_zero(&tmp_si);
tmp_si.si_signo = signo;
tmp_si.si_code = SI_NOINFO;
si = &tmp_si;
}
#endif
if (signo < 0 || signo > MAX_SIGNAL_VALUE)
return;
if (SIGNAL_IS_TERMINAL(signo))
signal_term_counter++;
/* remember that we're inside a signal handler which might have been
called at any time. don't do anything that's unsafe. we might also
get interrupted by another signal while inside this handler. */
saved_errno = errno;
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
if ((h->flags & LIBSIG_FLAG_DELAYED) == 0)
h->handler(si, h->context);
else if (pending_signals[signo].si_signo == 0) {
pending_signals[signo] = *si;
if (!have_pending_signals) {
if (write(sig_pipe_fd[1], &c, 1) != 1) {
lib_signals_syscall_error(
"signal: write(sigpipe) failed: ");
}
have_pending_signals = TRUE;
}
}
}
errno = saved_errno;
}
#ifdef SA_SIGINFO
static void sig_ignore(int signo ATTR_UNUSED, siginfo_t *si ATTR_UNUSED,
void *context ATTR_UNUSED)
#else
static void sig_ignore(int signo ATTR_UNUSED)
#endif
{
/* if we used SIG_IGN instead of this function,
the system call might be restarted */
}
static struct signal_ioloop *
lib_signals_ioloop_find(struct ioloop *ioloop)
{
struct signal_ioloop *l;
for (l = signal_ioloops; l != NULL; l = l->next) {
if (l->ioloop == ioloop)
break;
}
return l;
}
static void lib_signals_init_io(struct signal_ioloop *l)
{
i_assert(sig_pipe_fd[0] != -1);
l->io = io_add_to(l->ioloop, sig_pipe_fd[0], IO_READ, signal_read, NULL);
io_set_never_wait_alone(l->io, signals_expected == 0);
}
static struct signal_ioloop *
lib_signals_ioloop_ref(struct ioloop *ioloop)
{
struct signal_ioloop *l;
l = lib_signals_ioloop_find(ioloop);
if (l == NULL) {
l = i_new(struct signal_ioloop, 1);
l->ioloop = ioloop;
lib_signals_init_io(l);
DLLIST_PREPEND(&signal_ioloops, l);
}
l->refcount++;
return l;
}
static void lib_signals_ioloop_unref(struct signal_ioloop **_sig_ioloop)
{
struct signal_ioloop *sig_ioloop = *_sig_ioloop;
*_sig_ioloop = NULL;
if (sig_ioloop == NULL)
return;
i_assert(sig_ioloop->refcount > 0);
if (--sig_ioloop->refcount > 0)
return;
io_remove(&sig_ioloop->io);
DLLIST_REMOVE(&signal_ioloops, sig_ioloop);
i_free(sig_ioloop);
}
static void signal_handler_switch_ioloop(struct signal_handler *h)
{
lib_signals_ioloop_unref(&h->sig_ioloop);
if (current_ioloop != NULL)
h->sig_ioloop = lib_signals_ioloop_ref(current_ioloop);
else
have_missing_ioloops = TRUE;
}
static void signal_handler_free(struct signal_handler *h)
{
lib_signals_ioloop_unref(&h->sig_ioloop);
i_free(h);
}
static void signal_handle_shadowed(void)
{
const siginfo_t *sis;
unsigned int count, i;
if (!array_is_created(&pending_shadowed_signals) ||
array_count(&pending_shadowed_signals) == 0)
return;
sis = array_get(&pending_shadowed_signals, &count);
for (i = 0; i < count; i++) {
struct signal_handler *h;
bool shadowed = FALSE;
i_assert(sis[i].si_signo > 0);
for (h = signal_handlers[sis[i].si_signo]; h != NULL;
h = h->next) {
i_assert(h->sig_ioloop != NULL);
if ((h->flags & LIBSIG_FLAG_DELAYED) == 0 ||
(h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) != 0)
continue;
if (h->shadowed &&
h->sig_ioloop->ioloop != current_ioloop) {
shadowed = TRUE;
continue;
}
/* handler can be called now */
h->shadowed = FALSE;
h->handler(&sis[i], h->context);
}
if (!shadowed) {
/* no handlers are shadowed anymore; delete the signal
info */
array_delete(&pending_shadowed_signals, i, 1);
sis = array_get(&pending_shadowed_signals, &count);
}
}
}
static void signal_check_shadowed(void)
{
struct signal_ioloop *sig_ioloop;
if (!array_is_created(&pending_shadowed_signals) ||
array_count(&pending_shadowed_signals) == 0)
return;
sig_ioloop = lib_signals_ioloop_find(current_ioloop);
if (sig_ioloop != NULL)
io_set_pending(sig_ioloop->io);
}
static void signal_shadow(int signo, const siginfo_t *si)
{
const siginfo_t *sis;
unsigned int count, i;
/* remember last signal info for handlers that cannot run in
current ioloop */
if (!array_is_created(&pending_shadowed_signals))
i_array_init(&pending_shadowed_signals, 4);
sis = array_get(&pending_shadowed_signals, &count);
for (i = 0; i < count; i++) {
i_assert(sis[i].si_signo != 0);
if (sis[i].si_signo == signo)
break;
}
array_idx_set(&pending_shadowed_signals, i, si);
}
static void ATTR_NULL(1) signal_read(void *context ATTR_UNUSED)
{
siginfo_t signals[MAX_SIGNAL_VALUE+1];
sigset_t fullset, oldset;
struct signal_handler *h;
char buf[64];
int signo;
ssize_t ret;
if (ioloop_switched) {
ioloop_switched = FALSE;
/* handle any delayed signal handlers that emerged from the
shadow */
signal_handle_shadowed();
}
if (sigfillset(&fullset) < 0)
i_fatal("sigfillset() failed: %m");
if (sigprocmask(SIG_BLOCK, &fullset, &oldset) < 0)
i_fatal("sigprocmask() failed: %m");
/* typically we should read only a single byte, but if a signal is sent
while signal handler is running we might get more. */
ret = read(sig_pipe_fd[0], buf, sizeof(buf));
if (ret > 0) {
memcpy(signals, pending_signals, sizeof(signals));
memset(pending_signals, 0, sizeof(pending_signals));
have_pending_signals = FALSE;
} else if (ret < 0) {
if (errno != EAGAIN)
i_fatal("read(sigpipe) failed: %m");
} else {
i_fatal("read(sigpipe) failed: EOF");
}
if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
i_fatal("sigprocmask() failed: %m");
if (ret < 0)
return;
/* call the delayed handlers after signals are copied and unblocked */
for (signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
bool shadowed = FALSE;
if (signals[signo].si_signo == 0)
continue;
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
i_assert(h->sig_ioloop != NULL);
if ((h->flags & LIBSIG_FLAG_DELAYED) == 0) {
/* handler already called immediately in signal
context */
continue;
}
if ((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) == 0 &&
h->sig_ioloop->ioloop != current_ioloop) {
/* cannot run handler in current ioloop
(shadowed) */
h->shadowed = TRUE;
shadowed = TRUE;
continue;
}
/* handler can be called now */
h->handler(&signals[signo], h->context);
}
if (shadowed) {
/* remember last signal info for handlers that cannot
run in current ioloop (shadowed) */
signal_shadow(signo, &signals[signo]);
}
}
}
static void lib_signals_update_expected_signals(bool expected)
{
struct signal_ioloop *sig_ioloop;
if (expected)
signals_expected++;
else {
i_assert(signals_expected > 0);
signals_expected--;
}
sig_ioloop = signal_ioloops;
for (; sig_ioloop != NULL; sig_ioloop = sig_ioloop->next) {
if (sig_ioloop->io != NULL) {
io_set_never_wait_alone(sig_ioloop->io,
signals_expected == 0);
}
}
}
static void lib_signals_ioloop_switch(void)
{
struct signal_handler *h;
if (current_ioloop == NULL || sig_pipe_fd[0] <= 0)
return;
/* initialize current_ioloop for signal handlers created before the
first ioloop. */
for (int signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
if ((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) != 0)
lib_signals_ioloop_unref(&h->sig_ioloop);
if (h->sig_ioloop == NULL)
h->sig_ioloop = lib_signals_ioloop_ref(current_ioloop);
}
}
have_missing_ioloops = FALSE;
}
static void lib_signals_ioloop_switched(struct ioloop *prev_ioloop ATTR_UNUSED)
{
ioloop_switched = TRUE;
lib_signals_ioloop_switch();
/* check whether we can now handle any shadowed delayed signals */
signal_check_shadowed();
}
static void lib_signals_ioloop_destroyed(struct ioloop *ioloop)
{
struct signal_ioloop *sig_ioloop;
sig_ioloop = lib_signals_ioloop_find(ioloop);
if (sig_ioloop != NULL) {
io_remove(&sig_ioloop->io);
sig_ioloop->ioloop = NULL;
}
}
void lib_signals_ioloop_detach(void)
{
struct signal_handler *h;
for (int signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
if (h->sig_ioloop != NULL) {
lib_signals_ioloop_unref(&h->sig_ioloop);
have_missing_ioloops = TRUE;
}
}
}
}
void lib_signals_ioloop_attach(void)
{
if (have_missing_ioloops)
lib_signals_ioloop_switch();
}
static void lib_signals_set(int signo, enum libsig_flags flags)
{
struct sigaction act;
if (sigemptyset(&act.sa_mask) < 0)
i_fatal("sigemptyset(): %m");
#ifdef SA_SIGINFO
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = sig_handler;
#else
act.sa_flags = 0;
act.sa_handler = sig_handler;
#endif
if ((flags & LIBSIG_FLAG_RESTART) != 0)
act.sa_flags |= SA_RESTART;
if (sigaction(signo, &act, NULL) < 0)
i_fatal("sigaction(%d): %m", signo);
}
void lib_signals_set_handler(int signo, enum libsig_flags flags,
signal_handler_t *handler, void *context)
{
struct signal_handler *h;
i_assert(handler != NULL);
if (signo < 0 || signo > MAX_SIGNAL_VALUE) {
i_panic("Trying to set signal %d handler, but max is %d",
signo, MAX_SIGNAL_VALUE);
}
if (signal_handlers[signo] == NULL && signals_initialized)
lib_signals_set(signo, flags);
h = i_new(struct signal_handler, 1);
h->handler = handler;
h->context = context;
h->flags = flags;
/* atomically set to signal_handlers[] list */
h->next = signal_handlers[signo];
signal_handlers[signo] = h;
if ((flags & LIBSIG_FLAG_DELAYED) != 0 && sig_pipe_fd[0] == -1) {
/* first delayed handler */
if (pipe(sig_pipe_fd) < 0)
i_fatal("pipe() failed: %m");
fd_set_nonblock(sig_pipe_fd[0], TRUE);
fd_set_nonblock(sig_pipe_fd[1], TRUE);
fd_close_on_exec(sig_pipe_fd[0], TRUE);
fd_close_on_exec(sig_pipe_fd[1], TRUE);
}
signal_handler_switch_ioloop(h);
}
static void lib_signals_ignore_forced(int signo, bool restart_syscalls)
{
struct sigaction act;
if (sigemptyset(&act.sa_mask) < 0)
i_fatal("sigemptyset(): %m");
if (restart_syscalls) {
act.sa_flags = SA_RESTART;
act.sa_handler = SIG_IGN;
} else {
#ifdef SA_SIGINFO
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = sig_ignore;
#else
act.sa_flags = 0;
act.sa_handler = sig_ignore;
#endif
}
if (sigaction(signo, &act, NULL) < 0)
i_fatal("sigaction(%d): %m", signo);
}
void lib_signals_ignore(int signo, bool restart_syscalls)
{
if (signo < 0 || signo > MAX_SIGNAL_VALUE) {
i_panic("Trying to ignore signal %d, but max is %d",
signo, MAX_SIGNAL_VALUE);
}
i_assert(signal_handlers[signo] == NULL);
lib_signals_ignore_forced(signo, restart_syscalls);
}
void lib_signals_clear_handlers_and_ignore(int signo)
{
struct signal_handler *h;
if (signal_handlers[signo] == NULL)
return;
lib_signals_ignore_forced(signo, TRUE);
h = signal_handlers[signo];
signal_handlers[signo] = NULL;
while (h != NULL) {
struct signal_handler *h_next = h->next;
if (h->expected)
signals_expected--;
signal_handler_free(h);
h = h_next;
}
}
void lib_signals_unset_handler(int signo, signal_handler_t *handler,
void *context)
{
struct signal_handler *h, **p;
for (p = &signal_handlers[signo]; *p != NULL; p = &(*p)->next) {
if ((*p)->handler == handler && (*p)->context == context) {
if (p == &signal_handlers[signo] &&
(*p)->next == NULL) {
/* last handler is to be removed */
lib_signals_ignore_forced(signo, TRUE);
}
h = *p;
*p = h->next;
if (h->expected)
lib_signals_update_expected_signals(FALSE);
signal_handler_free(h);
return;
}
}
i_panic("lib_signals_unset_handler(%d, %p, %p): handler not found",
signo, (void *)handler, context);
}
void lib_signals_set_expected(int signo, bool expected,
signal_handler_t *handler, void *context)
{
struct signal_handler *h;
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
if (h->handler == handler && h->context == context) {
if (h->expected == expected)
return;
h->expected = expected;
lib_signals_update_expected_signals(expected);
return;
}
}
i_panic("lib_signals_set_expected(%d, %p, %p): handler not found",
signo, (void *)handler, context);
}
void lib_signals_switch_ioloop(int signo,
signal_handler_t *handler, void *context)
{
struct signal_handler *h;
for (h = signal_handlers[signo]; h != NULL; h = h->next) {
if (h->handler == handler && h->context == context) {
i_assert((h->flags & LIBSIG_FLAG_DELAYED) != 0);
i_assert((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) == 0);
signal_handler_switch_ioloop(h);
/* check whether we can now handle any shadowed delayed
signals */
signal_check_shadowed();
return;
}
}
i_panic("lib_signals_switch_ioloop(%d, %p, %p): handler not found",
signo, (void *)handler, context);
}
void lib_signals_syscall_error(const char *prefix)
{
/* @UNSAFE: We're in a signal handler. It's very limited what is
allowed in here. Especially strerror() isn't at least officially
allowed. */
char errno_buf[MAX_INT_STRLEN], *errno_str;
errno_str = dec2str_buf(errno_buf, errno);
size_t prefix_len = strlen(prefix);
size_t errno_str_len = strlen(errno_str);
char buf[prefix_len + errno_str_len + 1];
memcpy(buf, prefix, prefix_len);
memcpy(buf + prefix_len, errno_str, errno_str_len);
buf[prefix_len + errno_str_len] = '\n';
if (write_full(STDERR_FILENO, buf,
prefix_len + errno_str_len + 1) < 0) {
/* can't really do anything */
}
}
void lib_signals_init(void)
{
int i;
signals_initialized = TRUE;
io_loop_add_switch_callback(lib_signals_ioloop_switched);
io_loop_add_destroy_callback(lib_signals_ioloop_destroyed);
/* add signals that were already registered */
for (i = 0; i < MAX_SIGNAL_VALUE; i++) {
if (signal_handlers[i] != NULL)
lib_signals_set(i, signal_handlers[i]->flags);
}
}
void lib_signals_deinit(void)
{
int i;
for (i = 0; i < MAX_SIGNAL_VALUE; i++) {
if (signal_handlers[i] != NULL)
lib_signals_clear_handlers_and_ignore(i);
}
i_assert(signals_expected == 0);
if (sig_pipe_fd[0] != -1) {
if (close(sig_pipe_fd[0]) < 0)
i_error("close(sigpipe) failed: %m");
if (close(sig_pipe_fd[1]) < 0)
i_error("close(sigpipe) failed: %m");
sig_pipe_fd[0] = sig_pipe_fd[1] = -1;
}
if (array_is_created(&pending_shadowed_signals))
array_free(&pending_shadowed_signals);
i_assert(signal_ioloops == NULL);
}
dovecot-2.3.21.1/src/lib/base64.h 0000644 0000000 0000000 00000030446 14656633576 013116 0000000 0000000 #ifndef BASE64_H
#define BASE64_H
/*
* Common Base64
*/
/* max. buffer size required for base64_encode() */
#define MAX_BASE64_ENCODED_SIZE(size) \
((((size) + 2) / 3) * 4)
/* max. buffer size required for base64_decode() */
#define MAX_BASE64_DECODED_SIZE(size) \
(((size) + 3) / 4 * 3)
struct base64_scheme {
const char encmap[64];
const unsigned char decmap[256];
};
/*
* Low-level Base64 encoder
*/
enum base64_encode_flags {
/* Use CRLF instead of the default LF as line ending. */
BASE64_ENCODE_FLAG_CRLF = BIT(0),
/* Encode no padding at the end of the data. */
BASE64_ENCODE_FLAG_NO_PADDING = BIT(1),
};
struct base64_encoder {
const struct base64_scheme *b64;
enum base64_encode_flags flags;
size_t max_line_len;
/* state */
unsigned int sub_pos;
unsigned char buf;
size_t cur_line_len;
unsigned char w_buf[10];
unsigned int w_buf_len;
bool pending_lf:1;
bool finishing:1;
bool finished:1;
};
/* Returns TRUE when base64_encode_finish() was called on this encoder. */
static inline bool
base64_encode_is_finished(struct base64_encoder *enc)
{
return enc->finished;
}
/* Initialize the Base64 encoder. The b64 parameter is the definition of the
particular Base64 encoding scheme that is used.
*/
static inline void
base64_encode_init(struct base64_encoder *enc,
const struct base64_scheme *b64,
enum base64_encode_flags flags,
size_t max_line_len)
{
i_zero(enc);
enc->b64 = b64;
enc->flags = flags;
enc->max_line_len = (max_line_len == 0 ? SIZE_MAX : max_line_len);
}
/* Reset the Base64 encoder to its initial state. */
static inline void
base64_encode_reset(struct base64_encoder *enc)
{
const struct base64_scheme *b64 = enc->b64;
enum base64_encode_flags flags = enc->flags;
size_t max_line_len = enc->max_line_len;
base64_encode_init(enc, b64, flags, max_line_len);
}
/* Translate the size of the full encoder input to the size of the encoder
output.
*/
uoff_t base64_get_full_encoded_size(struct base64_encoder *enc,
uoff_t src_size);
/* Translate the size of the next input to the size of the output once encoded.
This yields the amount of data appended to the dest buffer by
base64_encode_more() with the indicated src_size. */
size_t base64_encode_get_size(struct base64_encoder *enc, size_t src_size);
/* Translate the space in the destination buffer to the number of bytes that can
be encoded at most to complete the full base64 encoding, including padding
and newlines if configured. */
size_t base64_encode_get_full_space(struct base64_encoder *enc,
size_t dst_space);
/* Translates binary data into some form of Base64. The src must not point to
dest buffer. Returns TRUE when all the provided data is encoded. Returns
FALSE when the space in the provided buffer is insufficient. The return value
may be ignored. If src_pos_r is non-NULL, it's updated to first
non-translated character in src.
*/
bool ATTR_NOWARN_UNUSED_RESULT
base64_encode_more(struct base64_encoder *enc, const void *src, size_t src_size,
size_t *src_pos_r, buffer_t *dest) ATTR_NULL(4);
/* Finishes Base64 encoding. Returns TRUE when all the provided data is encoded.
Returns FALSE when the space in the provided buffer is insufficient. The
return value may be ignored.
*/
bool ATTR_NOWARN_UNUSED_RESULT
base64_encode_finish(struct base64_encoder *enc, buffer_t *dest) ATTR_NULL(2);
/*
* Low-level Base64 decoder
*/
enum base64_decode_flags {
/* Decode input until a boundary is reached. This boundary is a
non-Base64 input sequence that would normally trigger a decode error;
e.g., Base64 data followed by a ':'. With this flag, it is possible
to decode such a Base64 prefix. The base64_decode_finish() function
will still check that the Base64 data ends properly (padding). */
BASE64_DECODE_FLAG_EXPECT_BOUNDARY = BIT(0),
/* Prohibit whitespace in the input. */
BASE64_DECODE_FLAG_NO_WHITESPACE = BIT(1),
/* Require absence of padding at the end of the input. */
BASE64_DECODE_FLAG_NO_PADDING = BIT(2),
/* Ignore padding at the end of the input. This flag is ignored when
BASE64_DECODE_FLAG_NO_PADDING is also set. If both of these flags are
absent, padding is required (the default). */
BASE64_DECODE_FLAG_IGNORE_PADDING = BIT(3),
};
struct base64_decoder {
const struct base64_scheme *b64;
enum base64_decode_flags flags;
/* state */
unsigned int sub_pos;
unsigned char buf;
bool seen_padding:1;
bool seen_end:1;
bool seen_boundary:1;
bool finished:1;
bool failed:1;
};
/* Returns TRUE when base64_decode_finish() was called on this decoder. */
static inline bool
base64_decode_is_finished(struct base64_decoder *dec)
{
return dec->finished;
}
/* Initialize the Base64 decoder. The b64 parameter is the definition of the
particular Base64 encoding scheme that is expected.
*/
static inline void
base64_decode_init(struct base64_decoder *dec,
const struct base64_scheme *b64,
enum base64_decode_flags flags)
{
i_zero(dec);
dec->b64 = b64;
dec->flags = flags;
}
/* Reset the Base64 decoder to its initial state. */
static inline void
base64_decode_reset(struct base64_decoder *dec)
{
const struct base64_scheme *b64 = dec->b64;
enum base64_decode_flags flags = dec->flags;
base64_decode_init(dec, b64, flags);
}
/* Translates some form of Base64 data into binary and appends it to dest
buffer. dest may point to same buffer as src. Returns 1 if all ok, 0 if end
of base64 data found, -1 if data is invalid.
By default, any CR, LF characters are ignored, as well as any whitespace.
This can be overridden using the BASE64_DECODE_FLAG_NO_WHITESPACE flag.
If src_pos is non-NULL, it's updated to first non-translated character in
src.
*/
int base64_decode_more(struct base64_decoder *dec,
const void *src, size_t src_size, size_t *src_pos_r,
buffer_t *dest) ATTR_NULL(4);
/* Finishes Base64 decoding. This function checks whether the encoded data ends
in the proper padding. Returns 0 if all ok, and -1 if data is invalid.
*/
int base64_decode_finish(struct base64_decoder *dec);
/*
* Generic Base64 API
*/
/* Translates binary data into some variant of Base64. The src must not point to
dest buffer.
The b64 parameter is the definition of the particular Base 64 encoding scheme
that is used. See below for specific functions.
*/
static inline void
base64_scheme_encode(const struct base64_scheme *b64,
enum base64_encode_flags flags, size_t max_line_len,
const void *src, size_t src_size, buffer_t *dest)
{
struct base64_encoder enc;
base64_encode_init(&enc, b64, flags, max_line_len);
base64_encode_more(&enc, src, src_size, NULL, dest);
base64_encode_finish(&enc, dest);
}
buffer_t *t_base64_scheme_encode(const struct base64_scheme *b64,
enum base64_encode_flags flags,
size_t max_line_len,
const void *src, size_t src_size);
static inline buffer_t *
t_base64_scheme_encode_str(const struct base64_scheme *b64,
enum base64_encode_flags flags, size_t max_line_len,
const char *src)
{
return t_base64_scheme_encode(b64, flags, max_line_len,
src, strlen(src));
}
/* Translates some variant of Base64 data into binary and appends it to dest
buffer. dest may point to same buffer as src. Returns 1 if all ok, 0 if end
of Base64 data found, -1 if data is invalid.
The b64 parameter is the definition of the particular Base 64 encoding scheme
that is expected. See below for specific functions.
Any CR, LF characters are ignored, as well as whitespace at beginning or
end of line.
*/
int base64_scheme_decode(const struct base64_scheme *b64,
enum base64_decode_flags flags,
const void *src, size_t src_size, buffer_t *dest);
/* Decode given data to a buffer allocated from data stack.
The b64 parameter is the definition of the particular Base 64 encoding scheme
that is expected. See below for specific functions.
*/
buffer_t *t_base64_scheme_decode(const struct base64_scheme *b64,
enum base64_decode_flags flags,
const void *src, size_t src_size);
/* Decode given string to a buffer allocated from data stack.
The b64 parameter is the definition of the particular Base 64 encoding scheme
that is expected. See below for specific functions.
*/
static inline buffer_t *
t_base64_scheme_decode_str(const struct base64_scheme *b64,
enum base64_decode_flags flags, const char *str)
{
return t_base64_scheme_decode(b64, flags, str, strlen(str));
}
/* Returns TRUE if c is a valid encoding character (excluding '=') for the
provided base64 mapping table */
static inline bool
base64_scheme_is_valid_char(const struct base64_scheme *b64, char c)
{
return b64->decmap[(uint8_t)c] != 0xff;
}
/*
* "base64" encoding scheme (RFC 4648, Section 4)
*/
extern struct base64_scheme base64_scheme;
/* Translates binary data into base64. See base64_scheme_encode(). */
static inline void
base64_encode(const void *src, size_t src_size, buffer_t *dest)
{
base64_scheme_encode(&base64_scheme, 0, 0, src, src_size, dest);
}
static inline buffer_t *
t_base64_encode(enum base64_encode_flags flags, size_t max_line_len,
const void *src, size_t src_size)
{
return t_base64_scheme_encode(&base64_scheme, flags, max_line_len,
src, src_size);
}
static inline buffer_t *
t_base64_encode_str(enum base64_encode_flags flags, size_t max_line_len,
const char *src)
{
return t_base64_scheme_encode(&base64_scheme, flags, max_line_len,
src, strlen(src));
}
/* Translates base64 data into binary and appends it to dest buffer. See
base64_scheme_decode().
The src_pos_r parameter is deprecated and MUST be NULL.
*/
static inline int
base64_decode(const void *src, size_t src_size, size_t *src_pos_r ATTR_UNUSED,
buffer_t *dest) ATTR_NULL(3)
{
// NOTE: src_pos_r is deprecated here; to be removed in v2.4 */
i_assert(src_pos_r == NULL);
return base64_scheme_decode(&base64_scheme, 0, src, src_size, dest);
}
/* Decode given data to a buffer allocated from data stack. */
static inline buffer_t *
t_base64_decode(enum base64_decode_flags flags,
const void *src, size_t src_size)
{
return t_base64_scheme_decode(&base64_scheme, flags, src, src_size);
}
/* Decode given string to a buffer allocated from data stack. */
static inline buffer_t *t_base64_decode_str(const char *str)
{
return t_base64_scheme_decode_str(&base64_scheme, 0, str);
}
/* Returns TRUE if c is a valid base64 encoding character (excluding '=') */
static inline bool base64_is_valid_char(char c)
{
return base64_scheme_is_valid_char(&base64_scheme, c);
}
/*
* "base64url" encoding scheme (RFC 4648, Section 5)
*/
extern struct base64_scheme base64url_scheme;
/* Translates binary data into base64url. See base64_scheme_encode(). */
static inline void
base64url_encode(enum base64_encode_flags flags, size_t max_line_len,
const void *src, size_t src_size, buffer_t *dest)
{
base64_scheme_encode(&base64url_scheme, flags, max_line_len,
src, src_size, dest);
}
static inline buffer_t *
t_base64url_encode(enum base64_encode_flags flags, size_t max_line_len,
const void *src, size_t src_size)
{
return t_base64_scheme_encode(&base64url_scheme, flags, max_line_len,
src, src_size);
}
static inline buffer_t *
t_base64url_encode_str(enum base64_encode_flags flags, size_t max_line_len,
const char *src)
{
return t_base64_scheme_encode(&base64url_scheme, flags, max_line_len,
src, strlen(src));
}
/* Translates base64url data into binary and appends it to dest buffer. See
base64_scheme_decode(). */
static inline int
base64url_decode(enum base64_decode_flags flags,
const void *src, size_t src_size, buffer_t *dest)
{
return base64_scheme_decode(&base64url_scheme, flags,
src, src_size, dest);
}
/* Decode given data to a buffer allocated from data stack. */
static inline buffer_t *
t_base64url_decode(enum base64_decode_flags flags,
const void *src, size_t src_size)
{
return t_base64_scheme_decode(&base64url_scheme, flags, src, src_size);
}
/* Decode given string to a buffer allocated from data stack. */
static inline buffer_t *
t_base64url_decode_str(enum base64_decode_flags flags, const char *str)
{
return t_base64_scheme_decode_str(&base64url_scheme, flags, str);
}
/* Returns TRUE if c is a valid base64url encoding character (excluding '=') */
static inline bool base64url_is_valid_char(char c)
{
return base64_scheme_is_valid_char(&base64url_scheme, c);
}
#endif
dovecot-2.3.21.1/src/lib/test-str-sanitize.c 0000644 0000000 0000000 00000007444 14656633576 015440 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "str-sanitize.h"
struct str_sanitize_test {
const char *str;
unsigned int max_len;
const char *sanitized; /* NULL for no change */
};
static void test_str_sanitize_max_bytes(void)
{
static const struct str_sanitize_test tests[] = {
{ NULL, 2, NULL },
{ "", 2, NULL },
{ "a", 2, NULL },
{ "ab", 2, NULL },
{ "abc", 2, "..." },
{ "abcd", 3, "..." },
{ "abcde", 4, "a..." },
{ "\xD1\x81", 1, "..." },
{ "\xD1\x81", 2, "\xD1\x81" },
{ "\xD1\x81", 3, NULL },
{ "\xC3\xA4\xC3\xA4zyxa", 1, "..." },
{ "\xC3\xA4\xC3\xA4zyxa", 2, "..." },
{ "\xC3\xA4\xC3\xA4zyxa", 3, "..." },
{ "\xC3\xA4\xC3\xA4zyxa", 4, "..." },
{ "\xC3\xA4\xC3\xA4zyxa", 5, "\xC3\xA4..." },
{ "\xC3\xA4\xC3\xA4zyxa", 6, "\xC3\xA4..." },
{ "\xC3\xA4\xC3\xA4zyxa", 7, "\xC3\xA4\xC3\xA4..." },
{ "\xC3\xA4\xC3\xA4zyxa", 8, "\xC3\xA4\xC3\xA4zyxa" },
{ "\001x\x1fy\x81", 10, "?x?y?" }
};
const char *str;
string_t *str2;
unsigned int i;
test_begin("str_sanitize");
for (i = 0; i < N_ELEMENTS(tests); i++) {
str = str_sanitize(tests[i].str, tests[i].max_len);
if (tests[i].sanitized != NULL)
test_assert_idx(null_strcmp(str, tests[i].sanitized) == 0, i);
else
test_assert_idx(str == tests[i].str, i);
}
test_end();
test_begin("str_sanitize_append");
str2 = t_str_new(128);
for (i = 0; i < N_ELEMENTS(tests); i++) {
if (tests[i].str == NULL)
continue;
str_truncate(str2, 0);
str_append(str2, "1234567890");
str_sanitize_append(str2, tests[i].str, tests[i].max_len);
test_assert_idx(str_begins(str_c(str2), "1234567890"), i);
if (tests[i].sanitized != NULL)
test_assert_idx(strcmp(str_c(str2)+10, tests[i].sanitized) == 0, i);
else
test_assert_idx(strcmp(str_c(str2)+10, tests[i].str) == 0, i);
}
test_end();
}
static void test_str_sanitize_max_codepoints(void)
{
static const struct str_sanitize_test tests[] = {
{ NULL, 2, NULL },
{ "", 2, NULL },
{ "a", 2, NULL },
{ "ab", 2, NULL },
{ "abc", 2, "a\xE2\x80\xA6" },
{ "abcd", 3, "ab\xE2\x80\xA6" },
{ "abcde", 4, "abc\xE2\x80\xA6" },
{ "\xD1\x81", 1, "\xD1\x81" },
{ "\xD1\x81", 2, "\xD1\x81" },
{ "\xD1\x81", 3, NULL },
{ "\xC3\xA4\xC3\xA4zyxa", 1, "\xE2\x80\xA6" },
{ "\xC3\xA4\xC3\xA4zyxa", 2, "\xC3\xA4\xE2\x80\xA6" },
{ "\xC3\xA4\xC3\xA4zyxa", 3, "\xC3\xA4\xC3\xA4\xE2\x80\xA6" },
{ "\xC3\xA4\xC3\xA4zyxa", 4, "\xC3\xA4\xC3\xA4z\xE2\x80\xA6" },
{ "\xC3\xA4\xC3\xA4zyxa", 5, "\xC3\xA4\xC3\xA4zy\xE2\x80\xA6" },
{ "\xC3\xA4\xC3\xA4zyxa", 6, "\xC3\xA4\xC3\xA4zyxa" },
{ "\xC3\xA4\xC3\xA4zyxa", 7, "\xC3\xA4\xC3\xA4zyxa" },
{ "\xC3\xA4\xC3\xA4zyxa", 8, "\xC3\xA4\xC3\xA4zyxa" },
{ "\001x\x1fy\x81", 10, "\xEF\xBF\xBDx\xEF\xBF\xBDy\xEF\xBF\xBD" }
};
const char *str;
string_t *str2;
unsigned int i;
test_begin("str_sanitize_utf8");
for (i = 0; i < N_ELEMENTS(tests); i++) {
str = str_sanitize_utf8(tests[i].str, tests[i].max_len);
if (tests[i].sanitized != NULL)
test_assert_idx(null_strcmp(str, tests[i].sanitized) == 0, i);
else
test_assert_idx(str == tests[i].str, i);
}
test_end();
test_begin("str_sanitize_append_utf8");
str2 = t_str_new(128);
for (i = 0; i < N_ELEMENTS(tests); i++) {
if (tests[i].str == NULL)
continue;
str_truncate(str2, 0);
str_append(str2, "1234567890");
str_sanitize_append_utf8(str2, tests[i].str, tests[i].max_len);
test_assert_idx(strncmp(str_c(str2), "1234567890", 10) == 0, i);
if (tests[i].sanitized != NULL)
test_assert_idx(strcmp(str_c(str2)+10, tests[i].sanitized) == 0, i);
else
test_assert_idx(strcmp(str_c(str2)+10, tests[i].str) == 0, i);
}
test_end();
}
void test_str_sanitize(void)
{
test_str_sanitize_max_bytes();
test_str_sanitize_max_codepoints();
}
dovecot-2.3.21.1/src/lib/istream-crlf.c 0000644 0000000 0000000 00000011452 14656633576 014411 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream-private.h"
#include "istream-crlf.h"
struct crlf_istream {
struct istream_private istream;
bool pending_cr:1;
bool last_cr:1;
};
static int i_stream_crlf_read_common(struct crlf_istream *cstream)
{
struct istream_private *stream = &cstream->istream;
size_t size, avail;
ssize_t ret;
size = i_stream_get_data_size(stream->parent);
if (size == 0) {
ret = i_stream_read_memarea(stream->parent);
if (ret <= 0) {
i_assert(ret != -2); /* 0 sized buffer can't be full */
stream->istream.stream_errno =
stream->parent->stream_errno;
stream->istream.eof = stream->parent->eof;
return ret;
}
size = i_stream_get_data_size(stream->parent);
i_assert(size != 0);
}
if (!i_stream_try_alloc(stream, size, &avail))
return -2;
return 1;
}
static ssize_t i_stream_crlf_read_crlf(struct istream_private *stream)
{
struct crlf_istream *cstream =
container_of(stream, struct crlf_istream, istream);
const unsigned char *data, *ptr, *src, *src_end;
unsigned char *dest, *dest_end;
size_t size, copy_len;
ssize_t ret;
ret = i_stream_crlf_read_common(cstream);
if (ret <= 0)
return ret;
/* at least one byte was read */
data = i_stream_get_data(stream->parent, &size);
dest = stream->w_buffer + stream->pos;
dest_end = stream->w_buffer + stream->buffer_size;
src = data;
src_end = data + size;
/* @UNSAFE: add missing CRs */
if (*src == '\n') {
if (!cstream->last_cr && dest < dest_end)
*dest++ = '\r';
if (dest < dest_end) {
*dest++ = '\n';
src++;
}
}
while (dest < dest_end) {
i_assert(src <= src_end);
ptr = memchr(src, '\n', src_end - src);
if (ptr == NULL)
ptr = src_end;
/* copy data up to LF */
copy_len = ptr - src;
if (dest + copy_len > dest_end)
copy_len = dest_end - dest;
if (copy_len > 0) {
memcpy(dest, src, copy_len);
dest += copy_len;
src += copy_len;
}
i_assert(dest <= dest_end && src <= src_end);
if (dest == dest_end || src == src_end)
break;
/* add the CR if necessary and copy the LF.
(src >= data+1, because data[0]=='\n' was
handled before this loop) */
if (src[-1] != '\r')
*dest++ = '\r';
if (dest == dest_end)
break;
*dest++ = '\n';
src++;
i_assert(src == ptr + 1);
}
i_assert(dest != stream->w_buffer);
cstream->last_cr = dest[-1] == '\r';
i_stream_skip(stream->parent, src - data);
ret = (dest - stream->w_buffer) - stream->pos;
i_assert(ret > 0);
stream->pos = dest - stream->w_buffer;
return ret;
}
static ssize_t i_stream_crlf_read_lf(struct istream_private *stream)
{
struct crlf_istream *cstream =
container_of(stream, struct crlf_istream, istream);
const unsigned char *data, *p;
size_t i, dest, size, max;
ssize_t ret;
bool pending_cr;
ret = i_stream_crlf_read_common(cstream);
if (ret <= 0)
return ret;
data = i_stream_get_data(stream->parent, &size);
/* @UNSAFE */
/* \r\n -> \n
\r -> \r
\r\r\n -> \r\n */
dest = stream->pos;
pending_cr = cstream->pending_cr;
for (i = 0; i < size && dest < stream->buffer_size; ) {
if (data[i] == '\r') {
if (pending_cr) {
/* \r\r */
stream->w_buffer[dest++] = '\r';
} else {
pending_cr = TRUE;
}
i++;
} else if (data[i] == '\n') {
/* [\r]\n */
pending_cr = FALSE;
stream->w_buffer[dest++] = '\n';
i++;
} else if (pending_cr) {
/* \r */
pending_cr = FALSE;
stream->w_buffer[dest++] = '\r';
} else {
/* copy everything until the next \r */
max = I_MIN(size - i, stream->buffer_size - dest);
p = memchr(data + i, '\r', max);
if (p != NULL)
max = p - (data+i);
memcpy(stream->w_buffer + dest, data + i, max);
dest += max;
i += max;
}
}
i_assert(i <= size);
i_assert(dest <= stream->buffer_size);
cstream->pending_cr = pending_cr;
i_stream_skip(stream->parent, i);
ret = dest - stream->pos;
if (ret == 0) {
i_assert(cstream->pending_cr && size == 1);
return i_stream_crlf_read_lf(stream);
}
i_assert(ret > 0);
stream->pos = dest;
return ret;
}
static struct istream *
i_stream_create_crlf_full(struct istream *input, bool crlf)
{
struct crlf_istream *cstream;
cstream = i_new(struct crlf_istream, 1);
cstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
cstream->istream.read = crlf ? i_stream_crlf_read_crlf :
i_stream_crlf_read_lf;
cstream->istream.istream.readable_fd = FALSE;
cstream->istream.istream.blocking = input->blocking;
cstream->istream.istream.seekable = FALSE;
return i_stream_create(&cstream->istream, input,
i_stream_get_fd(input), 0);
}
struct istream *i_stream_create_crlf(struct istream *input)
{
return i_stream_create_crlf_full(input, TRUE);
}
struct istream *i_stream_create_lf(struct istream *input)
{
return i_stream_create_crlf_full(input, FALSE);
}
dovecot-2.3.21.1/src/lib/json-tree.c 0000644 0000000 0000000 00000010430 14656633576 013722 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "json-tree.h"
struct json_tree {
pool_t pool;
struct json_tree_node *root, *cur, *cur_child;
};
struct json_tree *
json_tree_init_type(enum json_type container)
{
struct json_tree *tree;
pool_t pool;
pool = pool_alloconly_create("json tree", 1024);
tree = p_new(pool, struct json_tree, 1);
tree->pool = pool;
tree->root = tree->cur = p_new(tree->pool, struct json_tree_node, 1);
tree->cur->value_type = container == JSON_TYPE_ARRAY ? container : JSON_TYPE_OBJECT;
return tree;
}
void json_tree_deinit(struct json_tree **_tree)
{
struct json_tree *tree = *_tree;
*_tree = NULL;
pool_unref(&tree->pool);
}
static void
json_tree_append_child(struct json_tree *tree, enum json_type type,
const char *value)
{
struct json_tree_node *node;
node = p_new(tree->pool, struct json_tree_node, 1);
node->parent = tree->cur;
node->value_type = type;
node->value.str = p_strdup(tree->pool, value);
if (tree->cur_child == NULL)
tree->cur->value.child = node;
else
tree->cur_child->next = node;
tree->cur_child = node;
}
static void
json_tree_set_cur(struct json_tree *tree, struct json_tree_node *node)
{
tree->cur = node;
tree->cur_child = tree->cur->value.child;
if (tree->cur_child != NULL) {
while (tree->cur_child->next != NULL)
tree->cur_child = tree->cur_child->next;
}
}
static int
json_tree_append_value(struct json_tree *tree, enum json_type type,
const char *value)
{
switch (tree->cur->value_type) {
case JSON_TYPE_OBJECT_KEY:
/* "key": value - we already added the node and set its key,
so now just set the value */
tree->cur->value_type = type;
tree->cur->value.str = p_strdup(tree->pool, value);
json_tree_set_cur(tree, tree->cur->parent);
break;
case JSON_TYPE_ARRAY:
/* element in array - add a new node */
json_tree_append_child(tree, type, value);
break;
default:
return -1;
}
return 0;
}
int json_tree_append(struct json_tree *tree, enum json_type type,
const char *value)
{
switch (type) {
case JSON_TYPE_OBJECT_KEY:
if (tree->cur->value_type != JSON_TYPE_OBJECT)
return -1;
json_tree_append_child(tree, type, NULL);
json_tree_set_cur(tree, tree->cur_child);
tree->cur->key = p_strdup(tree->pool, value);
break;
case JSON_TYPE_ARRAY:
if (json_tree_append_value(tree, type, NULL) < 0)
return -1;
json_tree_set_cur(tree, tree->cur_child);
break;
case JSON_TYPE_OBJECT:
if (tree->cur->value_type == JSON_TYPE_OBJECT_KEY)
tree->cur->value_type = JSON_TYPE_OBJECT;
else if (tree->cur->value_type == JSON_TYPE_ARRAY) {
json_tree_append_child(tree, type, NULL);
json_tree_set_cur(tree, tree->cur_child);
} else {
return -1;
}
break;
case JSON_TYPE_OBJECT_END:
if (tree->cur->parent == NULL ||
tree->cur->value_type != JSON_TYPE_OBJECT)
return -1;
json_tree_set_cur(tree, tree->cur->parent);
break;
case JSON_TYPE_ARRAY_END:
if (tree->cur->parent == NULL ||
tree->cur->value_type != JSON_TYPE_ARRAY)
return -1;
json_tree_set_cur(tree, tree->cur->parent);
break;
case JSON_TYPE_STRING:
case JSON_TYPE_NUMBER:
case JSON_TYPE_TRUE:
case JSON_TYPE_FALSE:
case JSON_TYPE_NULL:
if (json_tree_append_value(tree, type, value) < 0)
return -1;
break;
}
return 0;
}
const struct json_tree_node *
json_tree_root(const struct json_tree *tree)
{
return tree->root;
}
const struct json_tree_node *
json_tree_find_key(const struct json_tree_node *node, const char *key)
{
i_assert(node->value_type == JSON_TYPE_OBJECT);
node = json_tree_get_child(node);
for (; node != NULL; node = node->next) {
if (node->key != NULL && strcmp(node->key, key) == 0)
return node;
}
return NULL;
}
const struct json_tree_node *
json_tree_find_child_with(const struct json_tree_node *node,
const char *key, const char *value)
{
const struct json_tree_node *child;
i_assert(node->value_type == JSON_TYPE_OBJECT ||
node->value_type == JSON_TYPE_ARRAY);
for (node = json_tree_get_child(node); node != NULL; node = node->next) {
if (node->value_type != JSON_TYPE_OBJECT)
continue;
child = json_tree_find_key(node, key);
if (child != NULL &&
json_tree_get_value_str(child) != NULL &&
strcmp(json_tree_get_value_str(child), value) == 0)
return node;
}
return NULL;
}
dovecot-2.3.21.1/src/lib/test-connection.c 0000644 0000000 0000000 00000045117 14656633576 015142 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "ioloop.h"
#include "connection.h"
#include "istream.h"
#include "ostream.h"
#include "strnum.h"
#include "strescape.h"
#include
static const struct connection_settings client_set =
{
.service_name_in = "TEST-S",
.service_name_out = "TEST-C",
.major_version = 1,
.minor_version = 0,
.client = TRUE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
};
static const struct connection_settings server_set =
{
.service_name_in = "TEST-C",
.service_name_out = "TEST-S",
.major_version = 1,
.minor_version = 0,
.client = FALSE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
};
static bool received_quit = FALSE;
static bool was_resumed = FALSE;
static bool was_idle_killed = FALSE;
static int received_count = 0;
static void test_connection_run(const struct connection_settings *set_s,
const struct connection_settings *set_c,
const struct connection_vfuncs *v_s,
const struct connection_vfuncs *v_c,
unsigned int iter_count)
{
int fds[2];
struct ioloop *loop = io_loop_create();
struct connection_list *clients = connection_list_init(set_c, v_c);
struct connection_list *servers = connection_list_init(set_s, v_s);
struct connection *conn_c = i_new(struct connection, 1);
struct connection *conn_s = i_new(struct connection, 1);
conn_s->ioloop = loop;
conn_c->ioloop = loop;
for(unsigned int iters = 0; iters < iter_count; iters++) {
test_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
fd_set_nonblock(fds[0], TRUE);
fd_set_nonblock(fds[1], TRUE);
connection_init_server(servers, conn_s, "client", fds[1], fds[1]);
connection_init_client_fd(clients, conn_c, "server", fds[0], fds[0]);
io_loop_run(loop);
connection_deinit(conn_c);
connection_deinit(conn_s);
}
i_free(conn_c);
i_free(conn_s);
connection_list_deinit(&clients);
connection_list_deinit(&servers);
io_loop_destroy(&loop);
}
/* BEGIN SIMPLE TEST */
static void test_connection_simple_client_connected(struct connection *conn, bool success)
{
if (conn->list->set.client)
o_stream_nsend_str(conn->output, "QUIT\n");
test_assert(success);
};
static int
test_connection_simple_input_args(struct connection *conn, const char *const *args)
{
if (strcmp(args[0], "QUIT") == 0) {
received_quit = TRUE;
connection_disconnect(conn);
return 0;
}
i_error("invalid input");
return -1;
}
static void test_connection_simple_destroy(struct connection *conn)
{
io_loop_stop(conn->ioloop);
connection_disconnect(conn);
}
static const struct connection_vfuncs simple_v =
{
.client_connected = test_connection_simple_client_connected,
.input_args = test_connection_simple_input_args,
.destroy = test_connection_simple_destroy,
};
static void test_connection_simple(void)
{
test_begin("connection simple");
test_connection_run(&server_set, &client_set, &simple_v, &simple_v, 10);
test_assert(received_quit);
received_quit = FALSE;
test_end();
}
/* BEGIN NO INPUT TEST */
static const struct connection_settings no_input_client_set =
{
.service_name_in = "TEST-S",
.service_name_out = "TEST-C",
.major_version = 1,
.minor_version = 0,
.client = TRUE,
.input_max_size = 0,
.output_max_size = SIZE_MAX,
};
static const struct connection_settings no_input_server_set =
{
.service_name_in = "TEST-C",
.service_name_out = "TEST-S",
.major_version = 1,
.minor_version = 0,
.client = FALSE,
.input_max_size = 0,
.output_max_size = SIZE_MAX,
};
static void
test_connection_no_input_input(struct connection *conn)
{
const char *input;
struct istream *is = i_stream_create_fd(conn->fd_in, SIZE_MAX);
i_stream_set_blocking(is, FALSE);
while ((input = i_stream_read_next_line(is)) != NULL) {
const char *const *args = t_strsplit_tabescaped(input);
if (!conn->handshake_received) {
if (connection_handshake_args_default(conn, args) > -1)
conn->handshake_received = TRUE;
continue;
}
if (strcmp(args[0], "QUIT") == 0) {
received_quit = TRUE;
io_loop_stop(conn->ioloop);
break;
}
}
i_stream_unref(&is);
}
static const struct connection_vfuncs no_input_v =
{
.client_connected = test_connection_simple_client_connected,
.input = test_connection_no_input_input,
.destroy = test_connection_simple_destroy,
};
static void test_connection_no_input(void)
{
test_begin("connection no input stream");
test_connection_run(&no_input_server_set, &no_input_client_set,
&no_input_v, &no_input_v, 1);
test_assert(received_quit);
received_quit = FALSE;
test_end();
}
/* BEGIN HANDSHAKE TEST */
static void test_connection_custom_handshake_client_connected(struct connection *conn, bool success)
{
if (conn->list->set.client)
o_stream_nsend_str(conn->output, "HANDSHAKE\tFRIEND\n");
test_assert(success);
};
static int test_connection_custom_handshake_args(struct connection *conn,
const char *const *args)
{
if (!conn->version_received) {
if (connection_handshake_args_default(conn, args) < 0)
return -1;
return 0;
}
if (!conn->handshake_received) {
if (strcmp(args[0], "HANDSHAKE") == 0 &&
strcmp(args[1], "FRIEND") == 0) {
if (!conn->list->set.client)
o_stream_nsend_str(conn->output, "HANDSHAKE\tFRIEND\n");
else
o_stream_nsend_str(conn->output, "QUIT\n");
return 1;
}
return -1;
}
return 1;
}
static const struct connection_vfuncs custom_handshake_v =
{
.client_connected = test_connection_custom_handshake_client_connected,
.input_args = test_connection_simple_input_args,
.handshake_args = test_connection_custom_handshake_args,
.destroy = test_connection_simple_destroy,
};
static void test_connection_custom_handshake(void)
{
test_begin("connection custom handshake");
test_connection_run(&server_set, &client_set, &custom_handshake_v,
&custom_handshake_v, 10);
test_assert(received_quit);
received_quit = FALSE;
test_end();
}
/* BEGIN PING PONG TEST */
static int test_connection_ping_pong_input_args(struct connection *conn, const char *const *args)
{
unsigned int n;
test_assert(args[0] != NULL && args[1] != NULL);
if (args[0] == NULL || args[1] == NULL)
return -1;
if (str_to_uint(args[1], &n) < 0)
return -1;
if (n > 10)
o_stream_nsend_str(conn->output, "QUIT\t0\n");
else if (strcmp(args[0], "QUIT") == 0)
connection_disconnect(conn);
else if (strcmp(args[0], "PING") == 0) {
received_count++;
o_stream_nsend_str(conn->output, t_strdup_printf("PONG\t%u\n", n+1));
} else if (strcmp(args[0], "PONG") == 0)
o_stream_nsend_str(conn->output, t_strdup_printf("PING\t%u\n", n));
else
return -1;
return 1;
}
static void test_connection_ping_pong_client_connected(struct connection *conn, bool success)
{
o_stream_nsend_str(conn->output, "PING\t1\n");
test_assert(success);
};
static const struct connection_vfuncs ping_pong_v =
{
.client_connected = test_connection_ping_pong_client_connected,
.input_args = test_connection_ping_pong_input_args,
.destroy = test_connection_simple_destroy,
};
static void test_connection_ping_pong(void)
{
test_begin("connection ping pong");
test_connection_run(&server_set, &client_set, &ping_pong_v,
&ping_pong_v, 10);
test_assert(received_count == 100);
test_end();
}
/* BEGIN INPUT FULL TEST */
static const struct connection_settings input_full_client_set =
{
.service_name_in = "TEST-S",
.service_name_out = "TEST-C",
.major_version = 1,
.minor_version = 0,
.client = TRUE,
.input_max_size = 100,
.output_max_size = SIZE_MAX,
};
static int test_connection_input_full_input_args(struct connection *conn,
const char *const *args ATTR_UNUSED)
{
/* send a long line */
for (unsigned int i = 0; i < 200; i++)
o_stream_nsend(conn->output, "c", 1);
return 1;
}
static void test_connection_input_full_destroy(struct connection *conn)
{
test_assert(conn->disconnect_reason == CONNECTION_DISCONNECT_BUFFER_FULL ||
conn->list->set.client == FALSE);
test_connection_simple_destroy(conn);
}
static const struct connection_vfuncs input_full_v =
{
.client_connected = test_connection_simple_client_connected,
.input_args = test_connection_input_full_input_args,
.destroy = test_connection_input_full_destroy,
};
static void test_connection_input_full(void)
{
test_begin("connection input full");
test_connection_run(&server_set, &input_full_client_set, &input_full_v,
&simple_v, 10);
test_end();
}
/* BEGIN RESUME TEST */
static struct timeout *to_send_quit = NULL;
static struct timeout *to_resume = NULL;
static void test_connection_resume_client_connected(struct connection *conn, bool success)
{
test_assert(success);
o_stream_nsend_str(conn->output, "BEGIN\n");
}
static void test_connection_resume_continue(struct connection *conn)
{
timeout_remove(&to_resume);
/* ensure QUIT wasn't received early */
was_resumed = !received_quit;
connection_input_resume(conn);
}
static void test_connection_resume_send_quit(struct connection *conn)
{
timeout_remove(&to_send_quit);
o_stream_nsend_str(conn->output, "QUIT\n");
}
static int test_connection_resume_input_args(struct connection *conn,
const char *const *args)
{
test_assert(args[0] != NULL);
if (args[0] == NULL)
return -1;
if (strcmp(args[0], "BEGIN") == 0) {
o_stream_nsend_str(conn->output, "HALT\n");
to_send_quit = timeout_add_short(10, test_connection_resume_send_quit, conn);
} else if (strcmp(args[0], "HALT") == 0) {
connection_input_halt(conn);
to_resume = timeout_add_short(100, test_connection_resume_continue, conn);
} else if (strcmp(args[0], "QUIT") == 0) {
received_quit = TRUE;
connection_disconnect(conn);
}
return 1;
}
static const struct connection_vfuncs resume_v =
{
.client_connected = test_connection_resume_client_connected,
.input_args = test_connection_resume_input_args,
.destroy = test_connection_simple_destroy,
};
static void test_connection_resume(void)
{
test_begin("connection resume");
was_resumed = received_quit = FALSE;
test_connection_run(&server_set, &client_set, &resume_v, &resume_v, 1);
test_assert(was_resumed);
test_assert(received_quit);
was_resumed = received_quit = FALSE;
test_end();
}
/* BEGIN RESUME PIPELINED TEST */
static int test_connection_resume_pipelined_input_args(struct connection *conn,
const char *const *args)
{
test_assert(args[0] != NULL);
if (args[0] == NULL)
return -1;
if (strcmp(args[0], "BEGIN") == 0) {
o_stream_nsend_str(conn->output, "HALT\nQUIT\n");
} else if (strcmp(args[0], "HALT") == 0) {
connection_input_halt(conn);
to_resume = timeout_add_short(100, test_connection_resume_continue, conn);
return 0;
} else if (strcmp(args[0], "QUIT") == 0) {
received_quit = TRUE;
connection_disconnect(conn);
}
return 1;
}
static const struct connection_vfuncs resume_pipelined_v =
{
.client_connected = test_connection_resume_client_connected,
.input_args = test_connection_resume_pipelined_input_args,
.destroy = test_connection_simple_destroy,
};
static void test_connection_resume_pipelined(void)
{
test_begin("connection resume pipelined");
was_resumed = received_quit = FALSE;
test_connection_run(&server_set, &client_set,
&resume_pipelined_v, &resume_pipelined_v, 1);
test_assert(was_resumed);
test_assert(received_quit);
was_resumed = received_quit = FALSE;
test_end();
}
/* BEGIN IDLE KILL TEST */
static void
test_connection_idle_kill_client_connected(struct connection *conn ATTR_UNUSED,
bool success)
{
test_assert(success);
};
static const struct connection_settings idle_kill_server_set =
{
.service_name_in = "TEST-C",
.service_name_out = "TEST-S",
.major_version = 1,
.minor_version = 0,
.client = FALSE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
.input_idle_timeout_secs = 1,
};
static void test_connection_idle_kill_timeout(struct connection *conn)
{
was_idle_killed = TRUE;
o_stream_nsend_str(conn->output, "QUIT\n");
}
static const struct connection_vfuncs idle_kill_v =
{
.client_connected = test_connection_idle_kill_client_connected,
.input_args = test_connection_simple_input_args,
.destroy = test_connection_simple_destroy,
.idle_timeout = test_connection_idle_kill_timeout,
};
static void test_connection_idle_kill(void)
{
test_begin("connection idle kill");
was_idle_killed = received_quit = FALSE;
test_connection_run(&idle_kill_server_set, &client_set, &idle_kill_v,
&idle_kill_v, 1);
test_assert(received_quit);
test_assert(was_idle_killed);
was_idle_killed = received_quit = FALSE;
test_end();
}
/* BEGIN HANDSHAKE FAILED TEST (version) */
static void test_connection_handshake_failed_destroy(struct connection *conn)
{
test_assert(conn->disconnect_reason == CONNECTION_DISCONNECT_HANDSHAKE_FAILED);
test_connection_simple_destroy(conn);
}
static const struct connection_vfuncs handshake_failed_version_v =
{
.client_connected = test_connection_simple_client_connected,
.input_args = test_connection_simple_input_args,
.destroy = test_connection_handshake_failed_destroy,
};
static void test_connection_handshake_failed_version(void)
{
static const struct connection_settings client_sets[] = {
{
.service_name_in = "TEST-S",
.service_name_out = "TEST-S",
.major_version = 1,
.minor_version = 0,
.client = TRUE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
},
{
.service_name_in = "TEST-C",
.service_name_out = "TEST-C",
.major_version = 1,
.minor_version = 0,
.client = TRUE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
},
{
.service_name_in = "TEST-S",
.service_name_out = "TEST-C",
.major_version = 2,
.minor_version = 0,
.client = TRUE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
}
};
static const struct connection_settings client_set_minor = {
.service_name_in = "TEST-S",
.service_name_out = "TEST-C",
.major_version = 1,
.minor_version = 2,
.client = TRUE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
};
test_begin("connection handshake failed (version)");
test_expect_errors(N_ELEMENTS(client_sets));
/* this should stay FALSE during the version mismatch sets */
received_quit = FALSE;
for (size_t i = 0; i < N_ELEMENTS(client_sets); i++) {
test_connection_run(&server_set, &client_sets[i], &simple_v,
&handshake_failed_version_v, 1);
test_assert(!received_quit);
}
received_quit = FALSE;
test_connection_run(&server_set, &client_set_minor, &simple_v,
&simple_v, 1);
test_assert(received_quit);
received_quit = FALSE;
test_end();
}
/* BEGIN HANDSHAKE FAILED TEST (args) */
static int test_connection_handshake_failed_1_args(struct connection *conn ATTR_UNUSED,
const char *const *args ATTR_UNUSED)
{
/* just fail */
return -1;
}
static const struct connection_vfuncs handshake_failed_1_v =
{
.client_connected = test_connection_simple_client_connected,
.input_args = test_connection_simple_input_args,
.handshake_args = test_connection_handshake_failed_1_args,
.destroy = test_connection_handshake_failed_destroy,
};
static void test_connection_handshake_failed_args(void)
{
test_begin("connection handshake failed (handshake_args)");
test_connection_run(&server_set, &client_set, &simple_v,
&handshake_failed_1_v, 10);
test_end();
}
/* BEGIN HANDSHAKE FAILED TEST (handshake_line) */
static int test_connection_handshake_failed_2_line(struct connection *conn ATTR_UNUSED,
const char *line ATTR_UNUSED)
{
return -1;
}
static const struct connection_vfuncs handshake_failed_2_v =
{
.client_connected = test_connection_simple_client_connected,
.input_args = test_connection_simple_input_args,
.handshake_line = test_connection_handshake_failed_2_line,
.destroy = test_connection_handshake_failed_destroy,
};
static void test_connection_handshake_failed_line(void)
{
test_begin("connection handshake failed (handshake_line)");
test_connection_run(&server_set, &client_set, &simple_v,
&handshake_failed_2_v, 10);
test_end();
}
/* BEGIN HANDSHAKE FAILED TEST (handshake) */
static int test_connection_handshake_failed_3(struct connection *conn ATTR_UNUSED)
{
return -1;
}
static const struct connection_vfuncs handshake_failed_3_v =
{
.client_connected = test_connection_simple_client_connected,
.input_args = test_connection_simple_input_args,
.handshake = test_connection_handshake_failed_3,
.destroy = test_connection_handshake_failed_destroy,
};
static void test_connection_handshake_failed_input(void)
{
test_begin("connection handshake failed (handshake)");
test_connection_run(&server_set, &client_set, &simple_v,
&handshake_failed_3_v, 10);
test_end();
}
/* BEGIN CONNECTION ERRORED TEST (ensure correct error) */
static void test_connection_errored_client_connected(struct connection *conn,
bool success)
{
test_assert(success);
o_stream_nsend_str(conn->output, "HELLO\n");
}
static void test_connection_errored_destroy(struct connection *conn)
{
test_assert(conn->disconnect_reason == CONNECTION_DISCONNECT_DEINIT);
test_connection_simple_destroy(conn);
}
static int test_connection_errored_input_line(struct connection *conn ATTR_UNUSED,
const char *line)
{
if (str_begins(line, "VERSION"))
return 1;
return -1;
}
static const struct connection_vfuncs test_connection_errored_1_v =
{
.client_connected = test_connection_errored_client_connected,
.input_line = test_connection_errored_input_line,
.destroy = test_connection_errored_destroy,
};
static void test_connection_input_error_reason(void)
{
test_begin("connection input error (correct disconnect reason)");
test_connection_run(&server_set, &client_set, &test_connection_errored_1_v,
&test_connection_errored_1_v, 10);
test_end();
}
/* END CONNECTION ERRORED TEST */
/* BEGIN NO VERSION TEST */
static const struct connection_settings no_version_client_set =
{
.major_version = 0,
.minor_version = 0,
.client = TRUE,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
.dont_send_version = TRUE,
};
static const struct connection_settings no_version_server_set =
{
.major_version = 0,
.minor_version = 0,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
.dont_send_version = TRUE,
};
static void test_connection_no_version(void)
{
test_begin("connection no version sent");
test_connection_run(&no_version_server_set, &no_version_client_set,
&simple_v, &simple_v, 10);
test_end();
}
/* END NO VERSION TEST */
void test_connection(void)
{
test_connection_simple();
test_connection_no_input();
test_connection_custom_handshake();
test_connection_ping_pong();
test_connection_input_full();
test_connection_resume();
test_connection_resume_pipelined();
test_connection_idle_kill();
test_connection_handshake_failed_version();
test_connection_handshake_failed_args();
test_connection_handshake_failed_line();
test_connection_handshake_failed_input();
test_connection_input_error_reason();
test_connection_no_version();
}
dovecot-2.3.21.1/src/lib/strescape.h 0000644 0000000 0000000 00000003210 14656633576 014010 0000000 0000000 #ifndef STRESCAPE_H
#define STRESCAPE_H
#define IS_ESCAPED_CHAR(c) ((c) == '"' || (c) == '\\' || (c) == '\'')
/* escape all '\', '"' and "'" characters,
this is nul safe */
const char *str_nescape(const void *str, size_t len);
/* escape string */
static inline const char *str_escape(const char *str)
{
return str_nescape(str, strlen(str));
}
void str_append_escaped(string_t *dest, const void *src, size_t src_size);
/* remove all '\' characters, append to given string */
void str_append_unescaped(string_t *dest, const void *src, size_t src_size);
/* remove all '\' characters */
char *str_unescape(char *str);
/* Remove all '\' chars from str until '"' is reached and return the unescaped
string. *str is updated to point to the character after the '"'. Returns 0
if ok, -1 if '"' wasn't found. */
int str_unescape_next(const char **str, const char **unescaped_r);
/* For Dovecot's internal protocols: Escape \001, \t, \r and \n characters
using \001. */
const char *str_tabescape(const char *str);
void str_append_tabescaped(string_t *dest, const char *src);
void str_append_tabescaped_n(string_t *dest, const unsigned char *src, size_t src_size);
void str_append_tabunescaped(string_t *dest, const void *src, size_t src_size);
char *str_tabunescape(char *str);
const char *t_str_tabunescape(const char *str);
char **p_strsplit_tabescaped(pool_t pool, const char *str);
const char *const *t_strsplit_tabescaped(const char *str);
/* Same as t_strsplit_tabescaped(), but the input string is modified and the
returned pointers inside the array point to the original string. */
const char *const *t_strsplit_tabescaped_inplace(char *str);
#endif
dovecot-2.3.21.1/src/lib/ostream-unix.h 0000644 0000000 0000000 00000000532 14656633576 014456 0000000 0000000 #ifndef OSTREAM_UNIX_H
#define OSTREAM_UNIX_H
struct ostream *o_stream_create_unix(int fd, size_t max_buffer_size);
/* Write fd to UNIX socket along with the next outgoing data block.
Returns TRUE if fd is accepted, and FALSE if a previous fd still
needs to be sent. */
bool o_stream_unix_write_fd(struct ostream *output, int fd);
#endif
dovecot-2.3.21.1/src/lib/test-malloc-overflow.c 0000644 0000000 0000000 00000006211 14656633576 016103 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
static void test_malloc_overflow_multiply(void)
{
static const struct {
size_t a, b;
} tests[] = {
{ 0, SIZE_MAX },
{ 1, SIZE_MAX },
{ SIZE_MAX/2, 2 },
};
test_begin("MALLOC_MULTIPLY()");
for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
test_assert_idx(MALLOC_MULTIPLY(tests[i].a, tests[i].b) == tests[i].a * tests[i].b, i);
test_assert_idx(MALLOC_MULTIPLY(tests[i].b, tests[i].a) == tests[i].b * tests[i].a, i);
}
test_end();
}
static void test_malloc_overflow_add(void)
{
static const struct {
size_t a, b;
} tests[] = {
{ 0, SIZE_MAX },
{ 1, SIZE_MAX-1 },
{ SIZE_MAX/2+1, SIZE_MAX/2 },
};
unsigned short n = 2;
test_begin("MALLOC_ADD()");
/* check that no compiler warning is given */
test_assert(MALLOC_ADD(2, n) == 2U+n);
for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
test_assert_idx(MALLOC_ADD(tests[i].a, tests[i].b) == tests[i].a + tests[i].b, i);
test_assert_idx(MALLOC_ADD(tests[i].b, tests[i].a) == tests[i].b + tests[i].a, i);
}
test_end();
}
void test_malloc_overflow(void)
{
test_malloc_overflow_multiply();
test_malloc_overflow_add();
}
static enum fatal_test_state fatal_malloc_overflow_multiply(unsigned int *stage)
{
const struct {
size_t a, b;
} mul_tests[] = {
{ SIZE_MAX/2+1, 2 },
};
unsigned int i;
test_expect_fatal_string("memory allocation overflow");
switch (*stage) {
case 0:
test_begin("MALLOC_MULTIPLY() overflows");
i_error("%zu", MALLOC_MULTIPLY((size_t)SIZE_MAX/2, (uint8_t)3));
break;
case 1:
i_error("%zu", MALLOC_MULTIPLY((uint8_t)3, (size_t)SIZE_MAX/2));
break;
}
*stage -= 2;
if (*stage >= N_ELEMENTS(mul_tests)*2) {
*stage -= N_ELEMENTS(mul_tests)*2;
if (*stage == 0)
test_end();
test_expect_fatal_string(NULL);
return FATAL_TEST_FINISHED;
}
i = *stage / 2;
if (*stage % 2 == 0)
i_error("%zu", MALLOC_MULTIPLY(mul_tests[i].a, mul_tests[i].b));
else
i_error("%zu", MALLOC_MULTIPLY(mul_tests[i].b, mul_tests[i].a));
return FATAL_TEST_FAILURE;
}
static enum fatal_test_state fatal_malloc_overflow_add(unsigned int *stage)
{
const struct {
size_t a, b;
} add_tests[] = {
{ SIZE_MAX, 1 },
{ SIZE_MAX/2+1, SIZE_MAX/2+1 },
};
unsigned int i;
test_expect_fatal_string("memory allocation overflow");
switch (*stage) {
case 0:
test_begin("MALLOC_ADD() overflows");
i_error("%zu", MALLOC_ADD((size_t)SIZE_MAX, (uint8_t)1));
break;
case 1:
i_error("%zu", MALLOC_ADD((uint8_t)1, (size_t)SIZE_MAX));
break;
}
*stage -= 2;
if (*stage >= N_ELEMENTS(add_tests)*2) {
*stage -= N_ELEMENTS(add_tests)*2;
if (*stage == 0)
test_end();
test_expect_fatal_string(NULL);
return FATAL_TEST_FINISHED;
}
i = *stage / 2;
if (*stage % 2 == 0)
i_error("%zu", MALLOC_ADD(add_tests[i].a, add_tests[i].b));
else
i_error("%zu", MALLOC_ADD(add_tests[i].b, add_tests[i].a));
return FATAL_TEST_FAILURE;
}
enum fatal_test_state fatal_malloc_overflow(unsigned int stage)
{
enum fatal_test_state state;
state = fatal_malloc_overflow_multiply(&stage);
if (state != FATAL_TEST_FINISHED)
return state;
return fatal_malloc_overflow_add(&stage);
}
dovecot-2.3.21.1/src/lib/mkdir-parents.c 0000644 0000000 0000000 00000010030 14656633576 014570 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "eacces-error.h"
#include "mkdir-parents.h"
#include "ipwd.h"
#include
#include
#include
static int ATTR_NULL(5)
mkdir_chown_full(const char *path, mode_t mode, uid_t uid,
gid_t gid, const char *gid_origin)
{
string_t *str;
mode_t old_mask;
unsigned int i;
int ret, fd = -1, orig_errno;
for (i = 0;; i++) {
old_mask = umask(0);
ret = mkdir(path, mode);
umask(old_mask);
if (ret < 0)
break;
fd = open(path, O_RDONLY);
if (fd != -1)
break;
if (errno != ENOENT || i == 3) {
i_error("open(%s) failed: %m", path);
return -1;
}
/* it was just rmdir()ed by someone else? retry */
}
if (ret < 0) {
if (errno == EISDIR || errno == ENOSYS) {
/* EISDIR check is for BSD/OS which returns it if path
contains '/' at the end and it exists.
ENOSYS check is for NFS mount points. */
errno = EEXIST;
}
i_assert(fd == -1);
return -1;
}
if (fchown(fd, uid, gid) < 0) {
i_close_fd(&fd);
orig_errno = errno;
if (rmdir(path) < 0 && errno != ENOENT)
i_error("rmdir(%s) failed: %m", path);
errno = orig_errno;
if (errno == EPERM && uid == (uid_t)-1) {
i_error("%s", eperm_error_get_chgrp("fchown", path, gid,
gid_origin));
return -1;
}
str = t_str_new(256);
str_printfa(str, "fchown(%s, %ld", path,
uid == (uid_t)-1 ? -1L : (long)uid);
if (uid != (uid_t)-1) {
struct passwd pw;
if (i_getpwuid(uid, &pw) > 0)
str_printfa(str, "(%s)", pw.pw_name);
}
str_printfa(str, ", %ld",
gid == (gid_t)-1 ? -1L : (long)gid);
if (gid != (gid_t)-1) {
struct group gr;
if (i_getgrgid(uid, &gr) > 0)
str_printfa(str, "(%s)", gr.gr_name);
}
errno = orig_errno;
i_error("%s) failed: %m", str_c(str));
return -1;
}
if (gid != (gid_t)-1 && (mode & S_ISGID) == 0) {
/* make sure the directory doesn't have setgid bit enabled
(in case its parent had) */
if (fchmod(fd, mode) < 0) {
orig_errno = errno;
if (rmdir(path) < 0 && errno != ENOENT)
i_error("rmdir(%s) failed: %m", path);
errno = orig_errno;
i_error("fchmod(%s) failed: %m", path);
i_close_fd(&fd);
return -1;
}
}
i_close_fd(&fd);
return 0;
}
int mkdir_chown(const char *path, mode_t mode, uid_t uid, gid_t gid)
{
return mkdir_chown_full(path, mode, uid, gid, NULL);
}
int mkdir_chgrp(const char *path, mode_t mode,
gid_t gid, const char *gid_origin)
{
return mkdir_chown_full(path, mode, (uid_t)-1, gid, gid_origin);
}
static int ATTR_NULL(5)
mkdir_parents_chown_full(const char *path, mode_t mode, uid_t uid, gid_t gid,
const char *gid_origin)
{
const char *p;
int ret;
if (mkdir_chown_full(path, mode, uid, gid, gid_origin) < 0) {
if (errno != ENOENT)
return -1;
/* doesn't exist, try recursively creating our parent dir */
p = strrchr(path, '/');
if (p == NULL || p == path)
return -1; /* shouldn't happen */
T_BEGIN {
ret = mkdir_parents_chown_full(t_strdup_until(path, p),
mode, uid,
gid, gid_origin);
} T_END;
if (ret < 0 && errno != EEXIST)
return -1;
/* should work now */
if (mkdir_chown_full(path, mode, uid, gid, gid_origin) < 0)
return -1;
}
return 0;
}
int mkdir_parents_chown(const char *path, mode_t mode, uid_t uid, gid_t gid)
{
return mkdir_parents_chown_full(path, mode, uid, gid, NULL);
}
int mkdir_parents_chgrp(const char *path, mode_t mode,
gid_t gid, const char *gid_origin)
{
return mkdir_parents_chown_full(path, mode, (uid_t)-1, gid, gid_origin);
}
int mkdir_parents(const char *path, mode_t mode)
{
return mkdir_parents_chown(path, mode, (uid_t)-1, (gid_t)-1);
}
int stat_first_parent(const char *path, const char **root_dir_r,
struct stat *st_r)
{
const char *p;
while (stat(path, st_r) < 0) {
if (errno != ENOENT || strcmp(path, "/") == 0) {
*root_dir_r = path;
return -1;
}
p = strrchr(path, '/');
if (p == NULL)
path = "/";
else
path = t_strdup_until(path, p);
}
*root_dir_r = path;
return 0;
}
dovecot-2.3.21.1/src/lib/hmac-cram-md5.c 0000644 0000000 0000000 00000003131 14656633576 014327 0000000 0000000 /*
* CRAM-MD5 (RFC 2195) compatibility code
* Copyright (c) 2003 Joshua Goodall
*
* This software is released under the MIT license.
*/
#include "lib.h"
#include "md5.h"
#include "hmac-cram-md5.h"
void hmac_md5_get_cram_context(struct hmac_context *_hmac_ctx,
unsigned char context_digest[CRAM_MD5_CONTEXTLEN])
{
struct hmac_context_priv *hmac_ctx = &_hmac_ctx->u.priv;
unsigned char *cdp;
struct md5_context *ctx = (void*)hmac_ctx->ctx;
struct md5_context *ctxo = (void*)hmac_ctx->ctxo;
#define CDPUT(p, c) STMT_START { \
*(p)++ = (c) & 0xff; \
*(p)++ = (c) >> 8 & 0xff; \
*(p)++ = (c) >> 16 & 0xff; \
*(p)++ = (c) >> 24 & 0xff; \
} STMT_END
cdp = context_digest;
CDPUT(cdp, ctxo->a);
CDPUT(cdp, ctxo->b);
CDPUT(cdp, ctxo->c);
CDPUT(cdp, ctxo->d);
CDPUT(cdp, ctx->a);
CDPUT(cdp, ctx->b);
CDPUT(cdp, ctx->c);
CDPUT(cdp, ctx->d);
}
void hmac_md5_set_cram_context(struct hmac_context *_hmac_ctx,
const unsigned char context_digest[CRAM_MD5_CONTEXTLEN])
{
struct hmac_context_priv *hmac_ctx = &_hmac_ctx->u.priv;
const unsigned char *cdp;
struct md5_context *ctx = (void*)hmac_ctx->ctx;
struct md5_context *ctxo = (void*)hmac_ctx->ctxo;
#define CDGET(p, c) STMT_START { \
(c) = (*p++); \
(c) += (*p++ << 8); \
(c) += (*p++ << 16); \
(c) += ((uint32_t)(*p++) << 24); \
} STMT_END
cdp = context_digest;
CDGET(cdp, ctxo->a);
CDGET(cdp, ctxo->b);
CDGET(cdp, ctxo->c);
CDGET(cdp, ctxo->d);
CDGET(cdp, ctx->a);
CDGET(cdp, ctx->b);
CDGET(cdp, ctx->c);
CDGET(cdp, ctx->d);
ctxo->lo = ctx->lo = 64;
ctxo->hi = ctx->hi = 0;
}
dovecot-2.3.21.1/src/lib/test-buffer.c 0000644 0000000 0000000 00000026257 14656633576 014260 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "buffer.h"
static void test_buffer_random(void)
{
#define BUF_TEST_SIZE (1024*2)
#define BUF_TEST_COUNT 1000
buffer_t *buf;
unsigned char *p, testdata[BUF_TEST_SIZE], shadowbuf[BUF_TEST_SIZE];
unsigned int i, shadowbuf_size;
size_t pos, pos2, size, size2;
int test = -1;
bool zero;
buf = buffer_create_dynamic(default_pool, 1);
for (i = 0; i < BUF_TEST_SIZE; i++)
testdata[i] = i_rand_uchar();
memset(shadowbuf, 0, sizeof(shadowbuf));
shadowbuf_size = 0;
for (i = 0; i < BUF_TEST_COUNT; i++) {
if (buf->used == BUF_TEST_SIZE) {
size = shadowbuf_size = i_rand_limit(buf->used - 1);
buffer_set_used_size(buf, size);
memset(shadowbuf + shadowbuf_size, 0,
BUF_TEST_SIZE - shadowbuf_size);
i_assert(buf->used < BUF_TEST_SIZE);
}
test = i_rand_limit(7);
zero = i_rand_limit(10) == 0;
switch (test) {
case 0:
pos = i_rand_limit(BUF_TEST_SIZE - 1);
size = i_rand_limit(BUF_TEST_SIZE - pos);
if (!zero) {
buffer_write(buf, pos, testdata, size);
memcpy(shadowbuf + pos, testdata, size);
} else {
buffer_write_zero(buf, pos, size);
memset(shadowbuf + pos, 0, size);
}
if (pos + size > shadowbuf_size)
shadowbuf_size = pos + size;
break;
case 1:
size = i_rand_limit(BUF_TEST_SIZE - buf->used);
if (!zero) {
buffer_append(buf, testdata, size);
memcpy(shadowbuf + shadowbuf_size,
testdata, size);
} else {
buffer_append_zero(buf, size);
memset(shadowbuf + shadowbuf_size, 0, size);
}
shadowbuf_size += size;
break;
case 2:
pos = i_rand_limit(BUF_TEST_SIZE - 1);
size = i_rand_limit(BUF_TEST_SIZE - I_MAX(buf->used, pos));
if (!zero) {
buffer_insert(buf, pos, testdata, size);
memmove(shadowbuf + pos + size,
shadowbuf + pos,
BUF_TEST_SIZE - (pos + size));
memcpy(shadowbuf + pos, testdata, size);
} else {
buffer_insert_zero(buf, pos, size);
memmove(shadowbuf + pos + size,
shadowbuf + pos,
BUF_TEST_SIZE - (pos + size));
memset(shadowbuf + pos, 0, size);
}
if (pos < shadowbuf_size)
shadowbuf_size += size;
else
shadowbuf_size = pos + size;
break;
case 3:
pos = i_rand_limit(BUF_TEST_SIZE - 1);
size = i_rand_limit(BUF_TEST_SIZE - pos);
buffer_delete(buf, pos, size);
if (pos < shadowbuf_size) {
if (pos + size > shadowbuf_size)
size = shadowbuf_size - pos;
memmove(shadowbuf + pos,
shadowbuf + pos + size,
BUF_TEST_SIZE - (pos + size));
shadowbuf_size -= size;
memset(shadowbuf + shadowbuf_size, 0,
BUF_TEST_SIZE - shadowbuf_size);
}
break;
case 4:
pos = i_rand_limit(BUF_TEST_SIZE - 1);
size = i_rand_limit(BUF_TEST_SIZE - pos);
size2 = i_rand_limit(BUF_TEST_SIZE -
I_MAX(buf->used, pos));
buffer_replace(buf, pos, size, testdata, size2);
if (pos < shadowbuf_size) {
if (pos + size > shadowbuf_size)
size = shadowbuf_size - pos;
memmove(shadowbuf + pos,
shadowbuf + pos + size,
BUF_TEST_SIZE - (pos + size));
shadowbuf_size -= size;
memset(shadowbuf + shadowbuf_size, 0,
BUF_TEST_SIZE - shadowbuf_size);
}
memmove(shadowbuf + pos + size2,
shadowbuf + pos,
BUF_TEST_SIZE - (pos + size2));
memcpy(shadowbuf + pos, testdata, size2);
if (pos < shadowbuf_size)
shadowbuf_size += size2;
else
shadowbuf_size = pos + size2;
break;
case 5:
if (shadowbuf_size <= 1)
break;
pos = i_rand_limit(shadowbuf_size - 1); /* dest */
pos2 = i_rand_limit(shadowbuf_size - 1); /* source */
size = i_rand_limit(shadowbuf_size - I_MAX(pos, pos2));
buffer_copy(buf, pos, buf, pos2, size);
memmove(shadowbuf + pos,
shadowbuf + pos2, size);
if (pos > pos2 && pos + size > shadowbuf_size)
shadowbuf_size = pos + size;
break;
case 6:
pos = i_rand_limit(BUF_TEST_SIZE - 1);
size = i_rand_limit(BUF_TEST_SIZE - pos);
p = buffer_get_space_unsafe(buf, pos, size);
memcpy(p, testdata, size);
memcpy(shadowbuf + pos, testdata, size);
if (pos + size > shadowbuf_size)
shadowbuf_size = pos + size;
break;
}
i_assert(shadowbuf_size <= BUF_TEST_SIZE);
if (buf->used != shadowbuf_size ||
memcmp(buf->data, shadowbuf, buf->used) != 0)
break;
}
if (i == BUF_TEST_COUNT)
test_out("buffer", TRUE);
else {
test_out_reason("buffer", FALSE,
t_strdup_printf("round %u test %d failed", i, test));
}
buffer_free(&buf);
}
static void test_buffer_write(void)
{
buffer_t *buf;
test_begin("buffer_write");
buf = t_buffer_create(8);
buffer_write(buf, 5, buf, 0);
test_assert(buf->used == 5);
test_end();
}
static void test_buffer_set_used_size(void)
{
buffer_t *buf;
test_begin("buffer_set_used_size");
buf = t_buffer_create(8);
memset(buffer_append_space_unsafe(buf, 7), 'a', 7);
buffer_set_used_size(buf, 4);
test_assert(memcmp(buffer_get_space_unsafe(buf, 0, 7), "aaaa\0\0\0", 7) == 0);
memset(buffer_get_space_unsafe(buf, 4, 7), 'b', 7);
buffer_set_used_size(buf, 10);
test_assert(memcmp(buffer_append_space_unsafe(buf, 1), "\0", 1) == 0);
buffer_set_used_size(buf, 11);
test_assert(memcmp(buffer_get_space_unsafe(buf, 0, 11), "aaaabbbbbb\0", 11) == 0);
test_end();
}
#if 0
/* this code is left here to produce the output found in
* buffer.h should it be needed for debugging purposes */
#include "str.h"
#include "hex-binary.h"
static const char *binary_to_10(const unsigned char *data, size_t size)
{
string_t *str = t_str_new(size*8);
for (size_t i = 0; i < size; i++) {
for (int j = 0; j < 8; j++) {
if ((data[i] & (1 << (7-j))) != 0)
str_append_c(str, '1');
else
str_append_c(str, '0');
}
}
return str_c(str);
}
static void test_foo(void)
{
buffer_t *buf = buffer_create_dynamic(default_pool, 100);
for (int i = 1; i <= 24; i++) {
buffer_set_used_size(buf, 0);
buffer_append_c(buf, 0xff);
buffer_append_c(buf, 0xff);
buffer_append_c(buf, 0xff);
buffer_truncate_rshift_bits(buf, i);
printf("%2d bits: %24s %s\n", i,
binary_to_hex(buf->data, buf->used),
binary_to_10(buf->data, buf->used));
}
}
#endif
static void test_buffer_truncate_bits(void)
{
buffer_t *buf;
test_begin("buffer_test_truncate_bits");
struct {
buffer_t input;
size_t bits;
buffer_t output;
} test_cases[] = {
{ { { { "\xff\xff\xff", 3 } } }, 0, { { { "", 0 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 1, { { { "\x01", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 2, { { { "\x03", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 3, { { { "\x07", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 4, { { { "\x0f", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 5, { { { "\x1f", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 6, { { { "\x3f", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 7, { { { "\x7f", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 8, { { { "\xff", 1 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 9, { { { "\x01\xff", 2 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 10, { { { "\x03\xff", 2 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 11, { { { "\x07\xff", 2 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 12, { { { "\x0f\xff", 2 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 13, { { { "\x1f\xff", 2 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 14, { { { "\x3f\xff", 2 } } } },
{ { { { "\xff\xff\xff", 3 } } }, 15, { { { "\x7f\xff", 2 } } } },
{ { { { "0123456789", 10 } } }, 16, { { { "01", 2 } } } },
{ { { { "0123456789", 10 } } }, 24, { { { "012", 3 } } } },
{ { { { "0123456789", 10 } } }, 32, { { { "0123", 4 } } } },
{ { { { "0123456789", 10 } } }, 40, { { { "01234", 5 } } } },
{ { { { "0123456789", 10 } } }, 48, { { { "012345", 6 } } } },
{ { { { "0123456789", 10 } } }, 56, { { { "0123456", 7 } } } },
{ { { { "0123456789", 10 } } }, 64, { { { "01234567", 8 } } } },
{ { { { "0123456789", 10 } } }, 72, { { { "012345678", 9 } } } },
{ { { { "0123456789", 10 } } }, 80, { { { "0123456789", 10 } } } },
{ { { { "\x58\x11\xed\x02\x4d\x87\x4a\xe2\x5c\xb2\xfa\x69\xf0\xa9\x46\x2e\x04\xca\x5d\x82", 20 } } },
13,
{ { { "\x0b\x02", 2 } } }
},
/* special test cases for auth policy */
{ { { { "\x34\x40\xc8\xc9\x3a\xb6\xe7\xc4\x3f\xc1\xc3\x4d\xd5\x56\xa3\xea\xfb\x5a\x33\x57\xac\x11\x39\x2c\x71\xcb\xee\xbb\xc8\x66\x2f\x64", 32 } } },
12,
{ { { "\x03\x44", 2 } } }
},
{ { { { "\x49\xe5\x8a\x88\x76\xd3\x25\x68\xc9\x89\x4a\xe0\x64\xe4\x04\xf4\xf9\x13\xec\x88\x97\x47\x30\x7f\x3f\xcd\x8f\x74\x4f\x40\xd1\x25", 32 } } },
12,
{ { { "\x04\x9e", 2 } } }
},
{ { { { "\x08\x3c\xdc\x14\x61\x80\x1c\xe8\x43\x81\x98\xfa\xc0\x64\x04\x7a\xa2\x73\x25\x6e\xe6\x4b\x85\x42\xd0\xe2\x78\xd7\x91\xb4\x89\x3f", 32 } } },
12,
{ { { "\x00\x83", 2 } } }
},
};
buf = t_buffer_create(10);
for(size_t i = 0; i < N_ELEMENTS(test_cases); i++) {
buffer_set_used_size(buf, 0);
buffer_copy(buf, 0, &test_cases[i].input, 0, SIZE_MAX);
buffer_truncate_rshift_bits(buf, test_cases[i].bits);
test_assert_idx(buffer_cmp(buf, &test_cases[i].output) == TRUE, i);
}
test_end();
}
static void test_buffer_replace(void)
{
const char orig_input[] = "123456789";
const char data[] = "abcdefghij";
buffer_t *buf, *buf2;
unsigned int init_size, pos, size, data_size;
test_begin("buffer_replace()");
for (init_size = 0; init_size <= sizeof(orig_input)-1; init_size++) {
for (pos = 0; pos < sizeof(orig_input)+1; pos++) {
for (size = 0; size < sizeof(orig_input)+1; size++) {
for (data_size = 0; data_size <= sizeof(data)-1; data_size++) T_BEGIN {
buf = buffer_create_dynamic(pool_datastack_create(), 4);
buf2 = buffer_create_dynamic(pool_datastack_create(), 4);
buffer_append(buf, orig_input, init_size);
buffer_append(buf2, orig_input, init_size);
buffer_replace(buf, pos, size, data, data_size);
buffer_delete(buf2, pos, size);
buffer_insert(buf2, pos, data, data_size);
test_assert(buf->used == buf2->used &&
memcmp(buf->data, buf2->data, buf->used) == 0);
} T_END;
}
}
}
test_end();
}
void test_buffer(void)
{
test_buffer_random();
test_buffer_write();
test_buffer_set_used_size();
test_buffer_truncate_bits();
test_buffer_replace();
}
static void fatal_buffer_free(buffer_t *buf)
{
buffer_free(&buf);
}
enum fatal_test_state fatal_buffer(unsigned int stage)
{
buffer_t *buf;
switch (stage) {
case 0:
test_begin("fatal buffer_create_dynamic_max()");
buf = buffer_create_dynamic_max(default_pool, 1, 5);
buffer_append(buf, "12345", 5);
test_expect_fatal_string("Buffer write out of range");
test_fatal_set_callback(fatal_buffer_free, buf);
buffer_append_c(buf, 'x');
return FATAL_TEST_FAILURE;
case 1:
buf = buffer_create_dynamic_max(default_pool, 1, 5);
test_expect_fatal_string("Buffer write out of range");
test_fatal_set_callback(fatal_buffer_free, buf);
buffer_append(buf, "123456", 6);
return FATAL_TEST_FAILURE;
default:
test_end();
return FATAL_TEST_FINISHED;
}
}
dovecot-2.3.21.1/src/lib/test-json-parser.c 0000644 0000000 0000000 00000030663 14656633576 015246 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "istream-private.h"
#include "json-parser.h"
#define TYPE_SKIP 100
#define TYPE_STREAM 101
static const char json_input[] =
"{\n"
"\t\"key\"\t:\t\t\"string\","
" \"key2\" : 1234, \n"
"\"key3\":true,"
"\"key4\":false,"
"\"skip1\": \"jsifjaisfjiasji\","
"\"skip2\": { \"x\":{ \"y\":123}, \"z\":[5,[6],{\"k\":0},3]},"
"\"key5\":null,"
"\"key6\": {},"
"\"key7\": {"
" \"sub1\":\"value\""
"},"
"\"key8\": {"
" \"sub2\":-12.456,\n"
" \"sub3\":12.456e9,\n"
" \"sub4\":0.456e-789"
"},"
"\"key9\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\u10ff\","
"\"key10\": \"foo\\\\\\\"\\b\\f\\n\\r\\t\\u0001\\u10ff\","
"\"key11\": [],"
"\"key12\": [ \"foo\" , 5.24,[true],{\"aobj\":[]}],"
"\"key13\": \"\\ud801\\udc37\","
"\"key14\": \"\xd8\xb3\xd9\x84\xd8\xa7\xd9\x85\","
"\"key15\": \"\\u10000\""
"}\n";
static const struct {
enum json_type type;
const char *value;
} json_output[] = {
{ JSON_TYPE_OBJECT_KEY, "key" },
{ JSON_TYPE_STRING, "string" },
{ JSON_TYPE_OBJECT_KEY, "key2" },
{ JSON_TYPE_NUMBER, "1234" },
{ JSON_TYPE_OBJECT_KEY, "key3" },
{ JSON_TYPE_TRUE, "true" },
{ JSON_TYPE_OBJECT_KEY, "key4" },
{ JSON_TYPE_FALSE, "false" },
{ JSON_TYPE_OBJECT_KEY, "skip1" },
{ TYPE_SKIP, NULL },
{ JSON_TYPE_OBJECT_KEY, "skip2" },
{ TYPE_SKIP, NULL },
{ JSON_TYPE_OBJECT_KEY, "key5" },
{ JSON_TYPE_NULL, NULL },
{ JSON_TYPE_OBJECT_KEY, "key6" },
{ JSON_TYPE_OBJECT, NULL },
{ JSON_TYPE_OBJECT_END, NULL },
{ JSON_TYPE_OBJECT_KEY, "key7" },
{ JSON_TYPE_OBJECT, NULL },
{ JSON_TYPE_OBJECT_KEY, "sub1" },
{ JSON_TYPE_STRING, "value" },
{ JSON_TYPE_OBJECT_END, NULL },
{ JSON_TYPE_OBJECT_KEY, "key8" },
{ JSON_TYPE_OBJECT, NULL },
{ JSON_TYPE_OBJECT_KEY, "sub2" },
{ JSON_TYPE_NUMBER, "-12.456" },
{ JSON_TYPE_OBJECT_KEY, "sub3" },
{ JSON_TYPE_NUMBER, "12.456e9" },
{ JSON_TYPE_OBJECT_KEY, "sub4" },
{ JSON_TYPE_NUMBER, "0.456e-789" },
{ JSON_TYPE_OBJECT_END, NULL },
{ JSON_TYPE_OBJECT_KEY, "key9" },
{ JSON_TYPE_STRING, "foo\\\"\b\f\n\r\t\001\xe1\x83\xbf" },
{ JSON_TYPE_OBJECT_KEY, "key10" },
{ TYPE_STREAM, "foo\\\"\b\f\n\r\t\001\xe1\x83\xbf" },
{ JSON_TYPE_OBJECT_KEY, "key11" },
{ JSON_TYPE_ARRAY, NULL },
{ JSON_TYPE_ARRAY_END, NULL },
{ JSON_TYPE_OBJECT_KEY, "key12" },
{ JSON_TYPE_ARRAY, NULL },
{ JSON_TYPE_STRING, "foo" },
{ JSON_TYPE_NUMBER, "5.24" },
{ JSON_TYPE_ARRAY, NULL },
{ JSON_TYPE_TRUE, "true" },
{ JSON_TYPE_ARRAY_END, NULL },
{ JSON_TYPE_OBJECT, NULL },
{ JSON_TYPE_OBJECT_KEY, "aobj" },
{ JSON_TYPE_ARRAY, NULL },
{ JSON_TYPE_ARRAY_END, NULL },
{ JSON_TYPE_OBJECT_END, NULL },
{ JSON_TYPE_ARRAY_END, NULL },
{ JSON_TYPE_OBJECT_KEY, "key13" },
{ JSON_TYPE_STRING, "\xf0\x90\x90\xb7" },
{ JSON_TYPE_OBJECT_KEY, "key14" },
{ JSON_TYPE_STRING, "\xd8\xb3\xd9\x84\xd8\xa7\xd9\x85" },
{ JSON_TYPE_OBJECT_KEY, "key15" },
{ JSON_TYPE_STRING, "\xe1\x80\x80""0" },
};
static int
stream_read_value(struct istream **input, const char **value_r)
{
const unsigned char *data;
size_t size;
ssize_t ret;
while ((ret = i_stream_read(*input)) > 0) ;
if (ret == 0)
return 0;
i_assert(ret == -1);
if ((*input)->stream_errno != 0)
return -1;
data = i_stream_get_data(*input, &size);
*value_r = t_strndup(data, size);
i_stream_unref(input);
return 1;
}
static void test_json_parser_success(bool full_size)
{
struct json_parser *parser;
struct istream *input, *jsoninput = NULL;
enum json_type type;
const char *value, *error;
unsigned int i, pos, json_input_len = strlen(json_input);
int ret = 0;
test_begin(full_size ? "json parser" : "json parser (nonblocking)");
input = test_istream_create_data(json_input, json_input_len);
test_istream_set_allow_eof(input, FALSE);
parser = json_parser_init(input);
i = full_size ? json_input_len : 0;
for (pos = 0; i <= json_input_len; i++) {
test_istream_set_size(input, i);
for (;;) {
value = NULL;
if (pos < N_ELEMENTS(json_output) &&
json_output[pos].type == (enum json_type)TYPE_SKIP) {
json_parse_skip_next(parser);
pos++;
continue;
} else if (pos == N_ELEMENTS(json_output) ||
json_output[pos].type != (enum json_type)TYPE_STREAM) {
ret = json_parse_next(parser, &type, &value);
} else {
ret = jsoninput != NULL ? 1 :
json_parse_next_stream(parser, &jsoninput);
if (ret > 0 && jsoninput != NULL)
ret = stream_read_value(&jsoninput, &value);
type = TYPE_STREAM;
}
if (ret <= 0)
break;
i_assert(pos < N_ELEMENTS(json_output));
test_assert_idx(json_output[pos].type == type, pos);
test_assert_idx(null_strcmp(json_output[pos].value, value) == 0, pos);
pos++;
}
test_assert_idx(ret == 0, pos);
}
test_assert(pos == N_ELEMENTS(json_output));
test_istream_set_allow_eof(input, TRUE);
test_assert(json_parse_next(parser, &type, &value) == -1);
i_stream_unref(&input);
test_assert(json_parser_deinit(&parser, &error) == 0);
test_end();
}
static void test_json_parser_skip_array(void)
{
static const char *test_input =
"[ 1, {\"foo\": 1 }, 2, \"bar\", 3, 1.234, 4, [], 5, [[]], 6, true ]";
struct json_parser *parser;
struct istream *input;
enum json_type type;
const char *value, *error;
int i;
test_begin("json parser skip array");
input = test_istream_create_data(test_input, strlen(test_input));
parser = json_parser_init_flags(input, JSON_PARSER_NO_ROOT_OBJECT);
test_assert(json_parse_next(parser, &type, &value) > 0 &&
type == JSON_TYPE_ARRAY);
for (i = 1; i <= 6; i++) {
test_assert(json_parse_next(parser, &type, &value) > 0 &&
type == JSON_TYPE_NUMBER && atoi(value) == i);
json_parse_skip_next(parser);
}
test_assert(json_parse_next(parser, &type, &value) > 0 &&
type == JSON_TYPE_ARRAY_END);
test_assert(json_parser_deinit(&parser, &error) == 0);
i_stream_unref(&input);
test_end();
}
static void test_json_parser_skip_object_fields(void)
{
static const char *test_input =
"{\"access_token\":\"9a2dea3c-f8be-4271-b9c8-5b37da4f2f7e\","
"\"grant_type\":\"authorization_code\","
"\"openid\":\"\","
"\"scope\":[\"openid\",\"profile\",\"email\"],"
"\"profile\":\"\","
"\"realm\":\"/employees\","
"\"token_type\":\"Bearer\","
"\"expires_in\":2377,"
"\"client_i\\u0064\":\"mosaic\\u0064\","
"\"email\":\"\","
"\"extensions\":"
"{\"algorithm\":\"cuttlefish\","
"\"tentacles\":8"
"}"
"}";
static const char *const keys[] = {
"access_token", "grant_type", "openid", "scope", "profile",
"realm", "token_type", "expires_in", "client_id", "email",
"extensions"
};
static const unsigned int keys_count = N_ELEMENTS(keys);
struct json_parser *parser;
struct istream *input;
enum json_type type;
const char *value, *error;
unsigned int i;
size_t pos;
int ret;
test_begin("json parser skip object fields (by key)");
input = test_istream_create_data(test_input, strlen(test_input));
parser = json_parser_init(input);
for (i = 0; i < keys_count; i++) {
ret = json_parse_next(parser, &type, &value);
if (ret < 0)
break;
test_assert(ret > 0 && type == JSON_TYPE_OBJECT_KEY);
test_assert(strcmp(value, keys[i]) == 0);
json_parse_skip_next(parser);
}
test_assert(i == keys_count);
test_assert(json_parser_deinit(&parser, &error) == 0);
i_stream_unref(&input);
i = 0;
input = test_istream_create_data(test_input, strlen(test_input));
parser = json_parser_init(input);
for (pos = 0; pos <= strlen(test_input)*2; pos++) {
test_istream_set_size(input, pos/2);
ret = json_parse_next(parser, &type, &value);
if (ret == 0)
continue;
if (ret < 0)
break;
i_assert(i < keys_count);
test_assert(ret > 0 && type == JSON_TYPE_OBJECT_KEY);
test_assert(strcmp(value, keys[i]) == 0);
json_parse_skip_next(parser);
i++;
}
test_assert(i == keys_count);
test_assert(json_parser_deinit(&parser, &error) == 0);
i_stream_unref(&input);
test_end();
test_begin("json parser skip object fields (by value type)");
input = test_istream_create_data(test_input, strlen(test_input));
parser = json_parser_init(input);
for (i = 0; i < keys_count; i++) {
ret = json_parse_next(parser, &type, &value);
if (ret < 0)
break;
test_assert(ret > 0 && type == JSON_TYPE_OBJECT_KEY);
test_assert(strcmp(value, keys[i]) == 0);
ret = json_parse_next(parser, &type, &value);
test_assert(ret > 0 && type != JSON_TYPE_OBJECT_KEY);
json_parse_skip(parser);
}
test_assert(i == keys_count);
test_assert(json_parser_deinit(&parser, &error) == 0);
i_stream_unref(&input);
i = 0;
input = test_istream_create_data(test_input, strlen(test_input));
parser = json_parser_init(input);
for (pos = 0; pos <= strlen(test_input)*2; pos++) {
test_istream_set_size(input, pos/2);
ret = json_parse_next(parser, &type, &value);
if (ret < 0)
break;
if (ret == 0)
continue;
test_assert(ret > 0);
if (type == JSON_TYPE_OBJECT_KEY) {
i_assert(i < keys_count);
test_assert(strcmp(value, keys[i]) == 0);
i++;
} else {
json_parse_skip(parser);
}
}
test_assert(i == keys_count);
test_assert(json_parser_deinit(&parser, &error) == 0);
i_stream_unref(&input);
test_end();
}
static int
test_json_parse_input(const void *test_input, size_t test_input_size,
enum json_parser_flags flags)
{
struct json_parser *parser;
struct istream *input;
enum json_type type;
const char *value, *error;
int ret = 0;
input = test_istream_create_data(test_input, test_input_size);
parser = json_parser_init_flags(input, flags);
while (json_parse_next(parser, &type, &value) > 0)
ret++;
if (json_parser_deinit(&parser, &error) < 0)
ret = -1;
i_stream_unref(&input);
return ret;
}
static void test_json_parser_primitive_values(void)
{
static const struct {
const char *str;
int ret;
} test_inputs[] = {
{ "\"hello\"", 1 },
{ "null", 1 },
{ "1234", 1 },
{ "1234.1234", 1 },
{ "{}", 2 },
{ "[]", 2 },
{ "true", 1 },
{ "false", 1 }
};
unsigned int i;
test_begin("json_parser (primitives)");
for (i = 0; i < N_ELEMENTS(test_inputs); i++)
test_assert_idx(test_json_parse_input(test_inputs[i].str,
strlen(test_inputs[i].str),
JSON_PARSER_NO_ROOT_OBJECT) == test_inputs[i].ret, i);
test_end();
}
static void test_json_parser_errors(void)
{
static const char *test_inputs[] = {
"{",
"{:}",
"{\"foo\":}",
"{\"foo\" []}",
"{\"foo\": [1}",
"{\"foo\": [1,]}",
"{\"foo\": [1,]}",
"{\"foo\": 1,}",
"{\"foo\": 1.}}",
"{\"foo\": 1},{}",
"{\"foo\": \"\\ud808\"}",
"{\"foo\": \"\\udfff\"}",
"{\"foo\": \"\\uyyyy\"}",
};
unsigned int i;
test_begin("json parser error handling");
for (i = 0; i < N_ELEMENTS(test_inputs); i++)
test_assert_idx(test_json_parse_input(test_inputs[i],
strlen(test_inputs[i]),
0) < 0, i);
test_end();
}
static void test_json_parser_nuls_in_string(void)
{
static const unsigned char test_input[] =
{ '{', '"', 'k', '"', ':', '"', '\0', '"', '}' };
static const unsigned char test_input2[] =
{ '{', '"', 'k', '"', ':', '"', '\\', '\0', '"', '}' };
static const unsigned char test_input3[] =
{ '{', '"', 'k', '"', ':', '"', '\\', 'u', '0', '0', '0', '0', '"', '}' };
test_begin("json parser nuls in string");
test_assert(test_json_parse_input(test_input, sizeof(test_input), 0) < 0);
test_assert(test_json_parse_input(test_input2, sizeof(test_input2), 0) < 0);
test_assert(test_json_parse_input(test_input3, sizeof(test_input3), 0) < 0);
test_end();
}
static void test_json_append_escaped(void)
{
string_t *str = t_str_new(32);
test_begin("json_append_escaped()");
json_append_escaped(str, "\b\f\r\n\t\"\\\001\002-\xC3\xA4\xf0\x90\x90\xb7\xe2\x80\xa8\xe2\x80\xa9\xff");
test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0001\\u0002-\xC3\xA4\xf0\x90\x90\xb7\\u2028\\u2029" UNICODE_REPLACEMENT_CHAR_UTF8) == 0);
test_end();
}
static void test_json_append_escaped_data(void)
{
static const unsigned char test_input[] =
"\b\f\r\n\t\"\\\000\001\002-\xC3\xA4\xf0\x90\x90\xb7\xe2\x80\xa8\xe2\x80\xa9\xff";
string_t *str = t_str_new(32);
test_begin("json_append_escaped_data()");
json_append_escaped_data(str, test_input, sizeof(test_input)-1);
test_assert(strcmp(str_c(str), "\\b\\f\\r\\n\\t\\\"\\\\\\u0000\\u0001\\u0002-\xC3\xA4\xf0\x90\x90\xb7\\u2028\\u2029" UNICODE_REPLACEMENT_CHAR_UTF8) == 0);
test_end();
}
void test_json_parser(void)
{
test_json_parser_success(TRUE);
test_json_parser_success(FALSE);
test_json_parser_skip_array();
test_json_parser_skip_object_fields();
test_json_parser_primitive_values();
test_json_parser_errors();
test_json_parser_nuls_in_string();
test_json_append_escaped();
test_json_append_escaped_data();
}
dovecot-2.3.21.1/src/lib/test-ioloop.c 0000644 0000000 0000000 00000022737 14656633576 014307 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "net.h"
#include "time-util.h"
#include "ioloop.h"
#include "istream.h"
#include
struct test_ctx {
bool got_left;
bool got_right;
bool got_to;
};
static void timeout_callback(struct timeval *tv)
{
i_gettimeofday(tv);
io_loop_stop(current_ioloop);
}
static void test_ioloop_fd_cb_left(struct test_ctx *ctx)
{
ctx->got_left = TRUE;
if (ctx->got_left && ctx->got_right)
io_loop_stop(current_ioloop);
}
static void test_ioloop_fd_cb_right(struct test_ctx *ctx)
{
ctx->got_right = TRUE;
if (ctx->got_left && ctx->got_right)
io_loop_stop(current_ioloop);
}
static void test_ioloop_fd_to(struct test_ctx *ctx)
{
ctx->got_to = TRUE;
io_loop_stop(current_ioloop);
}
static void test_ioloop_fd(void)
{
test_begin("ioloop fd");
struct test_ctx test_ctx;
int fds[2];
int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
test_assert(ret == 0);
if (ret < 0) {
i_error("socketpair() failed: %m");
test_end();
return;
}
i_zero(&test_ctx);
struct ioloop *ioloop = io_loop_create();
struct io *io_left =
io_add(fds[0], IO_READ,
test_ioloop_fd_cb_left, &test_ctx);
struct io *io_right =
io_add(fds[1], IO_READ,
test_ioloop_fd_cb_right, &test_ctx);
struct timeout *to = timeout_add(2000, test_ioloop_fd_to, &test_ctx);
if (write(fds[0], "ltr", 3) != 3 ||
write(fds[1], "rtl", 3) != 3)
i_fatal("write() failed: %m");
io_loop_run(ioloop);
timeout_remove(&to);
io_remove(&io_left);
io_remove(&io_right);
test_assert(test_ctx.got_to == FALSE);
test_assert(test_ctx.got_left == TRUE);
test_assert(test_ctx.got_right == TRUE);
io_loop_destroy(&ioloop);
i_close_fd(&fds[0]);
i_close_fd(&fds[1]);
test_end();
}
static void test_ioloop_timeout(void)
{
struct ioloop *ioloop, *ioloop2;
struct timeout *to, *to2;
struct timeval tv_start, tv_callback;
test_begin("ioloop timeout");
ioloop = io_loop_create();
/* add a timeout by moving it from another ioloop */
ioloop2 = io_loop_create();
test_assert(io_loop_is_empty(ioloop));
test_assert(io_loop_is_empty(ioloop2));
to2 = timeout_add(1000, timeout_callback, &tv_callback);
test_assert(io_loop_is_empty(ioloop));
test_assert(!io_loop_is_empty(ioloop2));
io_loop_set_current(ioloop);
to2 = io_loop_move_timeout(&to2);
test_assert(!io_loop_is_empty(ioloop));
test_assert(io_loop_is_empty(ioloop2));
io_loop_set_current(ioloop2);
io_loop_destroy(&ioloop2);
sleep(1);
/* add & remove immediately */
to = timeout_add(1000, timeout_callback, &tv_callback);
timeout_remove(&to);
/* add the timeout we're actually testing below */
to = timeout_add(1000, timeout_callback, &tv_callback);
i_gettimeofday(&tv_start);
io_loop_run(ioloop);
test_assert(timeval_diff_msecs(&tv_callback, &tv_start) >= 500);
timeout_remove(&to);
timeout_remove(&to2);
test_assert(io_loop_is_empty(ioloop));
io_loop_destroy(&ioloop);
test_end();
}
static void zero_timeout_callback(unsigned int *counter)
{
*counter += 1;
}
static void test_ioloop_zero_timeout(void)
{
struct ioloop *ioloop;
struct timeout *to;
struct io *io;
unsigned int counter = 0;
int fd[2];
test_begin("ioloop zero timeout");
if (pipe(fd) < 0)
i_fatal("pipe() failed: %m");
switch (fork()) {
case (pid_t)-1:
i_fatal("fork() failed: %m");
case 0:
sleep(1);
char c = 0;
if (write(fd[1], &c, 1) < 0)
i_fatal("write(pipe) failed: %m");
test_exit(0);
default:
break;
}
ioloop = io_loop_create();
to = timeout_add_short(0, zero_timeout_callback, &counter);
io = io_add(fd[0], IO_READ, io_loop_stop, ioloop);
io_loop_run(ioloop);
test_assert_ucmp(counter, >, 1000);
timeout_remove(&to);
io_remove(&io);
io_loop_destroy(&ioloop);
test_end();
}
struct zero_timeout_recreate_ctx {
struct timeout *to;
unsigned int counter;
};
static void
zero_timeout_recreate_callback(struct zero_timeout_recreate_ctx *ctx)
{
timeout_remove(&ctx->to);
ctx->to = timeout_add_short(0, zero_timeout_recreate_callback, ctx);
ctx->counter++;
}
static void test_ioloop_zero_timeout_recreate(void)
{
struct ioloop *ioloop;
struct io *io;
struct zero_timeout_recreate_ctx ctx = { .counter = 0 };
int fd[2];
test_begin("ioloop zero timeout recreate");
if (pipe(fd) < 0)
i_fatal("pipe() failed: %m");
switch (fork()) {
case (pid_t)-1:
i_fatal("fork() failed: %m");
case 0:
sleep(1);
char c = 0;
if (write(fd[1], &c, 1) < 0)
i_fatal("write(pipe) failed: %m");
test_exit(0);
default:
break;
}
ioloop = io_loop_create();
ctx.to = timeout_add_short(0, zero_timeout_recreate_callback, &ctx);
io = io_add(fd[0], IO_READ, io_loop_stop, ioloop);
io_loop_run(ioloop);
test_assert_ucmp(ctx.counter, >, 1000);
timeout_remove(&ctx.to);
io_remove(&io);
io_loop_destroy(&ioloop);
test_end();
}
static void io_callback(void *context ATTR_UNUSED)
{
}
static void test_ioloop_find_fd_conditions(void)
{
static struct {
enum io_condition condition;
int fd[2];
struct io *io;
} tests[] = {
{ IO_ERROR, { -1, -1 }, NULL },
{ IO_READ, { -1, -1 }, NULL },
{ IO_WRITE, { -1, -1 }, NULL },
{ IO_READ | IO_WRITE, { -1, -1 }, NULL },
{ IO_READ, { -1, -1 }, NULL } /* read+write as separate ios */
};
struct ioloop *ioloop;
struct io *io;
unsigned int i;
test_begin("ioloop find fd conditions");
ioloop = io_loop_create();
for (i = 0; i < N_ELEMENTS(tests); i++) {
if (socketpair(AF_UNIX, SOCK_STREAM, 0, tests[i].fd) < 0)
i_fatal("socketpair() failed: %m");
tests[i].io = io_add(tests[i].fd[0], tests[i].condition, io_callback, NULL);
}
io = io_add(tests[i-1].fd[0], IO_WRITE, io_callback, NULL);
tests[i-1].condition |= IO_WRITE;
for (i = 0; i < N_ELEMENTS(tests); i++)
test_assert_idx(io_loop_find_fd_conditions(ioloop, tests[i].fd[0]) == tests[i].condition, i);
io_remove(&io);
for (i = 0; i < N_ELEMENTS(tests); i++) {
io_remove(&tests[i].io);
i_close_fd(&tests[i].fd[0]);
i_close_fd(&tests[i].fd[1]);
}
io_loop_destroy(&ioloop);
test_end();
}
static void io_callback_pending_io(void *context ATTR_UNUSED)
{
io_loop_stop(current_ioloop);
}
static void test_ioloop_pending_io(void)
{
test_begin("ioloop pending io");
struct istream *is = i_stream_create_from_data("data", 4);
struct ioloop *ioloop = io_loop_create();
test_assert(io_loop_is_empty(ioloop));
struct io *io = io_add_istream(is, io_callback_pending_io, NULL);
test_assert(!io_loop_is_empty(ioloop));
io_loop_set_current(ioloop);
io_set_pending(io);
io_loop_run(ioloop);
io_remove(&io);
i_stream_unref(&is);
io_loop_destroy(&ioloop);
test_end();
}
static void test_ioloop_context_callback(struct ioloop_context *ctx)
{
test_assert(io_loop_get_current_context(current_ioloop) == ctx);
io_loop_stop(current_ioloop);
}
static void test_ioloop_context(void)
{
test_begin("ioloop context");
struct ioloop *ioloop = io_loop_create();
struct ioloop_context *ctx = io_loop_context_new(ioloop);
test_assert(io_loop_get_current_context(current_ioloop) == NULL);
io_loop_context_activate(ctx);
test_assert(io_loop_get_current_context(current_ioloop) == ctx);
struct timeout *to = timeout_add(0, test_ioloop_context_callback, ctx);
io_loop_run(ioloop);
test_assert(io_loop_get_current_context(current_ioloop) == NULL);
/* test that we don't crash at deinit if we leave the context active */
io_loop_context_activate(ctx);
test_assert(io_loop_get_current_context(current_ioloop) == ctx);
timeout_remove(&to);
io_loop_context_unref(&ctx);
io_loop_destroy(&ioloop);
test_end();
}
static void test_ioloop_context_events_run(struct event *root_event)
{
struct ioloop *ioloop = io_loop_create();
struct ioloop_context *ctx1, *ctx2;
/* create context 1 */
ctx1 = io_loop_context_new(ioloop);
io_loop_context_switch(ctx1);
struct event *ctx1_event1 = event_create(NULL);
event_push_global(ctx1_event1);
struct event *ctx1_event2 = event_create(NULL);
event_push_global(ctx1_event2);
io_loop_context_deactivate(ctx1);
test_assert(event_get_global() == root_event);
/* create context 2 */
ctx2 = io_loop_context_new(ioloop);
io_loop_context_switch(ctx2);
struct event *ctx2_event1 = event_create(NULL);
event_push_global(ctx2_event1);
io_loop_context_deactivate(ctx2);
test_assert(event_get_global() == root_event);
/* test switching contexts */
io_loop_context_switch(ctx1);
test_assert(event_get_global() == ctx1_event2);
io_loop_context_switch(ctx2);
test_assert(event_get_global() == ctx2_event1);
/* test popping away events */
io_loop_context_switch(ctx1);
event_pop_global(ctx1_event2);
io_loop_context_switch(ctx2);
event_pop_global(ctx2_event1);
io_loop_context_switch(ctx1);
test_assert(event_get_global() == ctx1_event1);
io_loop_context_switch(ctx2);
test_assert(event_get_global() == root_event);
io_loop_context_deactivate(ctx2);
io_loop_context_unref(&ctx1);
io_loop_context_unref(&ctx2);
io_loop_destroy(&ioloop);
event_unref(&ctx1_event1);
event_unref(&ctx1_event2);
event_unref(&ctx2_event1);
}
static void test_ioloop_context_events(void)
{
test_begin("ioloop context - no root event");
test_ioloop_context_events_run(NULL);
test_end();
test_begin("ioloop context - with root event");
struct event *root_event = event_create(NULL);
event_push_global(root_event);
test_ioloop_context_events_run(root_event);
event_pop_global(root_event);
event_unref(&root_event);
test_end();
}
void test_ioloop(void)
{
test_ioloop_timeout();
test_ioloop_zero_timeout();
test_ioloop_zero_timeout_recreate();
test_ioloop_find_fd_conditions();
test_ioloop_pending_io();
test_ioloop_fd();
test_ioloop_context();
test_ioloop_context_events();
}
dovecot-2.3.21.1/src/lib/iostream-pump.h 0000644 0000000 0000000 00000004647 14656633576 014640 0000000 0000000 #ifndef IOSTREAM_PUMP_H
#define IOSTREAM_PUMP_H
/* iostream-pump
=============
This construct pumps data from istream to ostream asynchronously.
The pump requires you to provide completion callback. The completion
callback is called with success parameter to indicate whether it ended
with error.
The istream and ostream are reffed on creation and unreffed
on unref.
*/
struct istream;
struct ostream;
struct ioloop;
struct iostream_pump;
enum iostream_pump_status {
/* pump succeeded - EOF received from istream and all output was
written successfully to ostream. */
IOSTREAM_PUMP_STATUS_INPUT_EOF,
/* pump failed - istream returned an error */
IOSTREAM_PUMP_STATUS_INPUT_ERROR,
/* pump failed - ostream returned an error */
IOSTREAM_PUMP_STATUS_OUTPUT_ERROR,
};
/* The callback is called once when the pump succeeds or fails due to
iostreams. (It's not called if pump is destroyed.) */
typedef void iostream_pump_callback_t(enum iostream_pump_status status,
void *context);
struct iostream_pump *
iostream_pump_create(struct istream *input, struct ostream *output);
struct istream *iostream_pump_get_input(struct iostream_pump *pump);
struct ostream *iostream_pump_get_output(struct iostream_pump *pump);
void iostream_pump_start(struct iostream_pump *pump);
void iostream_pump_stop(struct iostream_pump *pump);
void iostream_pump_ref(struct iostream_pump *pump);
void iostream_pump_unref(struct iostream_pump **_pump);
void iostream_pump_destroy(struct iostream_pump **_pump);
void iostream_pump_set_completion_callback(struct iostream_pump *pump,
iostream_pump_callback_t *callback,
void *context);
#define iostream_pump_set_completion_callback(pump, callback, context) \
iostream_pump_set_completion_callback(pump, \
(iostream_pump_callback_t *)callback, TRUE ? context : \
CALLBACK_TYPECHECK(callback, \
void (*)(enum iostream_pump_status, typeof(context))))
/* Returns TRUE if the pump is currently only writing to the ostream. The input
listener has been removed either because the ostream buffer is full or
because the istream already returned EOF. This function can also be called
from the completion callback in error conditions. */
bool iostream_pump_is_waiting_output(struct iostream_pump *pump);
void iostream_pump_switch_ioloop_to(struct iostream_pump *pump,
struct ioloop *ioloop);
void iostream_pump_switch_ioloop(struct iostream_pump *pump);
#endif
dovecot-2.3.21.1/src/lib/iostream-rawlog.h 0000644 0000000 0000000 00000002035 14656633576 015137 0000000 0000000 #ifndef IOSTREAM_RAWLOG_H
#define IOSTREAM_RAWLOG_H
enum iostream_rawlog_flags {
IOSTREAM_RAWLOG_FLAG_AUTOCLOSE = 0x01,
IOSTREAM_RAWLOG_FLAG_BUFFERED = 0x02,
IOSTREAM_RAWLOG_FLAG_TIMESTAMP = 0x04
};
/* Create rawlog *.in and *.out files to the given directory. */
int ATTR_NOWARN_UNUSED_RESULT
iostream_rawlog_create(const char *dir, struct istream **input,
struct ostream **output);
/* Create rawlog prefix.in and prefix.out files. */
int ATTR_NOWARN_UNUSED_RESULT
iostream_rawlog_create_prefix(const char *prefix, struct istream **input,
struct ostream **output);
/* Create rawlog path, writing both input and output to the same file. */
int ATTR_NOWARN_UNUSED_RESULT
iostream_rawlog_create_path(const char *path, struct istream **input,
struct ostream **output);
/* Create rawlog that appends to the given rawlog_output.
Both input and output are written to the same stream. */
void iostream_rawlog_create_from_stream(struct ostream *rawlog_output,
struct istream **input,
struct ostream **output);
#endif
dovecot-2.3.21.1/src/lib/hostpid.h 0000644 0000000 0000000 00000001042 14656633576 013472 0000000 0000000 #ifndef HOSTPID_H
#define HOSTPID_H
/* These environments override the hostname/hostdomain if they're set.
Master process normally sets these to child processes. */
#define MY_HOSTNAME_ENV "DOVECOT_HOSTNAME"
#define MY_HOSTDOMAIN_ENV "DOVECOT_HOSTDOMAIN"
extern const char *my_hostname;
extern const char *my_pid;
/* Initializes my_hostname and my_pid. */
void hostpid_init(void);
void hostpid_deinit(void);
/* Returns the current host+domain, or if it fails fallback to returning
hostname. */
const char *my_hostdomain(void);
#endif
dovecot-2.3.21.1/src/lib/test-istream.c 0000644 0000000 0000000 00000025417 14656633576 014450 0000000 0000000 /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "istream.h"
#include "istream-crlf.h"
static void test_istream_children(void)
{
struct istream *parent, *child1, *child2;
const unsigned char *data;
size_t size;
test_begin("istream children");
parent = test_istream_create_data("123456789", 9);
test_istream_set_max_buffer_size(parent, 3);
child1 = i_stream_create_limit(parent, UOFF_T_MAX);
child2 = i_stream_create_limit(parent, UOFF_T_MAX);
/* child1 read beginning */
test_assert(i_stream_read(child1) == 3);
data = i_stream_get_data(child1, &size);
test_assert(size == 3 && memcmp(data, "123", 3) == 0);
i_stream_skip(child1, 3);
/* child1 read middle.. */
test_assert(i_stream_read(child1) == 3);
data = i_stream_get_data(child1, &size);
test_assert(size == 3 && memcmp(data, "456", 3) == 0);
/* child2 read beginning.. */
test_assert(i_stream_read(child2) == 3);
data = i_stream_get_data(child2, &size);
test_assert(size == 3 && memcmp(data, "123", 3) == 0);
/* child1 check middle again.. the parent has been modified,
so it can't return the original data (without some code changes). */
test_assert(i_stream_get_data_size(child1) == 0);
i_stream_skip(child1, 3);
/* child1 read end */
test_assert(i_stream_read(child1) == 3);
data = i_stream_get_data(child1, &size);
test_assert(size == 3 && memcmp(data, "789", 3) == 0);
i_stream_skip(child1, 3);
test_assert(i_stream_read(child1) == -1);
/* child2 check beginning again.. */
test_assert(i_stream_get_data_size(child1) == 0);
i_stream_skip(child2, 3);
/* child2 read middle */
test_assert(i_stream_read(child2) == 3);
data = i_stream_get_data(child2, &size);
test_assert(size == 3 && memcmp(data, "456", 3) == 0);
i_stream_skip(child2, 3);
i_stream_destroy(&child1);
i_stream_destroy(&child2);
i_stream_destroy(&parent);
test_end();
}
static void test_istream_next_line_expect(struct istream *is, const char *expect,
unsigned int i)
{
const char *line = i_stream_next_line(is);
test_assert_strcmp_idx(line, expect, i);
}
static void test_istream_next_line(void)
{
/* single line cases */
#define TEST_CASE(a, s, b) { \
.input = (const unsigned char*)((a)), .input_len = sizeof((a)), \
.skip = s, \
.output = b }
const struct test_case_sl {
const unsigned char *input;
size_t input_len;
size_t skip;
const char *output;
} test_cases_sl[] = {
TEST_CASE("", 0, NULL),
TEST_CASE("a\n", 1, ""),
TEST_CASE("a\r\n", 0, "a"),
TEST_CASE("a\r\n", 1, ""),
TEST_CASE("a\r\n", 2, ""),
TEST_CASE("hello\nworld\n", 6, "world"),
TEST_CASE("hello\nworld", 6, NULL),
TEST_CASE("hello\n\n\n\n", 6, ""),
TEST_CASE("wrong\n\r\n\n", 0, "wrong"),
TEST_CASE("wrong\n\r\r\n", 6, "\r"),
TEST_CASE("wrong\n\r\r\n", 7, ""),
};
test_begin("i_stream_next_line");
for(unsigned int i = 0; i < N_ELEMENTS(test_cases_sl); i++) {
const struct test_case_sl *test_case = &test_cases_sl[i];
struct istream *input =
i_stream_create_copy_from_data(test_case->input, test_case->input_len);
test_assert_idx(i_stream_read(input) >= 0 ||
(input->stream_errno == 0 && input->eof), i);
i_stream_skip(input, test_case->skip);
test_assert_strcmp_idx(i_stream_next_line(input), test_case->output, i);
test_assert_idx(input->stream_errno == 0, i);
i_stream_unref(&input);
input = test_istream_create_data(test_case->input, test_case->input_len);
test_assert_idx(i_stream_read(input) >= 0 ||
(input->stream_errno == 0 && input->eof), i);
i_stream_skip(input, test_case->skip);
test_assert_strcmp_idx(i_stream_next_line(input), test_case->output, i);
test_assert_idx(input->stream_errno == 0, i);
i_stream_unref(&input);
}
#undef TEST_CASE
#define TEST_CASE(a) test_istream_create_data((a), sizeof(a))
/* multiline tests */
struct istream *is = TEST_CASE("\n\n\n\n\n\n");
size_t i;
test_assert(i_stream_read(is) >= 0 || (is->stream_errno == 0 && is->eof));
for(i = 0; i < 6; i++)
test_istream_next_line_expect(is, "", i);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
is = TEST_CASE(
"simple\r\n"
"multiline\n"
"test with\0"
"some exciting\n"
"things\r\n\0");
test_assert(i_stream_read(is) >= 0 || (is->stream_errno == 0 && is->eof));
test_istream_next_line_expect(is, "simple", 0);
test_istream_next_line_expect(is, "multiline", 1);
test_istream_next_line_expect(is, "test with", 2);
test_istream_next_line_expect(is, "things", 3);
test_istream_next_line_expect(is, NULL, 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
is = TEST_CASE(
"NUL\0"
"test\n");
test_assert(i_stream_read(is) >= 0 || (is->stream_errno == 0 && is->eof));
test_istream_next_line_expect(is, "NUL", 0);
test_istream_next_line_expect(is, NULL, 1);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
const char test_data_1[] =
"this is some data\n"
"written like this\n"
"to attempt and induce\n"
"errors or flaws\n";
is = TEST_CASE(test_data_1);
size_t n = 0;
const char *const *lines = t_strsplit(test_data_1, "\n");
for(i = 0; i < sizeof(test_data_1); i++) {
test_istream_set_size(is, i);
test_assert(i_stream_read(is) >= 0);
const char *line = i_stream_next_line(is);
if (line != NULL) {
test_assert_strcmp_idx(lines[n], line, n);
n++;
}
}
test_assert(n == 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
const char test_data_2[] =
"this is some data\n"
"written like this\n"
"to attempt and induce\n"
"errors or flaws";
is = TEST_CASE(test_data_2);
lines = t_strsplit(test_data_2, "\n");
i_stream_set_return_partial_line(is, TRUE);
n = 0;
/* requires one extra read to get the last line */
for(i = 0; i < sizeof(test_data_1) + 1; i++) {
test_istream_set_size(is, I_MIN(sizeof(test_data_1), i));
(void)i_stream_read(is);
const char *line = i_stream_next_line(is);
if (line != NULL) {
test_assert_strcmp_idx(lines[n], line, n);
n++;
}
(void)i_stream_read(is);
}
test_assert(n == 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
const char test_data_3[] =
"this is some data\r\n"
"written like this\r\n"
"to attempt and induce\r\n"
"errors or flaws\r\n";
struct istream *is_1 = TEST_CASE(test_data_3);
is = i_stream_create_crlf(is_1);
i_stream_unref(&is_1);
lines = t_strsplit_spaces(test_data_3, "\r\n");
n = 0;
for(i = 0; i < sizeof(test_data_3); i++) {
test_istream_set_size(is, i);
test_assert(i_stream_read(is) >= 0);
const char *line = i_stream_next_line(is);
if (line != NULL) {
test_assert_strcmp_idx(lines[n], line, n);
n++;
}
}
test_assert(n == 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
test_end();
}
static void test_istream_read_next_line(void)
{
/* single line cases */
#undef TEST_CASE
#define TEST_CASE(a, s, b) { \
.input = (const unsigned char*)((a)), .input_len = sizeof((a)), \
.skip = s, \
.output = b }
const struct test_case_sl {
const unsigned char *input;
size_t input_len;
size_t skip;
const char *output;
} test_cases_sl[] = {
TEST_CASE("", 0, NULL),
TEST_CASE("a\n", 1, ""),
TEST_CASE("a\r\n", 0, "a"),
TEST_CASE("a\r\n", 1, ""),
TEST_CASE("a\r\n", 2, ""),
TEST_CASE("hello\nworld\n", 6, "world"),
TEST_CASE("hello\nworld", 6, NULL),
TEST_CASE("hello\n\n\n\n", 6, ""),
TEST_CASE("wrong\n\r\n\n", 0, "wrong"),
TEST_CASE("wrong\n\r\r\n", 6, "\r"),
TEST_CASE("wrong\n\r\r\n", 7, ""),
};
test_begin("i_stream_read_next_line");
for(unsigned int i = 0; i < N_ELEMENTS(test_cases_sl); i++) {
const struct test_case_sl *test_case = &test_cases_sl[i];
struct istream *input =
i_stream_create_copy_from_data(test_case->input, test_case->input_len);
i_stream_skip(input, test_case->skip);
test_assert_strcmp_idx(i_stream_read_next_line(input), test_case->output, i);
test_assert_idx(input->stream_errno == 0, i);
i_stream_unref(&input);
input = test_istream_create_data(test_case->input, test_case->input_len);
i_stream_skip(input, test_case->skip);
test_assert_strcmp_idx(i_stream_read_next_line(input), test_case->output, i);
test_assert_idx(input->stream_errno == 0, i);
i_stream_unref(&input);
}
const char test_data_1[] =
"this is some data\n"
"written like this\n"
"to attempt and induce\n"
"errors or flaws\n";
#undef TEST_CASE
#define TEST_CASE(a) test_istream_create_data((a), sizeof(a))
/* multiline tests */
struct istream *is = TEST_CASE("\n\n\n\n\n\n");
size_t i;
for(i = 0; i < 6; i++)
test_assert_strcmp_idx(i_stream_read_next_line(is), "", i);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
is = TEST_CASE(
"simple\r\n"
"multiline\n"
"test with\0"
"some exciting\n"
"things\r\n\0");
test_assert_strcmp_idx(i_stream_read_next_line(is), "simple", 0);
test_assert_strcmp_idx(i_stream_read_next_line(is), "multiline", 1);
test_assert_strcmp_idx(i_stream_read_next_line(is), "test with", 2);
test_assert_strcmp_idx(i_stream_read_next_line(is), "things", 3);
test_assert_strcmp_idx(i_stream_read_next_line(is), NULL, 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
is = TEST_CASE(
"NUL\0"
"test\n");
test_assert_strcmp_idx(i_stream_read_next_line(is), "NUL", 0);
test_assert_strcmp_idx(i_stream_read_next_line(is), NULL, 1);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
is = TEST_CASE(test_data_1);
size_t n = 0;
const char *const *lines = t_strsplit(test_data_1, "\n");
for(i = 0; i < sizeof(test_data_1); i++) {
test_istream_set_size(is, i);
const char *line = i_stream_read_next_line(is);
if (line != NULL) {
test_assert_strcmp_idx(lines[n], line, n);
n++;
}
}
test_assert(n == 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
const char test_data_2[] =
"this is some data\n"
"written like this\n"
"to attempt and induce\n"
"errors or flaws";
is = TEST_CASE(test_data_2);
lines = t_strsplit(test_data_2, "\n");
i_stream_set_return_partial_line(is, TRUE);
n = 0;
for(i = 0; i < sizeof(test_data_1); i++) {
test_istream_set_size(is, i);
const char *line = i_stream_read_next_line(is);
if (line != NULL) {
test_assert_strcmp_idx(lines[n], line, n);
n++;
}
}
test_assert(n == 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
const char test_data_3[] =
"this is some data\r\n"
"written like this\r\n"
"to attempt and induce\r\n"
"errors or flaws\r\n";
struct istream *is_1 = TEST_CASE(test_data_3);
is = i_stream_create_crlf(is_1);
i_stream_unref(&is_1);
lines = t_strsplit_spaces(test_data_3, "\r\n");
n = 0;
for(i = 0; i < sizeof(test_data_3); i++) {
test_istream_set_size(is, i);
const char *line = i_stream_read_next_line(is);
if (line != NULL) {
test_assert_strcmp_idx(lines[n], line, n);
n++;
}
}
test_assert(n == 4);
test_assert(is->stream_errno == 0);
i_stream_unref(&is);
test_end();
}
void test_istream(void)
{
test_istream_children();
test_istream_next_line();
test_istream_read_next_line();
}
dovecot-2.3.21.1/src/lib/sendfile-util.h 0000644 0000000 0000000 00000001245 14656633576 014571 0000000 0000000 #ifndef SENDFILE_UTIL_H
#define SENDFILE_UTIL_H
/* Wrapper for various sendfile()-like calls. Read a maximum of count bytes
from the given offset in in_fd and write them to out_fd. The offset is
updated after the call. Note the call assert-crashes if count is 0.
Returns:
>0 number of bytes successfully written (maybe less than count)
0 if offset points to the input's EOF or past it
-1, errno=EINVAL if it isn't supported for some reason (out_fd isn't a
socket or there simply is no sendfile()).
-1, errno=EAGAIN if non-blocking write couldn't send anything */
ssize_t safe_sendfile(int out_fd, int in_fd, uoff_t *offset, size_t count);
#endif
dovecot-2.3.21.1/src/lib/event-filter-lexer.l 0000644 0000000 0000000 00000007053 14656633576 015555 0000000 0000000 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
%option nounput
%option noinput
%option noyywrap
%option noyyalloc noyyrealloc noyyfree
%option reentrant
%option bison-bridge
%option never-interactive
%option prefix="event_filter_parser_"
%{
#include "lib.h"
#include "str.h"
#include "event-filter-private.h"
#include "event-filter-parser.h"
#define YY_FATAL_ERROR(msg) { i_fatal("event filter parsing: %s", (msg)); }
/* mimic renaming done by bison's api.prefix %define */
#define YYSTYPE EVENT_FILTER_PARSER_STYPE
#define YY_INPUT(buf, result, max_size) \
result = event_filter_parser_input_proc(buf, max_size, yyscanner)
static size_t event_filter_parser_input_proc(char *buf, size_t size, yyscan_t scanner);
#pragma GCC diagnostic push
/* ignore strict bool warnings in generated code */
#ifdef HAVE_STRICT_BOOL
# pragma GCC diagnostic ignored "-Wstrict-bool"
#endif
/* ignore sign comparison errors (buggy flex) */
#pragma GCC diagnostic ignored "-Wsign-compare"
/* ignore unused functions */
#pragma GCC diagnostic ignored "-Wunused-function"
/* ignore unused parameters */
#pragma GCC diagnostic ignored "-Wunused-parameter"
%}
%x string
%%
string_t *str_buf = NULL;
\" {
BEGIN(string);
str_buf = t_str_new(128);
}
\" {
yylval->str = str_c(str_buf);
BEGIN(INITIAL);
return STRING;
}
/* Note: these have to match the event_filter_append_escaped() behavior */
[^\\"]+ { str_append(str_buf, yytext); }
\\\\ { str_append_c(str_buf, '\\'); }
\\\" { str_append_c(str_buf, '"'); }
\\. { str_append(str_buf, yytext); }
[Aa][Nn][Dd] { return AND; }
[Oo][Rr] { return OR; }
[Nn][Oo][Tt] { return NOT; }
[<>=()] { return *yytext; }
[A-Za-z0-9:.*?_-]+ { yylval->str = t_strdup(yytext); return TOKEN; }
[ \t\n\r] { /* ignore */ }
. {
/*
* We simply return the char to the
* and let the grammar error out
* with a syntax error.
*
* Note: The cast is significant
* since utf-8 bytes >=128 will
* otherwise result in sign
* extension and a negative int
* getting returned on some
* platforms (e.g., x86) which in
* turn confuses the parser. E.g.,
* if:
* *yytext = '\x80'
* we get:
* *yytext -> -128
* (int) *yytext -> -128
* which is wrong. With the
* unsigned char cast, we get:
* (u.c.) *yytext -> 128
* (int)(u.c.) *yytext -> 128
* which is correct.
*/
return (unsigned char) *yytext;
}
%%
#pragma GCC diagnostic pop
void *yyalloc(size_t bytes, void* yyscanner ATTR_UNUSED)
{
void *ptr = calloc(1, bytes);
if (ptr == NULL)
i_fatal_status(FATAL_OUTOFMEM, "calloc(1, %zu): Out of memory",
bytes);
return ptr;
}
void *yyrealloc (void *ptr, size_t bytes, void *yyscanner ATTR_UNUSED)
{
void *nptr = realloc(ptr, bytes);
if (nptr == NULL)
i_fatal_status(FATAL_OUTOFMEM, "realloc(ptr, %zu): Out of memory",
bytes);
return nptr;
}
void yyfree(void *ptr, void *yyscanner ATTR_UNUSED)
{
if (ptr == NULL)
return;
free(ptr);
}
static size_t event_filter_parser_input_proc(char *buf, size_t size, yyscan_t scanner)
{
struct event_filter_parser_state *state;
size_t num_bytes;
state = event_filter_parser_get_extra(scanner);
if (state->len == state->pos)
return 0;
i_assert(state->len > state->pos);
num_bytes = I_MIN(state->len - state->pos, size);
memcpy(buf, state->input + state->pos, num_bytes);
state->pos += num_bytes;
return num_bytes;
}
dovecot-2.3.21.1/src/lib/stats-dist.c 0000644 0000000 0000000 00000010527 14656633576 014122 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "stats-dist.h"
#include "sort.h"
/* In order to have a vaguely accurate 95th percentile, you need way
more than 20 in your subsample. */
#define TIMING_DEFAULT_SUBSAMPLING_BUFFER (20*24) /* 20*24 fits in a page */
struct stats_dist {
unsigned int sample_count;
unsigned int count;
bool sorted;
uint64_t min;
uint64_t max;
uint64_t sum;
uint64_t samples[];
};
struct stats_dist *stats_dist_init(void)
{
return stats_dist_init_with_size(TIMING_DEFAULT_SUBSAMPLING_BUFFER);
}
struct stats_dist *stats_dist_init_with_size(unsigned int sample_count)
{
i_assert(sample_count > 0);
struct stats_dist *stats =
i_malloc(sizeof(struct stats_dist) +
sizeof(uint64_t) * sample_count);
stats->sample_count = sample_count;
return stats;
}
void stats_dist_deinit(struct stats_dist **_stats)
{
i_free_and_null(*_stats);
}
void stats_dist_reset(struct stats_dist *stats)
{
unsigned int sample_count = stats->sample_count;
i_zero(stats);
stats->sample_count = sample_count;
}
void stats_dist_add(struct stats_dist *stats, uint64_t value)
{
if (stats->count < stats->sample_count) {
stats->samples[stats->count] = value;
if (stats->count == 0)
stats->min = stats->max = value;
} else {
unsigned int idx = i_rand_limit(stats->count);
if (idx < stats->sample_count)
stats->samples[idx] = value;
}
stats->count++;
stats->sum += value;
if (stats->max < value)
stats->max = value;
if (stats->min > value)
stats->min = value;
stats->sorted = FALSE;
}
unsigned int stats_dist_get_count(const struct stats_dist *stats)
{
return stats->count;
}
uint64_t stats_dist_get_sum(const struct stats_dist *stats)
{
return stats->sum;
}
uint64_t stats_dist_get_min(const struct stats_dist *stats)
{
return stats->min;
}
uint64_t stats_dist_get_max(const struct stats_dist *stats)
{
return stats->max;
}
double stats_dist_get_avg(const struct stats_dist *stats)
{
if (stats->count == 0)
return 0;
return (double)stats->sum / stats->count;
}
static void stats_dist_ensure_sorted(struct stats_dist *stats)
{
if (stats->sorted)
return;
unsigned int count = (stats->count < stats->sample_count)
? stats->count
: stats->sample_count;
i_qsort(stats->samples, count, sizeof(*stats->samples),
uint64_cmp);
stats->sorted = TRUE;
}
uint64_t stats_dist_get_median(struct stats_dist *stats)
{
if (stats->count == 0)
return 0;
/* cast-away const - reading requires sorting */
stats_dist_ensure_sorted(stats);
unsigned int count = (stats->count < stats->sample_count)
? stats->count
: stats->sample_count;
unsigned int idx1 = (count-1)/2, idx2 = count/2;
return (stats->samples[idx1] + stats->samples[idx2]) / 2;
}
double stats_dist_get_variance(const struct stats_dist *stats)
{
double sum = 0;
if (stats->count == 0)
return 0;
double avg = stats_dist_get_avg(stats);
double count = (stats->count < stats->sample_count)
? stats->count
: stats->sample_count;
for(unsigned int i = 0; i < count; i++) {
sum += (stats->samples[i] - avg)*(stats->samples[i] - avg);
}
return sum / count;
}
/* This is independent of the stats framework, useful for any selection task */
static unsigned int stats_dist_get_index(unsigned int range, double fraction)
{
/* With out of range fractions, we can give the caller what
they probably want rather than just crashing. */
if (fraction >= 1.)
return range - 1;
if (fraction <= 0.)
return 0;
double idx_float = range * fraction;
unsigned int idx = idx_float; /* C defaults to rounding down */
idx_float -= idx;
/* Exact boundaries belong to the open range below them.
As FP isn't exact, and ratios may be specified inexactly,
include a small amount of fuzz around the exact boundary. */
if (idx_float < 1e-8*range)
idx--;
return idx;
}
uint64_t stats_dist_get_percentile(struct stats_dist *stats, double fraction)
{
if (stats->count == 0)
return 0;
stats_dist_ensure_sorted(stats);
unsigned int count = (stats->count < stats->sample_count)
? stats->count
: stats->sample_count;
unsigned int idx = stats_dist_get_index(count, fraction);
return stats->samples[idx];
}
const uint64_t *stats_dist_get_samples(const struct stats_dist *stats,
unsigned int *count_r)
{
*count_r = (stats->count < stats->sample_count)
? stats->count
: stats->sample_count;
return stats->samples;
}
dovecot-2.3.21.1/src/lib/write-full.h 0000644 0000000 0000000 00000000600 14656633576 014111 0000000 0000000 #ifndef WRITE_FULL_H
#define WRITE_FULL_H
/* Write data into file. Returns -1 if error occurred, or 0 if all was ok.
If there's not enough space in device, -1 with ENOSPC is returned, and
it's unspecified how much data was actually written. */
int write_full(int fd, const void *data, size_t size);
int pwrite_full(int fd, const void *data, size_t size, off_t offset);
#endif
dovecot-2.3.21.1/src/lib/ostream-file-private.h 0000644 0000000 0000000 00000002250 14656633576 016061 0000000 0000000 #ifndef OSTREAM_FILE_PRIVATE_H
#define OSTREAM_FILE_PRIVATE_H
#include "ostream-private.h"
struct file_ostream {
struct ostream_private ostream;
ssize_t (*writev)(struct file_ostream *fstream,
const struct const_iovec *iov,
unsigned int iov_count);
int fd;
struct io *io;
uoff_t buffer_offset;
uoff_t real_offset;
unsigned char *buffer; /* ring-buffer */
size_t buffer_size, optimal_block_size;
size_t head, tail; /* first unsent/unused byte */
bool full:1; /* if head == tail, is buffer empty or full? */
bool file:1;
bool flush_pending:1;
bool socket_cork_set:1;
bool no_socket_cork:1;
bool no_socket_nodelay:1;
bool no_socket_quickack:1;
bool no_sendfile:1;
bool autoclose_fd:1;
};
struct ostream *
o_stream_create_file_common(struct file_ostream *fstream,
int fd, size_t max_buffer_size, bool autoclose_fd);
ssize_t o_stream_file_writev(struct file_ostream *fstream,
const struct const_iovec *iov,
unsigned int iov_size);
ssize_t o_stream_file_sendv(struct ostream_private *stream,
const struct const_iovec *iov,
unsigned int iov_count);
void o_stream_file_close(struct iostream_private *stream,
bool close_parent);
#endif
dovecot-2.3.21.1/src/lib/istream-unix.c 0000644 0000000 0000000 00000005237 14656633576 014452 0000000 0000000 /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "fdpass.h"
#include "istream-file-private.h"
#include "istream-unix.h"
struct unix_istream {
struct file_istream fstream;
bool next_read_fd;
int read_fd;
};
static void
i_stream_unix_close(struct iostream_private *stream, bool close_parent)
{
struct unix_istream *ustream =
container_of(stream, struct unix_istream,
fstream.istream.iostream);
i_close_fd(&ustream->read_fd);
i_stream_file_close(stream, close_parent);
}
static ssize_t i_stream_unix_read(struct istream_private *stream)
{
struct unix_istream *ustream =
container_of(stream, struct unix_istream, fstream.istream);
size_t size;
ssize_t ret;
if (!ustream->next_read_fd)
return i_stream_file_read(stream);
i_assert(ustream->read_fd == -1);
i_assert(ustream->fstream.skip_left == 0); /* not supported here.. */
if (!i_stream_try_alloc(stream, 1, &size))
return -2;
ret = fd_read(stream->fd, stream->w_buffer + stream->pos, size,
&ustream->read_fd);
if (ustream->read_fd != -1)
ustream->next_read_fd = FALSE;
if (ret == 0) {
/* EOF */
stream->istream.eof = TRUE;
ustream->fstream.seen_eof = TRUE;
return -1;
}
if (unlikely(ret < 0)) {
if ((errno == EINTR || errno == EAGAIN) &&
!stream->istream.blocking) {
return 0;
} else {
i_assert(errno != 0);
/* if we get EBADF for a valid fd, it means something's
really wrong and we'd better just crash. */
i_assert(errno != EBADF);
stream->istream.stream_errno = errno;
return -1;
}
}
stream->pos += ret;
return ret;
}
struct istream *i_stream_create_unix(int fd, size_t max_buffer_size)
{
struct unix_istream *ustream;
struct istream *input;
i_assert(fd != -1);
ustream = i_new(struct unix_istream, 1);
ustream->read_fd = -1;
input = i_stream_create_file_common(&ustream->fstream, fd, NULL,
max_buffer_size, FALSE);
input->real_stream->iostream.close = i_stream_unix_close;
input->real_stream->read = i_stream_unix_read;
return input;
}
void i_stream_unix_set_read_fd(struct istream *input)
{
struct unix_istream *ustream =
container_of(input->real_stream, struct unix_istream,
fstream.istream);
ustream->next_read_fd = TRUE;
}
void i_stream_unix_unset_read_fd(struct istream *input)
{
struct unix_istream *ustream =
container_of(input->real_stream, struct unix_istream,
fstream.istream);
ustream->next_read_fd = FALSE;
}
int i_stream_unix_get_read_fd(struct istream *input)
{
struct unix_istream *ustream =
container_of(input->real_stream, struct unix_istream,
fstream.istream);
int fd;
fd = ustream->read_fd;
ustream->read_fd = -1;
return fd;
}
dovecot-2.3.21.1/src/lib/hash-format.c 0000644 0000000 0000000 00000013175 14656633576 014236 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "base64.h"
#include "hex-binary.h"
#include "str.h"
#include "hash-method.h"
#include "hash-format.h"
enum hash_encoding {
HASH_ENCODING_HEX,
HASH_ENCODING_HEX_SHORT,
HASH_ENCODING_BASE64
};
struct hash_format_list {
struct hash_format_list *next;
const struct hash_method *method;
void *context;
unsigned int bits;
enum hash_encoding encoding;
};
struct hash_format {
pool_t pool;
const char *str;
struct hash_format_list *list, **pos;
unsigned char *digest;
};
static int
hash_format_parse(const char *str, unsigned int *idxp,
const struct hash_method **method_r,
unsigned int *bits_r, const char **error_r)
{
const char *name, *end, *bitsp;
unsigned int bits, i = *idxp;
/* we should have "hash_name}" or "hash_name:bits}" */
end = strchr(str+i, '}');
if (end == NULL) {
*error_r = "Missing '}'";
return -1;
}
*idxp = end - str;
name = t_strdup_until(str+i, end);
bitsp = strchr(name, ':');
if (bitsp != NULL)
name = t_strdup_until(name, bitsp++);
*method_r = hash_method_lookup(name);
if (*method_r == NULL) {
*error_r = t_strconcat("Unknown hash method: ", name, NULL);
return -1;
}
bits = (*method_r)->digest_size * 8;
if (bitsp != NULL) {
if (str_to_uint(bitsp, &bits) < 0 ||
bits == 0 || bits > (*method_r)->digest_size*8) {
*error_r = t_strconcat("Invalid :bits number: ",
bitsp, NULL);
return -1;
}
if ((bits % 8) != 0) {
*error_r = t_strconcat(
"Currently :bits must be divisible by 8: ",
bitsp, NULL);
return -1;
}
}
*bits_r = bits;
return 0;
}
static int
hash_format_string_analyze(struct hash_format *format, const char *str,
const char **error_r)
{
struct hash_format_list *list;
unsigned int i;
for (i = 0; str[i] != '\0'; i++) {
if (str[i] != '%')
continue;
i++;
list = p_new(format->pool, struct hash_format_list, 1);
list->encoding = HASH_ENCODING_HEX;
*format->pos = list;
format->pos = &list->next;
if (str[i] == 'B') {
list->encoding = HASH_ENCODING_BASE64;
i++;
} else if (str[i] == 'X') {
list->encoding = HASH_ENCODING_HEX_SHORT;
i++;
}
if (str[i++] != '{') {
*error_r = "No '{' after '%'";
return -1;
}
if (hash_format_parse(str, &i, &list->method,
&list->bits, error_r) < 0)
return -1;
list->context = p_malloc(format->pool,
list->method->context_size);
list->method->init(list->context);
}
return 0;
}
int hash_format_init(const char *format_string, struct hash_format **format_r,
const char **error_r)
{
struct hash_format *format;
pool_t pool;
int ret;
pool = pool_alloconly_create("hash format", 1024);
format = p_new(pool, struct hash_format, 1);
format->pool = pool;
format->str = p_strdup(pool, format_string);
format->pos = &format->list;
T_BEGIN {
ret = hash_format_string_analyze(format, format_string,
error_r);
if (ret < 0)
*error_r = p_strdup(format->pool, *error_r);
} T_END;
if (ret < 0) {
*error_r = t_strdup(*error_r);
pool_unref(&pool);
return -1;
}
*format_r = format;
return 0;
}
void hash_format_loop(struct hash_format *format,
const void *data, size_t size)
{
struct hash_format_list *list;
for (list = format->list; list != NULL; list = list->next)
list->method->loop(list->context, data, size);
}
void hash_format_reset(struct hash_format *format)
{
struct hash_format_list *list;
for (list = format->list; list != NULL; list = list->next) {
memset(list->context, 0, list->method->context_size);
list->method->init(list->context);
}
}
static void
hash_format_digest(string_t *dest, const struct hash_format_list *list,
const unsigned char *digest)
{
unsigned int i, orig_len, size = list->bits / 8;
i_assert(list->bits % 8 == 0);
switch (list->encoding) {
case HASH_ENCODING_HEX:
binary_to_hex_append(dest, digest, size);
break;
case HASH_ENCODING_HEX_SHORT:
orig_len = str_len(dest);
binary_to_hex_append(dest, digest, size);
/* drop leading zeros, except if it's the only one */
for (i = orig_len; i < str_len(dest); i++) {
if (str_data(dest)[i] != '0')
break;
}
if (i == str_len(dest)) i--;
str_delete(dest, orig_len, i-orig_len);
break;
case HASH_ENCODING_BASE64:
orig_len = str_len(dest);
base64_encode(digest, size, dest);
/* drop trailing '=' chars */
while (str_len(dest) > orig_len &&
str_data(dest)[str_len(dest)-1] == '=')
str_truncate(dest, str_len(dest)-1);
break;
}
}
void hash_format_write(struct hash_format *format, string_t *dest)
{
struct hash_format_list *list;
const char *p;
unsigned int i, max_digest_size = 0;
for (list = format->list; list != NULL; list = list->next) {
if (max_digest_size < list->method->digest_size)
max_digest_size = list->method->digest_size;
}
if (format->digest == NULL)
format->digest = p_malloc(format->pool, max_digest_size);
list = format->list;
for (i = 0; format->str[i] != '\0'; i++) {
if (format->str[i] != '%') {
str_append_c(dest, format->str[i]);
continue;
}
/* we already verified that the string is ok */
i_assert(list != NULL);
list->method->result(list->context, format->digest);
hash_format_digest(dest, list, format->digest);
list = list->next;
p = strchr(format->str+i, '}');
i_assert(p != NULL);
i = p - format->str;
}
}
void hash_format_deinit(struct hash_format **_format, string_t *dest)
{
struct hash_format *format = *_format;
*_format = NULL;
hash_format_write(format, dest);
pool_unref(&format->pool);
}
void hash_format_deinit_free(struct hash_format **_format)
{
struct hash_format *format = *_format;
*_format = NULL;
pool_unref(&format->pool);
}
dovecot-2.3.21.1/src/lib/cpu-limit.c 0000644 0000000 0000000 00000012254 14656633576 013725 0000000 0000000 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "lib-signals.h"
#include "time-util.h"
#include "cpu-limit.h"
#include
#include
struct cpu_limit {
struct cpu_limit *parent;
enum cpu_limit_type type;
unsigned int cpu_limit_secs;
struct rusage initial_usage;
bool limit_reached;
};
static struct cpu_limit *cpu_limit;
static struct rlimit orig_limit, last_set_rlimit;
static volatile sig_atomic_t xcpu_signal_counter;
static sig_atomic_t checked_signal_counter;
static unsigned int rlim_cur_adjust_secs;
static void
cpu_limit_handler(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
{
xcpu_signal_counter++;
}
static unsigned int
cpu_limit_get_usage_msecs_with(struct cpu_limit *climit,
enum cpu_limit_type type,
const struct rusage *rusage)
{
struct timeval cpu_usage = { 0, 0 };
int usage_diff;
if ((type & CPU_LIMIT_TYPE_USER) != 0)
timeval_add(&cpu_usage, &rusage->ru_utime);
if ((type & CPU_LIMIT_TYPE_SYSTEM) != 0)
timeval_add(&cpu_usage, &rusage->ru_stime);
struct timeval initial_total = { 0, 0 };
if ((type & CPU_LIMIT_TYPE_USER) != 0)
timeval_add(&initial_total, &climit->initial_usage.ru_utime);
if ((type & CPU_LIMIT_TYPE_SYSTEM) != 0)
timeval_add(&initial_total, &climit->initial_usage.ru_stime);
usage_diff = timeval_diff_msecs(&cpu_usage, &initial_total);
i_assert(usage_diff >= 0);
return (unsigned int)usage_diff;
}
unsigned int
cpu_limit_get_usage_msecs(struct cpu_limit *climit, enum cpu_limit_type type)
{
struct rusage rusage;
/* Query cpu usage so far */
if (getrusage(RUSAGE_SELF, &rusage) < 0)
i_fatal("getrusage() failed: %m");
return cpu_limit_get_usage_msecs_with(climit, type, &rusage);
}
static bool
cpu_limit_update_recursive(struct cpu_limit *climit,
const struct rusage *rusage,
unsigned int *max_wait_secs)
{
if (climit == NULL)
return FALSE;
if (cpu_limit_update_recursive(climit->parent, rusage, max_wait_secs)) {
/* parent's limit reached */
climit->limit_reached = TRUE;
return TRUE;
}
unsigned int secs_used =
cpu_limit_get_usage_msecs_with(climit, climit->type, rusage)/1000;
if (secs_used >= climit->cpu_limit_secs) {
climit->limit_reached = TRUE;
return TRUE;
}
unsigned int secs_left = climit->cpu_limit_secs - secs_used;
if (*max_wait_secs > secs_left)
*max_wait_secs = secs_left;
return FALSE;
}
static void cpu_limit_update_rlimit(void)
{
struct rusage rusage;
struct rlimit rlimit;
unsigned int max_wait_secs = UINT_MAX;
if (getrusage(RUSAGE_SELF, &rusage) < 0)
i_fatal("getrusage() failed: %m");
(void)cpu_limit_update_recursive(cpu_limit, &rusage, &max_wait_secs);
if (max_wait_secs == UINT_MAX) {
/* All the limits have reached now. Restore the original
limits. */
rlimit = orig_limit;
} else {
struct timeval tv_limit = rusage.ru_utime;
timeval_add(&tv_limit, &rusage.ru_stime);
i_zero(&rlimit);
/* Add +1 second to round up. */
rlimit.rlim_cur = tv_limit.tv_sec +
max_wait_secs + 1 + rlim_cur_adjust_secs;
rlimit.rlim_max = orig_limit.rlim_max;
}
if (last_set_rlimit.rlim_cur != rlimit.rlim_cur) {
last_set_rlimit = rlimit;
if (setrlimit(RLIMIT_CPU, &rlimit) < 0)
i_fatal("setrlimit() failed: %m");
}
}
struct cpu_limit *
cpu_limit_init(unsigned int cpu_limit_secs, enum cpu_limit_type type)
{
struct cpu_limit *climit;
struct rusage rusage;
i_assert(cpu_limit_secs > 0);
i_assert(type != 0);
climit = i_new(struct cpu_limit, 1);
climit->parent = cpu_limit;
climit->type = type;
climit->cpu_limit_secs = cpu_limit_secs;
/* Query current limit */
if (climit->parent == NULL) {
if (getrlimit(RLIMIT_CPU, &orig_limit) < 0)
i_fatal("getrlimit() failed: %m");
}
/* Query cpu usage so far */
if (getrusage(RUSAGE_SELF, &rusage) < 0)
i_fatal("getrusage() failed: %m");
climit->initial_usage = rusage;
if (climit->parent == NULL) {
lib_signals_set_handler(SIGXCPU, LIBSIG_FLAG_RESTART,
cpu_limit_handler, NULL);
}
cpu_limit = climit;
cpu_limit_update_rlimit();
return climit;
}
void cpu_limit_deinit(struct cpu_limit **_climit)
{
struct cpu_limit *climit = *_climit;
*_climit = NULL;
if (climit == NULL)
return;
i_assert(climit == cpu_limit);
cpu_limit = climit->parent;
cpu_limit_update_rlimit();
if (climit->parent == NULL)
lib_signals_unset_handler(SIGXCPU, cpu_limit_handler, NULL);
i_free(climit);
}
bool cpu_limit_exceeded(struct cpu_limit *climit)
{
static struct timeval tv_last = { 0, 0 };
struct timeval tv_now;
if (checked_signal_counter != xcpu_signal_counter) {
i_gettimeofday(&tv_now);
if (tv_last.tv_sec != 0 &&
timeval_diff_msecs(&tv_now, &tv_last) < 1000) {
/* Additional sanity check: We're getting here more
rapidly than once per second. This isn't expected
to happen, but at least in theory it could happen
because rlim_cur isn't clearly calculated from just
the user+system CPU usage. So in case rlim_cur is
too low and keeps firing XCPU signal, try to
increase rlim_cur by 1 second. Eventually it should
become large enough. */
rlim_cur_adjust_secs++;
}
checked_signal_counter = xcpu_signal_counter;
cpu_limit_update_rlimit();
}
return climit->limit_reached;
}
dovecot-2.3.21.1/src/lib/test-ostream-file.c 0000644 0000000 0000000 00000012351 14656633576 015364 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "net.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "randgen.h"
#include "istream.h"
#include "ostream.h"
#include
#include
#define MAX_BUFSIZE 256
static void test_ostream_file_random_once(void)
{
struct ostream *output;
string_t *path = t_str_new(128);
char buf[MAX_BUFSIZE*4], buf2[MAX_BUFSIZE*4], randbuf[MAX_BUFSIZE];
unsigned int i, offset, size;
ssize_t ret;
int fd;
memset(buf, 0, sizeof(buf));
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
if (fd == -1)
i_fatal("safe_mkstemp(%s) failed: %m", str_c(path));
i_unlink(str_c(path));
output = o_stream_create_fd(fd, MAX_BUFSIZE);
o_stream_cork(output);
size = i_rand_minmax(1, MAX_BUFSIZE);
random_fill(randbuf, size);
memcpy(buf, randbuf, size);
test_assert(o_stream_send(output, buf, size) > 0);
for (i = 0; i < 10; i++) {
offset = i_rand_limit(MAX_BUFSIZE * 3);
size = i_rand_minmax(1, MAX_BUFSIZE);
random_fill(randbuf, size);
memcpy(buf + offset, randbuf, size);
test_assert(o_stream_pwrite(output, randbuf, size, offset) == 0);
if (i_rand_limit(10) == 0)
test_assert(o_stream_flush(output) > 0);
}
o_stream_uncork(output);
test_assert(o_stream_finish(output) > 0);
ret = pread(fd, buf2, sizeof(buf2), 0);
if (ret < 0)
i_fatal("pread() failed: %m");
else {
i_assert(ret > 0);
test_assert(memcmp(buf, buf2, ret) == 0);
}
o_stream_unref(&output);
i_close_fd(&fd);
}
static void test_ostream_file_random(void)
{
unsigned int i;
test_begin("ostream pwrite random");
for (i = 0; i < 100; i++) T_BEGIN {
test_ostream_file_random_once();
} T_END;
test_end();
}
static void test_ostream_file_send_istream_file(void)
{
struct istream *input, *input2;
struct ostream *output;
char buf[10];
int fd;
test_begin("ostream file send istream file");
/* temp file istream */
fd = open(".temp.istream", O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd == -1)
i_fatal("creat(.temp.istream) failed: %m");
test_assert(write(fd, "1234567890", 10) == 10);
test_assert(lseek(fd, 0, SEEK_SET) == 0);
input = i_stream_create_fd_autoclose(&fd, 1024);
/* temp file ostream */
fd = open(".temp.ostream", O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd == -1)
i_fatal("creat(.temp.ostream) failed: %m");
output = o_stream_create_fd(fd, 0);
/* test that writing works between two files */
i_stream_seek(input, 3);
input2 = i_stream_create_limit(input, 4);
test_assert(o_stream_send_istream(output, input2) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 4);
test_assert(pread(fd, buf, sizeof(buf), 0) == 4 &&
memcmp(buf, "4567", 4) == 0);
i_stream_unref(&input2);
/* test that writing works within the same file */
i_stream_destroy(&input);
input = i_stream_create_fd(fd, 1024);
/* forwards: 4567 -> 4677 */
o_stream_seek(output, 1);
i_stream_seek(input, 2);
input2 = i_stream_create_limit(input, 2);
test_assert(o_stream_send_istream(output, input2) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 3);
test_assert(pread(fd, buf, sizeof(buf), 0) == 4 &&
memcmp(buf, "4677", 4) == 0);
i_stream_destroy(&input2);
i_stream_destroy(&input);
/* backwards: 1234 -> 11234 */
memcpy(buf, "1234", 4);
test_assert(pwrite(fd, buf, 4, 0) == 4);
input = i_stream_create_fd(fd, 1024);
o_stream_seek(output, 1);
test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 5);
test_assert(pread(fd, buf, sizeof(buf), 0) == 5 &&
memcmp(buf, "11234", 5) == 0);
i_stream_destroy(&input);
o_stream_destroy(&output);
i_close_fd(&fd);
i_unlink(".temp.istream");
i_unlink(".temp.ostream");
test_end();
}
static void test_ostream_file_send_istream_sendfile(void)
{
struct istream *input, *input2;
struct ostream *output;
char buf[10];
int fd, sock_fd[2];
test_begin("ostream file send istream sendfile()");
/* temp file istream */
fd = open(".temp.istream", O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd == -1)
i_fatal("creat(.temp.istream) failed: %m");
test_assert(write(fd, "abcdefghij", 10) == 10);
test_assert(lseek(fd, 0, SEEK_SET) == 0);
input = i_stream_create_fd_autoclose(&fd, 1024);
/* temp socket ostream */
i_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fd) == 0);
output = o_stream_create_fd_autoclose(sock_fd, 0);
/* test that sendfile() works */
i_stream_seek(input, 3);
input2 = i_stream_create_limit(input, 4);
test_assert(o_stream_send_istream(output, input2) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 4);
test_assert(read(sock_fd[1], buf, sizeof(buf)) == 4 &&
memcmp(buf, "defg", 4) == 0);
i_stream_unref(&input2);
/* test reading past EOF */
i_stream_seek(input, 0);
input2 = i_stream_create_limit(input, 20);
test_assert(o_stream_send_istream(output, input2) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(input2->v_offset == 10);
test_assert(output->offset == 14);
i_stream_unref(&input2);
i_stream_unref(&input);
o_stream_destroy(&output);
i_close_fd(&sock_fd[1]);
i_unlink(".temp.istream");
test_end();
}
void test_ostream_file(void)
{
test_ostream_file_random();
test_ostream_file_send_istream_file();
test_ostream_file_send_istream_sendfile();
}
dovecot-2.3.21.1/src/lib/hash.c 0000644 0000000 0000000 00000030222 14656633576 012740 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
/* @UNSAFE: whole file */
#include "lib.h"
#include "hash.h"
#include "primes.h"
#include
#define HASH_TABLE_MIN_SIZE 67
#undef hash_table_create
#undef hash_table_create_direct
#undef hash_table_destroy
#undef hash_table_clear
#undef hash_table_lookup
#undef hash_table_lookup_full
#undef hash_table_insert
#undef hash_table_update
#undef hash_table_try_remove
#undef hash_table_count
#undef hash_table_iterate_init
#undef hash_table_iterate
#undef hash_table_freeze
#undef hash_table_thaw
#undef hash_table_copy
struct hash_node {
struct hash_node *next;
void *key;
void *value;
};
struct hash_table {
pool_t node_pool;
int frozen;
unsigned int initial_size, nodes_count, removed_count;
unsigned int size;
struct hash_node *nodes;
struct hash_node *free_nodes;
hash_callback_t *hash_cb;
hash_cmp_callback_t *key_compare_cb;
};
struct hash_iterate_context {
struct hash_table *table;
struct hash_node *next;
unsigned int pos;
};
enum hash_table_operation{
HASH_TABLE_OP_INSERT,
HASH_TABLE_OP_UPDATE,
HASH_TABLE_OP_RESIZE
};
static bool hash_table_resize(struct hash_table *table, bool grow);
void hash_table_create(struct hash_table **table_r, pool_t node_pool,
unsigned int initial_size, hash_callback_t *hash_cb,
hash_cmp_callback_t *key_compare_cb)
{
struct hash_table *table;
pool_ref(node_pool);
table = i_new(struct hash_table, 1);
table->node_pool = node_pool;
table->initial_size =
I_MAX(primes_closest(initial_size), HASH_TABLE_MIN_SIZE);
table->hash_cb = hash_cb;
table->key_compare_cb = key_compare_cb;
table->size = table->initial_size;
table->nodes = i_new(struct hash_node, table->size);
*table_r = table;
}
static unsigned int direct_hash(const void *p)
{
/* NOTE: may truncate the value, but that doesn't matter. */
return POINTER_CAST_TO(p, unsigned int);
}
static int direct_cmp(const void *p1, const void *p2)
{
return p1 == p2 ? 0 : 1;
}
void hash_table_create_direct(struct hash_table **table_r, pool_t node_pool,
unsigned int initial_size)
{
hash_table_create(table_r, node_pool, initial_size,
direct_hash, direct_cmp);
}
static void free_node(struct hash_table *table, struct hash_node *node)
{
if (!table->node_pool->alloconly_pool)
p_free(table->node_pool, node);
else {
node->next = table->free_nodes;
table->free_nodes = node;
}
}
static void destroy_node_list(struct hash_table *table, struct hash_node *node)
{
struct hash_node *next;
while (node != NULL) {
next = node->next;
p_free(table->node_pool, node);
node = next;
}
}
static void hash_table_destroy_nodes(struct hash_table *table)
{
unsigned int i;
for (i = 0; i < table->size; i++) {
if (table->nodes[i].next != NULL)
destroy_node_list(table, table->nodes[i].next);
}
}
void hash_table_destroy(struct hash_table **_table)
{
struct hash_table *table = *_table;
if (table == NULL)
return;
*_table = NULL;
i_assert(table->frozen == 0);
if (!table->node_pool->alloconly_pool) {
hash_table_destroy_nodes(table);
destroy_node_list(table, table->free_nodes);
}
pool_unref(&table->node_pool);
i_free(table->nodes);
i_free(table);
}
void hash_table_clear(struct hash_table *table, bool free_nodes)
{
i_assert(table->frozen == 0);
if (!table->node_pool->alloconly_pool)
hash_table_destroy_nodes(table);
if (free_nodes) {
if (!table->node_pool->alloconly_pool)
destroy_node_list(table, table->free_nodes);
table->free_nodes = NULL;
}
memset(table->nodes, 0, sizeof(struct hash_node) * table->size);
table->nodes_count = 0;
table->removed_count = 0;
}
static struct hash_node *
hash_table_lookup_node(const struct hash_table *table,
const void *key, unsigned int hash)
{
struct hash_node *node;
node = &table->nodes[hash % table->size];
do {
if (node->key != NULL) {
if (table->key_compare_cb(node->key, key) == 0)
return node;
}
node = node->next;
} while (node != NULL);
return NULL;
}
void *hash_table_lookup(const struct hash_table *table, const void *key)
{
struct hash_node *node;
node = hash_table_lookup_node(table, key, table->hash_cb(key));
return node != NULL ? node->value : NULL;
}
bool hash_table_lookup_full(const struct hash_table *table,
const void *lookup_key,
void **orig_key, void **value)
{
struct hash_node *node;
node = hash_table_lookup_node(table, lookup_key,
table->hash_cb(lookup_key));
if (node == NULL)
return FALSE;
*orig_key = node->key;
*value = node->value;
return TRUE;
}
static void
hash_table_insert_node(struct hash_table *table, void *key, void *value,
enum hash_table_operation opcode)
{
struct hash_node *node, *prev;
unsigned int hash;
bool check_existing = TRUE;
i_assert(table->nodes_count < UINT_MAX);
i_assert(key != NULL);
if(opcode == HASH_TABLE_OP_RESIZE)
check_existing = FALSE;
hash = table->hash_cb(key);
if (check_existing && table->removed_count > 0) {
/* there may be holes, have to check everything */
node = hash_table_lookup_node(table, key, hash);
if (node != NULL) {
i_assert(opcode == HASH_TABLE_OP_UPDATE);
node->value = value;
return;
}
check_existing = FALSE;
}
/* a) primary node */
node = &table->nodes[hash % table->size];
if (node->key == NULL) {
table->nodes_count++;
node->key = key;
node->value = value;
return;
}
if (check_existing) {
if (table->key_compare_cb(node->key, key) == 0) {
i_assert(opcode == HASH_TABLE_OP_UPDATE);
node->value = value;
return;
}
}
/* b) collisions list */
prev = node; node = node->next;
while (node != NULL) {
if (node->key == NULL)
break;
if (check_existing) {
if (table->key_compare_cb(node->key, key) == 0) {
i_assert(opcode == HASH_TABLE_OP_UPDATE);
node->value = value;
return;
}
}
prev = node;
node = node->next;
}
if (node == NULL) {
if (table->frozen == 0 && hash_table_resize(table, TRUE)) {
/* resized table, try again */
hash_table_insert_node(table, key, value, HASH_TABLE_OP_RESIZE);
return;
}
if (table->free_nodes == NULL)
node = p_new(table->node_pool, struct hash_node, 1);
else {
node = table->free_nodes;
table->free_nodes = node->next;
node->next = NULL;
}
prev->next = node;
}
node->key = key;
node->value = value;
table->nodes_count++;
}
void hash_table_insert(struct hash_table *table, void *key, void *value)
{
hash_table_insert_node(table, key, value, HASH_TABLE_OP_INSERT);
}
void hash_table_update(struct hash_table *table, void *key, void *value)
{
hash_table_insert_node(table, key, value, HASH_TABLE_OP_UPDATE);
}
static void
hash_table_compress(struct hash_table *table, struct hash_node *root)
{
struct hash_node *node, *next;
i_assert(table->frozen == 0);
/* remove deleted nodes from the list */
for (node = root; node->next != NULL; ) {
next = node->next;
if (next->key == NULL) {
node->next = next->next;
free_node(table, next);
} else {
node = next;
}
}
/* update root */
if (root->key == NULL && root->next != NULL) {
next = root->next;
*root = *next;
free_node(table, next);
}
}
static void hash_table_compress_removed(struct hash_table *table)
{
unsigned int i;
for (i = 0; i < table->size; i++)
hash_table_compress(table, &table->nodes[i]);
table->removed_count = 0;
}
bool hash_table_try_remove(struct hash_table *table, const void *key)
{
struct hash_node *node;
unsigned int hash;
hash = table->hash_cb(key);
node = hash_table_lookup_node(table, key, hash);
if (unlikely(node == NULL))
return FALSE;
node->key = NULL;
table->nodes_count--;
if (table->frozen != 0)
table->removed_count++;
else if (!hash_table_resize(table, FALSE))
hash_table_compress(table, &table->nodes[hash % table->size]);
return TRUE;
}
unsigned int hash_table_count(const struct hash_table *table)
{
return table->nodes_count;
}
struct hash_iterate_context *hash_table_iterate_init(struct hash_table *table)
{
struct hash_iterate_context *ctx;
hash_table_freeze(table);
ctx = i_new(struct hash_iterate_context, 1);
ctx->table = table;
ctx->next = &table->nodes[0];
return ctx;
}
static struct hash_node *
hash_table_iterate_next(struct hash_iterate_context *ctx,
struct hash_node *node)
{
do {
node = node->next;
if (node == NULL) {
if (++ctx->pos == ctx->table->size) {
ctx->pos--;
return NULL;
}
node = &ctx->table->nodes[ctx->pos];
}
} while (node->key == NULL);
return node;
}
bool hash_table_iterate(struct hash_iterate_context *ctx,
void **key_r, void **value_r)
{
struct hash_node *node;
node = ctx->next;
if (node != NULL && node->key == NULL)
node = hash_table_iterate_next(ctx, node);
if (node == NULL) {
*key_r = *value_r = NULL;
return FALSE;
}
*key_r = node->key;
*value_r = node->value;
ctx->next = hash_table_iterate_next(ctx, node);
return TRUE;
}
void hash_table_iterate_deinit(struct hash_iterate_context **_ctx)
{
struct hash_iterate_context *ctx = *_ctx;
if (ctx == NULL)
return;
*_ctx = NULL;
hash_table_thaw(ctx->table);
i_free(ctx);
}
void hash_table_freeze(struct hash_table *table)
{
table->frozen++;
}
void hash_table_thaw(struct hash_table *table)
{
i_assert(table->frozen > 0);
if (--table->frozen > 0)
return;
if (table->removed_count > 0) {
if (!hash_table_resize(table, FALSE))
hash_table_compress_removed(table);
}
}
static bool hash_table_resize(struct hash_table *table, bool grow)
{
struct hash_node *old_nodes, *node, *next;
unsigned int next_size, old_size, i;
float nodes_per_list;
i_assert(table->frozen == 0);
nodes_per_list = (float) table->nodes_count / (float) table->size;
if (nodes_per_list > 0.3 && nodes_per_list < 2.0)
return FALSE;
next_size = I_MAX(primes_closest(table->nodes_count+1),
table->initial_size);
if (next_size == table->size)
return FALSE;
if (grow && table->size >= next_size)
return FALSE;
/* recreate primary table */
old_size = table->size;
old_nodes = table->nodes;
table->size = I_MAX(next_size, HASH_TABLE_MIN_SIZE);
table->nodes = i_new(struct hash_node, table->size);
table->nodes_count = 0;
table->removed_count = 0;
table->frozen++;
/* move the data */
for (i = 0; i < old_size; i++) {
node = &old_nodes[i];
if (node->key != NULL) {
hash_table_insert_node(table, node->key,
node->value, HASH_TABLE_OP_RESIZE);
}
for (node = node->next; node != NULL; node = next) {
next = node->next;
if (node->key != NULL) {
hash_table_insert_node(table, node->key,
node->value, HASH_TABLE_OP_RESIZE);
}
free_node(table, node);
}
}
table->frozen--;
i_free(old_nodes);
return TRUE;
}
void hash_table_copy(struct hash_table *dest, struct hash_table *src)
{
struct hash_iterate_context *iter;
void *key, *value;
hash_table_freeze(dest);
iter = hash_table_iterate_init(src);
while (hash_table_iterate(iter, &key, &value))
hash_table_insert(dest, key, value);
hash_table_iterate_deinit(&iter);
hash_table_thaw(dest);
}
/* a char* hash function from ASU -- from glib */
unsigned int ATTR_NO_SANITIZE_INTEGER
str_hash(const char *p)
{
const unsigned char *s = (const unsigned char *)p;
unsigned int g, h = 0;
while (*s != '\0') {
h = (h << 4) + *s;
if ((g = h & 0xf0000000UL) != 0) {
h = h ^ (g >> 24);
h = h ^ g;
}
s++;
}
return h;
}
/* a char* hash function from ASU -- from glib */
unsigned int ATTR_NO_SANITIZE_INTEGER
strcase_hash(const char *p)
{
const unsigned char *s = (const unsigned char *)p;
unsigned int g, h = 0;
while (*s != '\0') {
h = (h << 4) + i_toupper(*s);
if ((g = h & 0xf0000000UL) != 0) {
h = h ^ (g >> 24);
h = h ^ g;
}
s++;
}
return h;
}
unsigned int ATTR_NO_SANITIZE_INTEGER
mem_hash(const void *p, unsigned int size)
{
const unsigned char *s = p;
unsigned int i, g, h = 0;
for (i = 0; i < size; i++) {
h = (h << 4) + *s;
if ((g = h & 0xf0000000UL) != 0) {
h = h ^ (g >> 24);
h = h ^ g;
}
s++;
}
return h;
}
unsigned int ATTR_NO_SANITIZE_INTEGER
strfastcase_hash(const char *p)
{
const unsigned char *s = (const unsigned char *)p;
unsigned int g, h = 0;
while (*s != '\0') {
h = (h << 4) + ((*s) & ~0x20U);
if ((g = h & 0xf0000000UL) != 0) {
h = h ^ (g >> 24);
h = h ^ g;
}
s++;
}
return h;
}
dovecot-2.3.21.1/src/lib/istream-chain.h 0000644 0000000 0000000 00000001606 14656633576 014552 0000000 0000000 #ifndef ISTREAM_CHAIN_H
#define ISTREAM_CHAIN_H
struct istream_chain;
/* Flexibly couple input streams into a single chain stream. Input streams can
be added after creation of the chain stream, and the chain stream will not
signal EOF until all streams are read to EOF and the last stream added was
NULL. Streams that were finished to EOF are unreferenced. The chain stream
is obviously not seekable and it has no determinable size. The chain_r
argument returns a pointer to the chain object. */
struct istream *i_stream_create_chain(struct istream_chain **chain_r,
size_t max_buffer_size);
/* Append an input stream to the chain. */
void i_stream_chain_append(struct istream_chain *chain, struct istream *stream);
/* Mark the end of the chain. Only then reads from the chain stream can
return EOF. */
void i_stream_chain_append_eof(struct istream_chain *chain);
#endif
dovecot-2.3.21.1/src/lib/istream-tee.c 0000644 0000000 0000000 00000016022 14656633576 014236 0000000 0000000 /* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream-private.h"
#include "istream-tee.h"
struct tee_istream {
struct istream *input;
struct tee_child_istream *children;
uoff_t max_read_offset;
};
struct tee_child_istream {
struct istream_private istream;
struct tee_istream *tee;
struct tee_child_istream *next;
bool last_read_waiting:1;
};
static void tee_streams_update_buffer(struct tee_istream *tee)
{
struct tee_child_istream *tstream = tee->children;
const unsigned char *data;
size_t size, old_used;
data = i_stream_get_data(tee->input, &size);
for (; tstream != NULL; tstream = tstream->next) {
if (tstream->istream.istream.closed) {
tstream->istream.skip = tstream->istream.pos = 0;
continue;
}
old_used = tstream->istream.pos - tstream->istream.skip;
tstream->istream.buffer = data;
i_assert(tstream->istream.istream.v_offset >= tee->input->v_offset);
tstream->istream.skip = tstream->istream.istream.v_offset -
tee->input->v_offset;
i_assert(tstream->istream.skip + old_used <= size);
tstream->istream.pos = tstream->istream.skip + old_used;
tstream->istream.parent_expected_offset =
tee->input->v_offset;
tstream->istream.access_counter =
tee->input->real_stream->access_counter;
}
}
static void tee_streams_skip(struct tee_istream *tee)
{
struct tee_child_istream *tstream = tee->children;
size_t min_skip;
min_skip = SIZE_MAX;
for (; tstream != NULL; tstream = tstream->next) {
if (tstream->istream.skip < min_skip &&
!tstream->istream.istream.closed)
min_skip = tstream->istream.skip;
}
if (min_skip > 0 && min_skip != SIZE_MAX) {
i_stream_skip(tee->input, min_skip);
tee_streams_update_buffer(tee);
}
}
static void i_stream_tee_close(struct iostream_private *stream,
bool close_parent ATTR_UNUSED)
{
struct tee_child_istream *tstream =
container_of(stream, struct tee_child_istream,
istream.iostream);
tee_streams_skip(tstream->tee);
}
static void i_stream_tee_destroy(struct iostream_private *stream)
{
struct tee_child_istream *tstream =
container_of(stream, struct tee_child_istream,
istream.iostream);
struct tee_istream *tee = tstream->tee;
struct tee_child_istream **p;
if (tstream->istream.istream.v_offset > tee->max_read_offset)
tee->max_read_offset = tstream->istream.istream.v_offset;
for (p = &tee->children; *p != NULL; p = &(*p)->next) {
if (*p == tstream) {
*p = tstream->next;
break;
}
}
if (tee->children == NULL) {
/* last child. the tee is now destroyed */
i_assert(tee->input->v_offset <= tee->max_read_offset);
i_stream_skip(tee->input,
tee->max_read_offset - tee->input->v_offset);
i_stream_unref(&tee->input);
i_free(tee);
} else {
tee_streams_skip(tstream->tee);
}
/* i_stream_unref() shouldn't unref the parent */
tstream->istream.parent = NULL;
}
static void
i_stream_tee_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
struct tee_child_istream *tstream =
container_of(stream, struct tee_child_istream,
istream.iostream);
tstream->istream.max_buffer_size = max_size;
i_stream_set_max_buffer_size(tstream->tee->input, max_size);
}
static ssize_t i_stream_tee_read(struct istream_private *stream)
{
struct tee_child_istream *tstream =
container_of(stream, struct tee_child_istream, istream);
struct istream *input = tstream->tee->input;
const unsigned char *data;
size_t size;
uoff_t last_high_offset;
ssize_t ret;
tstream->last_read_waiting = FALSE;
if (stream->buffer == NULL) {
/* initial read */
tee_streams_update_buffer(tstream->tee);
}
data = i_stream_get_data(input, &size);
/* last_high_offset contains how far we have read this child tee stream
so far. input->v_offset + size contains how much is available in
the parent stream without having to read more. */
last_high_offset = stream->istream.v_offset +
(stream->pos - stream->skip);
if (stream->pos == size) {
/* we've read everything, need to read more */
i_assert(last_high_offset == input->v_offset + size);
tee_streams_skip(tstream->tee);
ret = i_stream_read(input);
if (ret <= 0) {
size = i_stream_get_data_size(input);
if (ret == -2 && stream->skip != 0) {
/* someone else is holding the data,
wait for it */
tstream->last_read_waiting = TRUE;
return 0;
}
stream->istream.stream_errno = input->stream_errno;
stream->istream.eof = input->eof;
return ret;
}
tee_streams_update_buffer(tstream->tee);
data = i_stream_get_data(input, &size);
} else {
/* there's still some data available from parent */
i_assert(last_high_offset < input->v_offset + size);
tee_streams_update_buffer(tstream->tee);
i_assert(stream->pos < size);
}
i_assert(stream->buffer == data);
ret = size - stream->pos;
i_assert(ret > 0);
stream->pos = size;
i_assert(stream->istream.v_offset + (stream->pos - stream->skip) ==
input->v_offset + size);
return ret;
}
static int
i_stream_tee_stat(struct istream_private *stream, bool exact)
{
struct tee_child_istream *tstream =
container_of(stream, struct tee_child_istream, istream);
const struct stat *st;
if (i_stream_stat(tstream->tee->input, exact, &st) < 0)
return -1;
stream->statbuf = *st;
return 0;
}
static void i_stream_tee_sync(struct istream_private *stream)
{
struct tee_child_istream *tstream =
container_of(stream, struct tee_child_istream, istream);
tee_streams_skip(tstream->tee);
if (i_stream_get_data_size(tstream->tee->input) != 0) {
i_panic("tee-istream: i_stream_sync() called "
"with data still buffered");
}
i_stream_sync(tstream->tee->input);
}
struct tee_istream *tee_i_stream_create(struct istream *input)
{
struct tee_istream *tee;
tee = i_new(struct tee_istream, 1);
if (input->v_offset == 0) {
i_stream_ref(input);
tee->input = input;
} else {
tee->input = i_stream_create_limit(input, UOFF_T_MAX);
}
return tee;
}
struct istream *tee_i_stream_create_child(struct tee_istream *tee)
{
struct tee_child_istream *tstream;
struct istream *ret, *input = tee->input;
tstream = i_new(struct tee_child_istream, 1);
tstream->tee = tee;
tstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
tstream->istream.iostream.close = i_stream_tee_close;
tstream->istream.iostream.destroy = i_stream_tee_destroy;
tstream->istream.iostream.set_max_buffer_size =
i_stream_tee_set_max_buffer_size;
tstream->istream.read = i_stream_tee_read;
tstream->istream.stat = i_stream_tee_stat;
tstream->istream.sync = i_stream_tee_sync;
tstream->next = tee->children;
tee->children = tstream;
ret = i_stream_create(&tstream->istream, input, i_stream_get_fd(input),
ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT);
i_stream_set_name(&tstream->istream.istream, i_stream_get_name(input));
/* we keep the reference in tee stream, no need for extra references */
i_stream_unref(&input);
return ret;
}
bool tee_i_stream_child_is_waiting(struct istream *input)
{
struct tee_child_istream *tstream =
container_of(input->real_stream,
struct tee_child_istream, istream);
return tstream->last_read_waiting;
}
dovecot-2.3.21.1/src/lib/child-wait.h 0000644 0000000 0000000 00000001706 14656633576 014054 0000000 0000000 #ifndef CHILD_WAIT_H
#define CHILD_WAIT_H
struct child_wait_status {
struct child_wait *wait;
pid_t pid;
int status;
};
typedef void child_wait_callback_t(const struct child_wait_status *status,
void *context);
struct child_wait *
child_wait_new_with_pid(pid_t pid, child_wait_callback_t *callback,
void *context) ATTR_NULL(3);
#define child_wait_new_with_pid(pid, callback, context) \
child_wait_new_with_pid(pid - \
CALLBACK_TYPECHECK(callback, void (*)( \
const struct child_wait_status *status, typeof(context))), \
(child_wait_callback_t *)callback, context)
#define child_wait_new(callback, context) \
child_wait_new_with_pid((pid_t)-1, callback, context)
void child_wait_free(struct child_wait **wait);
void child_wait_add_pid(struct child_wait *wait, pid_t pid);
void child_wait_remove_pid(struct child_wait *wait, pid_t pid);
void child_wait_switch_ioloop(void);
void child_wait_init(void);
void child_wait_deinit(void);
#endif
dovecot-2.3.21.1/src/lib/test-lib.inc 0000644 0000000 0000000 00000005176 14656633576 014101 0000000 0000000 /* This file may be multiply-included, with different definitions of
'TEST()' macro. This is sometimes called "the X trick" (as the
macro is often imaginatively called X(). */
TEST(test_aqueue)
TEST(test_array)
FATAL(fatal_array)
TEST(test_backtrace)
TEST(test_base32)
TEST(test_base64)
TEST(test_bits)
TEST(test_bsearch_insert_pos)
TEST(test_buffer)
TEST(test_buffer_append_full)
FATAL(fatal_buffer)
TEST(test_byteorder)
TEST(test_connection)
TEST(test_crc32)
TEST(test_cpu_limit)
TEST(test_data_stack)
FATAL(fatal_data_stack)
TEST(test_env_util)
FATAL(fatal_env_util)
TEST(test_event_category_register)
FATAL(fatal_event_category_register)
TEST(test_lib_event)
FATAL(fatal_lib_event)
TEST(test_event_filter)
TEST(test_event_filter_expr)
TEST(test_event_filter_merge)
TEST(test_event_filter_parser)
TEST(test_event_flatten)
TEST(test_event_log)
TEST(test_failures)
TEST(test_file_cache)
TEST(test_file_create_locked)
TEST(test_guid)
TEST(test_hash)
TEST(test_hash_format)
TEST(test_hash_method)
TEST(test_hmac)
TEST(test_hex_binary)
FATAL(fatal_i_close)
TEST(test_imem)
TEST(test_ioloop)
TEST(test_iso8601_date)
TEST(test_iostream_pump)
TEST(test_iostream_proxy)
TEST(test_iostream_temp)
TEST(test_istream)
TEST(test_istream_base64_decoder)
TEST(test_istream_base64_encoder)
TEST(test_istream_chain)
TEST(test_istream_concat)
TEST(test_istream_crlf)
TEST(test_istream_failure_at)
TEST(test_istream_jsonstr)
TEST(test_istream_multiplex)
TEST(test_istream_seekable)
TEST(test_istream_sized)
TEST(test_istream_tee)
TEST(test_istream_try)
TEST(test_istream_unix)
TEST(test_json_parser)
TEST(test_json_tree)
TEST(test_lib_event)
TEST(test_lib_signals)
TEST(test_llist)
TEST(test_log_throttle)
TEST(test_macros)
TEST(test_malloc_overflow)
FATAL(fatal_malloc_overflow)
TEST(test_memarea)
TEST(test_mempool)
FATAL(fatal_mempool)
TEST(test_mempool_alloconly)
FATAL(fatal_mempool_alloconly)
TEST(test_mempool_allocfree)
FATAL(fatal_mempool_allocfree)
TEST(test_net)
TEST(test_numpack)
TEST(test_ostream_buffer)
TEST(test_ostream_failure_at)
TEST(test_ostream_file)
TEST(test_ostream_multiplex)
TEST(test_multiplex)
TEST(test_path_util)
TEST(test_pkcs5_pbkdf2)
TEST(test_primes)
TEST(test_printf_format_fix)
FATAL(fatal_printf_format_fix)
TEST(test_priorityq)
TEST(test_random)
FATAL(fatal_random)
TEST(test_seq_range_array)
FATAL(fatal_seq_range_array)
TEST(test_seq_set_builder)
TEST(test_stats_dist)
TEST(test_str)
TEST(test_strescape)
TEST(test_strfuncs)
FATAL(fatal_strfuncs)
TEST(test_strnum)
TEST(test_str_find)
TEST(test_str_sanitize)
TEST(test_str_table)
TEST(test_time_util)
TEST(test_unichar)
TEST(test_uri)
TEST(test_utc_mktime)
TEST(test_var_expand)
TEST(test_wildcard_match)
dovecot-2.3.21.1/src/lib/ostream-multiplex.c 0000644 0000000 0000000 00000025335 14656633576 015521 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "ostream-private.h"
#include "ostream-multiplex.h"
/* all multiplex packets are [1 byte cid][4 byte length][data] */
struct multiplex_ostream;
struct multiplex_ochannel {
struct ostream_private ostream;
struct multiplex_ostream *mstream;
uint8_t cid;
buffer_t *buf;
uint64_t last_sent_counter;
bool closed:1;
bool corked:1;
};
struct multiplex_ostream {
struct ostream *parent;
stream_flush_callback_t *old_flush_callback;
void *old_flush_context;
/* channel 0 is main channel */
uint8_t cur_channel;
unsigned int remain;
size_t bufsize;
uint64_t send_counter;
ARRAY(struct multiplex_ochannel *) channels;
bool destroyed:1;
};
static struct multiplex_ochannel *
get_channel(struct multiplex_ostream *mstream, uint8_t cid)
{
struct multiplex_ochannel *channel;
i_assert(mstream != NULL);
array_foreach_elem(&mstream->channels, channel) {
if (channel != NULL && channel->cid == cid)
return channel;
}
return NULL;
}
static void propagate_error(struct multiplex_ostream *mstream, int stream_errno)
{
struct multiplex_ochannel *channel;
array_foreach_elem(&mstream->channels, channel)
if (channel != NULL)
channel->ostream.ostream.stream_errno = stream_errno;
}
static struct multiplex_ochannel *get_next_channel(struct multiplex_ostream *mstream)
{
struct multiplex_ochannel *oldest_channel = NULL;
struct multiplex_ochannel *channel;
uint64_t last_counter = mstream->send_counter;
array_foreach_elem(&mstream->channels, channel) {
if (channel != NULL &&
channel->last_sent_counter <= last_counter &&
channel->buf->used > 0) {
last_counter = channel->last_sent_counter;
oldest_channel = channel;
}
}
return oldest_channel;
}
static bool
o_stream_multiplex_sendv(struct multiplex_ostream *mstream)
{
struct multiplex_ochannel *channel;
ssize_t ret = 0;
bool all_sent = TRUE;
while((channel = get_next_channel(mstream)) != NULL) {
if (channel->buf->used == 0)
continue;
if (o_stream_get_buffer_avail_size(mstream->parent) < 6) {
all_sent = FALSE;
break;
}
/* check parent stream capacity */
size_t tmp = o_stream_get_buffer_avail_size(mstream->parent) - 5;
/* ensure it fits into 32 bit int */
size_t amt = I_MIN(UINT_MAX, I_MIN(tmp, channel->buf->used));
/* ensure amt fits */
if (tmp == 0)
break;
/* delay corking here now that we are going to send something */
if (!o_stream_is_corked(mstream->parent))
o_stream_cork(mstream->parent);
uint32_t len = cpu32_to_be(amt);
const struct const_iovec vec[] = {
{ &channel->cid, 1 },
{ &len, 4 },
{ channel->buf->data, amt }
};
if ((ret = o_stream_sendv(mstream->parent, vec, N_ELEMENTS(vec))) < 0) {
propagate_error(mstream, mstream->parent->stream_errno);
break;
}
i_assert((size_t)ret == 1 + 4 + amt);
buffer_delete(channel->buf, 0, amt);
channel->last_sent_counter = ++mstream->send_counter;
}
if (o_stream_is_corked(mstream->parent))
o_stream_uncork(mstream->parent);
return all_sent;
}
static int o_stream_multiplex_flush(struct multiplex_ostream *mstream)
{
int ret = o_stream_flush(mstream->parent);
if (ret >= 0) {
if (!o_stream_multiplex_sendv(mstream))
return 0;
}
/* a) Everything is flushed. See if one of the callbacks' flush
callbacks wants to write more data.
b) ostream failed. Notify the callbacks in case they need to know. */
struct multiplex_ochannel *channel;
bool unfinished = FALSE;
bool failed = FALSE;
array_foreach_elem(&mstream->channels, channel) {
if (channel != NULL && channel->ostream.callback != NULL) {
ret = channel->ostream.callback(channel->ostream.context);
if (ret < 0)
failed = TRUE;
else if (ret == 0)
unfinished = TRUE;
}
}
return failed ? -1 :
(unfinished ? 0 : 1);
}
static int o_stream_multiplex_ochannel_flush(struct ostream_private *stream)
{
ssize_t ret;
struct multiplex_ochannel *channel =
container_of(stream, struct multiplex_ochannel, ostream);
struct multiplex_ostream *mstream = channel->mstream;
/* flush parent stream always, so there is room for more. */
if ((ret = o_stream_flush(mstream->parent)) <= 0) {
if (ret == -1)
propagate_error(mstream, mstream->parent->stream_errno);
return ret;
}
/* send all channels */
o_stream_multiplex_sendv(mstream);
if (channel->buf->used > 0)
return 0;
return 1;
}
static void o_stream_multiplex_ochannel_cork(struct ostream_private *stream, bool set)
{
struct multiplex_ochannel *channel =
container_of(stream, struct multiplex_ochannel, ostream);
if (channel->corked != set && !set) {
/* flush */
(void)o_stream_multiplex_ochannel_flush(stream);
}
channel->corked = set;
}
static ssize_t
o_stream_multiplex_ochannel_sendv(struct ostream_private *stream,
const struct const_iovec *iov, unsigned int iov_count)
{
struct multiplex_ochannel *channel =
container_of(stream, struct multiplex_ochannel, ostream);
size_t total = 0, avail = o_stream_get_buffer_avail_size(&stream->ostream);
size_t optimal_size = I_MIN(IO_BLOCK_SIZE, avail);
for (unsigned int i = 0; i < iov_count; i++)
total += iov[i].iov_len;
if (avail < total) {
o_stream_multiplex_sendv(channel->mstream);
avail = o_stream_get_buffer_avail_size(&stream->ostream);
if (avail == 0)
return 0;
}
total = 0;
for (unsigned int i = 0; i < iov_count; i++) {
/* copy data to buffer */
size_t tmp = avail - total;
if (tmp == 0)
break;
buffer_append(channel->buf, iov[i].iov_base,
I_MIN(tmp, iov[i].iov_len));
total += I_MIN(tmp, iov[i].iov_len);
}
stream->ostream.offset += total;
/* will send later */
if (channel->corked && channel->buf->used < optimal_size)
return total;
o_stream_multiplex_sendv(channel->mstream);
return total;
}
static void
o_stream_multiplex_ochannel_set_flush_callback(struct ostream_private *stream,
stream_flush_callback_t *callback,
void *context)
{
/* We have overwritten our parent's flush-callback. Don't change it. */
stream->callback = callback;
stream->context = context;
}
static size_t
o_stream_multiplex_ochannel_get_buffer_used_size(const struct ostream_private *stream)
{
const struct multiplex_ochannel *channel =
container_of(stream, const struct multiplex_ochannel, ostream);
return channel->buf->used +
o_stream_get_buffer_used_size(channel->mstream->parent);
}
static size_t
o_stream_multiplex_ochannel_get_buffer_avail_size(const struct ostream_private *stream)
{
const struct multiplex_ochannel *channel =
container_of(stream, const struct multiplex_ochannel, ostream);
size_t max_avail = I_MIN(channel->mstream->bufsize,
o_stream_get_buffer_avail_size(stream->parent));
/* There is 5-byte overhead per message, so take that into account */
return max_avail <= (channel->buf->used + 5) ? 0 :
max_avail - (channel->buf->used + 5);
}
static void
o_stream_multiplex_ochannel_close(struct iostream_private *stream, bool close_parent)
{
struct multiplex_ochannel *arr_channel;
struct multiplex_ochannel *channel =
container_of(stream, struct multiplex_ochannel, ostream.iostream);
channel->closed = TRUE;
if (close_parent) {
array_foreach_elem(&channel->mstream->channels, arr_channel)
if (arr_channel != NULL && !arr_channel->closed)
return;
o_stream_close(channel->mstream->parent);
}
}
static void o_stream_multiplex_try_destroy(struct multiplex_ostream *mstream)
{
struct multiplex_ochannel *channel;
/* can't do anything until they are all closed */
array_foreach_elem(&mstream->channels, channel)
if (channel != NULL)
return;
i_assert(mstream->parent->real_stream->callback ==
(stream_flush_callback_t *)o_stream_multiplex_flush);
o_stream_set_flush_callback(mstream->parent,
*mstream->old_flush_callback,
mstream->old_flush_context);
o_stream_unref(&mstream->parent);
array_free(&mstream->channels);
i_free(mstream);
}
static void o_stream_multiplex_ochannel_destroy(struct iostream_private *stream)
{
struct multiplex_ochannel **channelp;
struct multiplex_ochannel *channel =
container_of(stream, struct multiplex_ochannel, ostream.iostream);
o_stream_unref(&channel->ostream.parent);
if (channel->buf != NULL)
buffer_free(&channel->buf);
/* delete the channel */
array_foreach_modifiable(&channel->mstream->channels, channelp) {
if (*channelp != NULL && (*channelp)->cid == channel->cid) {
*channelp = NULL;
break;
}
}
o_stream_multiplex_try_destroy(channel->mstream);
}
static struct ostream *
o_stream_add_channel_real(struct multiplex_ostream *mstream, uint8_t cid)
{
struct multiplex_ochannel *channel = i_new(struct multiplex_ochannel, 1);
channel->cid = cid;
channel->buf = buffer_create_dynamic(default_pool, 256);
channel->mstream = mstream;
channel->ostream.cork = o_stream_multiplex_ochannel_cork;
channel->ostream.flush = o_stream_multiplex_ochannel_flush;
channel->ostream.sendv = o_stream_multiplex_ochannel_sendv;
channel->ostream.set_flush_callback =
o_stream_multiplex_ochannel_set_flush_callback;
channel->ostream.get_buffer_used_size =
o_stream_multiplex_ochannel_get_buffer_used_size;
channel->ostream.get_buffer_avail_size =
o_stream_multiplex_ochannel_get_buffer_avail_size;
channel->ostream.iostream.close = o_stream_multiplex_ochannel_close;
channel->ostream.iostream.destroy = o_stream_multiplex_ochannel_destroy;
channel->ostream.fd = o_stream_get_fd(mstream->parent);
array_push_back(&channel->mstream->channels, &channel);
(void)o_stream_create(&channel->ostream, mstream->parent, -1);
/* o_stream_create() defaults the flush_callback to parent's callback.
Here it points to o_stream_multiplex_flush(), which just causes
infinite looping. */
channel->ostream.callback = NULL;
channel->ostream.context = NULL;
return &channel->ostream.ostream;
}
struct ostream *o_stream_multiplex_add_channel(struct ostream *stream, uint8_t cid)
{
struct multiplex_ochannel *chan =
container_of(stream->real_stream, struct multiplex_ochannel,
ostream);
i_assert(get_channel(chan->mstream, cid) == NULL);
return o_stream_add_channel_real(chan->mstream, cid);
}
struct ostream *o_stream_create_multiplex(struct ostream *parent, size_t bufsize)
{
struct multiplex_ostream *mstream;
mstream = i_new(struct multiplex_ostream, 1);
mstream->parent = parent;
mstream->bufsize = bufsize;
mstream->old_flush_callback = parent->real_stream->callback;
mstream->old_flush_context = parent->real_stream->context;
o_stream_set_flush_callback(parent, o_stream_multiplex_flush, mstream);
i_array_init(&mstream->channels, 8);
o_stream_ref(parent);
return o_stream_add_channel_real(mstream, 0);
}
uint8_t o_stream_multiplex_get_channel_id(struct ostream *stream)
{
struct multiplex_ochannel *channel =
container_of(stream->real_stream, struct multiplex_ochannel,
ostream);
return channel->cid;
}
dovecot-2.3.21.1/src/lib/ioloop-iolist.c 0000644 0000000 0000000 00000002255 14656633576 014624 0000000 0000000 /*
* Copyright (c) 2004 Andrey Panin
*
* This software is released under the MIT license.
*/
#include "lib.h"
#include "ioloop-private.h"
#include "ioloop-iolist.h"
bool ioloop_iolist_add(struct io_list *list, struct io_file *io)
{
int i, idx;
if ((io->io.condition & IO_READ) != 0)
idx = IOLOOP_IOLIST_INPUT;
else if ((io->io.condition & IO_WRITE) != 0)
idx = IOLOOP_IOLIST_OUTPUT;
else if ((io->io.condition & IO_ERROR) != 0)
idx = IOLOOP_IOLIST_ERROR;
else {
i_unreached();
}
if (list->ios[idx] != NULL) {
i_panic("io_add(0x%x) called twice fd=%d, callback=%p -> %p",
io->io.condition, io->fd, list->ios[idx]->io.callback,
io->io.callback);
}
i_assert(list->ios[idx] == NULL);
list->ios[idx] = io;
/* check if this was the first one */
for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
if (i != idx && list->ios[i] != NULL)
return FALSE;
}
return TRUE;
}
bool ioloop_iolist_del(struct io_list *list, struct io_file *io)
{
bool last = TRUE;
int i;
for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
if (list->ios[i] != NULL) {
if (list->ios[i] == io)
list->ios[i] = NULL;
else
last = FALSE;
}
}
return last;
}
dovecot-2.3.21.1/src/lib/test-iostream-temp.c 0000644 0000000 0000000 00000011636 14656633576 015570 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-temp.h"
#include
#include
static void test_iostream_temp_create_sized_memory(void)
{
struct ostream *output;
test_begin("iostream_temp_create_sized() memory");
output = iostream_temp_create_sized(".intentional-nonexistent-error/", 0, "test", 4);
test_assert(o_stream_send(output, "123", 3) == 3);
test_assert(output->offset == 3);
test_assert(o_stream_send(output, "4", 1) == 1);
test_assert(output->offset == 4);
test_assert(o_stream_get_fd(output) == -1);
/* now we'll try to switch to writing to a file, but it'll fail */
test_expect_error_string("safe_mkstemp");
test_assert(o_stream_send(output, "5", 1) == 1);
test_expect_no_more_errors();
test_assert(o_stream_get_fd(output) == -1);
o_stream_destroy(&output);
test_end();
}
static void test_iostream_temp_create_sized_disk(void)
{
struct ostream *output;
test_begin("iostream_temp_create_sized() disk");
output = iostream_temp_create_sized(".", 0, "test", 4);
test_assert(o_stream_send(output, "123", 3) == 3);
test_assert(output->offset == 3);
test_assert(o_stream_send(output, "4", 1) == 1);
test_assert(output->offset == 4);
test_assert(o_stream_get_fd(output) == -1);
test_assert(o_stream_send(output, "5", 1) == 1);
test_assert(output->offset == 5);
test_assert(o_stream_get_fd(output) != -1);
o_stream_destroy(&output);
test_end();
}
static void test_iostream_temp_create_write_error(void)
{
struct ostream *output;
test_begin("iostream_temp_create_sized() write error");
output = iostream_temp_create_sized(".", 0, "test", 1);
test_assert(o_stream_send(output, "123", 3) == 3);
test_assert(o_stream_get_fd(output) != -1);
test_assert(output->offset == 3);
test_assert(o_stream_temp_move_to_memory(output) == 0);
test_assert(o_stream_get_fd(output) == -1);
test_assert(o_stream_send(output, "45", 2) == 2);
test_assert(output->offset == 5);
const unsigned char *data;
size_t size;
struct istream *input = iostream_temp_finish(&output, 128);
test_assert(i_stream_read_bytes(input, &data, &size, 5) == 1 &&
memcmp(data, "12345", 5) == 0);
i_stream_destroy(&input);
test_end();
}
static void test_iostream_temp_istream(void)
{
struct istream *input, *input2, *temp_input;
struct ostream *output;
int fd;
test_begin("iostream_temp istream");
fd = open(".temp.istream", O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd == -1)
i_fatal("create(.temp.istream) failed: %m");
test_assert(write(fd, "foobar", 6) == 6);
test_assert(lseek(fd, 0, SEEK_SET) == 0);
input = i_stream_create_fd_autoclose(&fd, 1024);
/* a working fd-dup */
output = iostream_temp_create_sized(".nonexistent/",
IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 1);
test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 6);
temp_input = iostream_temp_finish(&output, 128);
test_assert(i_stream_read(temp_input) == 6);
i_stream_destroy(&temp_input);
/* non-working fd-dup: write data before sending istream */
i_stream_seek(input, 0);
output = iostream_temp_create_sized(".intentional-nonexistent-error/",
IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4);
test_assert(o_stream_send(output, "1234", 4) == 4);
test_assert(output->offset == 4);
test_expect_error_string("safe_mkstemp");
test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 10);
test_expect_no_more_errors();
o_stream_destroy(&output);
/* non-working fd-dup: write data after sending istream */
i_stream_seek(input, 0);
output = iostream_temp_create_sized(".intentional-nonexistent-error/",
IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4);
test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 6);
test_expect_error_string("safe_mkstemp");
test_assert(o_stream_send(output, "1", 1) == 1);
test_assert(output->offset == 7);
test_expect_no_more_errors();
o_stream_destroy(&output);
/* non-working fd-dup: send two istreams */
i_stream_seek(input, 0);
input2 = i_stream_create_limit(input, UOFF_T_MAX);
output = iostream_temp_create_sized(".intentional-nonexistent-error/",
IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4);
test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 6);
test_expect_error_string("safe_mkstemp");
test_assert(o_stream_send_istream(output, input2) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
test_assert(output->offset == 12);
test_expect_no_more_errors();
o_stream_destroy(&output);
i_stream_unref(&input2);
i_stream_destroy(&input);
i_unlink(".temp.istream");
test_end();
}
void test_iostream_temp(void)
{
test_iostream_temp_create_sized_memory();
test_iostream_temp_create_sized_disk();
test_iostream_temp_create_write_error();
test_iostream_temp_istream();
}
dovecot-2.3.21.1/src/lib/unicodemap.pl 0000755 0000000 0000000 00000010461 14656633576 014340 0000000 0000000 #!/usr/bin/env perl
use strict;
my (%titlecase8, %uni8_decomp);
my (@titlecase16_keys, @titlecase16_values);
my (@titlecase32_keys, @titlecase32_values);
my (@uni16_decomp_keys, @uni16_decomp_values);
my (@uni32_decomp_keys, @uni32_decomp_values);
my (@multidecomp_keys, @multidecomp_offsets, @multidecomp_values);
while (<>) {
chomp $_;
my @arr = split(";");
my $code = eval("0x".$arr[0]);
my $decomp = $arr[5];
my $titlecode = $arr[14];
if ($titlecode ne "") {
# titlecase mapping
my $value = eval("0x$titlecode");
if ($value == $code) {
# the same character, ignore
} elsif ($code <= 0xff) {
die "Error: We've assumed 8bit keys have max. 16bit values" if ($value > 0xffff);
$titlecase8{$code} = $value;
} elsif ($code <= 0xffff) {
die "Error: We've assumed 16bit keys have max. 16bit values" if ($value > 0xffff);
push @titlecase16_keys, $code;
push @titlecase16_values, $value;
} else {
push @titlecase32_keys, $code;
push @titlecase32_values, $value;
}
} elsif ($decomp =~ /(?:\<[^>]*> )?(.+)/) {
# decompositions
my $decomp_codes = $1;
if ($decomp_codes =~ /^([0-9A-Z]*)$/i) {
# unicharacter decomposition. use separate lists for this
my $value = eval("0x$1");
if ($value > 0xffffffff) {
print STDERR "Error: We've assumed decomposition codes are max. 32bit\n";
exit 1;
}
if ($code <= 0xff) {
$uni8_decomp{$code} = $value;
} elsif ($code <= 0xffff) {
push @uni16_decomp_keys, $code;
push @uni16_decomp_values, $value;
} else {
push @uni32_decomp_keys, $code;
push @uni32_decomp_values, $value;
}
} else {
# multicharacter decomposition.
if ($code > 0xffffffff) {
print STDERR "Error: We've assumed multi-decomposition key codes are max. 32bit\n";
exit 1;
}
push @multidecomp_keys, $code;
push @multidecomp_offsets, scalar(@multidecomp_values);
foreach my $dcode (split(" ", $decomp_codes)) {
my $value = eval("0x$dcode");
if ($value > 0xffffffff) {
print STDERR "Error: We've assumed decomposition codes are max. 32bit\n";
exit 1;
}
push @multidecomp_values, $value;
}
push @multidecomp_values, 0;
}
}
}
sub print_list {
my @list = @{$_[0]};
my $last = $#list;
my $n = 0;
foreach my $key (@list) {
printf("0x%05x", $key);
last if ($n == $last);
print ",";
$n++;
if (($n % 8) == 0) {
print "\n\t";
} else {
print " ";
}
}
}
print "/* This file is automatically generated by unicodemap.pl from UnicodeData.txt
NOTE: decompositions for characters having titlecase characters
are not included, because we first translate everything to titlecase */\n";
sub print_map8 {
my %map = %{$_[0]};
my @list;
for (my $i = 0; $i <= 0xff; $i++) {
if (defined($map{$i})) {
push @list, $map{$i};
} else {
push @list, $i;
}
}
print_list(\@list);
}
print "static const uint16_t titlecase8_map[256] = {\n\t";
print_map8(\%titlecase8);
print "\n};\n";
print "static const uint16_t titlecase16_keys[] = {\n\t";
print_list(\@titlecase16_keys);
print "\n};\n";
print "static const uint16_t titlecase16_values[] = {\n\t";
print_list(\@titlecase16_values);
print "\n};\n";
print "static const uint32_t titlecase32_keys[] = {\n\t";
print_list(\@titlecase32_keys);
print "\n};\n";
print "static const uint32_t titlecase32_values[] = {\n\t";
print_list(\@titlecase32_values);
print "\n};\n";
print "static const uint16_t uni8_decomp_map[256] = {\n\t";
print_map8(\%uni8_decomp);
print "\n};\n";
print "static const uint16_t uni16_decomp_keys[] = {\n\t";
print_list(\@uni16_decomp_keys);
print "\n};\n";
print "static const uint32_t uni16_decomp_values[] = {\n\t";
print_list(\@uni16_decomp_values);
print "\n};\n";
print "static const uint32_t uni32_decomp_keys[] = {\n\t";
print_list(\@uni32_decomp_keys);
print "\n};\n";
print "static const uint32_t uni32_decomp_values[] = {\n\t";
print_list(\@uni32_decomp_values);
print "\n};\n";
print "static const uint32_t multidecomp_keys[] = {\n\t";
print_list(\@multidecomp_keys);
print "\n};\n";
print "static const uint16_t multidecomp_offsets[] = {\n\t";
print_list(\@multidecomp_offsets);
print "\n};\n";
print "static const uint32_t multidecomp_values[] = {\n\t";
print_list(\@multidecomp_values);
print "\n};\n";
dovecot-2.3.21.1/src/lib/md4.h 0000644 0000000 0000000 00000001521 14656633576 012506 0000000 0000000 /*
* This is an OpenSSL-compatible implementation of the RSA Data Security,
* Inc. MD4 Message-Digest Algorithm.
*
* Written by Solar Designer in 2001, and placed in
* the public domain. See md4.c for more information.
*/
#ifndef MD4_H
#define MD4_H
#include "hash-method.h"
#define MD4_RESULTLEN (128/8)
struct md4_context {
uint_fast32_t lo, hi;
uint_fast32_t a, b, c, d;
unsigned char buffer[64];
uint_fast32_t block[MD4_RESULTLEN];
};
void md4_init(struct md4_context *ctx);
void md4_update(struct md4_context *ctx, const void *data, size_t size);
void md4_final(struct md4_context *ctx,
unsigned char result[STATIC_ARRAY MD4_RESULTLEN]);
void md4_get_digest(const void *data, size_t size,
unsigned char result[STATIC_ARRAY MD4_RESULTLEN]);
extern const struct hash_method hash_method_md4;
#endif
dovecot-2.3.21.1/src/lib/printf-format-fix.c 0000644 0000000 0000000 00000011666 14656633576 015404 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "printf-format-fix.h"
static const char *
fix_format_real(const char *fmt, const char *p, size_t *len_r)
{
const char *errstr;
char *buf;
size_t len1, len2, len3;
i_assert((size_t)(p - fmt) < INT_MAX);
i_assert(p[0] == '%' && p[1] == 'm');
errstr = strerror(errno);
/* we'll assume that there's only one %m in the format string.
this simplifies the code and there's really no good reason to have
it multiple times. Callers can trap this case themselves. */
len1 = p - fmt;
len2 = strlen(errstr);
len3 = strlen(p + 2);
/* @UNSAFE */
buf = t_buffer_get(len1 + len2 + len3 + 1);
memcpy(buf, fmt, len1);
memcpy(buf + len1, errstr, len2);
memcpy(buf + len1 + len2, p + 2, len3 + 1);
*len_r = len1 + len2 + len3;
return buf;
}
static bool verify_length(const char **p)
{
if (**p == '*') {
/* We don't bother supporting "*m$" - it's not used
anywhere and seems a bit dangerous. */
*p += 1;
} else if (**p >= '0' && **p <= '9') {
/* Limit to 4 digits - we'll never want more than that.
Some implementations might not handle long digits
correctly, or maybe even could be used for DoS due
to using too much CPU. If you want to express '99'
as '00099', then you lose in this function. */
unsigned int i = 0;
do {
*p += 1;
if (++i > 4)
return FALSE;
} while (**p >= '0' && **p <= '9');
}
return TRUE;
}
static const char *
printf_format_fix_noalloc(const char *format, size_t *len_r)
{
/* NOTE: This function is overly strict in what it accepts. Some
format strings that are valid (and safe) in C99 will cause a panic
here. This is because we don't really need to support the weirdest
special cases, and we're also being extra careful not to pass
anything to the underlying libc printf, which might treat the string
differently than us and unexpectedly handling it as %n. For example
"%**%n" with glibc. */
/* Allow only the standard C99 flags. There are also <'> and flags,
but we don't really need them. And at worst if they're not supported
by the underlying printf, they could potentially be used to work
around our restrictions. */
const char printf_flags[] = "#0- +";
/* As a tiny optimization keep the most commonly used conversion
specifiers first, so strchr() stops early. */
static const char *printf_specifiers = "sudcixXpoeEfFgGaA";
const char *ret, *p, *p2;
char *flag;
p = ret = format;
while ((p2 = strchr(p, '%')) != NULL) {
const unsigned int start_pos = p2 - format;
p = p2+1;
if (*p == '%') {
/* we'll be strict and allow %% only when there are no
optinal flags or modifiers. */
p++;
continue;
}
/* 1) zero or more flags. We'll add a further restriction that
each flag can be used only once, since there's no need to
use them more than once, and some implementations might
add their own limits. */
bool printf_flags_seen[N_ELEMENTS(printf_flags)] = { FALSE, };
while (*p != '\0' &&
(flag = strchr(printf_flags, *p)) != NULL) {
unsigned int flag_idx = flag - printf_flags;
if (printf_flags_seen[flag_idx]) {
i_panic("Duplicate %% flag '%c' starting at #%u in '%s'",
*p, start_pos, format);
}
printf_flags_seen[flag_idx] = TRUE;
p++;
}
/* 2) Optional minimum field width */
if (!verify_length(&p)) {
i_panic("Too large minimum field width starting at #%u in '%s'",
start_pos, format);
}
/* 3) Optional precision */
if (*p == '.') {
p++;
if (!verify_length(&p)) {
i_panic("Too large precision starting at #%u in '%s'",
start_pos, format);
}
}
/* 4) Optional length modifier */
switch (*p) {
case 'h':
if (*++p == 'h')
p++;
break;
case 'l':
if (*++p == 'l')
p++;
break;
case 'L':
case 'j':
case 'z':
case 't':
p++;
break;
}
/* 5) conversion specifier */
if (*p == '\0' || strchr(printf_specifiers, *p) == NULL) {
switch (*p) {
case 'n':
i_panic("%%n modifier used");
case 'm':
if (ret != format)
i_panic("%%m used twice");
ret = fix_format_real(format, p-1, len_r);
break;
case '\0':
i_panic("Missing %% specifier starting at #%u in '%s'",
start_pos, format);
default:
i_panic("Unsupported 0x%02x specifier starting at #%u in '%s'",
*p, start_pos, format);
}
}
p++;
}
if (ret == format)
*len_r = p - format + strlen(p);
return ret;
}
const char *printf_format_fix_get_len(const char *format, size_t *len_r)
{
const char *ret;
ret = printf_format_fix_noalloc(format, len_r);
if (ret != format)
t_buffer_alloc(*len_r + 1);
return ret;
}
const char *printf_format_fix(const char *format)
{
const char *ret;
size_t len;
ret = printf_format_fix_noalloc(format, &len);
if (ret != format)
t_buffer_alloc(len + 1);
return ret;
}
const char *printf_format_fix_unsafe(const char *format)
{
size_t len;
return printf_format_fix_noalloc(format, &len);
}
dovecot-2.3.21.1/src/lib/test-bsearch-insert-pos.c 0000644 0000000 0000000 00000002061 14656633576 016502 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "bsearch-insert-pos.h"
static int cmp_uint(const unsigned int *i1, const unsigned int *i2)
{
return (int)*i1 - (int)*i2;
}
void test_bsearch_insert_pos(void)
{
static const unsigned int input[] = {
1, 5, 9, 15, 16, UINT_MAX,
1, 5, 9, 15, 16, 17, UINT_MAX,
UINT_MAX
};
static const unsigned int max_key = 18;
const unsigned int *cur;
unsigned int key, len, i, idx;
bool success;
cur = input;
for (i = 0; cur[0] != UINT_MAX; i++) {
for (len = 0; cur[len] != UINT_MAX; len++) ;
for (key = 0; key < max_key; key++) {
if (bsearch_insert_pos(&key, cur, len, sizeof(*cur),
cmp_uint, &idx))
success = cur[idx] == key;
else if (idx == 0)
success = cur[0] > key;
else if (idx == len)
success = cur[len-1] < key;
else {
success = cur[idx-1] < key &&
cur[idx+1] > key;
}
if (!success)
break;
}
cur += len + 1;
test_out(t_strdup_printf("bsearch_insert_pos(%d,%d)", i, key),
success);
}
}
dovecot-2.3.21.1/src/lib/test-istream-base64-decoder.c 0000644 0000000 0000000 00000023331 14656633576 017126 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "istream-private.h"
#include "istream-base64.h"
#include "istream-sized.h"
#include "base64.h"
struct base64_istream_test {
const char *input;
const char *output;
int stream_errno;
};
static const struct base64_istream_test base64_tests[] = {
{ "", "", 0 },
{ "aGVsbG8gd29ybGQ=", "hello world", 0 },
{ "\naGVs\nbG8g\nd29y\nbGQ=\n", "hello world", 0 },
{ " aGVs \r\n bG8g \r\n d29y \t \r\n bGQ= \r\n\r\n",
"hello world", 0 },
{ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgtC+INC60YPRgCDQtNC+0Y/MgdGCLg==",
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e", 0 },
{ "\r", "", 0 },
{ "\n", "", 0 },
{ "\r\n", "", 0 },
{ " ", "", 0 },
{ "foo", "\x7e\x8a", EPIPE },
{ "foo ","\x7e\x8a", EPIPE },
{ "Zm9vC", "foo", EPIPE },
{ "Zm9v!", "foo", EINVAL },
{ "Zm9!v", "fo", EINVAL },
{ "Zm9 v", "foo", 0 },
{ "Zm 9v", "foo", 0 },
{ "Z m9v", "foo", 0 },
};
static const struct base64_istream_test base64url_tests[] = {
{ "", "", 0 },
{ "aGVsbG8gd29ybGQ=", "hello world", 0 },
{ "\naGVs\nbG8g\nd29y\nbGQ=\n", "hello world", 0 },
{ " aGVs \r\n bG8g \r\n d29y \t \r\n bGQ= \r\n\r\n",
"hello world", 0 },
{ "0JPQvtCy0L7RgNGPzIHRgiwg0YfRgtC-INC60YPRgCDQtNC-0Y_MgdGCLg==",
"\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e", 0 },
{ "\r", "", 0 },
{ "\n", "", 0 },
{ "\r\n", "", 0 },
{ " ", "", 0 },
{ "foo", "\x7e\x8a", EPIPE },
{ "foo ","\x7e\x8a", EPIPE },
{ "Zm9vC", "foo", EPIPE },
{ "Zm9v!", "foo", EINVAL },
{ "Zm9!v", "fo", EINVAL },
{ "Zm9 v", "foo", 0 },
{ "Zm 9v", "foo", 0 },
{ "Z m9v", "foo", 0 },
};
static void
decode_test(unsigned int base64_input_len,
struct istream *input_data, struct istream *input,
const char *output, int stream_errno)
{
const unsigned char *data;
size_t i, size;
int ret = 0;
for (i = 1; i <= base64_input_len; i++) {
test_istream_set_size(input_data, i);
while ((ret = i_stream_read(input)) > 0) ;
if (ret == -1 && stream_errno != 0)
break;
test_assert(ret == 0);
}
if (ret == 0) {
test_istream_set_allow_eof(input_data, TRUE);
while ((ret = i_stream_read(input)) > 0) ;
}
test_assert(ret == -1);
test_assert(input->stream_errno == stream_errno);
data = i_stream_get_data(input, &size);
test_assert(size == strlen(output));
if (size > 0)
test_assert(memcmp(data, output, size) == 0);
}
static void
decode_base64_test(const char *base64_input, const char *output,
int stream_errno)
{
unsigned int base64_input_len = strlen(base64_input);
struct istream *input_data, *input;
input_data = test_istream_create_data(base64_input, base64_input_len);
test_istream_set_allow_eof(input_data, FALSE);
input = i_stream_create_base64_decoder(input_data);
decode_test(base64_input_len, input_data, input, output, stream_errno);
i_stream_unref(&input);
i_stream_unref(&input_data);
}
static void
decode_base64url_test(const char *base64_input, const char *output,
int stream_errno)
{
unsigned int base64_input_len = strlen(base64_input);
struct istream *input_data, *input;
input_data = test_istream_create_data(base64_input, base64_input_len);
test_istream_set_allow_eof(input_data, FALSE);
input = i_stream_create_base64url_decoder(input_data);
decode_test(base64_input_len, input_data, input, output, stream_errno);
i_stream_unref(&input);
i_stream_unref(&input_data);
}
static void
test_istream_base64_io_random(void)
{
unsigned char in_buf[2048];
size_t in_buf_size;
buffer_t *out_buf;
unsigned int i, j;
int ret;
out_buf = t_buffer_create(sizeof(in_buf));
test_begin("istream base64 random I/O");
for (i = 0; !test_has_failed() && i < 4000; i++) {
struct istream *input1, *input2, *input3, *input4, *input5;
struct istream *sinput1, *sinput2, *sinput3, *sinput4;
struct istream *top_input;
const unsigned char *data;
unsigned int chpl1, chpl2;
unsigned int sized_streams;
unsigned int crlf_encode;
size_t size;
struct base64_encoder b64enc;
/* Initialize test data */
in_buf_size = i_rand_limit(sizeof(in_buf));
for (j = 0; j < in_buf_size; j++)
in_buf[j] = i_rand_uchar();
/* Reset final output buffer */
buffer_set_used_size(out_buf, 0);
/* Determine line lengths */
chpl1 = i_rand_limit(30)*4;
chpl2 = i_rand_limit(30)*4;
/* Create stream for test data */
input1 = i_stream_create_from_data(in_buf, in_buf_size);
i_stream_set_name(input1, "[data]");
/* Determine which stages have sized streams */
sized_streams = i_rand_minmax(0x00, 0x0f);
/* Determine which stages use CRLF */
crlf_encode = i_rand_minmax(0x00, 0x03);
/* Create first encoder stream */
input2 = i_stream_create_base64_encoder(
input1, chpl1, HAS_ALL_BITS(crlf_encode, BIT(0)));
i_stream_set_name(input2, "[base64_encoder #1]");
if (HAS_ALL_BITS(sized_streams, BIT(0))) {
/* Wrap the first encoder stream in a sized stream to
check size and trigger any buffer overflow problems
*/
base64_encode_init(&b64enc, &base64_scheme,
(HAS_ALL_BITS(crlf_encode, BIT(0)) ?
BASE64_ENCODE_FLAG_CRLF : 0),
chpl1);
sinput1 = i_stream_create_sized(input2,
base64_get_full_encoded_size(&b64enc,
in_buf_size));
i_stream_set_name(sinput1, "[sized #1]");
} else {
sinput1 = input2;
i_stream_ref(sinput1);
}
/* Create first decoder stream */
input3 = i_stream_create_base64_decoder(sinput1);
i_stream_set_name(input3, "[base64_decoder #1]");
if (HAS_ALL_BITS(sized_streams, BIT(1))) {
/* Wrap the first decoder stream in a sized stream to
check size and trigger any buffer overflow problems
*/
sinput2 = i_stream_create_sized(input3, in_buf_size);
i_stream_set_name(sinput2, "[sized #2]");
} else {
sinput2 = input3;
i_stream_ref(sinput2);
}
/* Create second encoder stream */
input4 = i_stream_create_base64_encoder(
sinput2, chpl2, HAS_ALL_BITS(crlf_encode, BIT(1)));
i_stream_set_name(input4, "[base64_encoder #2]");
if (HAS_ALL_BITS(sized_streams, BIT(2))) {
/* Wrap the second encoder stream in a sized stream to
check size and trigger any buffer overflow problems
*/
base64_encode_init(&b64enc, &base64_scheme,
(HAS_ALL_BITS(crlf_encode, BIT(1)) ?
BASE64_ENCODE_FLAG_CRLF : 0),
chpl2);
sinput3 = i_stream_create_sized(input4,
base64_get_full_encoded_size(&b64enc,
in_buf_size));
i_stream_set_name(sinput3, "[sized #3]");
} else {
sinput3 = input4;
i_stream_ref(sinput3);
}
/* Create second deoder stream */
input5 = i_stream_create_base64_decoder(sinput3);
i_stream_set_name(input5, "[base64_decoder #2]");
if (HAS_ALL_BITS(sized_streams, BIT(3))) {
/* Wrap the second decoder stream in a sized stream to
check size and trigger any buffer overflow problems
*/
sinput4 = i_stream_create_sized(input5, in_buf_size);
i_stream_set_name(sinput4, "[sized #4]");
} else {
sinput4 = input5;
i_stream_ref(sinput4);
}
/* Assign random buffer sizes */
i_stream_set_max_buffer_size(input5, i_rand_minmax(1, 512));
i_stream_set_max_buffer_size(input4, i_rand_minmax(1, 512));
i_stream_set_max_buffer_size(input3, i_rand_minmax(1, 512));
i_stream_set_max_buffer_size(input2, i_rand_minmax(1, 512));
/* Read the outer stream in full with random increments. */
top_input = sinput4;
while ((ret = i_stream_read_more(
top_input, &data, &size)) > 0) {
size_t ch = i_rand_limit(512);
size = I_MIN(size, ch);
buffer_append(out_buf, data, size);
i_stream_skip(top_input, size);
}
if (ret < 0 && top_input->stream_errno == 0) {
data = i_stream_get_data(top_input, &size);
if (size > 0) {
buffer_append(out_buf, data, size);
i_stream_skip(top_input, size);
}
}
/* Assert stream status */
test_assert_idx(ret < 0 && top_input->stream_errno == 0, i);
/* Assert input/output equality */
test_assert_idx(out_buf->used == in_buf_size &&
memcmp(in_buf, out_buf->data, in_buf_size) == 0,
i);
if (top_input->stream_errno != 0) {
i_error("%s: %s", i_stream_get_name(input1),
i_stream_get_error(input1));
i_error("%s: %s", i_stream_get_name(input2),
i_stream_get_error(input2));
i_error("%s: %s", i_stream_get_name(input3),
i_stream_get_error(input3));
i_error("%s: %s", i_stream_get_name(input4),
i_stream_get_error(input4));
i_error("%s: %s", i_stream_get_name(input5),
i_stream_get_error(input5));
}
if (test_has_failed()) {
i_info("Test parameters: size=%zu "
"line_length_1=%u line_length_2=%u",
in_buf_size, chpl1, chpl2);
}
/* Clean up */
i_stream_unref(&input1);
i_stream_unref(&input2);
i_stream_unref(&input3);
i_stream_unref(&input4);
i_stream_unref(&input5);
i_stream_unref(&sinput1);
i_stream_unref(&sinput2);
i_stream_unref(&sinput3);
i_stream_unref(&sinput4);
}
test_end();
}
void test_istream_base64_decoder(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(base64_tests); i++) {
const struct base64_istream_test *test = &base64_tests[i];
test_begin(t_strdup_printf("istream base64 decoder %u", i+1));
decode_base64_test(test->input, test->output,
test->stream_errno);
test_end();
}
for (i = 0; i < N_ELEMENTS(base64url_tests); i++) {
const struct base64_istream_test *test = &base64url_tests[i];
test_begin(t_strdup_printf("istream base64url decoder %u",
i+1));
decode_base64url_test(test->input, test->output,
test->stream_errno);
test_end();
}
test_istream_base64_io_random();
}
dovecot-2.3.21.1/src/lib/ostream-file.c 0000644 0000000 0000000 00000074345 14656633576 014422 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
/* @UNSAFE: whole file */
#include "lib.h"
#include "ioloop.h"
#include "write-full.h"
#include "net.h"
#include "sendfile-util.h"
#include "istream.h"
#include "istream-private.h"
#include "ostream-file-private.h"
#include
#include
#ifdef HAVE_SYS_UIO_H
# include
#endif
#include
/* try to keep the buffer size within 4k..128k. ReiserFS may actually return
128k as optimal size. */
#define DEFAULT_OPTIMAL_BLOCK_SIZE IO_BLOCK_SIZE
#define MAX_OPTIMAL_BLOCK_SIZE (128*1024)
#define IS_STREAM_EMPTY(fstream) \
((fstream)->head == (fstream)->tail && !(fstream)->full)
#define MAX_SSIZE_T(size) \
((size) < SSIZE_T_MAX ? (size_t)(size) : SSIZE_T_MAX)
static void stream_send_io(struct file_ostream *fstream);
static struct ostream * o_stream_create_fd_common(int fd,
size_t max_buffer_size, bool autoclose_fd);
static void stream_closed(struct file_ostream *fstream)
{
io_remove(&fstream->io);
if (fstream->autoclose_fd && fstream->fd != -1) {
/* Ignore ECONNRESET because we don't really care about it here,
as we are closing the socket down in any case. There might be
unsent data but nothing we can do about that. */
if (unlikely(close(fstream->fd) < 0 && errno != ECONNRESET)) {
i_error("file_ostream.close(%s) failed: %m",
o_stream_get_name(&fstream->ostream.ostream));
}
}
fstream->fd = -1;
fstream->ostream.ostream.closed = TRUE;
}
void o_stream_file_close(struct iostream_private *stream,
bool close_parent ATTR_UNUSED)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream.iostream);
stream_closed(fstream);
}
static void o_stream_file_destroy(struct iostream_private *stream)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream.iostream);
i_free(fstream->buffer);
}
static size_t file_buffer_get_used_size(struct file_ostream *fstream)
{
if (fstream->head == fstream->tail)
return fstream->full ? fstream->buffer_size : 0;
else if (fstream->head < fstream->tail) {
/* ...HXXXT... */
return fstream->tail - fstream->head;
} else {
/* XXXT...HXXX */
return fstream->tail +
(fstream->buffer_size - fstream->head);
}
}
static void update_buffer(struct file_ostream *fstream, size_t size)
{
size_t used;
if (IS_STREAM_EMPTY(fstream) || size == 0)
return;
if (fstream->head < fstream->tail) {
/* ...HXXXT... */
used = fstream->tail - fstream->head;
i_assert(size <= used);
fstream->head += size;
} else {
/* XXXT...HXXX */
used = fstream->buffer_size - fstream->head;
if (size > used) {
size -= used;
i_assert(size <= fstream->tail);
fstream->head = size;
} else {
fstream->head += size;
}
fstream->full = FALSE;
}
if (fstream->head == fstream->tail)
fstream->head = fstream->tail = 0;
if (fstream->head == fstream->buffer_size)
fstream->head = 0;
}
static void o_stream_socket_cork(struct file_ostream *fstream)
{
if (fstream->ostream.corked && !fstream->socket_cork_set) {
if (!fstream->no_socket_cork) {
if (net_set_cork(fstream->fd, TRUE) < 0)
fstream->no_socket_cork = TRUE;
else
fstream->socket_cork_set = TRUE;
}
}
}
static int o_stream_lseek(struct file_ostream *fstream)
{
off_t ret;
if (fstream->real_offset == fstream->buffer_offset)
return 0;
ret = lseek(fstream->fd, (off_t)fstream->buffer_offset, SEEK_SET);
if (ret < 0) {
io_stream_set_error(&fstream->ostream.iostream,
"lseek() failed: %m");
fstream->ostream.ostream.stream_errno = errno;
return -1;
}
if (ret != (off_t)fstream->buffer_offset) {
io_stream_set_error(&fstream->ostream.iostream,
"lseek() returned wrong value");
fstream->ostream.ostream.stream_errno = EINVAL;
return -1;
}
fstream->real_offset = fstream->buffer_offset;
return 0;
}
ssize_t o_stream_file_writev(struct file_ostream *fstream,
const struct const_iovec *iov,
unsigned int iov_count)
{
ssize_t ret;
size_t size, sent;
unsigned int i;
if (iov_count == 1) {
i_assert(iov->iov_len > 0);
if (!fstream->file ||
fstream->real_offset == fstream->buffer_offset) {
ret = write(fstream->fd, iov->iov_base, iov->iov_len);
if (ret > 0)
fstream->real_offset += ret;
} else {
ret = pwrite(fstream->fd, iov->iov_base, iov->iov_len,
fstream->buffer_offset);
}
} else {
if (o_stream_lseek(fstream) < 0)
return -1;
sent = 0;
while (iov_count > IOV_MAX) {
size = 0;
for (i = 0; i < IOV_MAX; i++)
size += iov[i].iov_len;
ret = writev(fstream->fd, (const struct iovec *)iov,
IOV_MAX);
if (ret != (ssize_t)size) {
break;
}
fstream->real_offset += ret;
fstream->buffer_offset += ret;
sent += ret;
iov += IOV_MAX;
iov_count -= IOV_MAX;
}
if (iov_count <= IOV_MAX) {
size = 0;
for (i = 0; i < iov_count; i++)
size += iov[i].iov_len;
ret = writev(fstream->fd, (const struct iovec *)iov,
iov_count);
}
if (ret > 0) {
fstream->real_offset += ret;
ret += sent;
} else if (!fstream->file && sent > 0) {
/* return what we managed to get sent */
ret = sent;
}
}
return ret;
}
static ssize_t
o_stream_file_writev_full(struct file_ostream *fstream,
const struct const_iovec *iov,
unsigned int iov_count)
{
ssize_t ret, ret2;
size_t size, total_size;
bool partial;
unsigned int i;
for (i = 0, total_size = 0; i < iov_count; i++)
total_size += iov[i].iov_len;
o_stream_socket_cork(fstream);
ret = fstream->writev(fstream, iov, iov_count);
partial = ret != (ssize_t)total_size;
if (ret < 0) {
if (fstream->file) {
if (errno == EINTR) {
/* automatically retry */
return o_stream_file_writev_full(fstream, iov, iov_count);
}
} else if (errno == EAGAIN || errno == EINTR) {
/* try again later */
return 0;
}
fstream->ostream.ostream.stream_errno = errno;
stream_closed(fstream);
return -1;
}
if (unlikely(ret == 0 && fstream->file)) {
/* assume out of disk space */
fstream->ostream.ostream.stream_errno = ENOSPC;
stream_closed(fstream);
return -1;
}
fstream->buffer_offset += ret;
if (partial && fstream->file) {
/* we failed to write everything to a file. either we ran out
of disk space or we're writing to NFS. try to write the
rest to resolve this. */
size = ret;
while (iov_count > 0 && size >= iov->iov_len) {
size -= iov->iov_len;
iov++;
iov_count--;
}
i_assert(iov_count > 0);
if (size == 0)
ret2 = o_stream_file_writev_full(fstream, iov, iov_count);
else {
/* write the first iov separately */
struct const_iovec new_iov;
new_iov.iov_base =
CONST_PTR_OFFSET(iov->iov_base, size);
new_iov.iov_len = iov->iov_len - size;
ret2 = o_stream_file_writev_full(fstream, &new_iov, 1);
if (ret2 > 0) {
i_assert((size_t)ret2 == new_iov.iov_len);
/* write the rest */
if (iov_count > 1) {
ret += ret2;
ret2 = o_stream_file_writev_full(fstream, iov + 1,
iov_count - 1);
}
}
}
i_assert(ret2 != 0);
if (ret2 < 0)
ret = ret2;
else
ret += ret2;
}
i_assert(ret < 0 || !fstream->file ||
(size_t)ret == total_size);
return ret;
}
/* returns how much of vector was used */
static int o_stream_fill_iovec(struct file_ostream *fstream,
struct const_iovec iov[2])
{
if (IS_STREAM_EMPTY(fstream))
return 0;
if (fstream->head < fstream->tail) {
iov[0].iov_base = fstream->buffer + fstream->head;
iov[0].iov_len = fstream->tail - fstream->head;
return 1;
} else {
iov[0].iov_base = fstream->buffer + fstream->head;
iov[0].iov_len = fstream->buffer_size - fstream->head;
if (fstream->tail == 0)
return 1;
else {
iov[1].iov_base = fstream->buffer;
iov[1].iov_len = fstream->tail;
return 2;
}
}
}
static int buffer_flush(struct file_ostream *fstream)
{
struct const_iovec iov[2];
int iov_len;
ssize_t ret;
iov_len = o_stream_fill_iovec(fstream, iov);
if (iov_len > 0) {
ret = o_stream_file_writev_full(fstream, iov, iov_len);
if (ret < 0)
return -1;
update_buffer(fstream, ret);
}
return IS_STREAM_EMPTY(fstream) ? 1 : 0;
}
static void o_stream_tcp_flush_via_nodelay(struct file_ostream *fstream)
{
if (net_set_tcp_nodelay(fstream->fd, TRUE) < 0) {
/* Don't bother logging errors. There are quite a lot of
different errors that need to be ignored, and it differs
between OSes. At least:
Linux: ENOTSUP, ENOTSOCK, ENOPROTOOPT
FreeBSD: EINVAL, ECONNRESET */
fstream->no_socket_nodelay = TRUE;
} else if (net_set_tcp_nodelay(fstream->fd, FALSE) < 0) {
/* We already successfully enabled TCP_NODELAY, so there
shouldn't really be errors. Except ECONNRESET can possibly
still happen between these two calls, so again don't log
errors. */
fstream->no_socket_nodelay = TRUE;
}
}
static void o_stream_file_cork(struct ostream_private *stream, bool set)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream);
struct iostream_private *iostream = &fstream->ostream.iostream;
int ret;
if (stream->corked != set && !stream->ostream.closed) {
if (set && fstream->io != NULL)
io_remove(&fstream->io);
else if (!set) {
/* buffer flushing might close the stream */
ret = buffer_flush(fstream);
stream->last_errors_not_checked = TRUE;
if (fstream->io == NULL &&
(ret == 0 || fstream->flush_pending) &&
!stream->ostream.closed) {
fstream->io = io_add_to(
io_stream_get_ioloop(iostream),
fstream->fd, IO_WRITE,
stream_send_io, fstream);
}
}
if (stream->ostream.closed) {
/* flushing may have closed the stream already */
return;
}
if (fstream->socket_cork_set) {
i_assert(!set);
if (net_set_cork(fstream->fd, FALSE) < 0)
fstream->no_socket_cork = TRUE;
fstream->socket_cork_set = FALSE;
}
if (!set && !fstream->no_socket_nodelay) {
/* Uncorking - send all the pending data immediately.
Remove nodelay immediately afterwards, so if any
output is sent outside corking it may get delayed. */
o_stream_tcp_flush_via_nodelay(fstream);
}
if (!set && !fstream->no_socket_quickack) {
/* Uncorking - disable delayed ACKs to reduce latency.
Note that this needs to be set repeatedly. */
if (net_set_tcp_quickack(fstream->fd, TRUE) < 0)
fstream->no_socket_quickack = TRUE;
}
stream->corked = set;
}
}
static int o_stream_file_flush(struct ostream_private *stream)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream);
return buffer_flush(fstream);
}
static void
o_stream_file_flush_pending(struct ostream_private *stream, bool set)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream);
struct iostream_private *iostream = &fstream->ostream.iostream;
fstream->flush_pending = set;
if (set && !stream->corked && fstream->io == NULL) {
fstream->io = io_add_to(io_stream_get_ioloop(iostream),
fstream->fd, IO_WRITE,
stream_send_io, fstream);
}
}
static size_t get_unused_space(const struct file_ostream *fstream)
{
if (fstream->head > fstream->tail) {
/* XXXT...HXXX */
return fstream->head - fstream->tail;
} else if (fstream->head < fstream->tail) {
/* ...HXXXT... */
return (fstream->buffer_size - fstream->tail) + fstream->head;
} else {
/* either fully unused or fully used */
return fstream->full ? 0 : fstream->buffer_size;
}
}
static size_t
o_stream_file_get_buffer_used_size(const struct ostream_private *stream)
{
const struct file_ostream *fstream =
container_of(stream, const struct file_ostream, ostream);
return fstream->buffer_size - get_unused_space(fstream);
}
static int o_stream_file_seek(struct ostream_private *stream, uoff_t offset)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream);
if (offset > OFF_T_MAX) {
stream->ostream.stream_errno = EINVAL;
return -1;
}
if (!fstream->file) {
stream->ostream.stream_errno = ESPIPE;
return -1;
}
if (buffer_flush(fstream) < 0)
return -1;
stream->ostream.offset = offset;
fstream->buffer_offset = offset;
return 1;
}
static void o_stream_grow_buffer(struct file_ostream *fstream, size_t bytes)
{
size_t size, new_size, end_size;
size = nearest_power(fstream->buffer_size + bytes);
if (size > fstream->ostream.max_buffer_size) {
/* limit the size */
size = fstream->ostream.max_buffer_size;
} else if (fstream->ostream.corked) {
/* try to use optimal buffer size with corking */
new_size = I_MIN(fstream->optimal_block_size,
fstream->ostream.max_buffer_size);
if (new_size > size)
size = new_size;
}
if (size <= fstream->buffer_size)
return;
fstream->buffer = i_realloc(fstream->buffer,
fstream->buffer_size, size);
if (fstream->tail <= fstream->head && !IS_STREAM_EMPTY(fstream)) {
/* move head forward to end of buffer */
end_size = fstream->buffer_size - fstream->head;
memmove(fstream->buffer + size - end_size,
fstream->buffer + fstream->head, end_size);
fstream->head = size - end_size;
}
fstream->full = FALSE;
fstream->buffer_size = size;
}
static void stream_send_io(struct file_ostream *fstream)
{
struct ostream *ostream = &fstream->ostream.ostream;
struct iostream_private *iostream = &fstream->ostream.iostream;
bool use_cork = !fstream->ostream.corked;
int ret;
/* Set flush_pending = FALSE first before calling the flush callback,
and change it to TRUE only if callback returns 0. That way the
callback can call o_stream_set_flush_pending() again and we don't
forget it even if flush callback returns 1. */
fstream->flush_pending = FALSE;
o_stream_ref(ostream);
if (use_cork)
o_stream_cork(ostream);
if (fstream->ostream.callback != NULL)
ret = fstream->ostream.callback(fstream->ostream.context);
else
ret = o_stream_file_flush(&fstream->ostream);
if (use_cork)
o_stream_uncork(ostream);
if (ret == 0)
fstream->flush_pending = TRUE;
if (!fstream->flush_pending && IS_STREAM_EMPTY(fstream)) {
io_remove(&fstream->io);
} else if (!fstream->ostream.ostream.closed) {
/* Add the IO handler if it's not there already. Callback
might have just returned 0 without there being any data
to be sent. */
if (fstream->io == NULL) {
fstream->io = io_add_to(io_stream_get_ioloop(iostream),
fstream->fd, IO_WRITE,
stream_send_io, fstream);
}
}
o_stream_unref(&ostream);
}
static size_t o_stream_add(struct file_ostream *fstream,
const void *data, size_t size)
{
struct iostream_private *iostream = &fstream->ostream.iostream;
size_t unused, sent;
int i;
unused = get_unused_space(fstream);
if (unused < size)
o_stream_grow_buffer(fstream, size-unused);
sent = 0;
for (i = 0; i < 2 && sent < size && !fstream->full; i++) {
unused = fstream->tail >= fstream->head ?
fstream->buffer_size - fstream->tail :
fstream->head - fstream->tail;
if (unused > size-sent)
unused = size-sent;
memcpy(fstream->buffer + fstream->tail,
CONST_PTR_OFFSET(data, sent), unused);
sent += unused;
fstream->tail += unused;
if (fstream->tail == fstream->buffer_size)
fstream->tail = 0;
if (fstream->head == fstream->tail &&
fstream->buffer_size > 0)
fstream->full = TRUE;
}
if (sent != 0 && fstream->io == NULL &&
!fstream->ostream.corked && !fstream->file) {
fstream->io = io_add_to(io_stream_get_ioloop(iostream),
fstream->fd, IO_WRITE, stream_send_io,
fstream);
}
return sent;
}
ssize_t o_stream_file_sendv(struct ostream_private *stream,
const struct const_iovec *iov,
unsigned int iov_count)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream);
size_t size, total_size, added, optimal_size;
unsigned int i;
ssize_t ret = 0;
for (i = 0, size = 0; i < iov_count; i++)
size += iov[i].iov_len;
total_size = size;
if (size > get_unused_space(fstream) && !IS_STREAM_EMPTY(fstream)) {
if (o_stream_file_flush(stream) < 0)
return -1;
}
optimal_size = I_MIN(fstream->optimal_block_size,
fstream->ostream.max_buffer_size);
if (IS_STREAM_EMPTY(fstream) &&
(!stream->corked || size >= optimal_size)) {
/* send immediately */
ret = o_stream_file_writev_full(fstream, iov, iov_count);
if (ret < 0)
return -1;
size = ret;
while (size > 0 && iov_count > 0 && size >= iov[0].iov_len) {
size -= iov[0].iov_len;
iov++;
iov_count--;
}
if (iov_count == 0)
i_assert(size == 0);
else {
added = o_stream_add(fstream,
CONST_PTR_OFFSET(iov[0].iov_base, size),
iov[0].iov_len - size);
ret += added;
if (added != iov[0].iov_len - size) {
/* buffer full */
stream->ostream.offset += ret;
return ret;
}
iov++;
iov_count--;
}
}
/* buffer it, at least partly */
for (i = 0; i < iov_count; i++) {
added = o_stream_add(fstream, iov[i].iov_base, iov[i].iov_len);
ret += added;
if (added != iov[i].iov_len)
break;
}
stream->ostream.offset += ret;
i_assert((size_t)ret <= total_size);
i_assert((size_t)ret == total_size || !fstream->file);
return ret;
}
static size_t
o_stream_file_update_buffer(struct file_ostream *fstream,
const void *data, size_t size, size_t pos)
{
size_t avail, copy_size;
if (fstream->head < fstream->tail) {
/* ...HXXXT... */
i_assert(pos < fstream->tail);
avail = fstream->tail - pos;
} else {
/* XXXT...HXXX */
avail = fstream->buffer_size - pos;
}
copy_size = I_MIN(size, avail);
memcpy(fstream->buffer + pos, data, copy_size);
data = CONST_PTR_OFFSET(data, copy_size);
size -= copy_size;
if (size > 0 && fstream->head >= fstream->tail) {
/* wraps to beginning of the buffer */
copy_size = I_MIN(size, fstream->tail);
memcpy(fstream->buffer, data, copy_size);
size -= copy_size;
}
return size;
}
static int
o_stream_file_write_at(struct ostream_private *stream,
const void *data, size_t size, uoff_t offset)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream);
size_t used, pos, skip, left;
/* update buffer if the write overlaps it */
used = file_buffer_get_used_size(fstream);
if (used > 0 &&
fstream->buffer_offset < offset + size &&
fstream->buffer_offset + used > offset) {
if (fstream->buffer_offset <= offset) {
/* updating from the beginning */
skip = 0;
} else {
skip = fstream->buffer_offset - offset;
}
pos = (fstream->head + offset + skip - fstream->buffer_offset) %
fstream->buffer_size;
left = o_stream_file_update_buffer(fstream,
CONST_PTR_OFFSET(data, skip), size - skip, pos);
if (left > 0) {
/* didn't write all of it */
if (skip > 0) {
/* we also have to write a prefix. don't
bother with two syscalls, just write all
of it in one pwrite(). */
} else {
/* write only the suffix */
size_t update_count = size - left;
data = CONST_PTR_OFFSET(data, update_count);
size -= update_count;
offset += update_count;
}
} else if (skip == 0) {
/* everything done */
return 0;
} else {
/* still have to write prefix */
size = skip;
}
}
/* we couldn't write everything to the buffer. flush the buffer
and pwrite() the rest. */
if (o_stream_file_flush(stream) < 0)
return -1;
if (pwrite_full(fstream->fd, data, size, offset) < 0) {
stream->ostream.stream_errno = errno;
stream_closed(fstream);
return -1;
}
return 0;
}
static bool
io_stream_sendfile(struct ostream_private *outstream,
struct istream *instream, int in_fd,
enum ostream_send_istream_result *res_r)
{
struct file_ostream *foutstream =
container_of(outstream, struct file_ostream, ostream);
uoff_t in_size, offset, send_size, v_offset, abs_start_offset;
ssize_t ret;
bool sendfile_not_supported = FALSE;
if ((ret = i_stream_get_size(instream, TRUE, &in_size)) < 0) {
*res_r = OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT;
return TRUE;
}
if (ret == 0) {
/* size unknown. we can't use sendfile(). */
return FALSE;
}
o_stream_socket_cork(foutstream);
/* flush out any data in buffer */
if ((ret = buffer_flush(foutstream)) < 0) {
*res_r = OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT;
return TRUE;
} else if (ret == 0) {
*res_r = OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT;
return TRUE;
}
if (o_stream_lseek(foutstream) < 0) {
*res_r = OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT;
return TRUE;
}
v_offset = instream->v_offset;
abs_start_offset = i_stream_get_absolute_offset(instream) - v_offset;
while (v_offset < in_size) {
offset = abs_start_offset + v_offset;
send_size = in_size - v_offset;
ret = safe_sendfile(foutstream->fd, in_fd, &offset,
MAX_SSIZE_T(send_size));
if (ret <= 0) {
if (ret == 0) {
/* Unexpectedly early EOF at input */
i_stream_seek(instream, v_offset);
instream->eof = TRUE;
*res_r = OSTREAM_SEND_ISTREAM_RESULT_FINISHED;
return TRUE;
}
if (foutstream->file) {
if (errno == EINTR) {
/* automatically retry */
continue;
}
} else {
if (errno == EINTR || errno == EAGAIN) {
ret = 0;
break;
}
}
if (errno == EINVAL)
sendfile_not_supported = TRUE;
else {
io_stream_set_error(&outstream->iostream,
"sendfile() failed: %m");
outstream->ostream.stream_errno = errno;
/* close only if error wasn't because
sendfile() isn't supported */
stream_closed(foutstream);
}
break;
}
v_offset += ret;
foutstream->real_offset += ret;
foutstream->buffer_offset += ret;
outstream->ostream.offset += ret;
}
i_stream_seek(instream, v_offset);
if (v_offset == in_size) {
instream->eof = TRUE;
*res_r = OSTREAM_SEND_ISTREAM_RESULT_FINISHED;
return TRUE;
}
i_assert(ret <= 0);
if (sendfile_not_supported)
return FALSE;
if (ret < 0)
*res_r = OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT;
else
*res_r = OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT;
return TRUE;
}
static enum ostream_send_istream_result
io_stream_copy_backwards(struct ostream_private *outstream,
struct istream *instream, uoff_t in_size)
{
struct file_ostream *foutstream =
container_of(outstream, struct file_ostream, ostream);
uoff_t in_start_offset, in_offset, in_limit, out_offset;
const unsigned char *data;
size_t buffer_size, size, read_size;
ssize_t ret;
i_assert(IS_STREAM_EMPTY(foutstream));
/* figure out optimal buffer size */
buffer_size = instream->real_stream->buffer_size;
if (buffer_size == 0 || buffer_size > foutstream->buffer_size) {
if (foutstream->optimal_block_size > foutstream->buffer_size) {
o_stream_grow_buffer(foutstream,
foutstream->optimal_block_size -
foutstream->buffer_size);
}
buffer_size = foutstream->buffer_size;
}
in_start_offset = instream->v_offset;
in_offset = in_limit = in_size;
out_offset = outstream->ostream.offset + (in_offset - in_start_offset);
while (in_offset > in_start_offset) {
if (in_offset - in_start_offset <= buffer_size)
read_size = in_offset - in_start_offset;
else
read_size = buffer_size;
in_offset -= read_size;
out_offset -= read_size;
for (;;) {
i_assert(in_offset <= in_limit);
i_stream_seek(instream, in_offset);
read_size = in_limit - in_offset;
/* FIXME: something's wrong here */
if (i_stream_read_bytes(instream, &data, &size,
read_size) == 0)
i_unreached();
if (size >= read_size) {
size = read_size;
if (instream->mmaped) {
/* we'll have to write it through
buffer or the file gets corrupted */
i_assert(size <=
foutstream->buffer_size);
memcpy(foutstream->buffer, data, size);
data = foutstream->buffer;
}
break;
}
/* buffer too large probably, try with smaller */
read_size -= size;
in_offset += read_size;
out_offset += read_size;
buffer_size -= read_size;
}
in_limit -= size;
ret = pwrite_full(foutstream->fd, data, size, out_offset);
if (ret < 0) {
/* error */
outstream->ostream.stream_errno = errno;
return OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT;
}
i_stream_skip(instream, size);
}
/* make it visible that we're at instream's EOF */
i_stream_seek(instream, in_size);
instream->eof = TRUE;
outstream->ostream.offset += in_size - in_start_offset;
return OSTREAM_SEND_ISTREAM_RESULT_FINISHED;
}
static enum ostream_send_istream_result
io_stream_copy_same_stream(struct ostream_private *outstream,
struct istream *instream)
{
uoff_t in_size;
off_t in_abs_offset, ret = 0;
/* copying data within same fd. we'll have to be careful with
seeks and overlapping writes. */
if ((ret = i_stream_get_size(instream, TRUE, &in_size)) < 0)
return OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT;
if (ret == 0) {
/* if we couldn't find out the size, it means that instream
isn't a regular file_istream. we can be reasonably sure that
we can copy it safely the regular way. (there's really no
other possibility, other than failing completely.) */
return io_stream_copy(&outstream->ostream, instream);
}
i_assert(instream->v_offset <= in_size);
in_abs_offset = i_stream_get_absolute_offset(instream);
ret = (off_t)outstream->ostream.offset - in_abs_offset;
if (ret == 0) {
/* copying data over itself. we don't really
need to do that, just fake it. */
return OSTREAM_SEND_ISTREAM_RESULT_FINISHED;
}
if (ret > 0 && in_size > (uoff_t)ret) {
/* overlapping */
i_assert(instream->seekable);
return io_stream_copy_backwards(outstream, instream, in_size);
} else {
/* non-overlapping */
return io_stream_copy(&outstream->ostream, instream);
}
}
static enum ostream_send_istream_result
o_stream_file_send_istream(struct ostream_private *outstream,
struct istream *instream)
{
struct file_ostream *foutstream =
container_of(outstream, struct file_ostream, ostream);
bool same_stream;
int in_fd;
enum ostream_send_istream_result res;
in_fd = !instream->readable_fd ? -1 : i_stream_get_fd(instream);
if (!foutstream->no_sendfile && in_fd != -1 &&
in_fd != foutstream->fd && instream->seekable) {
if (io_stream_sendfile(outstream, instream, in_fd, &res))
return res;
/* sendfile() not supported (with this fd), fallback to
regular sending. */
foutstream->no_sendfile = TRUE;
}
same_stream = i_stream_get_fd(instream) == foutstream->fd &&
foutstream->fd != -1;
if (!same_stream)
return io_stream_copy(&outstream->ostream, instream);
return io_stream_copy_same_stream(outstream, instream);
}
static void o_stream_file_switch_ioloop_to(struct ostream_private *stream,
struct ioloop *ioloop)
{
struct file_ostream *fstream =
container_of(stream, struct file_ostream, ostream);
if (fstream->io != NULL)
fstream->io = io_loop_move_io_to(ioloop, &fstream->io);
}
struct ostream *
o_stream_create_file_common(struct file_ostream *fstream,
int fd, size_t max_buffer_size, bool autoclose_fd)
{
struct ostream *ostream;
fstream->fd = fd;
fstream->autoclose_fd = autoclose_fd;
fstream->optimal_block_size = DEFAULT_OPTIMAL_BLOCK_SIZE;
fstream->ostream.iostream.close = o_stream_file_close;
fstream->ostream.iostream.destroy = o_stream_file_destroy;
fstream->ostream.cork = o_stream_file_cork;
fstream->ostream.flush = o_stream_file_flush;
fstream->ostream.flush_pending = o_stream_file_flush_pending;
fstream->ostream.get_buffer_used_size =
o_stream_file_get_buffer_used_size;
fstream->ostream.seek = o_stream_file_seek;
fstream->ostream.sendv = o_stream_file_sendv;
fstream->ostream.write_at = o_stream_file_write_at;
fstream->ostream.send_istream = o_stream_file_send_istream;
fstream->ostream.switch_ioloop_to = o_stream_file_switch_ioloop_to;
fstream->writev = o_stream_file_writev;
fstream->ostream.max_buffer_size = max_buffer_size;
ostream = o_stream_create(&fstream->ostream, NULL, fd);
if (max_buffer_size == 0)
fstream->ostream.max_buffer_size = fstream->optimal_block_size;
return ostream;
}
static void fstream_init_file(struct file_ostream *fstream)
{
struct stat st;
fstream->no_sendfile = TRUE;
if (fstat(fstream->fd, &st) < 0)
return;
if ((uoff_t)st.st_blksize > fstream->optimal_block_size) {
/* use the optimal block size, but with a reasonable limit */
fstream->optimal_block_size =
I_MIN(st.st_blksize, MAX_OPTIMAL_BLOCK_SIZE);
}
if (S_ISREG(st.st_mode)) {
fstream->no_socket_cork = TRUE;
fstream->no_socket_nodelay = TRUE;
fstream->no_socket_quickack = TRUE;
fstream->file = TRUE;
}
}
static
struct ostream * o_stream_create_fd_common(int fd, size_t max_buffer_size,
bool autoclose_fd)
{
struct file_ostream *fstream;
struct ostream *ostream;
off_t offset;
fstream = i_new(struct file_ostream, 1);
ostream = o_stream_create_file_common
(fstream, fd, max_buffer_size, autoclose_fd);
offset = lseek(fd, 0, SEEK_CUR);
if (offset >= 0) {
ostream->offset = offset;
fstream->real_offset = offset;
fstream->buffer_offset = offset;
fstream_init_file(fstream);
} else {
struct ip_addr local_ip;
if (net_getsockname(fd, &local_ip, NULL) < 0) {
/* not a socket */
fstream->no_sendfile = TRUE;
fstream->no_socket_cork = TRUE;
fstream->no_socket_nodelay = TRUE;
fstream->no_socket_quickack = TRUE;
} else if (local_ip.family == 0) {
/* UNIX domain socket */
fstream->no_socket_cork = TRUE;
fstream->no_socket_nodelay = TRUE;
fstream->no_socket_quickack = TRUE;
}
}
return ostream;
}
struct ostream *
o_stream_create_fd(int fd, size_t max_buffer_size)
{
return o_stream_create_fd_common(fd, max_buffer_size, FALSE);
}
struct ostream *
o_stream_create_fd_autoclose(int *fd, size_t max_buffer_size)
{
struct ostream *ostream = o_stream_create_fd_common(*fd,
max_buffer_size, TRUE);
*fd = -1;
return ostream;
}
struct ostream *
o_stream_create_fd_file(int fd, uoff_t offset, bool autoclose_fd)
{
struct file_ostream *fstream;
struct ostream *ostream;
if (offset == UOFF_T_MAX)
offset = lseek(fd, 0, SEEK_CUR);
fstream = i_new(struct file_ostream, 1);
ostream = o_stream_create_file_common(fstream, fd, 0, autoclose_fd);
fstream_init_file(fstream);
fstream->real_offset = offset;
fstream->buffer_offset = offset;
ostream->blocking = fstream->file;
ostream->offset = offset;
return ostream;
}
struct ostream *o_stream_create_fd_file_autoclose(int *fd, uoff_t offset)
{
struct ostream *output;
output = o_stream_create_fd_file(*fd, offset, TRUE);
*fd = -1;
return output;
}
struct ostream *o_stream_create_file(const char *path, uoff_t offset, mode_t mode,
enum ostream_create_file_flags flags)
{
int fd;
int open_flags = O_WRONLY|O_CREAT;
if (HAS_ANY_BITS(flags, OSTREAM_CREATE_FILE_FLAG_APPEND))
open_flags |= O_APPEND;
else
open_flags |= O_TRUNC;
if ((fd = open(path, open_flags, mode)) < 0)
return o_stream_create_error(errno);
return o_stream_create_fd_file_autoclose(&fd, offset);
}
dovecot-2.3.21.1/src/lib/istream-base64-encoder.c 0000644 0000000 0000000 00000013565 14656633576 016173 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "base64.h"
#include "istream-private.h"
#include "istream-base64.h"
struct base64_encoder_istream {
struct istream_private istream;
struct base64_encoder encoder;
};
static int i_stream_read_parent(struct istream_private *stream)
{
size_t size;
ssize_t ret;
size = i_stream_get_data_size(stream->parent);
if (size > 0)
return 1;
ret = i_stream_read_memarea(stream->parent);
if (ret <= 0) {
stream->istream.stream_errno = stream->parent->stream_errno;
return ret;
}
size = i_stream_get_data_size(stream->parent);
i_assert(size != 0);
return 1;
}
static int
i_stream_base64_try_encode(struct base64_encoder_istream *bstream)
{
struct istream_private *stream = &bstream->istream;
struct base64_encoder *b64enc = &bstream->encoder;
const unsigned char *data;
size_t size, pos, out_size, avail;
buffer_t buf;
data = i_stream_get_data(stream->parent, &size);
if (size == 0)
return 0;
out_size = base64_encode_get_size(b64enc, size);
if (!i_stream_try_alloc(stream, out_size, &avail))
return -2;
buffer_create_from_data(&buf, stream->w_buffer + stream->pos, avail);
base64_encode_more(b64enc, data, size, &pos, &buf);
i_assert(buf.used > 0);
stream->pos += buf.used;
i_stream_skip(stream->parent, pos);
return 1;
}
static int
i_stream_base64_finish_encode(struct base64_encoder_istream *bstream)
{
struct istream_private *stream = &bstream->istream;
struct base64_encoder *b64enc = &bstream->encoder;
size_t out_size, buffer_avail;
buffer_t buf;
out_size = base64_encode_get_size(b64enc, 0);
if (out_size == 0) {
if (base64_encode_finish(b64enc, NULL))
stream->istream.eof = TRUE;
return 1;
}
if (!i_stream_try_alloc(stream, out_size, &buffer_avail))
return -2;
buffer_create_from_data(&buf, stream->w_buffer + stream->pos,
buffer_avail);
if (base64_encode_finish(b64enc, &buf))
stream->istream.eof = TRUE;
i_assert(buf.used > 0);
stream->pos += buf.used;
return 1;
}
static ssize_t i_stream_base64_encoder_read(struct istream_private *stream)
{
struct base64_encoder_istream *bstream =
container_of(stream, struct base64_encoder_istream, istream);
size_t pre_count, post_count;
int ret;
if (base64_encode_is_finished(&bstream->encoder)) {
stream->istream.eof = TRUE;
return -1;
}
pre_count = post_count = 0;
do {
ret = i_stream_read_parent(stream);
if (ret == 0)
return 0;
if (ret < 0) {
if (stream->istream.stream_errno != 0)
return -1;
if (i_stream_get_data_size(stream->parent) == 0)
break;
/* add the final partial block */
}
/* encode as many lines as fits into destination buffer */
pre_count = stream->pos - stream->skip;
while ((ret = i_stream_base64_try_encode(bstream)) > 0) ;
post_count = stream->pos - stream->skip;
} while (ret == 0 && pre_count == post_count);
if (ret == -2) {
if (pre_count == post_count)
return -2;
} else if (ret < 0) {
if (i_stream_get_data_size(stream->parent) == 0) {
i_assert(post_count == pre_count);
pre_count = stream->pos - stream->skip;
ret = i_stream_base64_finish_encode(bstream);
post_count = stream->pos - stream->skip;
if (ret <= 0)
return ret;
}
if (pre_count == post_count) {
stream->istream.eof = TRUE;
return -1;
}
}
i_assert(post_count > pre_count);
return post_count - pre_count;
}
static void
i_stream_base64_encoder_seek(struct istream_private *stream,
uoff_t v_offset, bool mark)
{
struct base64_encoder_istream *bstream =
container_of(stream, struct base64_encoder_istream, istream);
if (v_offset < stream->istream.v_offset) {
/* seeking backwards - go back to beginning and seek
forward from there. */
stream->parent_expected_offset = stream->parent_start_offset;
stream->skip = stream->pos = 0;
stream->istream.v_offset = 0;
i_stream_seek(stream->parent, 0);
base64_encode_reset(&bstream->encoder);
}
i_stream_default_seek_nonseekable(stream, v_offset, mark);
}
static int
i_stream_base64_encoder_stat(struct istream_private *stream,
bool exact ATTR_UNUSED)
{
struct base64_encoder_istream *bstream =
container_of(stream, struct base64_encoder_istream, istream);
const struct stat *st;
if (i_stream_stat(stream->parent, exact, &st) < 0) {
stream->istream.stream_errno = stream->parent->stream_errno;
return -1;
}
stream->statbuf = *st;
if (st->st_size == 0)
return 0;
stream->statbuf.st_size =
base64_get_full_encoded_size(&bstream->encoder, st->st_size);
return 0;
}
static struct istream *
i_stream_create_base64_encoder_common(const struct base64_scheme *b64,
struct istream *input,
unsigned int chars_per_line, bool crlf)
{
struct base64_encoder_istream *bstream;
enum base64_encode_flags b64_flags = 0;
i_assert(chars_per_line % 4 == 0);
bstream = i_new(struct base64_encoder_istream, 1);
bstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
bstream->istream.read = i_stream_base64_encoder_read;
bstream->istream.seek = i_stream_base64_encoder_seek;
bstream->istream.stat = i_stream_base64_encoder_stat;
bstream->istream.istream.readable_fd = FALSE;
bstream->istream.istream.blocking = input->blocking;
bstream->istream.istream.seekable = input->seekable;
if (crlf)
b64_flags |= BASE64_ENCODE_FLAG_CRLF;
base64_encode_init(&bstream->encoder, b64, b64_flags, chars_per_line);
return i_stream_create(&bstream->istream, input,
i_stream_get_fd(input), 0);
}
struct istream *
i_stream_create_base64_encoder(struct istream *input,
unsigned int chars_per_line, bool crlf)
{
return i_stream_create_base64_encoder_common(&base64_scheme, input,
chars_per_line, crlf);
}
struct istream *
i_stream_create_base64url_encoder(struct istream *input,
unsigned int chars_per_line, bool crlf)
{
return i_stream_create_base64_encoder_common(&base64url_scheme, input,
chars_per_line, crlf);
}
dovecot-2.3.21.1/src/lib/hex-binary.c 0000644 0000000 0000000 00000003527 14656633576 014073 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "hex-binary.h"
static void
binary_to_hex_case(unsigned char *dest, const unsigned char *data,
size_t size, bool ucase)
{
unsigned char *p;
char base_char;
size_t i;
int value;
/* @UNSAFE */
base_char = ucase ? 'A' : 'a';
p = dest;
for (i = 0; i < size; i++) {
value = data[i] >> 4;
*p++ = value < 10 ? value + '0' : value - 10 + base_char;
value = data[i] & 0x0f;
*p++ = value < 10 ? value + '0' : value - 10 + base_char;
}
}
const char *binary_to_hex(const unsigned char *data, size_t size)
{
unsigned char *dest = t_malloc_no0(MALLOC_MULTIPLY(size, 2) + 1);
binary_to_hex_case(dest, data, size, FALSE);
dest[size*2] = '\0';
return (char *)dest;
}
const char *binary_to_hex_ucase(const unsigned char *data, size_t size)
{
unsigned char *dest = t_malloc_no0(MALLOC_MULTIPLY(size, 2) + 1);
binary_to_hex_case(dest, data, size, TRUE);
dest[size*2] = '\0';
return (char *)dest;
}
void binary_to_hex_append(string_t *dest, const unsigned char *data,
size_t size)
{
unsigned char *buf;
buf = buffer_append_space_unsafe(dest, size * 2);
binary_to_hex_case(buf, data, size, FALSE);
}
int hex_to_binary(const char *data, buffer_t *dest)
{
int value;
while (*data != '\0') {
if (*data >= '0' && *data <= '9')
value = (*data - '0') << 4;
else if (*data >= 'a' && *data <= 'f')
value = (*data - 'a' + 10) << 4;
else if (*data >= 'A' && *data <= 'F')
value = (*data - 'A' + 10) << 4;
else
return -1;
data++;
if (*data >= '0' && *data <= '9')
value |= *data - '0';
else if (*data >= 'a' && *data <= 'f')
value |= *data - 'a' + 10;
else if (*data >= 'A' && *data <= 'F')
value |= *data - 'A' + 10;
else
return -1;
buffer_append_c(dest, value);
data++;
}
return 0;
}
dovecot-2.3.21.1/src/lib/json-tree.h 0000644 0000000 0000000 00000003732 14656633576 013736 0000000 0000000 #ifndef JSON_TREE_H
#define JSON_TREE_H
#include "json-parser.h"
/* Direct access to this structure is not encouraged, use the inline
function accessors where possible, so that the implementation
details can remain fluid, or, even better, hidden. */
struct json_tree_node {
/* object key, or NULL if we're in a list */
const char *key;
struct json_tree_node *parent, *next;
enum json_type value_type;
struct {
/* for JSON_TYPE_OBJECT and JSON_TYPE_ARRAY */
struct json_tree_node *child;
/* for other types */
const char *str;
} value;
};
static inline ATTR_PURE const struct json_tree_node *json_tree_get_child(const struct json_tree_node *node)
{
return node->value.child;
}
static inline ATTR_PURE const char *json_tree_get_value_str(const struct json_tree_node *node)
{
return node->value.str;
}
/* You can build a list or an object, nothing else. */
struct json_tree *json_tree_init_type(enum json_type container);
static inline struct json_tree *json_tree_init(void)
{
return json_tree_init_type(JSON_TYPE_OBJECT);
}
static inline struct json_tree *json_tree_init_array(void)
{
return json_tree_init_type(JSON_TYPE_ARRAY);
}
void json_tree_deinit(struct json_tree **tree);
/* Append data to a tree. The type/value should normally come from json-parser.
Returns 0 on success, -1 if the input was invalid (which should never happen
if it's coming from json-parser). */
int json_tree_append(struct json_tree *tree, enum json_type type,
const char *value);
/* Return the root node. */
const struct json_tree_node *
json_tree_root(const struct json_tree *tree);
/* Find a node with the specified key from an OBJECT node */
const struct json_tree_node *
json_tree_find_key(const struct json_tree_node *node, const char *key);
/* Find an object node (from an array), which contains the specified key=value
in its values. */
const struct json_tree_node *
json_tree_find_child_with(const struct json_tree_node *node,
const char *key, const char *value);
#endif
dovecot-2.3.21.1/src/lib/istream-hash.c 0000644 0000000 0000000 00000004716 14656633576 014413 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "hash-method.h"
#include "istream-private.h"
#include "istream-hash.h"
struct hash_istream {
struct istream_private istream;
const struct hash_method *method;
void *hash_context;
uoff_t high_offset;
};
static ssize_t
i_stream_hash_read(struct istream_private *stream)
{
struct hash_istream *hstream =
container_of(stream, struct hash_istream, istream);
const unsigned char *data;
size_t size;
uoff_t skip;
ssize_t ret;
i_stream_seek(stream->parent, stream->parent_start_offset +
stream->istream.v_offset);
ret = i_stream_read_copy_from_parent(&stream->istream);
if (ret > 0 && hstream->hash_context != NULL) {
data = i_stream_get_data(&stream->istream, &size);
i_assert((size_t)ret <= size);
i_assert(stream->istream.v_offset <= hstream->high_offset);
skip = hstream->high_offset - stream->istream.v_offset;
if (skip < (size_t)size) {
hstream->high_offset += (size-skip);
hstream->method->loop(hstream->hash_context,
data+skip, size-skip);
}
} else if (ret < 0) {
/* we finished hashing it. don't access it anymore, because
the memory pointed by the hash may be freed before the
istream itself */
hstream->hash_context = NULL;
}
return ret;
}
static void
i_stream_hash_seek(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED)
{
struct hash_istream *hstream =
container_of(stream, struct hash_istream, istream);
if (hstream->hash_context != NULL) {
io_stream_set_error(&stream->iostream,
"Seeking not supported before hashing is finished");
stream->istream.stream_errno = ESPIPE;
}
stream->istream.v_offset = v_offset;
stream->skip = stream->pos = 0;
}
struct istream *
i_stream_create_hash(struct istream *input, const struct hash_method *method,
void *hash_context)
{
struct hash_istream *hstream;
hstream = i_new(struct hash_istream, 1);
hstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
hstream->istream.stream_size_passthrough = TRUE;
hstream->istream.read = i_stream_hash_read;
hstream->istream.seek = i_stream_hash_seek;
hstream->istream.istream.readable_fd = input->readable_fd;
hstream->istream.istream.blocking = input->blocking;
hstream->istream.istream.seekable = input->seekable;
hstream->method = method;
hstream->hash_context = hash_context;
return i_stream_create(&hstream->istream, input,
i_stream_get_fd(input), 0);
}
dovecot-2.3.21.1/src/lib/istream-sized.c 0000644 0000000 0000000 00000015065 14656633576 014605 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream-private.h"
#include "istream-sized.h"
struct sized_istream {
struct istream_private istream;
istream_sized_callback_t *error_callback;
void *error_context;
uoff_t size;
bool min_size_only;
};
static void i_stream_sized_destroy(struct iostream_private *stream)
{
struct sized_istream *sstream =
container_of(stream, struct sized_istream, istream.iostream);
uoff_t v_offset;
v_offset = sstream->istream.parent_start_offset +
sstream->istream.istream.v_offset;
if (sstream->istream.parent->seekable ||
v_offset > sstream->istream.parent->v_offset) {
/* get to same position in parent stream */
i_stream_seek(sstream->istream.parent, v_offset);
}
}
static const char *
i_stream_create_sized_default_error_callback(
const struct istream_sized_error_data *data, void *context ATTR_UNUSED)
{
if (data->v_offset + data->new_bytes < data->wanted_size) {
return t_strdup_printf("Stream is smaller than expected "
"(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
data->v_offset + data->new_bytes, data->wanted_size);
} else {
return t_strdup_printf("Stream is larger than expected "
"(%"PRIuUOFF_T" > %"PRIuUOFF_T", eof=%d)",
data->v_offset + data->new_bytes, data->wanted_size,
data->eof ? 1 : 0);
}
}
static ssize_t
i_stream_sized_parent_read(struct istream_private *stream, size_t *pos_r)
{
ssize_t ret;
do {
ret = i_stream_read_memarea(stream->parent);
stream->istream.stream_errno = stream->parent->stream_errno;
stream->istream.eof = stream->parent->eof;
stream->buffer = i_stream_get_data(stream->parent, pos_r);
} while (*pos_r <= stream->pos && ret > 0);
return ret;
}
static ssize_t i_stream_sized_read(struct istream_private *stream)
{
struct sized_istream *sstream =
container_of(stream, struct sized_istream, istream);
struct istream_sized_error_data data;
const char *error;
uoff_t left;
ssize_t ret;
size_t pos;
i_stream_seek(stream->parent, sstream->istream.parent_start_offset +
stream->istream.v_offset);
stream->pos -= stream->skip;
stream->skip = 0;
stream->buffer = i_stream_get_data(stream->parent, &pos);
if (pos > stream->pos)
ret = 0;
else {
if ((ret = i_stream_sized_parent_read(stream, &pos)) == -2)
return -2;
}
left = sstream->size - stream->istream.v_offset;
if (pos == left && ret != -1) {
/* we have exactly the wanted amount of data left, but we
don't know yet if there is more data in parent. */
ret = i_stream_sized_parent_read(stream, &pos);
}
i_zero(&data);
data.v_offset = stream->istream.v_offset;
data.new_bytes = pos;
data.wanted_size = sstream->size;
data.eof = stream->istream.eof;
if (pos == left) {
/* we may or may not be finished, depending on whether
parent is at EOF. */
} else if (pos > left) {
/* parent has more data available than expected */
if (!sstream->min_size_only) {
error = sstream->error_callback(&data, sstream->error_context);
io_stream_set_error(&stream->iostream, "%s", error);
stream->istream.stream_errno = EINVAL;
return -1;
}
pos = left;
if (pos <= stream->pos) {
stream->istream.eof = TRUE;
ret = -1;
}
} else if (!stream->istream.eof) {
/* still more to read */
} else if (stream->istream.stream_errno == ENOENT) {
/* lost the file */
} else {
/* EOF before we reached the wanted size */
error = sstream->error_callback(&data, sstream->error_context);
io_stream_set_error(&stream->iostream, "%s", error);
stream->istream.stream_errno = EPIPE;
}
ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
(ret == 0 ? 0 : -1);
stream->pos = pos;
i_assert(ret != -1 || stream->istream.eof ||
stream->istream.stream_errno != 0);
return ret;
}
static int
i_stream_sized_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
{
struct sized_istream *sstream =
container_of(stream, struct sized_istream, istream);
const struct stat *st;
/* parent stream may be base64-decoder. don't waste time decoding the
entire stream, since we already know what the size is supposed
to be. */
if (i_stream_stat(stream->parent, FALSE, &st) < 0) {
stream->istream.stream_errno = stream->parent->stream_errno;
return -1;
}
stream->statbuf = *st;
stream->statbuf.st_size = sstream->size;
return 0;
}
static struct sized_istream *
i_stream_create_sized_common(struct istream *input, uoff_t size)
{
struct sized_istream *sstream;
sstream = i_new(struct sized_istream, 1);
sstream->size = size;
sstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
sstream->istream.iostream.destroy = i_stream_sized_destroy;
sstream->istream.read = i_stream_sized_read;
sstream->istream.stat = i_stream_sized_stat;
sstream->istream.istream.readable_fd = input->readable_fd;
sstream->istream.istream.blocking = input->blocking;
sstream->istream.istream.seekable = input->seekable;
(void)i_stream_create(&sstream->istream, input,
i_stream_get_fd(input), 0);
return sstream;
}
struct istream *i_stream_create_sized(struct istream *input, uoff_t size)
{
struct sized_istream *sstream;
sstream = i_stream_create_sized_common(input, size);
sstream->error_callback = i_stream_create_sized_default_error_callback;
sstream->error_context = sstream;
return &sstream->istream.istream;
}
struct istream *i_stream_create_sized_range(struct istream *input,
uoff_t offset, uoff_t size)
{
uoff_t orig_offset = input->v_offset;
struct istream *ret;
input->v_offset = offset;
ret = i_stream_create_sized(input, size);
input->v_offset = orig_offset;
return ret;
}
struct istream *i_stream_create_min_sized(struct istream *input, uoff_t min_size)
{
struct istream *ret;
ret= i_stream_create_sized(input, min_size);
struct sized_istream *ret_sstream =
container_of(ret->real_stream, struct sized_istream, istream);
ret_sstream->min_size_only = TRUE;
return ret;
}
struct istream *i_stream_create_min_sized_range(struct istream *input,
uoff_t offset, uoff_t min_size)
{
struct istream *ret;
ret = i_stream_create_sized_range(input, offset, min_size);
struct sized_istream *ret_sstream =
container_of(ret->real_stream, struct sized_istream, istream);
ret_sstream->min_size_only = TRUE;
return ret;
}
#undef i_stream_create_sized_with_callback
struct istream *
i_stream_create_sized_with_callback(struct istream *input, uoff_t size,
istream_sized_callback_t *error_callback,
void *context)
{
struct sized_istream *sstream;
sstream = i_stream_create_sized_common(input, size);
sstream->error_callback = error_callback;
sstream->error_context = context;
return &sstream->istream.istream;
}
dovecot-2.3.21.1/src/lib/event-filter.h 0000644 0000000 0000000 00000005167 14656633576 014440 0000000 0000000 #ifndef EVENT_FILTER_H
#define EVENT_FILTER_H
struct event;
struct event_filter_field {
const char *key;
const char *value;
};
struct event_filter *event_filter_create(void);
struct event_filter *event_filter_create_fragment(pool_t pool);
void event_filter_ref(struct event_filter *filter);
void event_filter_unref(struct event_filter **filter);
/* Add queries from source filter to destination filter. */
void event_filter_merge(struct event_filter *dest,
const struct event_filter *src);
/* Add queries from source filter to destination filter, but with supplied
context overriding whatever context source queries had. */
void event_filter_merge_with_context(struct event_filter *dest,
const struct event_filter *src,
void *new_context);
/* Remove query with given context from filter.
Returns TRUE if query was removed, otherwise FALSE. */
bool event_filter_remove_queries_with_context(struct event_filter *filter,
void *context);
/* Export the filter into a string. The context pointers aren't exported. */
void event_filter_export(struct event_filter *filter, string_t *dest);
/* Add queries to the filter from the given string. The string is expected to
be generated by event_filter_export(). Returns TRUE on success, FALSE on
invalid string. */
#define event_filter_import(filter, str, error_r) \
(event_filter_parse((str), (filter), (error_r)) == 0)
/* Parse a string-ified query, filling the passed in filter */
int event_filter_parse(const char *str, struct event_filter *filter,
const char **error_r);
/* Returns TRUE if the event matches the event filter. */
bool event_filter_match(struct event_filter *filter, struct event *event,
const struct failure_context *ctx);
/* Same as event_filter_match(), but use the given source filename:linenum
instead of taking it from the event. */
bool event_filter_match_source(struct event_filter *filter, struct event *event,
const char *source_filename,
unsigned int source_linenum,
const struct failure_context *ctx);
/* Iterate through all queries with non-NULL context that match the event. */
struct event_filter_match_iter *
event_filter_match_iter_init(struct event_filter *filter, struct event *event,
const struct failure_context *ctx);
/* Return context for the query that matched, or NULL when there are no more
matches. Note: This skips over any queries that have NULL context. */
void *event_filter_match_iter_next(struct event_filter_match_iter *iter);
void event_filter_match_iter_deinit(struct event_filter_match_iter **iter);
void event_filter_init(void);
void event_filter_deinit(void);
#endif
dovecot-2.3.21.1/src/lib/istream-try.h 0000644 0000000 0000000 00000002423 14656633576 014304 0000000 0000000 #ifndef ISTREAM_TRY_H
#define ISTREAM_TRY_H
/* Read from the first input stream that doesn't fail with EINVAL. If any of
the streams fail with non-EINVAL, it's treated as a fatal failure and the
error is immediately returned. If a stream returns 0, more data is waited
for before continuing to the next stream. This allows the last stream to
be a fallback stream that always succeeds.
Once the stream is detected, all the other streams are unreferenced.
The streams should usually be children of the same parent tee-istream.
Detecting whether istream-tee buffer is full or not is a bit tricky.
There's no visible difference between non-blocking istream returning 0 and
istream-tee buffer being full. To work around this, we treat used buffer
sizes <= min_buffer_full_size as being non-blocking istreams, while
buffer sizes > min_buffer_full_size are assumed to be due to istream-tee
max buffer size being reached. Practically this means that
min_buffer_full_size must be smaller than the smallest of the istreams'
maximum buffer sizes, but large enough that all the istreams would have
returned EINVAL on invalid input by that position. */
struct istream *istream_try_create(struct istream *const input[],
size_t min_buffer_full_size);
#endif
dovecot-2.3.21.1/src/lib/istream-failure-at.c 0000644 0000000 0000000 00000005745 14656633576 015524 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream-private.h"
#include "istream-failure-at.h"
struct failure_at_istream {
struct istream_private istream;
int error_code;
char *error_string;
uoff_t failure_offset;
};
static void i_stream_failure_at_destroy(struct iostream_private *stream)
{
struct failure_at_istream *fstream =
container_of(stream, struct failure_at_istream,
istream.iostream);
i_free(fstream->error_string);
}
static ssize_t
i_stream_failure_at_read(struct istream_private *stream)
{
struct failure_at_istream *fstream =
container_of(stream, struct failure_at_istream, istream);
uoff_t new_offset;
ssize_t ret;
i_stream_seek(stream->parent, stream->parent_start_offset +
stream->istream.v_offset);
ret = i_stream_read_copy_from_parent(&stream->istream);
new_offset = stream->istream.v_offset + (stream->pos - stream->skip);
if (ret >= 0 && new_offset >= fstream->failure_offset) {
if (stream->istream.v_offset >= fstream->failure_offset) {
/* we already passed the wanted failure offset,
return error immediately. */
stream->pos = stream->skip;
stream->istream.stream_errno = errno =
fstream->error_code;
io_stream_set_error(&stream->iostream, "%s",
fstream->error_string);
ret = -1;
} else {
/* return data up to the wanted failure offset and
on the next read() call return failure */
size_t new_pos = fstream->failure_offset -
stream->istream.v_offset + stream->skip;
i_assert(new_pos >= stream->skip &&
stream->pos >= new_pos);
ret -= stream->pos - new_pos;
stream->pos = new_pos;
}
} else if (ret < 0 && stream->istream.stream_errno == 0 &&
fstream->failure_offset == UOFF_T_MAX) {
/* failure at EOF */
stream->istream.stream_errno = errno =
fstream->error_code;
io_stream_set_error(&stream->iostream, "%s",
fstream->error_string);
}
return ret;
}
struct istream *
i_stream_create_failure_at(struct istream *input, uoff_t failure_offset,
int stream_errno, const char *error_string)
{
struct failure_at_istream *fstream;
fstream = i_new(struct failure_at_istream, 1);
fstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
fstream->istream.stream_size_passthrough = TRUE;
fstream->istream.read = i_stream_failure_at_read;
fstream->istream.iostream.destroy = i_stream_failure_at_destroy;
fstream->istream.istream.readable_fd = input->readable_fd;
fstream->istream.istream.blocking = input->blocking;
fstream->istream.istream.seekable = input->seekable;
fstream->error_code = stream_errno;
fstream->error_string = i_strdup(error_string);
fstream->failure_offset = failure_offset;
return i_stream_create(&fstream->istream, input,
i_stream_get_fd(input), 0);
}
struct istream *
i_stream_create_failure_at_eof(struct istream *input, int stream_errno,
const char *error_string)
{
return i_stream_create_failure_at(input, UOFF_T_MAX, stream_errno,
error_string);
}
dovecot-2.3.21.1/src/lib/strnum.c 0000644 0000000 0000000 00000030604 14656633576 013351 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "strnum.h"
bool str_is_numeric(const char *str, char end_char)
{
if (*str == '\0' || *str == end_char)
return FALSE;
while (*str != '\0' && *str != end_char) {
if (*str < '0' || *str > '9')
return FALSE;
str++;
}
return TRUE;
}
bool str_is_float(const char *str, char end_char)
{
bool dot_seen = FALSE;
bool num_seen = FALSE;
if (*str == '\0' || *str == end_char)
return FALSE;
while (*str != '\0' && *str != end_char) {
if (*str == '.') {
if (dot_seen || !num_seen) return FALSE;
dot_seen = TRUE;
num_seen = FALSE;
str++;
/* enforce that number follows dot */
continue;
}
if (*str < '0' || *str > '9')
return FALSE;
num_seen = TRUE;
str++;
}
return num_seen;
}
/*
* Unsigned decimal
*/
#define STR_PARSE_U__TEMPLATE(name, type) \
int name(const char *str, type *num_r, const char **endp_r) \
{ \
uintmax_t l; \
if (str_parse_uintmax(str, &l, endp_r) < 0 || l > (type)-1) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_PARSE_U__TEMPLATE(str_parse_uint, unsigned int)
STR_PARSE_U__TEMPLATE(str_parse_ulong, unsigned long)
STR_PARSE_U__TEMPLATE(str_parse_ullong, unsigned long long)
STR_PARSE_U__TEMPLATE(str_parse_uint32, uint32_t)
STR_PARSE_U__TEMPLATE(str_parse_uint64, uint64_t)
#define STR_TO_U__TEMPLATE(name, type) \
int name(const char *str, type *num_r) \
{ \
uintmax_t l; \
if (str_to_uintmax(str, &l) < 0 || l > (type)-1) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_TO_U__TEMPLATE(str_to_uint, unsigned int)
STR_TO_U__TEMPLATE(str_to_ulong, unsigned long)
STR_TO_U__TEMPLATE(str_to_ullong, unsigned long long)
STR_TO_U__TEMPLATE(str_to_uint32, uint32_t)
STR_TO_U__TEMPLATE(str_to_uint64, uint64_t)
int str_parse_uintmax(const char *str, uintmax_t *num_r,
const char **endp_r)
{
uintmax_t n = 0;
if (*str < '0' || *str > '9')
return -1;
do {
if (n >= ((uintmax_t)-1 / 10)) {
if (n > (uintmax_t)-1 / 10)
return -1;
if ((uintmax_t)(*str - '0') > ((uintmax_t)-1 % 10))
return -1;
}
n = n * 10 + (*str - '0');
str++;
} while (*str >= '0' && *str <= '9');
if (endp_r != NULL)
*endp_r = str;
*num_r = n;
return 0;
}
int str_to_uintmax(const char *str, uintmax_t *num_r)
{
const char *endp;
uintmax_t n;
int ret = str_parse_uintmax(str, &n, &endp);
if ((ret != 0) || (*endp != '\0'))
return -1;
*num_r = n;
return 0;
}
bool str_uint_equals(const char *str, uintmax_t num)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return FALSE;
return l == num;
}
/*
* Unsigned hexadecimal
*/
#define STR_PARSE_UHEX__TEMPLATE(name, type) \
int name(const char *str, type *num_r, const char **endp_r) \
{ \
uintmax_t l; \
if (str_parse_uintmax_hex(str, &l, endp_r) < 0 || l > (type)-1) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_PARSE_UHEX__TEMPLATE(str_parse_uint_hex, unsigned int)
STR_PARSE_UHEX__TEMPLATE(str_parse_ulong_hex, unsigned long)
STR_PARSE_UHEX__TEMPLATE(str_parse_ullong_hex, unsigned long long)
STR_PARSE_UHEX__TEMPLATE(str_parse_uint32_hex, uint32_t)
STR_PARSE_UHEX__TEMPLATE(str_parse_uint64_hex, uint64_t)
#define STR_TO_UHEX__TEMPLATE(name, type) \
int name(const char *str, type *num_r) \
{ \
uintmax_t l; \
if (str_to_uintmax_hex(str, &l) < 0 || l > (type)-1) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_TO_UHEX__TEMPLATE(str_to_uint_hex, unsigned int)
STR_TO_UHEX__TEMPLATE(str_to_ulong_hex, unsigned long)
STR_TO_UHEX__TEMPLATE(str_to_ullong_hex, unsigned long long)
STR_TO_UHEX__TEMPLATE(str_to_uint32_hex, uint32_t)
STR_TO_UHEX__TEMPLATE(str_to_uint64_hex, uint64_t)
static inline int _str_parse_hex(const char ch,
unsigned int *hex_r)
{
switch (ch) {
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
*hex_r = (unsigned int)(ch - 'a' + 10);
return 0;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
*hex_r = (unsigned int)(ch - 'A' + 10);
return 0;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
*hex_r = (unsigned int)(ch - '0');
return 0;
default:
break;
}
return -1;
}
int str_parse_uintmax_hex(const char *str, uintmax_t *num_r,
const char **endp_r)
{
unsigned int hex;
uintmax_t n = 0;
if (_str_parse_hex(*str, &hex) < 0)
return -1;
do {
if (n > (uintmax_t)-1 >> 4)
return -1;
n = (n << 4) + hex;
str++;
} while (_str_parse_hex(*str, &hex) >= 0);
if (endp_r != NULL)
*endp_r = str;
*num_r = n;
return 0;
}
int str_to_uintmax_hex(const char *str, uintmax_t *num_r)
{
const char *endp;
uintmax_t n;
int ret = str_parse_uintmax_hex(str, &n, &endp);
if ((ret != 0) || (*endp != '\0'))
return -1;
*num_r = n;
return 0;
}
/*
* Unsigned octal
*/
#define STR_PARSE_UOCT__TEMPLATE(name, type) \
int name(const char *str, type *num_r, const char **endp_r) \
{ \
uintmax_t l; \
if (str_parse_uintmax_oct(str, &l, endp_r) < 0 || l > (type)-1) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_PARSE_UOCT__TEMPLATE(str_parse_uint_oct, unsigned int)
STR_PARSE_UOCT__TEMPLATE(str_parse_ulong_oct, unsigned long)
STR_PARSE_UOCT__TEMPLATE(str_parse_ullong_oct, unsigned long long)
STR_PARSE_UOCT__TEMPLATE(str_parse_uint32_oct, uint32_t)
STR_PARSE_UOCT__TEMPLATE(str_parse_uint64_oct, uint64_t)
#define STR_TO_UOCT__TEMPLATE(name, type) \
int name(const char *str, type *num_r) \
{ \
uintmax_t l; \
if (str_to_uintmax_oct(str, &l) < 0 || l > (type)-1) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_TO_UOCT__TEMPLATE(str_to_uint_oct, unsigned int)
STR_TO_UOCT__TEMPLATE(str_to_ulong_oct, unsigned long)
STR_TO_UOCT__TEMPLATE(str_to_ullong_oct, unsigned long long)
STR_TO_UOCT__TEMPLATE(str_to_uint32_oct, uint32_t)
STR_TO_UOCT__TEMPLATE(str_to_uint64_oct, uint64_t)
int str_parse_uintmax_oct(const char *str, uintmax_t *num_r,
const char **endp_r)
{
uintmax_t n = 0;
if (*str < '0' || *str > '7')
return -1;
for (; *str >= '0' && *str <= '7'; str++) {
if (n > (uintmax_t)-1 >> 3)
return -1;
n = (n << 3) + (*str - '0');
}
if (endp_r != NULL)
*endp_r = str;
*num_r = n;
return 0;
}
int str_to_uintmax_oct(const char *str, uintmax_t *num_r)
{
const char *endp;
uintmax_t n;
int ret = str_parse_uintmax_oct(str, &n, &endp);
if ((ret != 0) || (*endp != '\0'))
return -1;
*num_r = n;
return 0;
}
/*
* Signed
*/
#define STR_PARSE_S__TEMPLATE(name, type, int_min, int_max) \
int name(const char *str, type *num_r, const char **endp_r) \
{ \
intmax_t l; \
if (str_parse_intmax(str, &l, endp_r) < 0) \
return -1; \
if (l < int_min || l > int_max) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_PARSE_S__TEMPLATE(str_parse_int, int, INT_MIN, INT_MAX)
STR_PARSE_S__TEMPLATE(str_parse_long, long, LONG_MIN, LONG_MAX)
STR_PARSE_S__TEMPLATE(str_parse_llong, long long, LLONG_MIN, LLONG_MAX)
STR_PARSE_S__TEMPLATE(str_parse_int32, int32_t, INT32_MIN, INT32_MAX)
STR_PARSE_S__TEMPLATE(str_parse_int64, int64_t, INT64_MIN, INT64_MAX)
#define STR_TO_S__TEMPLATE(name, type, int_min, int_max) \
int name(const char *str, type *num_r) \
{ \
intmax_t l; \
if (str_to_intmax(str, &l) < 0) \
return -1; \
if (l < int_min || l > int_max) \
return -1; \
*num_r = (type)l; \
return 0; \
}
STR_TO_S__TEMPLATE(str_to_int, int, INT_MIN, INT_MAX)
STR_TO_S__TEMPLATE(str_to_long, long, LONG_MIN, LONG_MAX)
STR_TO_S__TEMPLATE(str_to_llong, long long, LLONG_MIN, LLONG_MAX)
STR_TO_S__TEMPLATE(str_to_int32, int32_t, INT32_MIN, INT32_MAX)
STR_TO_S__TEMPLATE(str_to_int64, int64_t, INT64_MIN, INT64_MAX)
int ATTR_NO_SANITIZE_IMPLICIT_CONVERSION ATTR_NO_SANITIZE_INTEGER
str_parse_intmax(const char *str, intmax_t *num_r, const char **endp_r)
{
bool neg = FALSE;
uintmax_t l;
if (*str == '-') {
neg = TRUE;
str++;
}
if (str_parse_uintmax(str, &l, endp_r) < 0)
return -1;
if (!neg) {
if (l > INTMAX_MAX)
return -1;
*num_r = (intmax_t)l;
} else {
if (l > UINTMAX_MAX - (UINTMAX_MAX + INTMAX_MIN))
return -1;
*num_r = (intmax_t) UNSIGNED_MINUS(l);
}
return 0;
}
int str_to_intmax(const char *str, intmax_t *num_r)
{
const char *endp;
intmax_t n;
int ret = str_parse_intmax(str, &n, &endp);
if ((ret != 0) || (*endp != '\0'))
return -1;
*num_r = n;
return 0;
}
/*
* Special numeric types
*/
static int verify_xid(uintmax_t l, unsigned int result_size)
{
unsigned int result_bits;
/* we assume that result is a signed type,
but that it can never be negative */
result_bits = result_size*CHAR_BIT - 1;
if ((l >> result_bits) != 0)
return -1;
return 0;
}
int str_to_uid(const char *str, uid_t *num_r)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return -1;
if (verify_xid(l, sizeof(*num_r)) < 0)
return -1;
*num_r = (uid_t)l;
return 0;
}
int str_to_gid(const char *str, gid_t *num_r)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return -1;
/* OS X uses negative GIDs */
#ifndef __APPLE__
if (verify_xid(l, sizeof(*num_r)) < 0)
return -1;
#endif
*num_r = (gid_t)l;
return 0;
}
int str_to_pid(const char *str, pid_t *num_r)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return -1;
if (verify_xid(l, sizeof(*num_r)) < 0)
return -1;
*num_r = (pid_t)l;
return 0;
}
int str_to_ino(const char *str, ino_t *num_r)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return -1;
if (verify_xid(l, sizeof(*num_r)) < 0)
return -1;
*num_r = (ino_t)l;
return 0;
}
int str_to_uoff(const char *str, uoff_t *num_r)
{
uintmax_t l;
if (str_to_uintmax(str, &l) < 0)
return -1;
if (l > UOFF_T_MAX)
return -1;
*num_r = (uoff_t)l;
return 0;
}
int str_to_time(const char *str, time_t *num_r)
{
intmax_t l;
if (str_to_intmax(str, &l) < 0)
return -1;
*num_r = (time_t)l;
return 0;
}
STR_PARSE_U__TEMPLATE(str_parse_uoff, uoff_t)
/*
* Error handling
*/
const char *str_num_error(const char *str)
{
if (*str == '-') {
if (!str_is_numeric(str + 1, '\0'))
return "Not a valid number";
return "Number too small";
} else {
if (!str_is_numeric(str, '\0'))
return "Not a valid number";
return "Number too large";
}
}
dovecot-2.3.21.1/src/lib/safe-mkstemp.h 0000644 0000000 0000000 00000001157 14656633576 014423 0000000 0000000 #ifndef SAFE_MKSTEMP_H
#define SAFE_MKSTEMP_H
/* Create a new file with a given prefix. The string is updated to contain the
created filename. uid and gid can be (uid_t)-1 and (gid_t)-1 to use the
defaults. */
int safe_mkstemp(string_t *prefix, mode_t mode, uid_t uid, gid_t gid);
int safe_mkstemp_group(string_t *prefix, mode_t mode,
gid_t gid, const char *gid_origin);
/* Append host and PID to the prefix. */
int safe_mkstemp_hostpid(string_t *prefix, mode_t mode, uid_t uid, gid_t gid);
int safe_mkstemp_hostpid_group(string_t *prefix, mode_t mode,
gid_t gid, const char *gid_origin);
#endif
dovecot-2.3.21.1/src/lib/test-event-flatten.c 0000644 0000000 0000000 00000021053 14656633576 015550 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "ioloop.h"
#include "time-util.h"
#include "lib-event-private.h"
#include "failures-private.h"
#include "array.h"
#include "str.h"
#define CHECK_FLATTEN_SAME(e) \
check_event_same(event_flatten(e), (e))
#define CHECK_FLATTEN_DIFF(e, c, nc, f, nf) \
check_event_diff(event_flatten(e), (e), \
(c), (nc), \
(f), (nf))
static struct event_category cats[] = {
{ .name = "cat0", },
{ .name = "cat1", },
};
static void check_event_diff_cats(struct event_category *const *got,
unsigned int ngot, const char **exp,
unsigned int nexp)
{
unsigned int i;
test_assert(ngot == nexp);
for (i = 0; i < nexp; i++)
test_assert(strcmp(got[i]->name, exp[i]) == 0);
}
static void check_event_diff_fields(const struct event_field *got, unsigned int ngot,
const struct event_field *exp, unsigned int nexp)
{
unsigned int i;
const char *got_str;
test_assert(ngot == nexp);
for (i = 0; i < nexp; i++) {
if (got[i].value_type != exp[i].value_type) {
test_assert(FALSE);
continue;
}
switch (exp[i].value_type) {
case EVENT_FIELD_VALUE_TYPE_STR:
test_assert(strcmp(exp[i].value.str,
got[i].value.str) == 0);
break;
case EVENT_FIELD_VALUE_TYPE_INTMAX:
test_assert(exp[i].value.intmax == got[i].value.intmax);
break;
case EVENT_FIELD_VALUE_TYPE_TIMEVAL:
test_assert(timeval_cmp(&exp[i].value.timeval,
&got[i].value.timeval) == 0);
break;
case EVENT_FIELD_VALUE_TYPE_STRLIST:
got_str = t_array_const_string_join(&got[i].value.strlist, ",");
test_assert_strcmp(exp[i].value.str, got_str);
break;
}
}
}
static void check_event_diff(struct event *e, struct event *orig,
const char **expected_cats,
unsigned int num_expected_cats,
const struct event_field *expected_fields,
unsigned int num_expected_fields)
{
struct event_category *const *cats;
const struct event_field *fields;
unsigned int num_cats;
unsigned int num_fields;
test_assert(e != orig);
test_assert(e->parent == NULL);
/* different pointers implies different ids */
test_assert(e->id != orig->id); /* TODO: does this make sense? */
test_assert(timeval_cmp(&e->tv_created_ioloop, &orig->tv_created_ioloop) == 0);
test_assert(timeval_cmp(&e->tv_created, &orig->tv_created) == 0);
test_assert(timeval_cmp(&e->tv_last_sent, &orig->tv_last_sent) == 0);
test_assert(strcmp(e->source_filename, orig->source_filename) == 0);
test_assert(e->source_linenum == orig->source_linenum);
/* FIXME: check sending name? */
cats = event_get_categories(e, &num_cats);
check_event_diff_cats(cats, num_cats,
expected_cats, num_expected_cats);
fields = event_get_fields(e, &num_fields);
check_event_diff_fields(fields, num_fields,
expected_fields, num_expected_fields);
event_unref(&e);
}
static void check_event_same(struct event *e, struct event *orig)
{
test_assert(e == orig);
/* the pointers are the same; nothing can possibly differ */
event_unref(&e);
}
static void test_event_flatten_no_parent(void)
{
struct event *e;
test_begin("event flatten: no parent");
e = event_create(NULL);
CHECK_FLATTEN_SAME(e);
event_add_int(e, "abc", 4);
CHECK_FLATTEN_SAME(e);
event_add_int(e, "def", 2);
CHECK_FLATTEN_SAME(e);
event_add_str(e, "abc", "foo");
CHECK_FLATTEN_SAME(e);
event_add_category(e, &cats[0]);
CHECK_FLATTEN_SAME(e);
event_unref(&e);
test_end();
}
static void test_event_flatten_one_parent(void)
{
static const char *exp_1cat[] = {
"cat0",
};
static const char *exp_2cat[] = {
"cat1",
"cat0",
};
static struct event_field exp_int = {
.key = "abc",
.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX,
.value = {
.str = NULL,
.intmax = 42,
.timeval = {0,0},
}
};
static struct event_field exp_2int[2] = {
{
.key = "abc",
.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX,
.value = {
.intmax = 42,
.str = NULL,
.timeval = {0,0},
}
},
{
.key = "def",
.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX,
.value = {
.intmax = 49,
.str = NULL,
.timeval = {0,0},
}
},
};
static struct event_field exp_1str1int[2] = {
{
.key = "abc",
.value_type = EVENT_FIELD_VALUE_TYPE_STR,
.value = {
.str = "foo",
.intmax = 0,
.timeval = {0,0},
}
},
{
.key = "def",
.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX,
.value = {
.intmax = 49,
.str = NULL,
.timeval = {0,0},
}
},
};
static struct event_field exp_1str1int1strlist[3] = {
{
.key = "abc",
.value_type = EVENT_FIELD_VALUE_TYPE_STR,
.value = {
.str = "foo",
.intmax = 0,
.timeval = {0,0},
}
},
{
.key = "def",
.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX,
.value = {
.intmax = 49,
.str = NULL,
.timeval = {0,0},
}
},
{
.key = "cba",
.value_type = EVENT_FIELD_VALUE_TYPE_STRLIST,
.value = {
.str = "one,two,three",
},
},
};
struct event *parent;
struct event *e;
test_begin("event flatten: one parent");
t_array_init(&exp_1str1int1strlist[0].value.strlist, 3);
const char *str = "one";
array_push_back(&exp_1str1int1strlist[0].value.strlist, &str);
str = "two";
array_push_back(&exp_1str1int1strlist[0].value.strlist, &str);
str = "three";
array_push_back(&exp_1str1int1strlist[0].value.strlist, &str);
parent = event_create(NULL);
e = event_create(parent);
CHECK_FLATTEN_DIFF(e, NULL, 0, NULL, 0);
event_add_int(e, "abc", 42);
CHECK_FLATTEN_DIFF(e, NULL, 0, &exp_int, 1);
event_add_int(e, "def", 49);
CHECK_FLATTEN_DIFF(e, NULL, 0, exp_2int, 2);
event_add_str(e, "abc", "foo");
CHECK_FLATTEN_DIFF(e, NULL, 0, exp_1str1int, 2);
event_add_category(e, &cats[0]);
CHECK_FLATTEN_DIFF(e, exp_1cat, 1, exp_1str1int, 2);
event_add_category(e, &cats[1]);
CHECK_FLATTEN_DIFF(e, exp_2cat, 2, exp_1str1int, 2);
event_strlist_append(e, "cba", "one");
event_strlist_append(e, "cba", "two");
event_strlist_append(e, "cba", "three");
CHECK_FLATTEN_DIFF(e, exp_2cat, 2, exp_1str1int1strlist, 3);
event_unref(&e);
event_unref(&parent);
test_end();
}
static void test_event_flatten_override_parent_field(void)
{
static struct event_field exp_int = {
.key = "abc",
.value_type = EVENT_FIELD_VALUE_TYPE_INTMAX,
.value = {
.intmax = 42,
.str = NULL,
.timeval = {0,0},
}
};
static struct event_field exp_str = {
.key = "abc",
.value_type = EVENT_FIELD_VALUE_TYPE_STR,
.value = {
.str = "def",
.intmax = 0,
.timeval = {0,0},
}
};
static struct event_field exp_2str[2] = {
{
.key = "abc",
.value_type = EVENT_FIELD_VALUE_TYPE_STR,
.value = {
.str = "def",
.intmax = 0,
.timeval = {0,0},
}
},
{
.key = "foo",
.value_type = EVENT_FIELD_VALUE_TYPE_STR,
.value = {
.str = "bar",
.intmax = 0,
.timeval = {0,0},
}
},
};
struct event *parent;
struct event *e;
test_begin("event flatten: override parent field");
parent = event_create(NULL);
event_add_int(parent, "abc", 5);
e = event_create(parent);
event_add_int(e, "abc", 42);
CHECK_FLATTEN_DIFF(e, NULL, 0, &exp_int, 1);
event_add_str(e, "abc", "def");
CHECK_FLATTEN_DIFF(e, NULL, 0, &exp_str, 1);
event_add_str(parent, "foo", "bar");
CHECK_FLATTEN_DIFF(e, NULL, 0, exp_2str, 2);
event_unref(&e);
event_unref(&parent);
test_end();
}
static void test_event_strlist_flatten(void)
{
test_begin("event flatten: strlist");
struct event *l1 = event_create(NULL);
event_strlist_append(l1, "test", "l3");
struct event *l2 = event_create(l1);
event_strlist_append(l2, "test", "l1");
struct event *l3 = event_create(l2);
unsigned int line = __LINE__ - 1;
event_strlist_append(l3, "test", "l2");
string_t *dest = t_str_new(32);
struct event *event = event_flatten(l3);
event_export(event, dest);
/* see if it matches .. */
const char *reference = t_strdup_printf("%"PRIdTIME_T"\t%u"
"\ts"__FILE__
"\t%u\tLtest\t3\tl3\tl1\tl2",
event->tv_created.tv_sec,
(unsigned int)event->tv_created.tv_usec,
line);
test_assert_strcmp(str_c(dest), reference);
/* these should not end up duplicated */
event_strlist_append(event, "test", "l1");
event_strlist_append(event, "test", "l2");
event_strlist_append(event, "test", "l3");
/* and export should look the same */
str_truncate(dest, 0);
event_export(event, dest);
test_assert_strcmp(str_c(dest), reference);
event_unref(&event);
/* export event */
event_unref(&l3);
event_unref(&l2);
event_unref(&l1);
test_end();
}
void test_event_flatten(void)
{
test_event_flatten_no_parent();
test_event_flatten_one_parent();
test_event_flatten_override_parent_field();
test_event_strlist_flatten();
}
dovecot-2.3.21.1/src/lib/sort.h 0000644 0000000 0000000 00000001767 14656633576 013025 0000000 0000000 #ifndef SORT_H
#define SORT_H
#define INTEGER_CMP(name, type) \
static inline int name(const type *i1, const type *i2) \
{ \
if (*i1 < *i2) \
return -1; \
else if (*i1 > *i2) \
return 1; \
else \
return 0; \
}
INTEGER_CMP(uint64_cmp, uint64_t)
INTEGER_CMP(uint32_cmp, uint32_t)
#define i_qsort(base, nmemb, size, cmp) \
qsort(base, nmemb, size - \
CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*base) *), \
typeof(const typeof(*base) *))), \
(int (*)(const void *, const void *))cmp)
#define i_bsearch(key, base, nmemb, size, cmp) \
bsearch(key, base, nmemb, size - \
CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*key) *), \
typeof(const typeof(*base) *))), \
(int (*)(const void *, const void *))cmp)
int bsearch_strcmp(const char *key, const char *const *member) ATTR_PURE;
int bsearch_strcasecmp(const char *key, const char *const *member) ATTR_PURE;
#endif
dovecot-2.3.21.1/src/lib/test-hmac.c 0000644 0000000 0000000 00000050462 14656633576 013712 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "hash-method.h"
#include "hmac.h"
#include "sha-common.h"
#include "buffer.h"
#include "hex-binary.h"
struct test_vector {
const char *prf;
const unsigned char *key;
size_t key_len;
const unsigned char *data;
size_t data_len;
const unsigned char *res;
size_t res_len;
};
#define TEST_BUF(x) (const unsigned char*)x, sizeof(x)-1
/* RFC 4231 test vectors */
static const struct test_vector test_vectors[] = {
/* Test Case 1 */
{ "sha256",
TEST_BUF("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
TEST_BUF("Hi There"),
TEST_BUF("\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7")
},
/* Test Case 2 */
{ "sha256",
TEST_BUF("\x4a\x65\x66\x65"), /* "Jefe" */
TEST_BUF("what do ya want for nothing?"),
TEST_BUF("\x5b\xdc\xc1\x46\xbf\x60\x75\x4e\x6a\x04\x24\x26\x08\x95\x75\xc7\x5a\x00\x3f\x08\x9d\x27\x39\x83\x9d\xec\x58\xb9\x64\xec\x38\x43")
},
/* Test Case 3 */
{ "sha256",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"),
TEST_BUF("\x77\x3e\xa9\x1e\x36\x80\x0e\x46\x85\x4d\xb8\xeb\xd0\x91\x81\xa7\x29\x59\x09\x8b\x3e\xf8\xc1\x22\xd9\x63\x55\x14\xce\xd5\x65\xfe")
},
/* Test Case 4 */
{ "sha256",
TEST_BUF("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19"),
TEST_BUF("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
TEST_BUF("\x82\x55\x8a\x38\x9a\x44\x3c\x0e\xa4\xcc\x81\x98\x99\xf2\x08\x3a\x85\xf0\xfa\xa3\xe5\x78\xf8\x07\x7a\x2e\x3f\xf4\x67\x29\x66\x5b")
},
/* Test Case 5 */
{ "sha256",
TEST_BUF("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
TEST_BUF("\x54\x65\x73\x74\x20\x57\x69\x74\x68\x20\x54\x72\x75\x6e\x63\x61\x74\x69\x6f\x6e"), /* "Test With Truncation" */
TEST_BUF("\xa3\xb6\x16\x74\x73\x10\x0e\xe0\x6e\x0c\x79\x6c\x29\x55\x55\x2b")
},
/* Test Case 6 */
{ "sha256",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74"), /* "Test Using Larger Than Block-Size Key - Hash Key First" */
TEST_BUF("\x60\xe4\x31\x59\x1e\xe0\xb6\x7f\x0d\x8a\x26\xaa\xcb\xf5\xb7\x7f\x8e\x0b\xc6\x21\x37\x28\xc5\x14\x05\x46\x04\x0f\x0e\xe3\x7f\x54")
},
/* Test Case 7 */
{ "sha256",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e"),
/* "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." */
TEST_BUF("\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2")
}
};
static const struct test_vector test_vectors_hmac384[] = {
/* Test Case 1 */
{ "sha384",
TEST_BUF("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
TEST_BUF("Hi There"),
TEST_BUF("\xaf\xd0\x39\x44\xd8\x48\x95\x62\x6b\x08\x25\xf4\xab\x46\x90\x7f\x15\xf9\xda\xdb\xe4\x10\x1e\xc6\x82\xaa\x03\x4c\x7c\xeb\xc5\x9c\xfa\xea\x9e\xa9\x07\x6e\xde\x7f\x4a\xf1\x52\xe8\xb2\xfa\x9c\xb6"),
},
/* Test Case 2 */
{ "sha384",
TEST_BUF("\x4a\x65\x66\x65"), /* "Jefe" */
TEST_BUF("what do ya want for nothing?"),
TEST_BUF("\xaf\x45\xd2\xe3\x76\x48\x40\x31\x61\x7f\x78\xd2\xb5\x8a\x6b\x1b\x9c\x7e\xf4\x64\xf5\xa0\x1b\x47\xe4\x2e\xc3\x73\x63\x22\x44\x5e\x8e\x22\x40\xca\x5e\x69\xe2\xc7\x8b\x32\x39\xec\xfa\xb2\x16\x49"),
},
/* Test Case 3 */
{ "sha384",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"),
TEST_BUF("\x88\x06\x26\x08\xd3\xe6\xad\x8a\x0a\xa2\xac\xe0\x14\xc8\xa8\x6f\x0a\xa6\x35\xd9\x47\xac\x9f\xeb\xe8\x3e\xf4\xe5\x59\x66\x14\x4b\x2a\x5a\xb3\x9d\xc1\x38\x14\xb9\x4e\x3a\xb6\xe1\x01\xa3\x4f\x27"),
},
/* Test Case 4 */
{ "sha384",
TEST_BUF("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19"),
TEST_BUF("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
TEST_BUF("\x3e\x8a\x69\xb7\x78\x3c\x25\x85\x19\x33\xab\x62\x90\xaf\x6c\xa7\x7a\x99\x81\x48\x08\x50\x00\x9c\xc5\x57\x7c\x6e\x1f\x57\x3b\x4e\x68\x01\xdd\x23\xc4\xa7\xd6\x79\xcc\xf8\xa3\x86\xc6\x74\xcf\xfb"),
},
/* Test Case 5 */
{ "sha384",
TEST_BUF("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
TEST_BUF("\x54\x65\x73\x74\x20\x57\x69\x74\x68\x20\x54\x72\x75\x6e\x63\x61\x74\x69\x6f\x6e"), /* "Test With Truncation" */
TEST_BUF("\x3a\xbf\x34\xc3\x50\x3b\x2a\x23\xa4\x6e\xfc\x61\x9b\xae\xf8\x97"),
},
/* Test Case 6 */
{ "sha384",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74"), /* "Test Using Larger Than Block-Size Key - Hash Key First" */
TEST_BUF("\x4e\xce\x08\x44\x85\x81\x3e\x90\x88\xd2\xc6\x3a\x04\x1b\xc5\xb4\x4f\x9e\xf1\x01\x2a\x2b\x58\x8f\x3c\xd1\x1f\x05\x03\x3a\xc4\xc6\x0c\x2e\xf6\xab\x40\x30\xfe\x82\x96\x24\x8d\xf1\x63\xf4\x49\x52"),
},
/* Test Case 7 */
{ "sha384",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e"),
/* "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." */
TEST_BUF("\x66\x17\x17\x8e\x94\x1f\x02\x0d\x35\x1e\x2f\x25\x4e\x8f\xd3\x2c\x60\x24\x20\xfe\xb0\xb8\xfb\x9a\xdc\xce\xbb\x82\x46\x1e\x99\xc5\xa6\x78\xcc\x31\xe7\x99\x17\x6d\x38\x60\xe6\x11\x0c\x46\x52\x3e"),
}
};
static const struct test_vector test_vectors_hmac512[] = {
/* Test Case 1 */
{ "sha512",
TEST_BUF("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
TEST_BUF("Hi There"),
TEST_BUF("\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0\xb3\x05\x45\xe1\x7c\xde\xda\xa8\x33\xb7\xd6\xb8\xa7\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4\xbe\x9d\x91\x4e\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54")
},
/* Test Case 2 */
{ "sha512",
TEST_BUF("\x4a\x65\x66\x65"), /* "Jefe" */
TEST_BUF("what do ya want for nothing?"),
TEST_BUF("\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3\x87\xbd\x64\x22\x2e\x83\x1f\xd6\x10\x27\x0c\xd7\xea\x25\x05\x54\x97\x58\xbf\x75\xc0\x5a\x99\x4a\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b\x63\x6e\x07\x0a\x38\xbc\xe7\x37")
},
/* Test Case 3 */
{ "sha512",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd"),
TEST_BUF("\xfa\x73\xb0\x08\x9d\x56\xa2\x84\xef\xb0\xf0\x75\x6c\x89\x0b\xe9\xb1\xb5\xdb\xdd\x8e\xe8\x1a\x36\x55\xf8\x3e\x33\xb2\x27\x9d\x39\xbf\x3e\x84\x82\x79\xa7\x22\xc8\x06\xb4\x85\xa4\x7e\x67\xc8\x07\xb9\x46\xa3\x37\xbe\xe8\x94\x26\x74\x27\x88\x59\xe1\x32\x92\xfb")
},
/* Test Case 4 */
{ "sha512",
TEST_BUF("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19"),
TEST_BUF("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"),
TEST_BUF("\xb0\xba\x46\x56\x37\x45\x8c\x69\x90\xe5\xa8\xc5\xf6\x1d\x4a\xf7\xe5\x76\xd9\x7f\xf9\x4b\x87\x2d\xe7\x6f\x80\x50\x36\x1e\xe3\xdb\xa9\x1c\xa5\xc1\x1a\xa2\x5e\xb4\xd6\x79\x27\x5c\xc5\x78\x80\x63\xa5\xf1\x97\x41\x12\x0c\x4f\x2d\xe2\xad\xeb\xeb\x10\xa2\x98\xdd")
},
/* Test Case 5 */
{ "sha512",
TEST_BUF("\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c"),
TEST_BUF("\x54\x65\x73\x74\x20\x57\x69\x74\x68\x20\x54\x72\x75\x6e\x63\x61\x74\x69\x6f\x6e"), /* "Test With Truncation" */
TEST_BUF("\x41\x5f\xad\x62\x71\x58\x0a\x53\x1d\x41\x79\xbc\x89\x1d\x87\xa6")
},
/* Test Case 6 */
{ "sha512",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74"), /* "Test Using Larger Than Block-Size Key - Hash Key First" */
TEST_BUF("\x80\xb2\x42\x63\xc7\xc1\xa3\xeb\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1\x12\x1b\x01\x37\x83\xf8\xf3\x52\x6b\x56\xd0\x37\xe0\x5f\x25\x98\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52\x95\xe6\x4f\x73\xf6\x3f\x0a\xec\x8b\x91\x5a\x98\x5d\x78\x65\x98")
},
/* Test Case 7 */
{ "sha512",
TEST_BUF("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"),
TEST_BUF("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e"),
/* "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." */
TEST_BUF("\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44\xb6\x02\x2c\xac\x3c\x49\x82\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58")
}
};
/* RFC 5869 test vectors */
static const struct test_vector_5869 {
const char *prf;
const unsigned char *ikm;
size_t ikm_len;
const unsigned char *salt;
size_t salt_len;
const unsigned char *info;
size_t info_len;
const unsigned char *okm;
size_t okm_len;
} test_vectors_5869[] = {
{ "sha256",
TEST_BUF("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
TEST_BUF("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c"),
TEST_BUF("\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9"),
TEST_BUF("\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36\x2f\x2a\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65")
},
{ "sha256",
TEST_BUF("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"),
TEST_BUF("\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"),
TEST_BUF("\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"),
TEST_BUF("\xb1\x1e\x39\x8d\xc8\x03\x27\xa1\xc8\xe7\xf7\x8c\x59\x6a\x49\x34\x4f\x01\x2e\xda\x2d\x4e\xfa\xd8\xa0\x50\xcc\x4c\x19\xaf\xa9\x7c\x59\x04\x5a\x99\xca\xc7\x82\x72\x71\xcb\x41\xc6\x5e\x59\x0e\x09\xda\x32\x75\x60\x0c\x2f\x09\xb8\x36\x77\x93\xa9\xac\xa3\xdb\x71\xcc\x30\xc5\x81\x79\xec\x3e\x87\xc1\x4c\x01\xd5\xc1\xf3\x43\x4f\x1d\x87")
},
{ "sha256",
TEST_BUF("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
TEST_BUF(""),
TEST_BUF(""),
TEST_BUF("\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f\x71\x5f\x80\x2a\x06\x3c\x5a\x31\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d\x9d\x20\x13\x95\xfa\xa4\xb6\x1a\x96\xc8")
},
/* should be equal to above */
{ "sha256",
TEST_BUF("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
NULL, 0,
NULL, 0,
TEST_BUF("\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f\x71\x5f\x80\x2a\x06\x3c\x5a\x31\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d\x9d\x20\x13\x95\xfa\xa4\xb6\x1a\x96\xc8")
},
};
static void test_hmac_rfc(void)
{
test_begin("hmac sha256 rfc4231 vectors");
for(size_t i = 0; i < N_ELEMENTS(test_vectors); i++) {
const struct test_vector *vec = &(test_vectors[i]);
struct hmac_context ctx;
hmac_init(&ctx, vec->key, vec->key_len, hash_method_lookup(vec->prf));
hmac_update(&ctx, vec->data, vec->data_len);
unsigned char res[SHA256_RESULTLEN];
hmac_final(&ctx, res);
test_assert_idx(memcmp(res, vec->res, vec->res_len) == 0, i);
}
test_end();
}
static void test_hmac384_rfc(void)
{
test_begin("hmac sha384 rfc4231 vectors");
for (size_t i = 0; i < N_ELEMENTS(test_vectors_hmac384); i++) {
const struct test_vector *vec = &(test_vectors_hmac384[i]);
struct hmac_context ctx;
hmac_init(&ctx, vec->key, vec->key_len, hash_method_lookup(vec->prf));
hmac_update(&ctx, vec->data, vec->data_len);
unsigned char res[SHA384_RESULTLEN];
hmac_final(&ctx, res);
test_assert_idx(memcmp(res, vec->res, vec->res_len) == 0, i);
}
test_end();
}
static void test_hmac512_rfc(void)
{
test_begin("hmac sha512 rfc4231 vectors");
for (size_t i = 0; i < N_ELEMENTS(test_vectors_hmac512); i++) {
const struct test_vector *vec = &(test_vectors_hmac512[i]);
struct hmac_context ctx;
hmac_init(&ctx, vec->key, vec->key_len, hash_method_lookup(vec->prf));
hmac_update(&ctx, vec->data, vec->data_len);
unsigned char res[SHA512_RESULTLEN];
hmac_final(&ctx, res);
test_assert_idx(memcmp(res, vec->res, vec->res_len) == 0, i);
}
test_end();
}
static void test_hmac_buffer(void)
{
const struct test_vector *vec = &(test_vectors[0]);
test_begin("hmac temporary buffer");
buffer_t *tmp;
tmp = t_hmac_data(hash_method_lookup(vec->prf), vec->key, vec->key_len,
vec->data, vec->data_len);
test_assert(tmp->used == vec->res_len &&
memcmp(tmp->data, vec->res, vec->res_len) == 0);
test_end();
}
static void test_hkdf_rfc(void)
{
test_begin("hkdf sha256 rfc5869 vectors");
buffer_t *res = t_buffer_create(82);
for(size_t i = 0; i < N_ELEMENTS(test_vectors_5869); i++) {
buffer_set_used_size(res, 0);
const struct test_vector_5869 *vec = &(test_vectors_5869[i]);
const struct hash_method *m = hash_method_lookup(vec->prf);
hmac_hkdf(m, vec->salt, vec->salt_len, vec->ikm, vec->ikm_len,
vec->info, vec->info_len, res, vec->okm_len);
test_assert_idx(memcmp(res->data, vec->okm, vec->okm_len) == 0, i);
}
test_end();
}
static void test_hkdf_buffer(void)
{
test_begin("hkdf temporary buffer");
const struct test_vector_5869 *vec = &(test_vectors_5869[0]);
const struct hash_method *m = hash_method_lookup(vec->prf);
buffer_t *tmp = t_hmac_hkdf(m, vec->salt, vec->salt_len, vec->ikm,
vec->ikm_len, vec->info, vec->info_len,
vec->okm_len);
test_assert(tmp->used == vec->okm_len &&
memcmp(tmp->data, vec->okm, vec->okm_len) == 0);
test_end();
}
void test_hmac(void)
{
test_hmac_rfc();
test_hmac384_rfc();
test_hmac512_rfc();
test_hmac_buffer();
test_hkdf_rfc();
test_hkdf_buffer();
}
dovecot-2.3.21.1/src/lib/fd-util.h 0000644 0000000 0000000 00000002045 14656633576 013370 0000000 0000000 #ifndef FD_UTIL_H
#define FD_UTIL_H
/* Change close-on-exec flag of fd. */
void fd_close_on_exec(int fd, bool set);
/* Verify that fds in given range don't exist. */
void fd_debug_verify_leaks(int first_fd, int last_fd);
/* Set file descriptor to blocking/nonblocking state */
void fd_set_nonblock(int fd, bool nonblock);
/* Close fd_in and fd_out, unless they're already -1. They can point to the
same fd, in which case they're closed only once. If they point to stdin
or stdout, they're replaced with /dev/null. */
void fd_close_maybe_stdio(int *fd_in, int *fd_out);
/* Close the fd and set it to -1. This assert-crashes if fd == 0, and is a
no-op if fd == -1. Normally fd == 0 would happen only if an uninitialized
fd is attempted to be closed, which is a bug. */
void i_close_fd_path(int *fd, const char *path, const char *arg,
const char *func, const char *file, int line);
#define i_close_fd_path(fd, path) i_close_fd_path((fd), (path), #fd, __func__, __FILE__, __LINE__)
#define i_close_fd(fd) i_close_fd_path((fd), NULL)
#endif
dovecot-2.3.21.1/src/lib/test-iostream-pump.c 0000644 0000000 0000000 00000017746 14656633576 015614 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "istream.h"
#include "ostream.h"
#include "buffer.h"
#include "str.h"
#include "ioloop.h"
#include "iostream-pump.h"
#include "istream-failure-at.h"
#include "ostream-failure-at.h"
#include
#include
#include
struct nonblock_ctx {
struct istream *in;
struct ostream *out;
uoff_t pos, max_size;
};
static unsigned char data[] = "hello, world";
static void completed(enum iostream_pump_status status, int *u0)
{
/* to somehow discern between error and success .. */
(*u0) -= (status == IOSTREAM_PUMP_STATUS_INPUT_EOF ? 1 : 2);
io_loop_stop(current_ioloop);
}
static void failed(int *u0)
{
*u0 = -1; /* ensure failure */
io_loop_stop(current_ioloop);
}
static void pump_nonblocking_timeout(struct nonblock_ctx *ctx)
{
switch (ctx->pos % 4) {
case 0:
break;
case 1:
/* allow more input */
if (ctx->in->blocking)
break;
if (ctx->pos/4 == ctx->max_size+1)
test_istream_set_allow_eof(ctx->in, TRUE);
else
test_istream_set_size(ctx->in, ctx->pos/4);
i_stream_set_input_pending(ctx->in, TRUE);
break;
case 2:
break;
case 3: {
/* allow more output. give always one byte less than the
input size so there's something in internal buffer. */
if (ctx->out->blocking)
break;
size_t size = ctx->pos/4;
if (size > 0)
test_ostream_set_max_output_size(ctx->out, size-1);
break;
}
}
ctx->pos++;
}
static const char *
run_pump(struct istream *in, struct ostream *out, int *counter,
buffer_t *out_buffer)
{
struct iostream_pump *pump;
struct ioloop *ioloop = io_loop_create();
io_loop_set_current(ioloop);
struct nonblock_ctx ctx = { in, out, 0, 0 };
struct timeout *to2 = NULL;
if (!in->blocking) {
test_assert(i_stream_get_size(in, TRUE, &ctx.max_size) > 0);
test_istream_set_size(in, 0);
test_istream_set_allow_eof(in, FALSE);
}
if (!out->blocking) {
test_ostream_set_max_output_size(out, 0);
}
if (!in->blocking || !out->blocking) {
to2 = timeout_add_short(0, pump_nonblocking_timeout, &ctx);
}
pump = iostream_pump_create(in, out);
i_stream_unref(&in);
o_stream_unref(&out);
iostream_pump_set_completion_callback(pump, completed, counter);
iostream_pump_start(pump);
alarm(5);
struct timeout *to = timeout_add(3000, failed, counter);
io_loop_run(current_ioloop);
timeout_remove(&to);
timeout_remove(&to2);
alarm(0);
test_assert(*counter == 0);
if (!ctx.out->blocking && ctx.in->stream_errno != 0 &&
ctx.out->stream_errno == 0) {
/* input failed, finish flushing output */
test_ostream_set_max_output_size(ctx.out, SIZE_MAX);
test_assert(o_stream_flush(ctx.out) > 0);
} else {
test_assert(o_stream_flush(ctx.out) != 0);
}
const char *ret = t_strdup(str_c(out_buffer));
iostream_pump_unref(&pump);
io_loop_destroy(&ioloop);
return ret;
}
static void
test_iostream_setup(bool in_block, bool out_block,
struct istream **in_r, struct ostream **out_r,
buffer_t **out_buffer_r)
{
*out_buffer_r = t_buffer_create(128);
*in_r = test_istream_create_data(data, sizeof(data));
(*in_r)->blocking = in_block;
if (out_block)
*out_r = test_ostream_create(*out_buffer_r);
else
*out_r = test_ostream_create_nonblocking(*out_buffer_r, 1);
}
static void
test_iostream_pump_simple(bool in_block, bool out_block)
{
int counter;
struct istream *in;
struct ostream *out;
buffer_t *buffer;
test_begin(t_strdup_printf("iostream_pump "
"(in=%sblocking, out=%sblocking)",
(in_block ? "" : "non-"),
(out_block ? "" : "non-")));
test_iostream_setup(in_block, out_block, &in, &out, &buffer);
counter = 1;
test_assert(strcmp(run_pump(in, out, &counter, buffer),
"hello, world") == 0);
test_end();
}
static void
test_iostream_pump_failure_start_read(bool in_block, bool out_block)
{
int counter;
struct istream *in, *in_2;
struct ostream *out;
buffer_t *buffer;
test_begin(t_strdup_printf("iostream_pump failure start-read "
"(in=%sblocking, out=%sblocking)",
(in_block ? "" : "non-"),
(out_block ? "" : "non-")));
test_iostream_setup(in_block, out_block, &in_2, &out, &buffer);
in = i_stream_create_failure_at(in_2, 0, EIO, "test pump fail");
i_stream_unref(&in_2);
counter = 2;
test_assert(strcmp(run_pump(in, out, &counter, buffer), "") == 0);
test_end();
}
static void
test_iostream_pump_failure_mid_read(bool in_block, bool out_block)
{
int counter;
struct istream *in, *in_2;
struct ostream *out;
buffer_t *buffer;
test_begin(t_strdup_printf("iostream_pump failure mid-read "
"(in=%sblocking, out=%sblocking)",
(in_block ? "" : "non-"),
(out_block ? "" : "non-")));
test_iostream_setup(in_block, out_block, &in_2, &out, &buffer);
in = i_stream_create_failure_at(in_2, 4, EIO, "test pump fail");
i_stream_unref(&in_2);
counter = 2;
test_assert(strcmp(run_pump(in, out, &counter, buffer), "hell") == 0);
test_end();
}
static void
test_iostream_pump_failure_end_read(bool in_block, bool out_block)
{
int counter;
struct istream *in, *in_2;
struct ostream *out;
buffer_t *buffer;
test_begin(t_strdup_printf("iostream_pump failure mid-read "
"(in=%sblocking, out=%sblocking)",
(in_block ? "" : "non-"),
(out_block ? "" : "non-")));
test_iostream_setup(in_block, out_block, &in_2, &out, &buffer);
in = i_stream_create_failure_at_eof(in_2, EIO, "test pump fail");
i_stream_unref(&in_2);
counter = 2;
test_assert(strcmp(run_pump(in, out, &counter, buffer),
"hello, world") == 0);
test_end();
}
static void
test_iostream_pump_failure_start_write(bool in_block, bool out_block)
{
int counter;
struct istream *in;
struct ostream *out, *out_2;
buffer_t *buffer;
test_begin(t_strdup_printf("iostream_pump failure start-write "
"(in=%sblocking, out=%sblocking)",
(in_block ? "" : "non-"),
(out_block ? "" : "non-")));
test_iostream_setup(in_block, out_block, &in, &out_2, &buffer);
out = o_stream_create_failure_at(out_2, 0, "test pump fail");
o_stream_unref(&out_2);
counter = 2;
test_assert(strcmp(run_pump(in, out, &counter, buffer), "") == 0);
test_end();
}
static void
test_iostream_pump_failure_mid_write(bool in_block, bool out_block)
{
int counter;
struct istream *in;
struct ostream *out, *out_2;
buffer_t *buffer;
test_begin(t_strdup_printf("iostream_pump failure mid-write "
"(in=%sblocking, out=%sblocking)",
(in_block ? "" : "non-"),
(out_block ? "" : "non-")));
test_iostream_setup(in_block, out_block, &in, &out_2, &buffer);
out = o_stream_create_failure_at(out_2, 4, "test pump fail");
o_stream_unref(&out_2);
counter = 2;
/* "hel" because the last byte is only in internal buffer */
test_assert(strcmp(run_pump(in, out, &counter, buffer),
(out_block ? (in_block ? "" : "hell") :
"hel")) == 0);
test_end();
}
static void
test_iostream_pump_failure_end_write(bool in_block, bool out_block)
{
int counter;
struct istream *in;
struct ostream *out, *out_2;
buffer_t *buffer;
if (!out_block || !in_block) {
/* we'll get flushes constantly */
return;
}
test_begin("iostream_pump failure end-write (blocking)");
test_iostream_setup(in_block, out_block, &in, &out_2, &buffer);
out = o_stream_create_failure_at_flush(out_2, "test pump fail");
o_stream_unref(&out_2);
counter = 2;
test_assert(strcmp(run_pump(in, out, &counter, buffer),
"hello, world") == 0);
test_end();
}
static void
test_iostream_pump_real(void)
{
for(int i = 0; i < 3; i++) {
bool in_block = ((i & BIT(0)) != 0);
bool out_block = ((i & BIT(1)) != 0);
test_iostream_pump_simple(in_block, out_block);
test_iostream_pump_failure_start_read(in_block, out_block);
test_iostream_pump_failure_mid_read(in_block, out_block);
test_iostream_pump_failure_end_read(in_block, out_block);
test_iostream_pump_failure_start_write(in_block, out_block);
test_iostream_pump_failure_mid_write(in_block, out_block);
test_iostream_pump_failure_end_write(in_block, out_block);
}
}
void test_iostream_pump(void)
{
T_BEGIN {
test_iostream_pump_real();
} T_END;
}
dovecot-2.3.21.1/src/lib/priorityq.h 0000644 0000000 0000000 00000003016 14656633576 014065 0000000 0000000 #ifndef PRIORITYQ_H
#define PRIORITYQ_H
/* Priority queue implementation using heap. The items you add to the queue
must begin with a struct priorityq_item. This is necessary for
priorityq_remove() to work fast. */
struct priorityq_item {
/* Current index in the queue array, updated automatically. */
unsigned int idx;
/* [your own data] */
};
/* Returns <0, 0 or >0 */
typedef int priorityq_cmp_callback_t(const void *p1, const void *p2);
/* Create a new priority queue. Callback is used to compare added items. */
struct priorityq *
priorityq_init(priorityq_cmp_callback_t *cmp_callback, unsigned int init_size);
void priorityq_deinit(struct priorityq **pq);
/* Return number of items in the queue. */
unsigned int priorityq_count(const struct priorityq *pq) ATTR_PURE;
/* Add a new item to the queue. */
void priorityq_add(struct priorityq *pq, struct priorityq_item *item);
/* Remove the specified item from the queue. */
void priorityq_remove(struct priorityq *pq, struct priorityq_item *item);
/* Return the item with the highest priority. Returns NULL if queue is empty. */
struct priorityq_item *priorityq_peek(struct priorityq *pq);
/* Like priorityq_peek(), but also remove the returned item from the queue. */
struct priorityq_item *priorityq_pop(struct priorityq *pq);
/* Returns array containing all the priorityq_items. Only the first item is
guaranteed to be the highest priority item, the rest can't be assumed to
be in any order. */
struct priorityq_item *const *priorityq_items(struct priorityq *pq);
#endif
dovecot-2.3.21.1/src/lib/file-lock.c 0000644 0000000 0000000 00000031330 14656633576 013663 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "file-lock.h"
#include "file-dotlock.h"
#include "time-util.h"
#include
#include
#ifdef HAVE_FLOCK
# include
#endif
struct file_lock {
struct file_lock_settings set;
int fd;
char *path;
struct dotlock *dotlock;
struct timeval locked_time;
int lock_type;
};
static struct timeval lock_wait_start;
static uint64_t file_lock_wait_usecs = 0;
static long long file_lock_slow_warning_usecs = -1;
static void file_lock_log_warning_if_slow(struct file_lock *lock);
bool file_lock_method_parse(const char *name, enum file_lock_method *method_r)
{
if (strcasecmp(name, "fcntl") == 0)
*method_r = FILE_LOCK_METHOD_FCNTL;
else if (strcasecmp(name, "flock") == 0)
*method_r = FILE_LOCK_METHOD_FLOCK;
else if (strcasecmp(name, "dotlock") == 0)
*method_r = FILE_LOCK_METHOD_DOTLOCK;
else
return FALSE;
return TRUE;
}
const char *file_lock_method_to_str(enum file_lock_method method)
{
switch (method) {
case FILE_LOCK_METHOD_FCNTL:
return "fcntl";
case FILE_LOCK_METHOD_FLOCK:
return "flock";
case FILE_LOCK_METHOD_DOTLOCK:
return "dotlock";
}
i_unreached();
}
int file_try_lock(int fd, const char *path, int lock_type,
const struct file_lock_settings *set,
struct file_lock **lock_r, const char **error_r)
{
return file_wait_lock(fd, path, lock_type, set, 0, lock_r, error_r);
}
static const char *
file_lock_find_fcntl(int lock_fd, int lock_type)
{
struct flock fl;
i_zero(&fl);
fl.l_type = lock_type;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
if (fcntl(lock_fd, F_GETLK, &fl) < 0 ||
fl.l_type == F_UNLCK || fl.l_pid == -1 || fl.l_pid == 0)
return "";
return t_strdup_printf(" (%s lock held by pid %ld)",
fl.l_type == F_RDLCK ? "READ" : "WRITE", (long)fl.l_pid);
}
static const char *
file_lock_find_proc_locks(int lock_fd ATTR_UNUSED)
{
/* do anything except Linux support this? don't bother trying it for
OSes we don't know about. */
#ifdef __linux__
static bool have_proc_locks = TRUE;
struct stat st;
char node_buf[MAX_INT_STRLEN * 3 + 2];
struct istream *input;
const char *line, *lock_type = "";
pid_t pid = 0;
int fd;
if (!have_proc_locks)
return NULL;
if (fstat(lock_fd, &st) < 0)
return "";
i_snprintf(node_buf, sizeof(node_buf), "%02x:%02x:%llu",
major(st.st_dev), minor(st.st_dev),
(unsigned long long)st.st_ino);
fd = open("/proc/locks", O_RDONLY);
if (fd == -1) {
have_proc_locks = FALSE;
return "";
}
input = i_stream_create_fd_autoclose(&fd, 512);
while (pid == 0 && (line = i_stream_read_next_line(input)) != NULL) T_BEGIN {
const char *const *args = t_strsplit_spaces(line, " ");
/* number: FLOCK/POSIX ADVISORY READ/WRITE pid
major:minor:inode region-start region-end */
if (str_array_length(args) < 8) {
; /* don't continue from within a T_BEGIN {...} T_END */
} else if (strcmp(args[5], node_buf) == 0) {
lock_type = strcmp(args[3], "READ") == 0 ?
"READ" : "WRITE";
if (str_to_pid(args[4], &pid) < 0)
pid = 0;
}
} T_END;
i_stream_destroy(&input);
if (pid == 0) {
/* not found */
return "";
}
if (pid == getpid())
return " (BUG: lock is held by our own process)";
return t_strdup_printf(" (%s lock held by pid %ld)", lock_type, (long)pid);
#else
return "";
#endif
}
const char *file_lock_find(int lock_fd, enum file_lock_method lock_method,
int lock_type)
{
const char *ret;
if (lock_method == FILE_LOCK_METHOD_FCNTL) {
ret = file_lock_find_fcntl(lock_fd, lock_type);
if (ret[0] != '\0')
return ret;
}
return file_lock_find_proc_locks(lock_fd);
}
static bool err_is_lock_timeout(time_t started, unsigned int timeout_secs)
{
/* if EINTR took at least timeout_secs-1 number of seconds,
assume it was the alarm. otherwise log EINTR failure.
(We most likely don't want to retry EINTR since a signal
means somebody wants us to stop blocking). */
return errno == EINTR &&
(unsigned long)(time(NULL) - started + 1) >= timeout_secs;
}
static int file_lock_do(int fd, const char *path, int lock_type,
const struct file_lock_settings *set,
unsigned int timeout_secs, const char **error_r)
{
const char *lock_type_str;
time_t started = time(NULL);
int ret;
i_assert(fd != -1);
if (timeout_secs != 0) {
alarm(timeout_secs);
file_lock_wait_start();
}
lock_type_str = lock_type == F_UNLCK ? "unlock" :
(lock_type == F_RDLCK ? "read-lock" : "write-lock");
switch (set->lock_method) {
case FILE_LOCK_METHOD_FCNTL: {
#ifndef HAVE_FCNTL
*error_r = t_strdup_printf(
"Can't lock file %s: fcntl() locks not supported", path);
return -1;
#else
struct flock fl;
fl.l_type = lock_type;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
ret = fcntl(fd, timeout_secs != 0 ? F_SETLKW : F_SETLK, &fl);
if (timeout_secs != 0) {
alarm(0);
file_lock_wait_end(path);
}
if (ret == 0)
break;
if (timeout_secs == 0 &&
(errno == EACCES || errno == EAGAIN)) {
/* locked by another process */
*error_r = t_strdup_printf(
"fcntl(%s, %s, F_SETLK) locking failed: %m "
"(File is already locked)", path, lock_type_str);
return 0;
}
if (err_is_lock_timeout(started, timeout_secs)) {
errno = EAGAIN;
*error_r = t_strdup_printf(
"fcntl(%s, %s, F_SETLKW) locking failed: "
"Timed out after %u seconds%s",
path, lock_type_str, timeout_secs,
file_lock_find(fd, set->lock_method,
lock_type));
return 0;
}
*error_r = t_strdup_printf("fcntl(%s, %s, %s) locking failed: %m",
path, lock_type_str, timeout_secs == 0 ? "F_SETLK" : "F_SETLKW");
if (errno == EDEADLK && !set->allow_deadlock) {
i_panic("%s%s", *error_r,
file_lock_find(fd, set->lock_method,
lock_type));
}
return -1;
#endif
}
case FILE_LOCK_METHOD_FLOCK: {
#ifndef HAVE_FLOCK
*error_r = t_strdup_printf(
"Can't lock file %s: flock() not supported", path);
return -1;
#else
int operation = timeout_secs != 0 ? 0 : LOCK_NB;
switch (lock_type) {
case F_RDLCK:
operation |= LOCK_SH;
break;
case F_WRLCK:
operation |= LOCK_EX;
break;
case F_UNLCK:
operation |= LOCK_UN;
break;
}
ret = flock(fd, operation);
if (timeout_secs != 0) {
alarm(0);
file_lock_wait_end(path);
}
if (ret == 0)
break;
if (timeout_secs == 0 && errno == EWOULDBLOCK) {
/* locked by another process */
*error_r = t_strdup_printf(
"flock(%s, %s) failed: %m "
"(File is already locked)", path, lock_type_str);
return 0;
}
if (err_is_lock_timeout(started, timeout_secs)) {
errno = EAGAIN;
*error_r = t_strdup_printf("flock(%s, %s) failed: "
"Timed out after %u seconds%s",
path, lock_type_str, timeout_secs,
file_lock_find(fd, set->lock_method,
lock_type));
return 0;
}
*error_r = t_strdup_printf("flock(%s, %s) failed: %m",
path, lock_type_str);
if (errno == EDEADLK && !set->allow_deadlock) {
i_panic("%s%s", *error_r,
file_lock_find(fd, set->lock_method,
lock_type));
}
return -1;
#endif
}
case FILE_LOCK_METHOD_DOTLOCK:
/* we shouldn't get here */
i_unreached();
}
return 1;
}
int file_wait_lock(int fd, const char *path, int lock_type,
const struct file_lock_settings *set,
unsigned int timeout_secs,
struct file_lock **lock_r, const char **error_r)
{
struct file_lock *lock;
int ret;
ret = file_lock_do(fd, path, lock_type, set, timeout_secs, error_r);
if (ret <= 0)
return ret;
lock = i_new(struct file_lock, 1);
lock->set = *set;
lock->fd = fd;
lock->path = i_strdup(path);
lock->lock_type = lock_type;
i_gettimeofday(&lock->locked_time);
*lock_r = lock;
return 1;
}
int file_lock_try_update(struct file_lock *lock, int lock_type)
{
const char *error;
int ret;
ret = file_lock_do(lock->fd, lock->path, lock_type, &lock->set, 0,
&error);
if (ret <= 0)
return ret;
file_lock_log_warning_if_slow(lock);
lock->lock_type = lock_type;
return 1;
}
void file_lock_set_unlink_on_free(struct file_lock *lock, bool set)
{
lock->set.unlink_on_free = set;
}
void file_lock_set_close_on_free(struct file_lock *lock, bool set)
{
lock->set.close_on_free = set;
}
struct file_lock *file_lock_from_dotlock(struct dotlock **dotlock)
{
struct file_lock *lock;
lock = i_new(struct file_lock, 1);
lock->set.lock_method = FILE_LOCK_METHOD_DOTLOCK;
lock->fd = -1;
lock->path = i_strdup(file_dotlock_get_lock_path(*dotlock));
lock->lock_type = F_WRLCK;
i_gettimeofday(&lock->locked_time);
lock->dotlock = *dotlock;
*dotlock = NULL;
return lock;
}
static void file_unlock_real(struct file_lock *lock)
{
const char *error;
if (file_lock_do(lock->fd, lock->path, F_UNLCK, &lock->set, 0,
&error) == 0) {
/* this shouldn't happen */
i_error("file_unlock(%s) failed: %m", lock->path);
}
}
void file_unlock(struct file_lock **_lock)
{
struct file_lock *lock = *_lock;
*_lock = NULL;
/* unlocking is unnecessary when the file is unlinked. or alternatively
the unlink() must be done before unlocking, because otherwise it
could be deleting the new lock. */
i_assert(!lock->set.unlink_on_free);
if (lock->dotlock == NULL)
file_unlock_real(lock);
file_lock_free(&lock);
}
static void file_try_unlink_locked(struct file_lock *lock)
{
struct file_lock *temp_lock = NULL;
struct file_lock_settings temp_set = lock->set;
struct stat st1, st2;
const char *error;
int ret;
temp_set.close_on_free = FALSE;
temp_set.unlink_on_free = FALSE;
file_unlock_real(lock);
ret = file_try_lock(lock->fd, lock->path, F_WRLCK, &temp_set,
&temp_lock, &error);
if (ret < 0) {
i_error("file_lock_free(): Unexpectedly failed to retry locking %s: %s",
lock->path, error);
} else if (ret == 0) {
/* already locked by someone else */
} else if (fstat(lock->fd, &st1) < 0) {
/* not expected to happen */
i_error("file_lock_free(): fstat(%s) failed: %m", lock->path);
} else if (stat(lock->path, &st2) < 0) {
if (errno != ENOENT)
i_error("file_lock_free(): stat(%s) failed: %m", lock->path);
} else if (st1.st_ino != st2.st_ino ||
!CMP_DEV_T(st1.st_dev, st2.st_dev)) {
/* lock file was recreated already - don't delete it */
} else {
/* nobody was waiting on the lock - unlink it */
i_unlink(lock->path);
}
file_lock_free(&temp_lock);
}
void file_lock_free(struct file_lock **_lock)
{
struct file_lock *lock = *_lock;
if (lock == NULL)
return;
*_lock = NULL;
if (lock->dotlock != NULL)
file_dotlock_delete(&lock->dotlock);
if (lock->set.unlink_on_free)
file_try_unlink_locked(lock);
if (lock->set.close_on_free)
i_close_fd(&lock->fd);
file_lock_log_warning_if_slow(lock);
i_free(lock->path);
i_free(lock);
}
const char *file_lock_get_path(struct file_lock *lock)
{
return lock->path;
}
void file_lock_set_path(struct file_lock *lock, const char *path)
{
if (path != lock->path) {
i_free(lock->path);
lock->path = i_strdup(path);
}
}
void file_lock_wait_start(void)
{
i_assert(lock_wait_start.tv_sec == 0);
i_gettimeofday(&lock_wait_start);
}
static void file_lock_wait_init_warning(void)
{
const char *value;
i_assert(file_lock_slow_warning_usecs == -1);
value = getenv("FILE_LOCK_SLOW_WARNING_MSECS");
if (value == NULL)
file_lock_slow_warning_usecs = LLONG_MAX;
else if (str_to_llong(value, &file_lock_slow_warning_usecs) == 0 &&
file_lock_slow_warning_usecs > 0) {
file_lock_slow_warning_usecs *= 1000;
} else {
i_error("FILE_LOCK_SLOW_WARNING_MSECS: "
"Invalid value '%s' - ignoring", value);
file_lock_slow_warning_usecs = LLONG_MAX;
}
}
static void file_lock_log_warning_if_slow(struct file_lock *lock)
{
if (file_lock_slow_warning_usecs < 0)
file_lock_wait_init_warning();
if (file_lock_slow_warning_usecs == LLONG_MAX) {
/* slowness checking is disabled */
return;
}
if (lock->lock_type != F_WRLCK) {
/* some shared locks can legitimately be kept for a long time.
don't warn about them. */
return;
}
struct timeval now;
i_gettimeofday(&now);
int diff = timeval_diff_msecs(&now, &lock->locked_time);
if (diff > file_lock_slow_warning_usecs/1000) {
i_warning("Lock %s kept for %d.%03d secs", lock->path,
diff / 1000, diff % 1000);
}
}
void file_lock_wait_end(const char *lock_name)
{
struct timeval now;
i_assert(lock_wait_start.tv_sec != 0);
i_gettimeofday(&now);
long long diff = timeval_diff_usecs(&now, &lock_wait_start);
if (diff < 0) {
/* time moved backwards */
diff = 0;
}
if (diff > file_lock_slow_warning_usecs) {
if (file_lock_slow_warning_usecs < 0)
file_lock_wait_init_warning();
if (diff > file_lock_slow_warning_usecs) {
int diff_msecs = (diff + 999) / 1000;
i_warning("Locking %s took %d.%03d secs", lock_name,
diff_msecs / 1000, diff_msecs % 1000);
}
}
file_lock_wait_usecs += diff;
lock_wait_start.tv_sec = 0;
}
uint64_t file_lock_wait_get_total_usecs(void)
{
return file_lock_wait_usecs;
}
dovecot-2.3.21.1/src/lib/test-priorityq.c 0000644 0000000 0000000 00000005351 14656633576 015041 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "priorityq.h"
struct pq_test_item {
struct priorityq_item item;
int num;
};
static int cmp_int(const void *p1, const void *p2)
{
const struct pq_test_item *i1 = p1, *i2 = p2;
return i1->num - i2->num;
}
void test_priorityq(void)
{
#define PQ_MAX_ITEMS 100
static const int input[] = {
1, 2, 3, 4, 5, 6, 7, 8, -1,
8, 7, 6, 5, 4, 3, 2, 1, -1,
8, 7, 5, 6, 1, 3, 4, 2, -1,
-1
};
static const int output[] = {
1, 2, 3, 4, 5, 6, 7, 8
};
struct pq_test_item *item, items[PQ_MAX_ITEMS];
struct priorityq_item *const *all_items;
unsigned int i, j;
struct priorityq *pq;
pool_t pool;
int prev;
pool = pool_alloconly_create("priorityq items", 1024);
/* simple tests with popping only */
test_begin("priorityq");
for (i = 0; input[i] != -1; i++) {
p_clear(pool);
pq = priorityq_init(cmp_int, 1);
for (j = 0; input[i] != -1; i++, j++) {
test_assert(priorityq_count(pq) == j);
item = p_new(pool, struct pq_test_item, 1);
item->num = input[i];
priorityq_add(pq, &item->item);
}
all_items = priorityq_items(pq);
test_assert(priorityq_count(pq) == N_ELEMENTS(output));
item = (struct pq_test_item *)all_items[0];
test_assert(item->num == output[0]);
for (j = 1; j < N_ELEMENTS(output); j++) {
item = (struct pq_test_item *)all_items[j];
test_assert(item->num > output[0]);
test_assert(item->num <= output[N_ELEMENTS(output)-1]);
}
for (j = 0; j < N_ELEMENTS(output); j++) {
test_assert(priorityq_count(pq) == N_ELEMENTS(output) - j);
item = (struct pq_test_item *)priorityq_peek(pq);
i_assert(item != NULL);
test_assert(output[j] == item->num);
item = (struct pq_test_item *)priorityq_pop(pq);
i_assert(item != NULL);
test_assert(output[j] == item->num);
}
test_assert(priorityq_count(pq) == 0);
test_assert(priorityq_peek(pq) == NULL);
test_assert(priorityq_pop(pq) == NULL);
priorityq_deinit(&pq);
}
test_end();
/* randomized tests, remove elements */
test_begin("priorityq randomized");
for (i = 0; i < 100; i++) {
pq = priorityq_init(cmp_int, 1);
for (j = 0; j < PQ_MAX_ITEMS; j++) {
items[j].num = i_rand_limit(INT_MAX);
priorityq_add(pq, &items[j].item);
}
for (j = 0; j < PQ_MAX_ITEMS; j++) {
if (i_rand_limit(3) == 0) {
priorityq_remove(pq, &items[j].item);
items[j].num = -1;
}
}
prev = 0;
while (priorityq_count(pq) > 0) {
item = (struct pq_test_item *)priorityq_pop(pq);
i_assert(item != NULL);
test_assert(item->num >= 0 && prev <= item->num);
prev = item->num;
item->num = -1;
}
for (j = 0; j < PQ_MAX_ITEMS; j++) {
test_assert(items[j].num == -1);
}
priorityq_deinit(&pq);
}
test_end();
pool_unref(&pool);
}
dovecot-2.3.21.1/src/lib/event-log.c 0000644 0000000 0000000 00000030333 14656633576 013720 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "event-filter.h"
#include "lib-event-private.h"
unsigned int event_filter_replace_counter = 1;
static struct event_filter *global_debug_log_filter = NULL;
static struct event_filter *global_debug_send_filter = NULL;
static struct event_filter *global_core_log_filter = NULL;
#undef e_error
void e_error(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...)
{
struct event_log_params params = {
.log_type = LOG_TYPE_ERROR,
.source_filename = source_filename,
.source_linenum = source_linenum,
};
va_list args;
va_start(args, fmt);
T_BEGIN {
event_logv(event, ¶ms, fmt, args);
} T_END;
va_end(args);
}
#undef e_warning
void e_warning(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...)
{
struct event_log_params params = {
.log_type = LOG_TYPE_WARNING,
.source_filename = source_filename,
.source_linenum = source_linenum,
};
va_list args;
va_start(args, fmt);
T_BEGIN {
event_logv(event, ¶ms, fmt, args);
} T_END;
va_end(args);
}
#undef e_info
void e_info(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...)
{
struct event_log_params params = {
.log_type = LOG_TYPE_INFO,
.source_filename = source_filename,
.source_linenum = source_linenum,
};
va_list args;
va_start(args, fmt);
T_BEGIN {
event_logv(event, ¶ms, fmt, args);
} T_END;
va_end(args);
}
#undef e_debug
void e_debug(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...)
{
struct event_log_params params = {
.log_type = LOG_TYPE_DEBUG,
.source_filename = source_filename,
.source_linenum = source_linenum,
};
va_list args;
va_start(args, fmt);
T_BEGIN {
event_logv(event, ¶ms, fmt, args);
} T_END;
va_end(args);
}
#undef e_log
void e_log(struct event *event, enum log_type level,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...)
{
struct event_log_params params = {
.log_type = level,
.source_filename = source_filename,
.source_linenum = source_linenum,
};
va_list args;
va_start(args, fmt);
T_BEGIN {
event_logv(event, ¶ms, fmt, args);
} T_END;
va_end(args);
}
struct event_get_log_message_context {
const struct event_log_params *params;
string_t *log_prefix;
const char *message;
unsigned int type_pos;
bool replace_prefix:1;
bool str_out_done:1;
};
static inline void ATTR_FORMAT(2, 0)
event_get_log_message_str_out(struct event_get_log_message_context *glmctx,
const char *fmt, va_list args)
{
const struct event_log_params *params = glmctx->params;
string_t *str_out = params->base_str_out;
/* The message is appended once in full, rather than incremental during
the recursion. */
if (glmctx->str_out_done || str_out == NULL)
return;
/* append the current log prefix to the string buffer */
if (params->base_str_prefix != NULL && !glmctx->replace_prefix)
str_append(str_out, params->base_str_prefix);
str_append_str(str_out, glmctx->log_prefix);
if (glmctx->message != NULL) {
/* a child event already constructed a message */
str_append(str_out, glmctx->message);
} else {
va_list args_copy;
/* construct message from format and arguments */
VA_COPY(args_copy, args);
str_vprintfa(str_out, fmt, args_copy);
va_end(args_copy);
}
/* finished with the string buffer */
glmctx->str_out_done = TRUE;
}
static bool ATTR_FORMAT(4, 0)
event_get_log_message(struct event *event,
struct event_get_log_message_context *glmctx,
unsigned int prefixes_dropped,
const char *fmt, va_list args)
{
const struct event_log_params *params = glmctx->params;
const char *prefix = event->log_prefix;
bool ret = FALSE;
/* Reached the base event? */
if (event == params->base_event) {
/* Append the message to the provided string buffer. */
event_get_log_message_str_out(glmctx, fmt, args);
/* Insert the base send prefix */
if (params->base_send_prefix != NULL) {
str_insert(glmctx->log_prefix, 0,
params->base_send_prefix);
ret = TRUE;
}
}
/* Call the message amendment callback for this event if there is one.
*/
if (event->log_message_callback != NULL) {
const char *in_message;
/* construct the log message composed by children and arguments
*/
if (glmctx->message == NULL) {
str_vprintfa(glmctx->log_prefix, fmt, args);
in_message = str_c(glmctx->log_prefix);
} else if (str_len(glmctx->log_prefix) == 0) {
in_message = glmctx->message;
} else {
str_append(glmctx->log_prefix, glmctx->message);
in_message = str_c(glmctx->log_prefix);
}
/* reformat the log message */
glmctx->message = event->log_message_callback(
event->log_message_callback_context,
glmctx->params->log_type, in_message);
/* continue with a cleared prefix buffer (as prefix is now part
of *message_r). */
str_truncate(glmctx->log_prefix, 0);
ret = TRUE;
}
if (event->log_prefix_callback != NULL) {
prefix = event->log_prefix_callback(
event->log_prefix_callback_context);
}
if (event->log_prefix_replace) {
/* this event replaces all parent log prefixes */
glmctx->replace_prefix = TRUE;
glmctx->type_pos = (prefix == NULL ? 0 : strlen(prefix));
event_get_log_message_str_out(glmctx, fmt, args);
}
if (prefix != NULL) {
if (event->log_prefix_replace || prefixes_dropped == 0) {
str_insert(glmctx->log_prefix, 0, prefix);
ret = TRUE;
} else if (prefixes_dropped > 0) {
prefixes_dropped--;
}
}
if (event->parent == NULL) {
event_get_log_message_str_out(glmctx, fmt, args);
if (params->base_event == NULL &&
params->base_send_prefix != NULL &&
!glmctx->replace_prefix) {
str_insert(glmctx->log_prefix, 0,
params->base_send_prefix);
ret = TRUE;
}
} else if (!event->log_prefix_replace &&
(!params->no_send || !glmctx->str_out_done)) {
prefixes_dropped += event->log_prefixes_dropped;
if (event_get_log_message(event->parent, glmctx,
prefixes_dropped, fmt, args))
ret = TRUE;
}
return ret;
}
void event_log(struct event *event, const struct event_log_params *params,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
event_logv(event, params, fmt, args);
va_end(args);
}
#undef event_want_log_level
bool event_want_log_level(struct event *event, enum log_type level,
const char *source_filename,
unsigned int source_linenum)
{
struct failure_context ctx = { .type = LOG_TYPE_DEBUG };
if (level >= event->min_log_level) {
/* Always log when level is at least this high */
return TRUE;
}
if (event->debug_level_checked_filter_counter == event_filter_replace_counter) {
/* Log filters haven't changed since we last checked this, so
we can rely on the last cached value. FIXME: this doesn't
work correctly if event changes and the change affects
whether the filters would match. */
return event->sending_debug_log;
}
event->debug_level_checked_filter_counter =
event_filter_replace_counter;
if (event->forced_debug) {
/* Debugging is forced for this event (and its children) */
event->sending_debug_log = TRUE;
} else if (global_debug_log_filter != NULL &&
event_filter_match_source(global_debug_log_filter, event,
source_filename, source_linenum, &ctx)) {
/* log_debug filter matched */
event->sending_debug_log = TRUE;
} else if (global_core_log_filter != NULL &&
event_filter_match_source(global_core_log_filter, event,
source_filename, source_linenum, &ctx)) {
/* log_core_filter matched */
event->sending_debug_log = TRUE;
} else {
event->sending_debug_log = FALSE;
}
return event->sending_debug_log;
}
#undef event_want_level
bool event_want_level(struct event *event, enum log_type level,
const char *source_filename,
unsigned int source_linenum)
{
if (event_want_log_level(event, level, source_filename, source_linenum))
return TRUE;
/* see if debug send filtering matches */
if (global_debug_send_filter != NULL) {
struct failure_context ctx = { .type = LOG_TYPE_DEBUG };
if (event_filter_match_source(global_debug_send_filter, event,
source_filename, source_linenum,
&ctx))
return TRUE;
}
return FALSE;
}
static void ATTR_FORMAT(3, 0)
event_logv_params(struct event *event, const struct event_log_params *params,
const char *fmt, va_list args)
{
struct event_get_log_message_context glmctx;
struct failure_context ctx = {
.type = params->log_type,
};
bool abort_after_event = FALSE;
i_assert(!params->no_send || params->base_str_out != NULL);
if (global_core_log_filter != NULL &&
event_filter_match_source(global_core_log_filter, event,
event->source_filename,
event->source_linenum, &ctx))
abort_after_event = TRUE;
i_zero(&glmctx);
glmctx.params = params;
glmctx.log_prefix = t_str_new(64);
if (!event_get_log_message(event, &glmctx, 0, fmt, args)) {
/* keep log prefix as it is */
if (params->base_str_out != NULL && !glmctx.str_out_done) {
va_list args_copy;
VA_COPY(args_copy, args);
str_vprintfa(params->base_str_out, fmt, args_copy);
va_end(args_copy);
}
if (!params->no_send)
event_vsend(event, &ctx, fmt, args);
} else if (params->no_send) {
/* don't send the event */
} else if (glmctx.replace_prefix) {
/* event overrides the log prefix (even if it's "") */
ctx.log_prefix = str_c(glmctx.log_prefix);
ctx.log_prefix_type_pos = glmctx.type_pos;
if (glmctx.message != NULL)
event_send(event, &ctx, "%s", glmctx.message);
else
event_vsend(event, &ctx, fmt, args);
} else {
/* append to log prefix, but don't fully replace it */
if (glmctx.message != NULL)
str_append(glmctx.log_prefix, glmctx.message);
else
str_vprintfa(glmctx.log_prefix, fmt, args);
event_send(event, &ctx, "%s", str_c(glmctx.log_prefix));
}
if (abort_after_event)
abort();
}
void event_logv(struct event *event, const struct event_log_params *params,
const char *fmt, va_list args)
{
const char *orig_source_filename = event->source_filename;
unsigned int orig_source_linenum = event->source_linenum;
int old_errno = errno;
if (params->source_filename != NULL) {
event_set_source(event, params->source_filename,
params->source_linenum, TRUE);
}
(void)event_want_log_level(event, params->log_type,
event->source_filename,
event->source_linenum);
event_ref(event);
event_logv_params(event, params, fmt, args);
event_set_source(event, orig_source_filename,
orig_source_linenum, TRUE);
event_unref(&event);
errno = old_errno;
}
struct event *event_set_forced_debug(struct event *event, bool force)
{
if (force)
event->forced_debug = TRUE;
event_recalculate_debug_level(event);
return event;
}
struct event *event_unset_forced_debug(struct event *event)
{
event->forced_debug = FALSE;
event_recalculate_debug_level(event);
return event;
}
void event_set_global_debug_log_filter(struct event_filter *filter)
{
event_unset_global_debug_log_filter();
global_debug_log_filter = filter;
event_filter_ref(global_debug_log_filter);
event_filter_replace_counter++;
}
struct event_filter *event_get_global_debug_log_filter(void)
{
return global_debug_log_filter;
}
void event_unset_global_debug_log_filter(void)
{
event_filter_unref(&global_debug_log_filter);
event_filter_replace_counter++;
}
void event_set_global_debug_send_filter(struct event_filter *filter)
{
event_unset_global_debug_send_filter();
global_debug_send_filter = filter;
event_filter_ref(global_debug_send_filter);
event_filter_replace_counter++;
}
struct event_filter *event_get_global_debug_send_filter(void)
{
return global_debug_send_filter;
}
void event_unset_global_debug_send_filter(void)
{
event_filter_unref(&global_debug_send_filter);
event_filter_replace_counter++;
}
void event_set_global_core_log_filter(struct event_filter *filter)
{
event_unset_global_core_log_filter();
global_core_log_filter = filter;
event_filter_ref(global_core_log_filter);
event_filter_replace_counter++;
}
struct event_filter *event_get_global_core_log_filter(void)
{
return global_core_log_filter;
}
void event_unset_global_core_log_filter(void)
{
event_filter_unref(&global_core_log_filter);
event_filter_replace_counter++;
}
dovecot-2.3.21.1/src/lib/unlink-directory.c 0000644 0000000 0000000 00000016333 14656633576 015326 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
/*
There's a bit tricky race condition with recursive deletion.
Suppose this happens:
lstat(dir, ..) -> OK, it's a directory
// attacker deletes dir, replaces it with symlink to /
opendir(dir) -> it actually opens /
Most portable solution is to lstat() the dir, chdir() there, then check
that "." points to same device/inode as we originally lstat()ed. This
assumes that the device has usable inodes, most should except for some NFS
implementations.
Filesystems may also reassign a deleted inode to another file
immediately after it's deleted. That in theory makes it possible to exploit
this race to delete the new directory. However, the new inode is quite
unlikely to be any important directory, and attacker is quite unlikely to
find out which directory even got the inode. Maybe with some setuid program
or daemon interaction something could come out of it though.
Another less portable solution is to fchdir(open(dir, O_NOFOLLOW)).
This should be completely safe.
The actual file deletion also has to be done relative to current
directory, to make sure that the whole directory structure isn't replaced
with another one while we're deleting it. Going back to parent directory
isn't too easy either - safest (and easiest) way again is to open() the
directory and fchdir() back there.
*/
#define _GNU_SOURCE /* for O_NOFOLLOW with Linux */
#include "lib.h"
#include "path-util.h"
#include "unlink-directory.h"
#include
#include
#include
#include
#define ERROR_FORMAT "%s(%s) failed: %m"
#define ERROR_FORMAT_DNAME "%s(%s/%s) failed: %m"
static void ATTR_FORMAT(3,4)
unlink_directory_error(const char **error,
int *first_errno,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
const char *err = t_strdup_vprintf(fmt, args);
if (*error == NULL) {
if (first_errno != NULL)
*first_errno = errno;
*error = err;
} else
i_error("%s", err);
va_end(args);
}
static int
unlink_directory_r(const char *dir, enum unlink_directory_flags flags,
const char **error)
{
DIR *dirp;
struct dirent *d;
struct stat st;
int dir_fd, old_errno;
#ifdef O_NOFOLLOW
dir_fd = open(dir, O_RDONLY | O_NOFOLLOW);
if (dir_fd == -1) {
unlink_directory_error(error, NULL,
"open(%s, O_RDONLY | O_NOFOLLOW) failed: %m",
dir);
return -1;
}
#else
struct stat st2;
if (lstat(dir, &st) < 0) {
unlink_directory_error(error_r, NULL, ERROR_FORMAT, "lstat", dir);
return -1;
}
if (!S_ISDIR(st.st_mode)) {
if ((st.st_mode & S_IFMT) != S_IFLNK) {
unlink_directory_error(error_r, NULL, "%s is not a directory: %s", dir);
errno = ENOTDIR;
} else {
/* be compatible with O_NOFOLLOW */
errno = ELOOP;
unlink_directory_error(error_r, NULL, "%s is a symlink, not a directory: %s", dir);
}
return -1;
}
dir_fd = open(dir, O_RDONLY);
if (dir_fd == -1) {
unlink_directory_error(error_r, NULL, "open(%s, O_RDONLY) failed: %m", dir);
return -1;
}
if (fstat(dir_fd, &st2) < 0) {
i_close_fd(&dir_fd);
unlink_directory_error(error_r, NULL, ERROR_FORMAT, "fstat", dir);
return -1;
}
if (st.st_ino != st2.st_ino ||
!CMP_DEV_T(st.st_dev, st2.st_dev)) {
/* directory was just replaced with something else. */
i_close_fd(&dir_fd);
errno = ENOTDIR;
unlink_directory_error(error_r, NULL, "%s race condition: directory was just replaced", dir);
return -1;
}
#endif
if (fchdir(dir_fd) < 0) {
i_close_fd(&dir_fd);
unlink_directory_error(error, NULL, ERROR_FORMAT, "fchdir", dir);
return -1;
}
dirp = opendir(".");
if (dirp == NULL) {
i_close_fd(&dir_fd);
unlink_directory_error(error, NULL, "opendir(.) (in %s) failed: %m", dir);
return -1;
}
int first_errno = 0;
for (;;) {
errno = 0;
d = readdir(dirp);
if (d == NULL) {
if (errno != 0) {
unlink_directory_error(error,
&first_errno,
ERROR_FORMAT,
"readdir",
dir);
}
break;
}
if (d->d_name[0] == '.') {
if ((d->d_name[1] == '\0' ||
(d->d_name[1] == '.' && d->d_name[2] == '\0'))) {
/* skip . and .. */
continue;
}
if ((flags & UNLINK_DIRECTORY_FLAG_SKIP_DOTFILES) != 0)
continue;
}
if (unlink(d->d_name) < 0 && errno != ENOENT) {
old_errno = errno;
if (lstat(d->d_name, &st) < 0) {
if (errno != ENOENT) {
unlink_directory_error(error,
&first_errno,
ERROR_FORMAT,
"lstat",
dir);
break;
}
} else if (S_ISDIR(st.st_mode) &&
(flags & UNLINK_DIRECTORY_FLAG_FILES_ONLY) == 0) {
if (unlink_directory_r(d->d_name, flags, error) < 0) {
if (first_errno == 0)
first_errno = errno;
if (errno != ENOENT)
break;
}
if (fchdir(dir_fd) < 0) {
unlink_directory_error(error,
&first_errno,
ERROR_FORMAT,
"fchdir",
dir);
break;
}
if (rmdir(d->d_name) < 0 &&
errno != ENOENT) {
if (errno == EEXIST)
/* standardize errno */
errno = ENOTEMPTY;
unlink_directory_error(error,
&first_errno,
ERROR_FORMAT,
"rmdir",
dir);
break;
}
} else if (S_ISDIR(st.st_mode) &&
(flags & UNLINK_DIRECTORY_FLAG_FILES_ONLY) != 0) {
/* skip directory */
} else if (old_errno == EBUSY &&
str_begins(d->d_name, ".nfs")) {
/* can't delete NFS files that are still
in use. let the caller decide if this error
is worth logging about */
break;
} else
/* so it wasn't a directory */
unlink_directory_error(error,
&first_errno,
ERROR_FORMAT_DNAME,
"unlink",
dir,
d->d_name);
}
}
i_close_fd(&dir_fd);
if (closedir(dirp) < 0)
unlink_directory_error(error,
&first_errno,
ERROR_FORMAT,
"closedir",
dir);
if (*error != NULL) {
errno = first_errno;
return -1;
}
return 0;
}
int unlink_directory(const char *dir, enum unlink_directory_flags flags,
const char **error_r)
{
const char *orig_dir, *error;
int fd, ret, old_errno;
if (t_get_working_dir(&orig_dir, &error) < 0) {
i_warning("Could not get working directory in unlink_directory(): %s",
error);
orig_dir = ".";
}
fd = open(".", O_RDONLY);
if (fd == -1) {
*error_r = t_strdup_printf(
"Can't preserve current directory %s: "
"open(.) failed: %m", orig_dir);
return -1;
}
/* Cannot set error_r to NULL inside of unlink_directory_r()
because of recursion */
*error_r = NULL;
ret = unlink_directory_r(dir, flags, error_r);
old_errno = errno;
if (fchdir(fd) < 0) {
i_fatal("unlink_directory(%s): "
"Can't fchdir() back to our original dir %s: %m", dir, orig_dir);
}
i_close_fd(&fd);
if (ret < 0) {
errno = old_errno;
return errno == ENOENT ? 0 : -1;
}
if ((flags & UNLINK_DIRECTORY_FLAG_RMDIR) != 0) {
if (rmdir(dir) < 0 && errno != ENOENT) {
*error_r = t_strdup_printf("rmdir(%s) failed: %m", dir);
if (errno == EEXIST) {
/* standardize errno */
errno = ENOTEMPTY;
}
return errno == ENOENT ? 0 : 1;
}
}
return 1;
}
dovecot-2.3.21.1/src/lib/file-copy.h 0000644 0000000 0000000 00000000671 14656633576 013716 0000000 0000000 #ifndef FILE_COPY_H
#define FILE_COPY_H
/* Copy file atomically. First try hardlinking, then fallback to creating
a temporary file (destpath.tmp) and rename()ing it over srcpath.
If the destination file already exists, it may or may not be overwritten,
so that shouldn't be relied on.
Returns -1 = error, 0 = source file not found, 1 = ok */
int file_copy(const char *srcpath, const char *destpath, bool try_hardlink);
#endif
dovecot-2.3.21.1/src/lib/wildcard-match.c 0000644 0000000 0000000 00000005560 14656633576 014707 0000000 0000000 /*
* This code would not have been possible without the prior work and
* suggestions of various sourced. Special thanks to Robey for
* all his time/help tracking down bugs and his ever-helpful advice.
*
* 04/09: Fixed the "*\*" against "*a" bug (caused an endless loop)
*
* Chris Fuller (aka Fred1@IRC & Fwitz@IRC)
* crf@cfox.bchs.uh.edu
*
* I hereby release this code into the public domain
*
*/
#include "lib.h"
#include "wildcard-match.h"
#include
#define WILDS '*' /* matches 0 or more characters (including spaces) */
#define WILDQ '?' /* matches exactly one character */
#define NOMATCH 0
#define MATCH (match+sofar)
static int wildcard_match_int(const char *data, const char *mask, bool icase)
{
const char *ma = mask, *na = data, *lsm = NULL, *lsn = NULL;
int match = 1;
int sofar = 0;
if (na[0] == '\0') {
/* empty string can match only "*" wildcard(s) */
while (ma[0] == '*') ma++;
return ma[0] == '\0' ? MATCH : NOMATCH;
}
/* find the end of each string */
while (*(mask++) != '\0');
mask-=2;
while (*(data++) != '\0');
data-=2;
while (data >= na) {
/* If the mask runs out of chars before the string, fall back on
* a wildcard or fail. */
if (mask < ma) {
if (lsm != NULL) {
data = --lsn;
mask = lsm;
if (data < na)
lsm = NULL;
sofar = 0;
}
else
return NOMATCH;
}
switch (*mask) {
case WILDS: /* Matches anything */
do
mask--; /* Zap redundant wilds */
while ((mask >= ma) && (*mask == WILDS));
lsm = mask;
lsn = data;
match += sofar;
sofar = 0; /* Update fallback pos */
if (mask < ma)
return MATCH;
continue; /* Next char, please */
case WILDQ:
mask--;
data--;
continue; /* '?' always matches */
}
if (icase ? (i_toupper(*mask) == i_toupper(*data)) :
(*mask == *data)) { /* If matching char */
mask--;
data--;
sofar++; /* Tally the match */
continue; /* Next char, please */
}
if (lsm != NULL) { /* To to fallback on '*' */
data = --lsn;
mask = lsm;
if (data < na)
lsm = NULL; /* Rewind to saved pos */
sofar = 0;
continue; /* Next char, please */
}
return NOMATCH; /* No fallback=No match */
}
while ((mask >= ma) && (*mask == WILDS))
mask--; /* Zap leftover %s & *s */
return (mask >= ma) ? NOMATCH : MATCH; /* Start of both = match */
}
bool wildcard_match(const char *data, const char *mask)
{
return wildcard_match_int(data, mask, FALSE) != 0;
}
bool wildcard_match_icase(const char *data, const char *mask)
{
return wildcard_match_int(data, mask, TRUE) != 0;
}
dovecot-2.3.21.1/src/lib/str.c 0000644 0000000 0000000 00000007140 14656633576 012630 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "printf-format-fix.h"
#include "unichar.h"
#include "str.h"
#include
string_t *str_new(pool_t pool, size_t initial_size)
{
/* never allocate a 0 byte size buffer. this is especially important
when str_c() is called on an empty string from a different stack
frame (see the comment in buffer.c about this). */
return buffer_create_dynamic(pool, I_MAX(initial_size, 1));
}
string_t *str_new_const(pool_t pool, const char *str, size_t len)
{
string_t *ret;
i_assert(str[len] == '\0');
ret = p_new(pool, buffer_t, 1);
buffer_create_from_const_data(ret, str, len + 1);
str_truncate(ret, len);
return ret;
}
string_t *t_str_new(size_t initial_size)
{
return str_new(pool_datastack_create(), initial_size);
}
string_t *t_str_new_const(const char *str, size_t len)
{
return str_new_const(pool_datastack_create(), str, len);
}
void str_free(string_t **str)
{
if (str == NULL || *str == NULL)
return;
buffer_free(str);
}
static void str_add_nul(string_t *str)
{
const unsigned char *data = str_data(str);
size_t len = str_len(str);
size_t alloc = buffer_get_size(str);
if (len == alloc || data[len] != '\0') {
buffer_write(str, len, "", 1);
/* remove the \0 - we don't want to keep it */
buffer_set_used_size(str, len);
}
}
char *str_free_without_data(string_t **str)
{
str_add_nul(*str);
return buffer_free_without_data(str);
}
const char *str_c(string_t *str)
{
str_add_nul(str);
return str->data;
}
char *str_c_modifiable(string_t *str)
{
str_add_nul(str);
return buffer_get_modifiable_data(str, NULL);
}
bool str_equals(const string_t *str1, const string_t *str2)
{
if (str1->used != str2->used)
return FALSE;
return memcmp(str1->data, str2->data, str1->used) == 0;
}
void str_append_max(string_t *str, const char *cstr, size_t max_len)
{
const char *p;
size_t len;
p = memchr(cstr, '\0', max_len);
if (p == NULL)
len = max_len;
else
len = p - (const char *)cstr;
buffer_append(str, cstr, len);
}
void str_printfa(string_t *str, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
str_vprintfa(str, fmt, args);
va_end(args);
}
void str_vprintfa(string_t *str, const char *fmt, va_list args)
{
#define SNPRINTF_INITIAL_EXTRA_SIZE 128
va_list args2;
char *tmp;
size_t init_size;
size_t pos = str->used;
int ret, ret2;
VA_COPY(args2, args);
/* the format string is modified only if %m exists in it. it happens
only in error conditions, so don't try to t_push() here since it'll
just slow down the normal code path. */
fmt = printf_format_fix_get_len(fmt, &init_size);
init_size += SNPRINTF_INITIAL_EXTRA_SIZE;
/* @UNSAFE */
if (pos+init_size > buffer_get_writable_size(str) &&
pos < buffer_get_writable_size(str)) {
/* avoid growing buffer larger if possible. this is also
required if buffer isn't dynamically growing. */
init_size = buffer_get_writable_size(str)-pos;
}
tmp = buffer_get_space_unsafe(str, pos, init_size);
ret = vsnprintf(tmp, init_size, fmt, args);
i_assert(ret >= 0);
if ((unsigned int)ret >= init_size) {
/* didn't fit with the first guess. now we know the size,
so try again. */
tmp = buffer_get_space_unsafe(str, pos, ret + 1);
ret2 = vsnprintf(tmp, ret + 1, fmt, args2);
i_assert(ret2 == ret);
}
va_end(args2);
/* drop the unused data, including terminating NUL */
buffer_set_used_size(str, pos + ret);
}
void str_truncate_utf8(string_t *str, size_t len)
{
size_t size = str_len(str);
if (size <= len)
return;
str_truncate(str, uni_utf8_data_truncate(str_data(str), size, len));
}
dovecot-2.3.21.1/src/lib/event-log.h 0000644 0000000 0000000 00000014367 14656633576 013736 0000000 0000000 #ifndef EVENT_LOG_H
#define EVENT_LOG_H
struct event_filter;
#include "lib-event.h"
struct event_log_params {
enum log_type log_type;
const char *source_filename;
unsigned int source_linenum;
/* Base event used as a reference for base_* parameters (see below) */
struct event *base_event;
/* Append the event message to base_str_out in addition to emitting the
event as normal. The message appended to the string buffer includes
prefixes and message callback modifications by parent events up until
the base_event. The event is otherwise sent as normal with the full
prefixes and all modifications up to the root event (unless
no_send=TRUE). This is primarily useful to mimic (part of) event
logging in parallel logs that are visible to users. */
string_t *base_str_out;
/* Prefix inserted at the base_event for the sent log message. */
const char *base_send_prefix;
/* Prefix inserted at the base_event for the log message appended to the
string buffer. */
const char *base_str_prefix;
/* Don't actually send the event; only append to the provided string
buffer (base_str_out must not be NULL). */
bool no_send:1;
};
/* Increased every time global event filters have changed. */
extern unsigned int event_filter_replace_counter;
void e_error(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...) ATTR_FORMAT(4, 5);
#define e_error(_event, ...) STMT_START { \
struct event *_tmp_event = (_event); \
if (event_want_level(_tmp_event, LOG_TYPE_ERROR)) \
e_error(_tmp_event, __FILE__, __LINE__, __VA_ARGS__); \
else \
event_send_abort(_tmp_event); \
} STMT_END
void e_warning(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...) ATTR_FORMAT(4, 5);
#define e_warning(_event, ...) STMT_START { \
struct event *_tmp_event = (_event); \
if (event_want_level(_tmp_event, LOG_TYPE_WARNING)) \
e_warning(_tmp_event, __FILE__, __LINE__, __VA_ARGS__); \
else \
event_send_abort(_tmp_event); \
} STMT_END
void e_info(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...) ATTR_FORMAT(4, 5);
#define e_info(_event, ...) STMT_START { \
struct event *_tmp_event = (_event); \
if (event_want_level(_tmp_event, LOG_TYPE_INFO)) \
e_info(_tmp_event, __FILE__, __LINE__, __VA_ARGS__); \
else \
event_send_abort(_tmp_event); \
} STMT_END
void e_debug(struct event *event,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...) ATTR_FORMAT(4, 5);
#define e_debug(_event, ...) STMT_START { \
struct event *_tmp_event = (_event); \
if (event_want_debug(_tmp_event)) \
e_debug(_tmp_event, __FILE__, __LINE__, __VA_ARGS__); \
else \
event_send_abort(_tmp_event); \
} STMT_END
void e_log(struct event *event, enum log_type level,
const char *source_filename, unsigned int source_linenum,
const char *fmt, ...) ATTR_FORMAT(5, 6);
#define e_log(_event, level, ...) STMT_START { \
struct event *_tmp_event = (_event); \
if (event_want_level(_tmp_event, level)) \
e_log(_tmp_event, level, __FILE__, __LINE__, __VA_ARGS__); \
else \
event_send_abort(_tmp_event); \
} STMT_END
/* Returns TRUE if event should be logged. Typically event_want_debug_log()
could be used in deciding whether to build an expensive debug log message
(e.g. requires extra disk IO). Note that if this is used, the actual
event being sent won't be matched against event filters because it's never
called. The result of the check is cached in the event, so repeated calls
are efficient. */
bool event_want_log_level(struct event *event, enum log_type level,
const char *source_filename,
unsigned int source_linenum);
#define event_want_log_level(_event, level) event_want_log_level((_event), (level), __FILE__, __LINE__)
#define event_want_debug_log(_event) event_want_log_level((_event), LOG_TYPE_DEBUG)
/* Returns TRUE if event should be processed (for logging or sending to stats).
The logging is checked with event_want_log_level() with the same caching
behavior. */
bool event_want_level(struct event *event, enum log_type level,
const char *source_filename,
unsigned int source_linenum);
#define event_want_level(_event, level) event_want_level((_event), (level), __FILE__, __LINE__)
#define event_want_debug(_event) event_want_level((_event), LOG_TYPE_DEBUG)
void event_log(struct event *event, const struct event_log_params *params,
const char *fmt, ...)
ATTR_FORMAT(3, 4);
void event_logv(struct event *event, const struct event_log_params *params,
const char *fmt, va_list args)
ATTR_FORMAT(3, 0);
/* If debugging is forced, the global debug log filter is ignored. Changing
this applies only to this event and any child event that is created
afterwards. It doesn't apply to existing child events (mainly for
performance reasons).
Note that event_set_forced_debug(event, FALSE) is a no-op. To disable
forced-debug, use event_unset_forced_debug(event). */
struct event *event_set_forced_debug(struct event *event, bool force);
/* Set the forced-debug to FALSE */
struct event *event_unset_forced_debug(struct event *event);
/* Set the global filter to logging debug events. */
void event_set_global_debug_log_filter(struct event_filter *filter);
/* Return the current global debug log event filter. */
struct event_filter *event_get_global_debug_log_filter(void);
/* Unset global debug log filter, if one exists. */
void event_unset_global_debug_log_filter(void);
/* Set the global filter to sending debug events. The debug events are also
sent if they match the global debug log filter. */
void event_set_global_debug_send_filter(struct event_filter *filter);
/* Return the current global debug send event filter. */
struct event_filter *event_get_global_debug_send_filter(void);
/* Unset global debug send filter, if one exists. */
void event_unset_global_debug_send_filter(void);
/* Set/replace the global core filter, which abort()s on matching events. */
void event_set_global_core_log_filter(struct event_filter *filter);
/* Return the current global core filter. */
struct event_filter *event_get_global_core_log_filter(void);
/* Unset the global core filter, if one exists. */
void event_unset_global_core_log_filter(void);
#endif
dovecot-2.3.21.1/src/lib/crc32.h 0000644 0000000 0000000 00000000452 14656633576 012740 0000000 0000000 #ifndef CRC32_H
#define CRC32_H
uint32_t crc32_data(const void *data, size_t size) ATTR_PURE;
uint32_t crc32_str(const char *str) ATTR_PURE;
uint32_t crc32_data_more(uint32_t crc, const void *data, size_t size) ATTR_PURE;
uint32_t crc32_str_more(uint32_t crc, const char *str) ATTR_PURE;
#endif
dovecot-2.3.21.1/src/lib/sha2.c 0000644 0000000 0000000 00000042351 14656633576 012660 0000000 0000000 /*
* FIPS 180-2 SHA-224/256/384/512 implementation
* Last update: 02/02/2007
* Issue date: 04/30/2005
*
* Copyright (C) 2005, 2007 Olivier Gay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "lib.h"
#include "sha2.h"
#define SHFR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define CH(x, y, z) ((x & y) ^ (~x & z))
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
#define SHA384_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
#define SHA384_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
#define SHA384_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
#define SHA384_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
#define UNPACK32(x, str) \
{ \
*((str) + 3) = (uint8_t) ((x) ); \
*((str) + 2) = (uint8_t) ((x) >> 8); \
*((str) + 1) = (uint8_t) ((x) >> 16); \
*((str) + 0) = (uint8_t) ((x) >> 24); \
}
#define PACK32(str, x) \
{ \
*(x) = ((uint32_t) *((str) + 3) ) \
| ((uint32_t) *((str) + 2) << 8) \
| ((uint32_t) *((str) + 1) << 16) \
| ((uint32_t) *((str) + 0) << 24); \
}
#define UNPACK64(x, str) \
{ \
*((str) + 7) = (uint8_t) ((x) ); \
*((str) + 6) = (uint8_t) ((x) >> 8); \
*((str) + 5) = (uint8_t) ((x) >> 16); \
*((str) + 4) = (uint8_t) ((x) >> 24); \
*((str) + 3) = (uint8_t) ((x) >> 32); \
*((str) + 2) = (uint8_t) ((x) >> 40); \
*((str) + 1) = (uint8_t) ((x) >> 48); \
*((str) + 0) = (uint8_t) ((x) >> 56); \
}
#define PACK64(str, x) \
{ \
*(x) = ((uint64_t) *((str) + 7) ) \
| ((uint64_t) *((str) + 6) << 8) \
| ((uint64_t) *((str) + 5) << 16) \
| ((uint64_t) *((str) + 4) << 24) \
| ((uint64_t) *((str) + 3) << 32) \
| ((uint64_t) *((str) + 2) << 40) \
| ((uint64_t) *((str) + 1) << 48) \
| ((uint64_t) *((str) + 0) << 56); \
}
#define SHA256_SCR(i) \
{ \
w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \
+ SHA256_F3(w[i - 15]) + w[i - 16]; \
}
#define SHA384_SCR(i) \
{ \
w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \
+ SHA512_F3(w[i - 15]) + w[i - 16]; \
}
#define SHA512_SCR(i) \
{ \
w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \
+ SHA512_F3(w[i - 15]) + w[i - 16]; \
}
static const uint32_t sha256_h0[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
static const uint64_t sha384_h0[8] =
{0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL,
0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL};
static const uint64_t sha512_h0[8] =
{0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};
static const uint32_t sha256_k[64] =
{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
static const uint64_t sha512_k[80] =
{0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
/* SHA-256 functions */
static void ATTR_UNSIGNED_WRAPS
sha256_transf(struct sha256_ctx *ctx, const unsigned char *data,
size_t block_nb)
{
uint32_t w[64];
uint32_t wv[8];
uint32_t t1, t2;
const unsigned char *sub_block;
int i,j;
for (i = 0; i < (int) block_nb; i++) {
sub_block = data + (i << 6);
for (j = 0; j < 16; j++) {
PACK32(&sub_block[j << 2], &w[j]);
}
for (j = 16; j < 64; j++) {
SHA256_SCR(j);
}
for (j = 0; j < 8; j++) {
wv[j] = ctx->h[j];
}
for (j = 0; j < 64; j++) {
t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ sha256_k[j] + w[j];
t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
ctx->h[j] += wv[j];
}
}
}
void sha256_init(struct sha256_ctx *ctx)
{
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha256_h0[i];
}
ctx->len = 0;
ctx->tot_len = 0;
}
void sha256_loop(struct sha256_ctx *ctx, const void *data,
size_t len)
{
const unsigned char *shifted_message;
size_t block_nb;
size_t new_len, rem_len, tmp_len;
tmp_len = SHA256_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], data, rem_len);
if (ctx->len + len < SHA256_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA256_BLOCK_SIZE;
shifted_message = CONST_PTR_OFFSET(data, rem_len);
sha256_transf(ctx, ctx->block, 1);
sha256_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA256_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 6;
}
void sha256_result(struct sha256_ctx *ctx,
unsigned char digest[STATIC_ARRAY SHA256_RESULTLEN])
{
size_t block_nb;
size_t pm_len;
uint64_t len_b;
int i;
block_nb = (1 + ((SHA256_BLOCK_SIZE - 9)
< (ctx->len % SHA256_BLOCK_SIZE)));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 6;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK64(len_b, ctx->block + pm_len - 8);
sha256_transf(ctx, ctx->block, block_nb);
for (i = 0 ; i < 8; i++) {
UNPACK32(ctx->h[i], &digest[i << 2]);
}
}
void sha256_get_digest(const void *data, size_t size,
unsigned char digest[STATIC_ARRAY SHA256_RESULTLEN])
{
struct sha256_ctx ctx;
sha256_init(&ctx);
sha256_loop(&ctx, data, size);
sha256_result(&ctx, digest);
}
/* SHA-384 functions */
static void ATTR_UNSIGNED_WRAPS
sha384_transf(struct sha384_ctx *ctx, const unsigned char *data,
size_t block_nb)
{
uint64_t w[80];
uint64_t wv[8];
uint64_t t1, t2;
const unsigned char *sub_block;
int i, j;
for (i = 0; i < (int) block_nb; i++) {
sub_block = data + (i << 7);
for (j = 0; j < 16; j++) {
PACK64(&sub_block[j << 3], &w[j]);
}
for (j = 16; j < 80; j++) {
SHA384_SCR(j);
}
for (j = 0; j < 8; j++) {
wv[j] = ctx->h[j];
}
for (j = 0; j < 80; j++) {
/* sha384_k is same as sha512_k */
t1 = wv[7] + SHA384_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ sha512_k[j] + w[j];
t2 = SHA384_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
ctx->h[j] += wv[j];
}
}
}
void sha384_init(struct sha384_ctx *ctx)
{
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha384_h0[i];
}
ctx->len = 0;
ctx->tot_len = 0;
}
void sha384_loop(struct sha384_ctx *ctx, const void *data,
size_t len)
{
const unsigned char *shifted_message;
size_t block_nb;
size_t new_len, rem_len, tmp_len;
tmp_len = SHA384_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], data, rem_len);
if (ctx->len + len < SHA384_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA384_BLOCK_SIZE;
shifted_message = CONST_PTR_OFFSET(data, rem_len);
sha384_transf(ctx, ctx->block, 1);
sha384_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA384_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 7;
}
void sha384_result(struct sha384_ctx *ctx,
unsigned char digest[STATIC_ARRAY SHA384_RESULTLEN])
{
unsigned int block_nb;
unsigned int pm_len;
uint64_t len_b;
int i;
block_nb = 1 + ((SHA384_BLOCK_SIZE - 17)
< (ctx->len % SHA384_BLOCK_SIZE));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 7;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK64(len_b, ctx->block + pm_len - 8);
sha384_transf(ctx, ctx->block, block_nb);
for (i = 0 ; i < 6; i++) {
UNPACK64(ctx->h[i], &digest[i << 3]);
}
}
void sha384_get_digest(const void *data, size_t size,
unsigned char digest[STATIC_ARRAY SHA384_RESULTLEN])
{
struct sha384_ctx ctx;
sha384_init(&ctx);
sha384_loop(&ctx, data, size);
sha384_result(&ctx, digest);
}
/* SHA-512 functions */
static void ATTR_UNSIGNED_WRAPS
sha512_transf(struct sha512_ctx *ctx, const unsigned char *data,
size_t block_nb)
{
uint64_t w[80];
uint64_t wv[8];
uint64_t t1, t2;
const unsigned char *sub_block;
int i, j;
for (i = 0; i < (int) block_nb; i++) {
sub_block = data + (i << 7);
for (j = 0; j < 16; j++) {
PACK64(&sub_block[j << 3], &w[j]);
}
for (j = 16; j < 80; j++) {
SHA512_SCR(j);
}
for (j = 0; j < 8; j++) {
wv[j] = ctx->h[j];
}
for (j = 0; j < 80; j++) {
t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ sha512_k[j] + w[j];
t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
ctx->h[j] += wv[j];
}
}
}
void sha512_init(struct sha512_ctx *ctx)
{
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha512_h0[i];
}
ctx->len = 0;
ctx->tot_len = 0;
}
void sha512_loop(struct sha512_ctx *ctx, const void *data,
size_t len)
{
const unsigned char *shifted_message;
size_t block_nb;
size_t new_len, rem_len, tmp_len;
tmp_len = SHA512_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], data, rem_len);
if (ctx->len + len < SHA512_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA512_BLOCK_SIZE;
shifted_message = CONST_PTR_OFFSET(data, rem_len);
sha512_transf(ctx, ctx->block, 1);
sha512_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA512_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 7;
}
void sha512_result(struct sha512_ctx *ctx,
unsigned char digest[STATIC_ARRAY SHA512_RESULTLEN])
{
unsigned int block_nb;
unsigned int pm_len;
uint64_t len_b;
int i;
block_nb = 1 + ((SHA512_BLOCK_SIZE - 17)
< (ctx->len % SHA512_BLOCK_SIZE));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 7;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK64(len_b, ctx->block + pm_len - 8);
sha512_transf(ctx, ctx->block, block_nb);
for (i = 0 ; i < 8; i++) {
UNPACK64(ctx->h[i], &digest[i << 3]);
}
}
void sha512_get_digest(const void *data, size_t size,
unsigned char digest[STATIC_ARRAY SHA512_RESULTLEN])
{
struct sha512_ctx ctx;
sha512_init(&ctx);
sha512_loop(&ctx, data, size);
sha512_result(&ctx, digest);
}
static void hash_method_init_sha256(void *context)
{
sha256_init(context);
}
static void hash_method_loop_sha256(void *context, const void *data, size_t size)
{
sha256_loop(context, data, size);
}
static void hash_method_result_sha256(void *context, unsigned char *result_r)
{
sha256_result(context, result_r);
}
const struct hash_method hash_method_sha256 = {
.name = "sha256",
.block_size = SHA256_BLOCK_SIZE,
.context_size = sizeof(struct sha256_ctx),
.digest_size = SHA256_RESULTLEN,
.init = hash_method_init_sha256,
.loop = hash_method_loop_sha256,
.result = hash_method_result_sha256,
};
static void hash_method_init_sha384(void *context)
{
sha384_init(context);
}
static void hash_method_loop_sha384(void *context, const void *data, size_t size)
{
sha384_loop(context, data, size);
}
static void hash_method_result_sha384(void *context, unsigned char *result_r)
{
sha384_result(context, result_r);
}
const struct hash_method hash_method_sha384 = {
.name = "sha384",
.block_size = SHA384_BLOCK_SIZE,
.context_size = sizeof(struct sha384_ctx),
.digest_size = SHA384_RESULTLEN,
.init = hash_method_init_sha384,
.loop = hash_method_loop_sha384,
.result = hash_method_result_sha384,
};
static void hash_method_init_sha512(void *context)
{
sha512_init(context);
}
static void hash_method_loop_sha512(void *context, const void *data, size_t size)
{
sha512_loop(context, data, size);
}
static void hash_method_result_sha512(void *context, unsigned char *result_r)
{
sha512_result(context, result_r);
}
const struct hash_method hash_method_sha512 = {
.name = "sha512",
.block_size = SHA512_BLOCK_SIZE,
.context_size = sizeof(struct sha512_ctx),
.digest_size = SHA512_RESULTLEN,
.init = hash_method_init_sha512,
.loop = hash_method_loop_sha512,
.result = hash_method_result_sha512,
};
dovecot-2.3.21.1/src/lib/test-istream-multiplex.c 0000644 0000000 0000000 00000024227 14656633576 016467 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "ioloop.h"
#include "str.h"
#include "crc32.h"
#include "randgen.h"
#include "istream-private.h"
#include "istream-multiplex.h"
#include "ostream.h"
#include
static void test_istream_multiplex_simple(void)
{
test_begin("istream multiplex (simple)");
static const char data[] = "\x00\x00\x00\x00\x06Hello\x00"
"\x01\x00\x00\x00\x03Wor"
"\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x03ld\x00";
static const size_t data_len = sizeof(data)-1;
struct istream *input = test_istream_create_data(data, data_len);
size_t siz;
struct istream *chan0 = i_stream_create_multiplex(input, SIZE_MAX);
struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
/* nothing to read until the first byte */
for (size_t i = 0; i <= 1+4; i++) {
test_istream_set_size(input, i);
test_assert(i_stream_read(chan0) == 0);
test_assert(i_stream_read(chan1) == 0);
}
/* partial read of the first packet */
size_t input_max = 1+4+3;
test_istream_set_size(input, input_max);
test_assert(i_stream_read(chan0) == 3);
test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hel", 3) == 0 &&
siz == 3);
test_assert(i_stream_read(chan1) == 0);
/* read the rest of the first packet and the second packet.
read chan1 before chan0 to see that it works. */
input_max += 3 + 1+4+3;
test_istream_set_size(input, input_max);
test_assert(i_stream_read(chan1) == 3);
test_assert(i_stream_read(chan0) == 3);
test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello\0", 6) == 0 &&
siz == 6);
test_assert(memcmp(i_stream_get_data(chan1, &siz), "Wor", 3) == 0 &&
siz == 3);
/* 0-sized packet is ignored */
input_max += 1+4;
test_istream_set_size(input, input_max);
test_assert(i_stream_read(chan0) == 0);
test_assert(i_stream_read(chan1) == 0);
/* read the final packet */
input_max += 1+4+3;
i_assert(input_max == data_len);
test_istream_set_size(input, input_max);
test_assert(i_stream_read(chan0) == 0);
test_assert(i_stream_read(chan1) == 3);
/* we should have the final data in all channels now */
test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello\0", 6) == 0 &&
siz == 6);
test_assert(memcmp(i_stream_get_data(chan1, &siz), "World\0", 6) == 0 &&
siz == 6);
/* all channels should return EOF */
test_assert(i_stream_read(chan0) == -1 && chan0->stream_errno == 0);
i_stream_unref(&chan0);
test_assert(i_stream_read(chan1) == -1 && chan1->stream_errno == 0);
i_stream_unref(&chan1);
i_stream_unref(&input);
test_end();
}
static void test_istream_multiplex_maxbuf(void)
{
test_begin("istream multiplex (maxbuf)");
static const char data[] = "\x00\x00\x00\x00\x06Hello\x00"
"\x01\x00\x00\x00\x06World\x00";
static const size_t data_len = sizeof(data)-1;
struct istream *input = test_istream_create_data(data, data_len);
size_t siz;
struct istream *chan0 = i_stream_create_multiplex(input, 5);
struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
/* we get data for channel 0 and congest */
test_assert(i_stream_read(chan1) == 0);
/* we read data for channel 0 */
test_assert(i_stream_read(chan0) == 5);
/* and now it's congested */
test_assert(i_stream_read(chan0) == -2);
test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello", 5) == 0 &&
siz == 5);
/* consume data */
i_stream_skip(chan0, 5);
/* we read data for channel 1 */
test_assert(i_stream_read(chan1) == 5);
test_assert(memcmp(i_stream_get_data(chan1, &siz), "World", 5) == 0 &&
siz == 5);
/* consume data */
i_stream_skip(chan1, 5);
/* read last byte */
test_assert(i_stream_read(chan0) == 1);
/* now we get byte for channel 1 */
test_assert(i_stream_read(chan0) == 0);
/* now we read byte for channel 1 */
test_assert(i_stream_read(chan1) == 1);
/* and everything should return EOF now */
test_assert(i_stream_read(chan1) == -1);
test_assert(i_stream_read(chan0) == -1);
i_stream_unref(&chan0);
i_stream_unref(&chan1);
i_stream_unref(&input);
test_end();
}
static void test_istream_multiplex_random(void)
{
const unsigned int max_channel = 6;
const unsigned int packets_count = 30;
test_begin("istream multiplex (random)");
unsigned int i;
uoff_t bytes_written = 0, bytes_read = 0;
buffer_t *buf = buffer_create_dynamic(default_pool, 10240);
uint32_t input_crc[max_channel];
uint32_t output_crc[max_channel];
memset(input_crc, 0, sizeof(input_crc));
memset(output_crc, 0, sizeof(output_crc));
for (i = 0; i < packets_count; i++) {
unsigned int len = i_rand_limit(1024+1);
unsigned char packet_data[len];
uint32_t len_be = cpu32_to_be(len);
unsigned int channel = i_rand_limit(max_channel);
random_fill(packet_data, len);
input_crc[channel] =
crc32_data_more(input_crc[channel], packet_data, len);
buffer_append_c(buf, channel);
buffer_append(buf, &len_be, sizeof(len_be));
buffer_append(buf, packet_data, len);
bytes_written += len;
}
struct istream *input = test_istream_create_data(buf->data, buf->used);
struct istream *chan[max_channel];
chan[0] = i_stream_create_multiplex(input, 1024/4);
for (i = 1; i < max_channel; i++)
chan[i] = i_stream_multiplex_add_channel(chan[0], i);
test_istream_set_size(input, 0);
/* read from each stream, 1 byte at a time */
size_t input_size = 0;
int max_ret = -3;
unsigned int read_max_channel = max_channel/2;
bool something_read = FALSE;
for (i = 0;;) {
ssize_t ret = i_stream_read(chan[i]);
if (max_ret < ret)
max_ret = ret;
if (ret > 0) {
size_t size;
const unsigned char *data =
i_stream_get_data(chan[i], &size);
output_crc[i] = crc32_data_more(output_crc[i], data, size);
bytes_read += size;
test_assert((size_t)ret == size);
i_stream_skip(chan[i], size);
something_read = TRUE;
}
if (++i < read_max_channel)
;
else if (max_ret == 0 && !something_read &&
read_max_channel < max_channel) {
read_max_channel++;
} else {
if (max_ret <= -1) {
test_assert(max_ret == -1);
break;
}
if (max_ret == 0)
test_istream_set_size(input, ++input_size);
i = 0;
max_ret = -3;
something_read = FALSE;
read_max_channel = max_channel/2;
}
}
test_assert(bytes_read == bytes_written);
for (i = 0; i < max_channel; i++) {
test_assert_idx(input_crc[i] == output_crc[i], i);
test_assert_idx(i_stream_read(chan[i]) == -1 &&
chan[i]->stream_errno == 0, i);
i_stream_unref(&chan[i]);
}
i_stream_unref(&input);
buffer_free(&buf);
test_end();
}
static unsigned int channel_counter[2] = {0, 0};
static const char *msgs[] = {
"",
"a",
"bb",
"ccc",
"dddd",
"eeeee",
"ffffff"
};
static void test_istream_multiplex_stream_read(struct istream *channel)
{
uint8_t cid = i_stream_multiplex_get_channel_id(channel);
const char *line;
size_t siz;
if (i_stream_read(channel) < 0)
return;
while((line = i_stream_next_line(channel)) != NULL) {
siz = strlen(line);
test_assert_idx(siz > 0 && siz < N_ELEMENTS(msgs),
channel_counter[cid]);
if (siz > 0 && siz < N_ELEMENTS(msgs)) {
test_assert_idx(strcmp(line, msgs[siz]) == 0,
channel_counter[cid]);
}
channel_counter[cid]++;
}
if (channel_counter[0] > 100 && channel_counter[1] > 100)
io_loop_stop(current_ioloop);
}
static void test_send_msg(struct ostream *os, uint8_t cid, const char *msg)
{
uint32_t len = cpu32_to_be(strlen(msg) + 1);
const struct const_iovec iov[] = {
{ &cid, sizeof(cid) },
{ &len, sizeof(len) },
{ msg, strlen(msg) },
{ "\n", 1 } /* newline added for i_stream_next_line */
};
o_stream_nsendv(os, iov, N_ELEMENTS(iov));
}
static void test_istream_multiplex_stream_write(struct ostream *channel)
{
size_t rounds = i_rand_limit(10);
for(size_t i = 0; i < rounds; i++) {
uint8_t cid = i_rand_limit(2);
test_send_msg(channel, cid,
msgs[1 + i_rand_limit(N_ELEMENTS(msgs) - 1)]);
}
}
static void test_istream_multiplex_stream(void)
{
test_begin("istream multiplex (stream)");
struct ioloop *ioloop = io_loop_create();
io_loop_set_current(ioloop);
int fds[2];
test_assert(pipe(fds) == 0);
fd_set_nonblock(fds[0], TRUE);
fd_set_nonblock(fds[1], TRUE);
struct ostream *os = o_stream_create_fd(fds[1], SIZE_MAX);
struct istream *is = i_stream_create_fd(fds[0], 10 + i_rand_limit(10));
struct istream *chan0 = i_stream_create_multiplex(is, SIZE_MAX);
struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
struct io *io0 =
io_add_istream(chan0, test_istream_multiplex_stream_read, chan0);
struct io *io1 =
io_add_istream(chan1, test_istream_multiplex_stream_read, chan1);
struct io *io2 =
io_add(fds[1], IO_WRITE, test_istream_multiplex_stream_write, os);
io_loop_run(current_ioloop);
io_remove(&io0);
io_remove(&io1);
io_remove(&io2);
i_stream_unref(&chan1);
i_stream_unref(&chan0);
i_stream_unref(&is);
test_assert(o_stream_finish(os) > 0);
o_stream_unref(&os);
io_loop_destroy(&ioloop);
i_close_fd(&fds[0]);
i_close_fd(&fds[1]);
test_end();
}
static void test_istream_multiplex_close_channel(void)
{
test_begin("istream multiplex (close channel)");
static const char *data = "\x00\x00\x00\x00\x06Hello\x00"
"\x01\x00\x00\x00\x06World\x00";
static const size_t data_len = 22;
struct istream *input = test_istream_create_data(data, data_len);
size_t siz;
struct istream *chan0 = i_stream_create_multiplex(input, SIZE_MAX);
struct istream *chan1 = i_stream_multiplex_add_channel(chan0, 1);
i_stream_unref(&chan1);
test_assert(i_stream_read(chan0) == 6);
test_assert(memcmp(i_stream_get_data(chan0, &siz), "Hello\0", 6) == 0 &&
siz == 6);
i_stream_unref(&chan0);
i_stream_unref(&input);
input = test_istream_create_data(data, data_len);
chan0 = i_stream_create_multiplex(input, SIZE_MAX);
chan1 = i_stream_multiplex_add_channel(chan0, 1);
/* this is needed to populate chan1 data */
(void)i_stream_read(chan0);
i_stream_unref(&chan0);
test_assert(i_stream_read(chan1) == 6);
test_assert(memcmp(i_stream_get_data(chan1, &siz), "World\0", 6) == 0 &&
siz == 6);
i_stream_unref(&chan1);
i_stream_unref(&input);
test_end();
}
void test_istream_multiplex(void)
{
test_istream_multiplex_simple();
test_istream_multiplex_maxbuf();
test_istream_multiplex_random();
test_istream_multiplex_stream();
test_istream_multiplex_close_channel();
}
dovecot-2.3.21.1/src/lib/restrict-process-size.h 0000644 0000000 0000000 00000001532 14656633576 016307 0000000 0000000 #ifndef RESTRICT_PROCESS_SIZE_H
#define RESTRICT_PROCESS_SIZE_H
#include
#ifdef HAVE_SYS_RESOURCE_H
# include
#endif
/* Restrict max. process size. */
void restrict_process_size(rlim_t bytes);
/* Restrict max. number of processes. */
void restrict_process_count(rlim_t count);
/* Set fd limit to count. */
void restrict_fd_limit(rlim_t count);
/* Get the core dump size limit. Returns 0 if ok, -1 if lookup failed. */
int restrict_get_core_limit(rlim_t *limit_r);
/* Get the process VSZ size limit. Returns 0 if ok, -1 if lookup failed. */
int restrict_get_process_size(rlim_t *limit_r);
/* Get the process count limit. Returns 0 if ok, -1 if lookup failed. */
int restrict_get_process_limit(rlim_t *limit_r);
/* Get the fd limit. Returns 0 if ok, -1 if lookup failed. */
int restrict_get_fd_limit(rlim_t *limit_r);
#endif
dovecot-2.3.21.1/src/lib/hash-method.h 0000644 0000000 0000000 00000002602 14656633576 014224 0000000 0000000 #ifndef HASH_METHOD_H
#define HASH_METHOD_H
#include "buffer.h"
struct hash_method {
const char *name;
/* Block size for the algorithm */
unsigned int block_size;
/* Number of bytes that must be allocated for context */
unsigned int context_size;
/* Number of bytes that must be allocated for result()'s digest */
unsigned int digest_size;
void (*init)(void *context);
void (*loop)(void *context, const void *data, size_t size);
void (*result)(void *context, unsigned char *digest_r);
};
const struct hash_method *hash_method_lookup(const char *name);
/* NULL-terminated list of all hash methods */
extern const struct hash_method *hash_methods[];
void hash_method_get_digest(const struct hash_method *meth,
const void *data, size_t data_len,
unsigned char *result_r);
/** Simple datastack helpers for digesting (hashing)
* USAGE:
buffer_t *result = t_hash_str(hash_method_lookup("sha256"), "hello world");
const char *hex = binary_to_hex(result->data, result->used);
*/
buffer_t *t_hash_data(const struct hash_method *meth,
const void *data, size_t data_len);
static inline
buffer_t *t_hash_buffer(const struct hash_method *meth,
const buffer_t *data)
{
return t_hash_data(meth, data->data, data->used);
}
static inline
buffer_t *t_hash_str(const struct hash_method *meth,
const char *data)
{
return t_hash_data(meth, data, strlen(data));
}
#endif
dovecot-2.3.21.1/src/lib/test-lib.c 0000644 0000000 0000000 00000001213 14656633576 013536 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
int main(int argc, char **argv)
{
const char *match = "";
if (argc > 2 && strcmp(argv[1], "--match") == 0)
match = argv[2];
static const struct named_test test_functions[] = {
#define TEST(x) TEST_NAMED(x)
#define FATAL(x)
#include "test-lib.inc"
#undef TEST
#undef FATAL
{ NULL, NULL }
};
static const struct named_fatal fatal_functions[] = {
#define TEST(x)
#define FATAL(x) FATAL_NAMED(x)
#include "test-lib.inc"
#undef TEST
#undef FATAL
{ NULL, NULL }
};
return test_run_named_with_fatals(match, test_functions, fatal_functions);
}
dovecot-2.3.21.1/src/lib/test-macros.c 0000644 0000000 0000000 00000002736 14656633576 014267 0000000 0000000 /* Copyright (c) 2021 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
struct parent {
unsigned int a;
};
struct child {
unsigned int b;
struct parent p;
};
static void test_container_of(void)
{
struct child child;
struct parent *parent = &child.p;
test_begin("container_of()");
struct child *ptr_child = container_of(parent, struct child, p);
test_assert(ptr_child == &child);
test_end();
}
static void test_pointer_cast(void)
{
#define TEST_POINTER_CAST(type, prefix, value) \
type prefix ## _num = value; \
void *prefix ## _ptr = POINTER_CAST(prefix ## _num); \
test_assert(POINTER_CAST_TO(prefix ## _ptr, type) == prefix ## _num);
test_begin("POINTER_CAST");
TEST_POINTER_CAST(unsigned int, uint, 0x87654321);
TEST_POINTER_CAST(uint32_t, uint32, 0xf00dabcd);
TEST_POINTER_CAST(uint16_t, uint16, 0x9876);
TEST_POINTER_CAST(uint8_t, uint8, 0xf8);
#if SIZEOF_VOID_P == 8
TEST_POINTER_CAST(unsigned long, ulong, 0xfedcba9876543210);
TEST_POINTER_CAST(size_t, size, 0xfedcba9876543210);
#else
TEST_POINTER_CAST(unsigned long, ulong, 0xfedcba98);
TEST_POINTER_CAST(size_t, size, 0xfedcba98);
#endif
test_end();
}
static void test_ptr_offset(void)
{
uint32_t foo[] = { 1, 2, 3 };
const uint32_t foo2[] = { 1, 2, 3 };
test_begin("PTR_OFFSET");
test_assert(PTR_OFFSET(foo, 4) == &foo[1]);
test_assert(CONST_PTR_OFFSET(foo2, 8) == &foo2[2]);
test_end();
}
void test_macros(void)
{
test_container_of();
test_pointer_cast();
test_ptr_offset();
}
dovecot-2.3.21.1/src/lib/mmap-util.h 0000644 0000000 0000000 00000002026 14656633576 013730 0000000 0000000 #ifndef MMAP_UTIL_H
#define MMAP_UTIL_H
#include
#ifdef HAVE_LINUX_MREMAP
# define __USE_GNU /* for MREMAP_MAYMOVE */
#endif
#include
#undef __USE_GNU
#if !defined (MREMAP_MAYMOVE) && !defined (HAVE_LINUX_MREMAP)
# define MREMAP_MAYMOVE 1
#endif
#define madvise my_madvise
int my_madvise(void *start, size_t length, int advice);
#ifndef HAVE_MADVISE
# ifndef MADV_NORMAL
# define MADV_NORMAL 0
# define MADV_RANDOM 0
# define MADV_SEQUENTIAL 0
# define MADV_WILLNEED 0
# define MADV_DONTNEED 0
# endif
#endif
void *mmap_file(int fd, size_t *length, int prot);
void *mmap_ro_file(int fd, size_t *length);
void *mmap_rw_file(int fd, size_t *length);
/* for allocating anonymous mmap()s, with portable mremap(). these must not
be mixed with any standard mmap calls. */
void *mmap_anon(size_t length);
void *mremap_anon(void *old_address, size_t old_size, size_t new_size,
unsigned long flags);
int munmap_anon(void *start, size_t length);
size_t mmap_get_page_size(void) ATTR_CONST;
#endif
dovecot-2.3.21.1/src/lib/test-data-stack.c 0000644 0000000 0000000 00000032046 14656633576 015014 0000000 0000000 /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "lib-event-private.h"
#include "event-filter.h"
#include "data-stack.h"
static int ds_grow_event_count = 0;
static bool
test_ds_grow_event_callback(struct event *event,
enum event_callback_type type,
struct failure_context *ctx,
const char *fmt ATTR_UNUSED,
va_list args ATTR_UNUSED)
{
const struct event_field *field;
if (type != EVENT_CALLBACK_TYPE_SEND)
return TRUE;
ds_grow_event_count++;
test_assert(ctx->type == LOG_TYPE_DEBUG);
field = event_find_field_nonrecursive(event, "alloc_size");
test_assert(field != NULL &&
field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX &&
field->value.intmax >= 1024 * (5 + 100));
field = event_find_field_nonrecursive(event, "used_size");
test_assert(field != NULL &&
field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX &&
field->value.intmax >= 1024 * (5 + 100));
field = event_find_field_nonrecursive(event, "last_alloc_size");
test_assert(field != NULL &&
field->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX &&
field->value.intmax >= 1024 * 100);
field = event_find_field_nonrecursive(event, "frame_marker");
test_assert(field != NULL &&
field->value_type == EVENT_FIELD_VALUE_TYPE_STR &&
strstr(field->value.str, "data-stack.c") != NULL);
return TRUE;
}
static void test_ds_grow_event(void)
{
const char *error;
test_begin("data-stack grow event");
event_register_callback(test_ds_grow_event_callback);
i_assert(event_get_global_debug_log_filter() == NULL);
struct event_filter *filter = event_filter_create();
test_assert(event_filter_parse("event=data_stack_grow", filter, &error) == 0);
event_set_global_debug_log_filter(filter);
event_filter_unref(&filter);
/* make sure the test won't fail due to earlier data stack
allocations. */
data_stack_free_unused();
T_BEGIN {
(void)t_malloc0(1024*5);
test_assert(ds_grow_event_count == 0);
(void)t_malloc0(1024*100);
test_assert(ds_grow_event_count == 1);
} T_END;
event_unset_global_debug_log_filter();
event_unregister_callback(test_ds_grow_event_callback);
test_end();
}
static void test_ds_get_used_size(void)
{
test_begin("data-stack data_stack_get_used_size()");
size_t size1 = data_stack_get_used_size();
(void)t_malloc0(500);
size_t size2 = data_stack_get_used_size();
test_assert(size1 + 500 <= size2);
T_BEGIN {
(void)t_malloc0(300);
size_t sub_size1 = data_stack_get_used_size();
T_BEGIN {
(void)t_malloc0(300);
} T_END;
test_assert_cmp(sub_size1, ==, data_stack_get_used_size());
} T_END;
test_assert_cmp(size2, ==, data_stack_get_used_size());
test_end();
}
static void test_ds_get_bytes_available(void)
{
test_begin("data-stack t_get_bytes_available()");
for (unsigned int i = 0; i < 32; i++) {
size_t orig_avail = t_get_bytes_available();
size_t avail1;
T_BEGIN {
if (i > 0)
t_malloc_no0(i);
avail1 = t_get_bytes_available();
t_malloc_no0(avail1);
test_assert_idx(t_get_bytes_available() == 0, i);
t_malloc_no0(1);
test_assert_idx(t_get_bytes_available() > 0, i);
} T_END;
T_BEGIN {
if (i > 0)
t_malloc_no0(i);
size_t avail2 = t_get_bytes_available();
test_assert_idx(avail1 == avail2, i);
t_malloc_no0(avail2 + 1);
test_assert_idx(t_get_bytes_available() > 0, i);
} T_END;
test_assert_idx(t_get_bytes_available() == orig_avail, i);
}
test_end();
}
static void ATTR_FORMAT(2, 0)
test_ds_growing_debug(const struct failure_context *ctx ATTR_UNUSED,
const char *format, va_list args)
{
ds_grow_event_count++;
(void)t_strdup_vprintf(format, args);
}
static void test_ds_grow_in_event(void)
{
size_t i, alloc1 = 8096;
unsigned char *buf;
const char *error;
test_begin("data-stack grow in event");
struct event_filter *filter = event_filter_create();
event_set_global_debug_log_filter(filter);
test_assert(event_filter_parse("event=data_stack_grow", filter, &error) == 0);
event_filter_unref(&filter);
i_set_debug_handler(test_ds_growing_debug);
buf = t_buffer_get(alloc1);
for (i = 0; i < alloc1; i++)
buf[i] = i & 0xff;
test_assert(ds_grow_event_count == 0);
buf = t_buffer_reget(buf, 65536);
test_assert(ds_grow_event_count == 1);
for (i = 0; i < alloc1; i++) {
if (buf[i] != (unsigned char)i)
break;
}
test_assert(i == alloc1);
i_set_debug_handler(default_error_handler);
event_unset_global_debug_log_filter();
test_end();
}
static void test_ds_buffers(void)
{
test_begin("data-stack buffer growth");
T_BEGIN {
size_t i;
unsigned char *p;
size_t left = t_get_bytes_available();
while (left < 10000) {
t_malloc_no0(left+1); /* force a new block */
left = t_get_bytes_available();
}
left -= 64; /* make room for the sentry if DEBUG */
p = t_buffer_get(1);
p[0] = 1;
for (i = 2; i <= left; i++) {
/* grow it */
unsigned char *p2 = t_buffer_get(i);
test_assert_idx(p == p2, i);
p[i-1] = i & 0xff;
test_assert_idx(p[i-2] == (unsigned char)(i-1), i);
}
/* now fix it permanently */
t_buffer_alloc_last_full();
test_assert(t_get_bytes_available() < 64 + MEM_ALIGN(1));
} T_END;
test_end();
test_begin("data-stack buffer interruption");
T_BEGIN {
void *b = t_buffer_get(1000);
void *a = t_malloc_no0(1);
void *b2 = t_buffer_get(1001);
test_assert(a == b); /* expected, not guaranteed */
test_assert(b2 != b);
} T_END;
test_end();
test_begin("data-stack buffer with reallocs");
T_BEGIN {
size_t bigleft = t_get_bytes_available();
size_t i;
/* with DEBUG: the stack frame allocation takes 96 bytes
and malloc takes extra 40 bytes + alignment, so don't let
"i" be too high. */
for (i = 1; i < bigleft-96-40-16; i += i_rand_limit(32)) T_BEGIN {
unsigned char *p, *p2;
size_t left;
t_malloc_no0(i);
left = t_get_bytes_available();
/* The most useful idx for the assert is 'left' */
test_assert_idx(left <= bigleft-i, left);
p = t_buffer_get(left/2);
p[0] = 'Z'; p[left/2 - 1] = 'Z';
p2 = t_buffer_get(left + left/2);
test_assert_idx(p != p2, left);
test_assert_idx(p[0] == 'Z', left);
test_assert_idx(p[left/2 -1] == 'Z', left);
} T_END;
} T_END;
test_end();
}
static void test_ds_realloc()
{
test_begin("data-stack realloc");
T_BEGIN {
size_t i;
unsigned char *p;
size_t left = t_get_bytes_available();
while (left < 10000) {
t_malloc_no0(left+1); /* force a new block */
left = t_get_bytes_available();
}
left -= 64; /* make room for the sentry if DEBUG */
p = t_malloc_no0(1);
p[0] = 1;
for (i = 2; i <= left; i++) {
/* grow it */
test_assert_idx(t_try_realloc(p, i), i);
p[i-1] = i & 0xff;
test_assert_idx(p[i-2] == (unsigned char)(i-1), i);
}
test_assert(t_get_bytes_available() < 64 + MEM_ALIGN(1));
} T_END;
test_end();
}
static void test_ds_recurse(int depth, int number, size_t size)
{
int i;
char **ps;
char tag[2] = { depth+1, '\0' };
int try_fails = 0;
data_stack_frame_t t_id = t_push_named("test_ds_recurse[%i]", depth);
ps = t_buffer_get(sizeof(char *) * number);
i_assert(ps != NULL);
t_buffer_alloc(sizeof(char *) * number);
for (i = 0; i < number; i++) {
ps[i] = t_malloc_no0(size/2);
bool re = t_try_realloc(ps[i], size);
i_assert(ps[i] != NULL);
if (!re) {
try_fails++;
ps[i] = t_malloc_no0(size);
}
/* drop our own canaries */
memset(ps[i], tag[0], size);
ps[i][size-2] = 0;
}
/* Do not expect a high failure rate from t_try_realloc */
test_assert_idx(try_fails <= number / 20, depth);
/* Now recurse... */
if(depth>0)
test_ds_recurse(depth-1, number, size);
/* Test our canaries are still intact */
for (i = 0; i < number; i++) {
test_assert_idx(strspn(ps[i], tag) == size - 2, i);
test_assert_idx(ps[i][size-1] == tag[0], i);
}
test_assert_idx(t_pop(&t_id), depth);
}
static void test_ds_recursive(void)
{
int count = 20, depth = 80;
int i;
test_begin("data-stack recursive");
size_t init_size = data_stack_get_used_size();
for(i = 0; i < count; i++) T_BEGIN {
int number=i_rand_limit(100)+50;
int size=i_rand_limit(100)+50;
test_ds_recurse(depth, number, size);
} T_END;
test_assert_cmp(init_size, ==, data_stack_get_used_size());
test_end();
}
static void test_ds_pass_str(void)
{
data_stack_frame_t frames[32*2 + 1]; /* BLOCK_FRAME_COUNT*2 + 1 */
const char *strings[N_ELEMENTS(frames)];
test_begin("data-stack pass string");
for (unsigned int frame = 0; frame < N_ELEMENTS(frames); frame++) {
frames[frame] = t_push("test");
if (frame % 10 == 5) {
/* increase block counts */
(void)t_malloc_no0(1024*30);
(void)t_malloc_no0(1024*30);
}
strings[frame] = t_strdup_printf("frame %d", frame);
for (unsigned int i = 0; i <= frame; i++) {
test_assert_idx(data_stack_frame_contains(&frames[frame], strings[i]) == (i == frame),
frame * 100 + i);
}
}
const char *last_str = strings[N_ELEMENTS(frames)-1];
for (unsigned int frame = N_ELEMENTS(frames); frame > 0; ) {
frame--;
test_assert(t_pop_pass_str(&frames[frame], &last_str));
}
test_assert_strcmp(last_str, "frame 64");
/* make sure the pass_condition works properly */
const char *error, *orig_error, *orig2_error;
T_BEGIN {
(void)t_strdup("qwertyuiop");
error = orig_error = t_strdup("123456");
} T_END_PASS_STR_IF(TRUE, &error);
orig2_error = orig_error;
T_BEGIN {
(void)t_strdup("abcdefghijklmnopqrstuvwxyz");
} T_END_PASS_STR_IF(FALSE, &orig2_error);
/* orig_error and orig2_error both point to freed data stack frame */
test_assert(orig_error == orig2_error);
/* the passed error is still valid though */
test_assert_strcmp(error, "123456");
test_end();
}
void test_data_stack(void)
{
void (*tests[])(void) = {
test_ds_grow_event,
test_ds_get_used_size,
test_ds_get_bytes_available,
test_ds_grow_in_event,
test_ds_buffers,
test_ds_realloc,
test_ds_recursive,
test_ds_pass_str,
};
for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
ds_grow_event_count = 0;
data_stack_free_unused();
T_BEGIN {
tests[i]();
} T_END;
}
}
enum fatal_test_state fatal_data_stack(unsigned int stage)
{
#ifdef DEBUG
#define NONEXISTENT_STACK_FRAME_ID (data_stack_frame_t)999999999
/* If we abort, then we'll be left with a dangling t_push()
keep a record of our temporary stack id, so we can clean up. */
static data_stack_frame_t t_id = NONEXISTENT_STACK_FRAME_ID;
static unsigned char *undo_ptr = NULL;
static unsigned char undo_data;
static bool things_are_messed_up = FALSE;
if (stage != 0) {
/* Presume that we need to clean up from the prior test:
undo the evil write, then we will be able to t_pop cleanly,
and finally we can end the test stanza. */
if (things_are_messed_up || undo_ptr == NULL)
return FATAL_TEST_ABORT; /* abort, things are messed up with t_pop */
*undo_ptr = undo_data;
undo_ptr = NULL;
/* t_pop mustn't abort, that would cause recursion */
things_are_messed_up = TRUE;
if (t_id != NONEXISTENT_STACK_FRAME_ID && !t_pop(&t_id))
return FATAL_TEST_ABORT; /* abort, things are messed up with us */
things_are_messed_up = FALSE;
t_id = NONEXISTENT_STACK_FRAME_ID;
test_end();
}
switch(stage) {
case 0: {
unsigned char *p;
test_begin("fatal data-stack underrun");
t_id = t_push_named("fatal_data_stack underrun");
size_t left = t_get_bytes_available();
p = t_malloc_no0(left-80); /* will fit */
p = t_malloc_no0(100); /* won't fit, will get new block */
int seek = 0;
/* Seek back for the canary, don't assume endianness */
while(seek > -60 &&
((p[seek+1] != 0xDB) ||
((p[seek] != 0xBA || p[seek+2] != 0xAD) &&
(p[seek+2] != 0xBA || p[seek] != 0xAD))))
seek--;
if (seek <= -60)
return FATAL_TEST_ABORT; /* abort, couldn't find header */
undo_ptr = p + seek;
undo_data = *undo_ptr;
*undo_ptr = '*';
/* t_malloc_no0 will panic block header corruption */
test_expect_fatal_string("Corrupted data stack canary");
(void)t_malloc_no0(10);
return FATAL_TEST_FAILURE;
}
case 1: case 2: {
test_begin(stage == 1 ? "fatal t_malloc_no0 overrun near" : "fatal t_malloc_no0 overrun far");
t_id = t_push_named(stage == 1 ? "fatal t_malloc_no0 overrun first" : "fatal t_malloc_no0 overrun far");
unsigned char *p = t_malloc_no0(10);
undo_ptr = p + 10 + (stage == 1 ? 0 : 8*4-1); /* presumes sentry size */
undo_data = *undo_ptr;
*undo_ptr = '*';
/* t_pop will now fail */
test_expect_fatal_string("buffer overflow");
(void)t_pop(&t_id);
t_id = NONEXISTENT_STACK_FRAME_ID; /* We're FUBAR, mustn't pop next entry */
return FATAL_TEST_FAILURE;
}
case 3: case 4: {
test_begin(stage == 3 ? "fatal t_buffer_get overrun near" : "fatal t_buffer_get overrun far");
t_id = t_push_named(stage == 3 ? "fatal t_buffer overrun near" : "fatal t_buffer_get overrun far");
unsigned char *p = t_buffer_get(10);
undo_ptr = p + 10 + (stage == 3 ? 0 : 8*4-1);
undo_data = *undo_ptr;
*undo_ptr = '*';
/* t_pop will now fail */
test_expect_fatal_string("buffer overflow");
(void)t_pop(&t_id);
t_id = NONEXISTENT_STACK_FRAME_ID; /* We're FUBAR, mustn't pop next entry */
return FATAL_TEST_FAILURE;
}
default:
things_are_messed_up = TRUE;
return FATAL_TEST_FINISHED;
}
#else
return stage == 0 ? FATAL_TEST_FINISHED : FATAL_TEST_ABORT;
#endif
}
dovecot-2.3.21.1/src/lib/ioloop-epoll.c 0000644 0000000 0000000 00000013317 14656633576 014435 0000000 0000000 /* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "sleep.h"
#include "ioloop-private.h"
#include "ioloop-iolist.h"
#ifdef IOLOOP_EPOLL
#include
#include
struct ioloop_handler_context {
int epfd;
unsigned int deleted_count;
ARRAY(struct io_list *) fd_index;
ARRAY(struct epoll_event) events;
};
void io_loop_handler_init(struct ioloop *ioloop, unsigned int initial_fd_count)
{
struct ioloop_handler_context *ctx;
ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
i_array_init(&ctx->events, initial_fd_count);
i_array_init(&ctx->fd_index, initial_fd_count);
ctx->epfd = epoll_create(initial_fd_count);
if (ctx->epfd < 0) {
if (errno != EMFILE)
i_fatal("epoll_create(): %m");
else {
i_fatal("epoll_create(): %m (you may need to increase "
"/proc/sys/fs/epoll/max_user_instances)");
}
}
fd_close_on_exec(ctx->epfd, TRUE);
}
void io_loop_handler_deinit(struct ioloop *ioloop)
{
struct ioloop_handler_context *ctx = ioloop->handler_context;
struct io_list **list;
unsigned int i, count;
list = array_get_modifiable(&ctx->fd_index, &count);
for (i = 0; i < count; i++)
i_free(list[i]);
if (close(ctx->epfd) < 0)
i_error("close(epoll) failed: %m");
array_free(&ioloop->handler_context->fd_index);
array_free(&ioloop->handler_context->events);
i_free(ioloop->handler_context);
}
#define IO_EPOLL_ERROR (EPOLLERR | EPOLLHUP)
#define IO_EPOLL_INPUT (EPOLLIN | EPOLLPRI | IO_EPOLL_ERROR)
#define IO_EPOLL_OUTPUT (EPOLLOUT | IO_EPOLL_ERROR)
static int epoll_event_mask(struct io_list *list)
{
int events = 0, i;
struct io_file *io;
for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
io = list->ios[i];
if (io == NULL)
continue;
if ((io->io.condition & IO_READ) != 0)
events |= IO_EPOLL_INPUT;
if ((io->io.condition & IO_WRITE) != 0)
events |= IO_EPOLL_OUTPUT;
if ((io->io.condition & IO_ERROR) != 0)
events |= IO_EPOLL_ERROR;
}
return events;
}
void io_loop_handle_add(struct io_file *io)
{
struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
struct io_list **list;
struct epoll_event event;
int op;
bool first;
list = array_idx_get_space(&ctx->fd_index, io->fd);
if (*list == NULL)
*list = i_new(struct io_list, 1);
first = ioloop_iolist_add(*list, io);
i_zero(&event);
event.data.ptr = *list;
event.events = epoll_event_mask(*list);
op = first ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
if (errno == EPERM && op == EPOLL_CTL_ADD) {
i_panic("epoll_ctl(add, %d) failed: %m "
"(fd doesn't support epoll%s)", io->fd,
io->fd != STDIN_FILENO ? "" :
" - instead of 'fd);
}
if (first) {
/* allow epoll_wait() to return the maximum number of events
by keeping space allocated for each file descriptor */
if (ctx->deleted_count > 0)
ctx->deleted_count--;
else
array_append_zero(&ctx->events);
}
}
void io_loop_handle_remove(struct io_file *io, bool closed)
{
struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
struct io_list **list;
struct epoll_event event;
int op;
bool last;
list = array_idx_modifiable(&ctx->fd_index, io->fd);
last = ioloop_iolist_del(*list, io);
if (!closed) {
i_zero(&event);
event.data.ptr = *list;
event.events = epoll_event_mask(*list);
op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
const char *errstr = t_strdup_printf(
"epoll_ctl(%s, %d) failed: %m",
op == EPOLL_CTL_DEL ? "del" : "mod", io->fd);
if (errno != ENOSPC && errno != ENOMEM)
i_panic("%s", errstr);
else
i_error("%s", errstr);
}
}
if (last) {
/* since we're not freeing memory in any case, just increase
deleted counter so next handle_add() can just decrease it
instead of appending to the events array */
ctx->deleted_count++;
}
i_free(io);
}
void io_loop_handler_run_internal(struct ioloop *ioloop)
{
struct ioloop_handler_context *ctx = ioloop->handler_context;
struct epoll_event *events;
const struct epoll_event *event;
struct io_list *list;
struct io_file *io;
struct timeval tv;
unsigned int events_count;
int msecs, ret, i, j;
bool call;
i_assert(ctx != NULL);
/* get the time left for next timeout task */
msecs = io_loop_run_get_wait_time(ioloop, &tv);
events = array_get_modifiable(&ctx->events, &events_count);
if (ioloop->io_files != NULL && events_count > ctx->deleted_count) {
ret = epoll_wait(ctx->epfd, events, events_count, msecs);
if (ret < 0 && errno != EINTR)
i_fatal("epoll_wait(): %m");
} else {
/* no I/Os, but we should have some timeouts.
just wait for them. */
i_assert(msecs >= 0);
i_sleep_intr_msecs(msecs);
ret = 0;
}
/* execute timeout handlers */
io_loop_handle_timeouts(ioloop);
if (!ioloop->running)
return;
for (i = 0; i < ret; i++) {
/* io_loop_handle_add() may cause events array reallocation,
so we have use array_idx() */
event = array_idx(&ctx->events, i);
list = event->data.ptr;
for (j = 0; j < IOLOOP_IOLIST_IOS_PER_FD; j++) {
io = list->ios[j];
if (io == NULL)
continue;
call = FALSE;
if ((event->events & (EPOLLHUP | EPOLLERR)) != 0)
call = TRUE;
else if ((io->io.condition & IO_READ) != 0)
call = (event->events & EPOLLIN) != 0;
else if ((io->io.condition & IO_WRITE) != 0)
call = (event->events & EPOLLOUT) != 0;
else if ((io->io.condition & IO_ERROR) != 0)
call = (event->events & IO_EPOLL_ERROR) != 0;
if (call) {
io_loop_call_io(&io->io);
if (!ioloop->running)
return;
}
}
}
}
#endif /* IOLOOP_EPOLL */
dovecot-2.3.21.1/src/lib/aqueue.c 0000644 0000000 0000000 00000006062 14656633576 013307 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "aqueue.h"
struct aqueue *aqueue_init(struct array *array)
{
struct aqueue *aqueue;
aqueue = i_new(struct aqueue, 1);
aqueue->arr = array;
aqueue->area_size = buffer_get_writable_size(aqueue->arr->buffer) /
aqueue->arr->element_size;
i_assert(aqueue->area_size > 0);
return aqueue;
}
void aqueue_deinit(struct aqueue **_aqueue)
{
struct aqueue *aqueue = *_aqueue;
*_aqueue = NULL;
i_free(aqueue);
}
static void aqueue_grow(struct aqueue *aqueue)
{
unsigned int orig_area_size, count;
i_assert(aqueue->full && aqueue->head == aqueue->tail);
orig_area_size = aqueue->area_size;
(void)array_append_space_i(aqueue->arr);
aqueue->area_size = buffer_get_writable_size(aqueue->arr->buffer) /
aqueue->arr->element_size;
i_assert(orig_area_size < aqueue->area_size);
count = I_MIN(aqueue->area_size - orig_area_size, aqueue->head);
array_copy(aqueue->arr, orig_area_size, aqueue->arr, 0, count);
if (count < aqueue->area_size - orig_area_size)
aqueue->head = orig_area_size + count;
else {
array_copy(aqueue->arr, 0, aqueue->arr, count,
aqueue->head - count);
aqueue->head -= count;
}
i_assert(aqueue->head != aqueue->tail);
aqueue->full = FALSE;
}
void aqueue_append(struct aqueue *aqueue, const void *data)
{
if (aqueue->full) {
aqueue_grow(aqueue);
i_assert(!aqueue->full);
}
array_idx_set_i(aqueue->arr, aqueue->head, data);
aqueue->head = (aqueue->head + 1) % aqueue->area_size;
aqueue->full = aqueue->head == aqueue->tail;
}
void aqueue_delete(struct aqueue *aqueue, unsigned int n)
{
unsigned int idx, count = aqueue_count(aqueue);
i_assert(n < count);
aqueue->full = FALSE;
if (n == 0) {
/* optimized deletion from tail */
aqueue->tail = (aqueue->tail + 1) % aqueue->area_size;
return;
}
if (n == count-1) {
/* optimized deletion from head */
aqueue->head = (aqueue->head + aqueue->area_size - 1) %
aqueue->area_size;
return;
}
idx = aqueue_idx(aqueue, n);
if ((n < count/2 || idx > aqueue->head) && idx > aqueue->tail) {
/* move tail forward.
..tail##idx##head.. or ##head..tail##idx## */
array_copy(aqueue->arr, aqueue->tail + 1,
aqueue->arr, aqueue->tail,
idx - aqueue->tail);
aqueue->tail++;
i_assert(aqueue->tail < aqueue->area_size);
} else {
/* move head backward.
..tail##idx##head.. or ##idx##head..tail## */
i_assert(idx < aqueue->head);
array_copy(aqueue->arr, idx,
aqueue->arr, idx + 1,
aqueue->head - idx);
aqueue->head = (aqueue->head + aqueue->area_size - 1) %
aqueue->area_size;
}
i_assert(aqueue->head < aqueue->area_size &&
aqueue->head != aqueue->tail);
}
void aqueue_delete_tail(struct aqueue *aqueue)
{
aqueue_delete(aqueue, 0);
}
void aqueue_clear(struct aqueue *aqueue)
{
aqueue->head = aqueue->tail = 0;
aqueue->full = FALSE;
}
unsigned int aqueue_count(const struct aqueue *aqueue)
{
unsigned int area_size = aqueue->area_size;
return aqueue->full ? area_size :
(area_size - aqueue->tail + aqueue->head) % area_size;
}
dovecot-2.3.21.1/src/lib/pkcs5.c 0000644 0000000 0000000 00000005061 14656633576 013045 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "hash-method.h"
#include "hmac.h"
#include "pkcs5.h"
#include
#include
static
int pkcs5_pbkdf1(const struct hash_method *hash,
const unsigned char *password, size_t password_len,
const unsigned char *salt, size_t salt_len,
unsigned int iter, uint32_t length,
buffer_t *result)
{
if (length < 1 ||
length > hash->digest_size) return -1;
if (iter < 1) return -1;
unsigned char dk[hash->digest_size];
unsigned char ctx[hash->context_size];
hash->init(ctx);
hash->loop(ctx, password, password_len);
hash->loop(ctx, salt, salt_len);
hash->result(ctx, dk);
length--;
for(;length>0;length--) {
hash->init(ctx);
hash->loop(ctx, dk, hash->digest_size);
hash->result(ctx, dk);
}
buffer_append(result, dk, hash->digest_size);
return 0;
}
static
int pkcs5_pbkdf2(const struct hash_method *hash,
const unsigned char *password, size_t password_len,
const unsigned char *salt, size_t salt_len,
unsigned int iter, uint32_t length,
buffer_t *result)
{
if (length < 1 || iter < 1) return -1;
size_t l = (length + hash->digest_size - 1)/hash->digest_size; /* same as ceil(length/hash->digest_size) */
unsigned char dk[l * hash->digest_size];
unsigned char *block;
struct hmac_context hctx;
unsigned int c,i,t;
unsigned char U_c[hash->digest_size];
for(t = 0; t < l; t++) {
block = &(dk[t*hash->digest_size]);
/* U_1 = PRF(Password, Salt|| INT_BE32(Block_Number)) */
c = htonl(t+1);
hmac_init(&hctx, password, password_len, hash);
hmac_update(&hctx, salt, salt_len);
hmac_update(&hctx, &c, sizeof(c));
hmac_final(&hctx, U_c);
/* block = U_1 ^ .. ^ U_iter */
memcpy(block, U_c, hash->digest_size);
/* U_c = PRF(Password, U_c-1) */
for(c = 1; c < iter; c++) {
hmac_init(&hctx, password, password_len, hash);
hmac_update(&hctx, U_c, hash->digest_size);
hmac_final(&hctx, U_c);
for(i = 0; i < hash->digest_size; i++)
block[i] ^= U_c[i];
}
}
buffer_append(result, dk, length);
return 0;
}
int pkcs5_pbkdf(enum pkcs5_pbkdf_mode mode, const struct hash_method *hash,
const unsigned char *password, size_t password_len,
const unsigned char *salt, size_t salt_len,
unsigned int iterations, uint32_t dk_len,
buffer_t *result)
{
if (mode == PKCS5_PBKDF1)
return pkcs5_pbkdf1(hash,password,password_len,
salt,salt_len,iterations,dk_len,result);
else if (mode == PKCS5_PBKDF2)
return pkcs5_pbkdf2(hash,password,password_len,
salt,salt_len,iterations,dk_len,result);
i_unreached();
}
dovecot-2.3.21.1/src/lib/sort.c 0000644 0000000 0000000 00000000547 14656633576 013013 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "sort.h"
#include
#include
int bsearch_strcmp(const char *key, const char *const *member)
{
return strcmp(key, *member);
}
int bsearch_strcasecmp(const char *key, const char *const *member)
{
return strcasecmp(key, *member);
}
dovecot-2.3.21.1/src/lib/ostream-multiplex.h 0000644 0000000 0000000 00000000452 14656633576 015517 0000000 0000000 #ifndef OSTREAM_MULTIPLEX
#define OSTREAM_MULTIPLEX 1
struct ostream *o_stream_create_multiplex(struct ostream *parent, size_t bufsize);
struct ostream *o_stream_multiplex_add_channel(struct ostream *stream, uint8_t cid);
uint8_t o_stream_multiplex_get_channel_id(struct ostream *stream);
#endif
dovecot-2.3.21.1/src/lib/test-ostream-failure-at.c 0000644 0000000 0000000 00000003550 14656633576 016477 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "buffer.h"
#include "ostream.h"
#include "ostream-failure-at.h"
#define TEST_DATA_LENGTH 128
#define TEST_ERRMSG "test-ostream-failure-at error triggered"
void test_ostream_failure_at(void)
{
unsigned char test_data[TEST_DATA_LENGTH];
struct ostream *output, *buf_output;
buffer_t *buf = t_buffer_create(256);
unsigned int i;
test_begin("ostream failure at");
for (i = 0; i < sizeof(test_data); i++)
test_data[i] = i;
for (i = 0; i < TEST_DATA_LENGTH; i++) {
buf_output = o_stream_create_buffer(buf);
output = o_stream_create_failure_at(buf_output, i, TEST_ERRMSG);
if (i > 0)
test_assert(o_stream_send(output, test_data, sizeof(test_data)) == (int)i);
test_assert_idx(o_stream_send(output, test_data, sizeof(test_data)) == -1 &&
output->offset == i &&
output->stream_errno == EIO &&
strcmp(o_stream_get_error(output), TEST_ERRMSG) == 0, i);
o_stream_destroy(&output);
o_stream_destroy(&buf_output);
}
/* shouldn't fail */
buf_output = o_stream_create_buffer(buf);
output = o_stream_create_failure_at(buf_output, TEST_DATA_LENGTH, TEST_ERRMSG);
test_assert(o_stream_send(output, test_data, sizeof(test_data)) == TEST_DATA_LENGTH);
test_assert(o_stream_flush(output) > 0 &&
output->offset == TEST_DATA_LENGTH &&
output->stream_errno == 0);
o_stream_destroy(&output);
o_stream_destroy(&buf_output);
/* fail at flush */
buf_output = o_stream_create_buffer(buf);
output = o_stream_create_failure_at_flush(buf_output, TEST_ERRMSG);
test_assert(o_stream_send(output, test_data, sizeof(test_data)) == TEST_DATA_LENGTH);
test_assert(o_stream_flush(output) < 0 && output->stream_errno == EIO &&
strcmp(o_stream_get_error(output), TEST_ERRMSG) == 0);
o_stream_destroy(&output);
o_stream_destroy(&buf_output);
test_end();
}
dovecot-2.3.21.1/src/lib/unichar.c 0000644 0000000 0000000 00000023344 14656633576 013455 0000000 0000000 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "bsearch-insert-pos.h"
#include "unichar.h"
#include "unicodemap.c"
#define HANGUL_FIRST 0xac00
#define HANGUL_LAST 0xd7a3
const unsigned char utf8_replacement_char[UTF8_REPLACEMENT_CHAR_LEN] =
{ 0xef, 0xbf, 0xbd }; /* 0xfffd */
static const uint8_t utf8_non1_bytes[256 - 192 - 2] = {
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
const uint8_t *const uni_utf8_non1_bytes = utf8_non1_bytes;
unsigned int uni_strlen(const unichar_t *str)
{
unsigned int len = 0;
for (len = 0; str[len] != 0; len++) ;
return len;
}
int uni_utf8_get_char(const char *input, unichar_t *chr_r)
{
return uni_utf8_get_char_n((const unsigned char *)input, SIZE_MAX,
chr_r);
}
int uni_utf8_get_char_n(const void *_input, size_t max_len, unichar_t *chr_r)
{
static unichar_t lowest_valid_chr_table[] =
{ 0, 0, 0x80, 0x800, 0x10000, 0x200000, 0x4000000 };
const unsigned char *input = _input;
unichar_t chr, lowest_valid_chr;
unsigned int i, len;
int ret;
i_assert(max_len > 0);
if (*input < 0x80) {
*chr_r = *input;
return 1;
}
/* first byte has len highest bits set, followed by zero bit.
the rest of the bits are used as the highest bits of the value. */
chr = *input;
len = uni_utf8_char_bytes(*input);
switch (len) {
case 2:
chr &= 0x1f;
break;
case 3:
chr &= 0x0f;
break;
case 4:
chr &= 0x07;
break;
case 5:
chr &= 0x03;
break;
case 6:
chr &= 0x01;
break;
default:
/* only 7bit chars should have len==1 */
i_assert(len == 1);
return -1;
}
if (len <= max_len) {
lowest_valid_chr = lowest_valid_chr_table[len];
ret = len;
} else {
/* check first if the input is invalid before returning 0 */
lowest_valid_chr = 0;
ret = 0;
len = max_len;
}
/* the following bytes must all be 10xxxxxx */
for (i = 1; i < len; i++) {
if ((input[i] & 0xc0) != 0x80)
return input[i] == '\0' ? 0 : -1;
chr <<= 6;
chr |= input[i] & 0x3f;
}
/* these are specified as invalid encodings by standards
see RFC3629 */
if (!uni_is_valid_ucs4(chr))
return -1;
if (chr < lowest_valid_chr) {
/* overlong encoding */
return -1;
}
*chr_r = chr;
return ret;
}
int uni_utf8_to_ucs4(const char *input, ARRAY_TYPE(unichars) *output)
{
unichar_t chr;
while (*input != '\0') {
int len = uni_utf8_get_char(input, &chr);
if (len <= 0) {
/* invalid input */
return -1;
}
input += len;
array_push_back(output, &chr);
}
return 0;
}
int uni_utf8_to_ucs4_n(const unsigned char *input, size_t size,
ARRAY_TYPE(unichars) *output)
{
unichar_t chr;
while (size > 0) {
int len = uni_utf8_get_char_n(input, size, &chr);
if (len <= 0)
return -1; /* invalid input */
input += len; size -= len;
array_push_back(output, &chr);
}
return 0;
}
void uni_ucs4_to_utf8(const unichar_t *input, size_t len, buffer_t *output)
{
for (; len > 0 && *input != '\0'; input++, len--)
uni_ucs4_to_utf8_c(*input, output);
}
void uni_ucs4_to_utf8_c(unichar_t chr, buffer_t *output)
{
unsigned char first;
int bitpos;
if (chr < 0x80) {
buffer_append_c(output, chr);
return;
}
i_assert(uni_is_valid_ucs4(chr));
if (chr < (1 << (6 + 5))) {
/* 110xxxxx */
bitpos = 6;
first = 0x80 | 0x40;
} else if (chr < (1 << ((2*6) + 4))) {
/* 1110xxxx */
bitpos = 2*6;
first = 0x80 | 0x40 | 0x20;
} else if (chr < (1 << ((3*6) + 3))) {
/* 11110xxx */
bitpos = 3*6;
first = 0x80 | 0x40 | 0x20 | 0x10;
} else if (chr < (1 << ((4*6) + 2))) {
/* 111110xx */
bitpos = 4*6;
first = 0x80 | 0x40 | 0x20 | 0x10 | 0x08;
} else {
/* 1111110x */
bitpos = 5*6;
first = 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04;
}
buffer_append_c(output, first | (chr >> bitpos));
do {
bitpos -= 6;
buffer_append_c(output, 0x80 | ((chr >> bitpos) & 0x3f));
} while (bitpos > 0);
}
unsigned int uni_utf8_strlen(const char *input)
{
return uni_utf8_strlen_n(input, strlen(input));
}
unsigned int uni_utf8_strlen_n(const void *input, size_t size)
{
size_t partial_pos;
return uni_utf8_partial_strlen_n(input, size, &partial_pos);
}
unsigned int uni_utf8_partial_strlen_n(const void *_input, size_t size,
size_t *partial_pos_r)
{
const unsigned char *input = _input;
unsigned int count, len = 0;
size_t i;
for (i = 0; i < size; ) {
count = uni_utf8_char_bytes(input[i]);
if (i + count > size)
break;
i += count;
len++;
}
*partial_pos_r = i;
return len;
}
static bool uint16_find(const uint16_t *data, unsigned int count,
uint16_t value, unsigned int *idx_r)
{
BINARY_NUMBER_SEARCH(data, count, value, idx_r);
}
static bool uint32_find(const uint32_t *data, unsigned int count,
uint32_t value, unsigned int *idx_r)
{
BINARY_NUMBER_SEARCH(data, count, value, idx_r);
}
unichar_t uni_ucs4_to_titlecase(unichar_t chr)
{
unsigned int idx;
if (chr <= 0xff)
return titlecase8_map[chr];
else if (chr <= 0xffff) {
if (!uint16_find(titlecase16_keys, N_ELEMENTS(titlecase16_keys),
chr, &idx))
return chr;
else
return titlecase16_values[idx];
} else {
if (!uint32_find(titlecase32_keys, N_ELEMENTS(titlecase32_keys),
chr, &idx))
return chr;
else
return titlecase32_values[idx];
}
}
static bool uni_ucs4_decompose_uni(unichar_t *chr)
{
unsigned int idx;
if (*chr <= 0xff) {
if (uni8_decomp_map[*chr] == *chr)
return FALSE;
*chr = uni8_decomp_map[*chr];
} else if (*chr <= 0xffff) {
if (*chr < uni16_decomp_keys[0])
return FALSE;
if (!uint16_find(uni16_decomp_keys,
N_ELEMENTS(uni16_decomp_keys), *chr, &idx))
return FALSE;
*chr = uni16_decomp_values[idx];
} else {
if (!uint32_find(uni32_decomp_keys,
N_ELEMENTS(uni32_decomp_keys), *chr, &idx))
return FALSE;
*chr = uni32_decomp_values[idx];
}
return TRUE;
}
static void uni_ucs4_decompose_hangul_utf8(unichar_t chr, buffer_t *output)
{
#define SBase HANGUL_FIRST
#define LBase 0x1100
#define VBase 0x1161
#define TBase 0x11A7
#define LCount 19
#define VCount 21
#define TCount 28
#define NCount (VCount * TCount)
unsigned int SIndex = chr - SBase;
unichar_t L = LBase + SIndex / NCount;
unichar_t V = VBase + (SIndex % NCount) / TCount;
unichar_t T = TBase + SIndex % TCount;
uni_ucs4_to_utf8_c(L, output);
uni_ucs4_to_utf8_c(V, output);
if (T != TBase) uni_ucs4_to_utf8_c(T, output);
}
static bool uni_ucs4_decompose_multi_utf8(unichar_t chr, buffer_t *output)
{
const uint32_t *value;
unsigned int idx;
if (chr < multidecomp_keys[0] || chr > 0xffff)
return FALSE;
if (!uint32_find(multidecomp_keys, N_ELEMENTS(multidecomp_keys),
chr, &idx))
return FALSE;
value = &multidecomp_values[multidecomp_offsets[idx]];
for (; *value != 0; value++)
uni_ucs4_to_utf8_c(*value, output);
return TRUE;
}
static void output_add_replacement_char(buffer_t *output)
{
if (output->used >= UTF8_REPLACEMENT_CHAR_LEN &&
memcmp(CONST_PTR_OFFSET(output->data,
output->used - UTF8_REPLACEMENT_CHAR_LEN),
utf8_replacement_char, UTF8_REPLACEMENT_CHAR_LEN) == 0) {
/* don't add the replacement char multiple times */
return;
}
buffer_append(output, utf8_replacement_char, UTF8_REPLACEMENT_CHAR_LEN);
}
int uni_utf8_to_decomposed_titlecase(const void *_input, size_t size,
buffer_t *output)
{
const unsigned char *input = _input;
unichar_t chr;
int ret = 0;
while (size > 0) {
int bytes = uni_utf8_get_char_n(input, size, &chr);
if (bytes <= 0) {
/* invalid input. try the next byte. */
ret = -1;
input++; size--;
output_add_replacement_char(output);
continue;
}
input += bytes;
size -= bytes;
chr = uni_ucs4_to_titlecase(chr);
if (chr >= HANGUL_FIRST && chr <= HANGUL_LAST)
uni_ucs4_decompose_hangul_utf8(chr, output);
else if (uni_ucs4_decompose_uni(&chr) ||
!uni_ucs4_decompose_multi_utf8(chr, output))
uni_ucs4_to_utf8_c(chr, output);
}
return ret;
}
static inline unsigned int
is_valid_utf8_seq(const unsigned char *input, unsigned int size)
{
unichar_t chr;
int len = uni_utf8_get_char_n(input, size, &chr);
return len <= 0 ? 0 : len;
}
static int uni_utf8_find_invalid_pos(const unsigned char *input, size_t size,
size_t *pos_r)
{
size_t i, len;
/* find the first invalid utf8 sequence */
for (i = 0; i < size;) {
if (input[i] < 0x80)
i++;
else {
len = is_valid_utf8_seq(input + i, size-i);
if (unlikely(len == 0)) {
*pos_r = i;
return -1;
}
i += len;
}
}
return 0;
}
bool uni_utf8_get_valid_data(const unsigned char *input, size_t size,
buffer_t *buf)
{
size_t i, len;
if (uni_utf8_find_invalid_pos(input, size, &i) == 0)
return TRUE;
/* broken utf-8 input - skip the broken characters */
buffer_append(buf, input, i++);
output_add_replacement_char(buf);
while (i < size) {
if (input[i] < 0x80) {
buffer_append_c(buf, input[i++]);
continue;
}
len = is_valid_utf8_seq(input + i, size-i);
if (len == 0) {
i++;
output_add_replacement_char(buf);
continue;
}
buffer_append(buf, input + i, len);
i += len;
}
return FALSE;
}
bool uni_utf8_str_is_valid(const char *str)
{
size_t i;
return uni_utf8_find_invalid_pos((const unsigned char *)str,
strlen(str), &i) == 0;
}
bool uni_utf8_data_is_valid(const unsigned char *data, size_t size)
{
size_t i;
return uni_utf8_find_invalid_pos(data, size, &i) == 0;
}
size_t uni_utf8_data_truncate(const unsigned char *data, size_t old_size,
size_t max_new_size)
{
if (max_new_size >= old_size)
return old_size;
if (max_new_size == 0)
return 0;
if ((data[max_new_size] & 0x80) == 0)
return max_new_size;
while (max_new_size > 0 && (data[max_new_size-1] & 0xc0) == 0x80)
max_new_size--;
if (max_new_size > 0 && (data[max_new_size-1] & 0xc0) == 0xc0)
max_new_size--;
return max_new_size;
}
dovecot-2.3.21.1/src/lib/sleep.c 0000644 0000000 0000000 00000003066 14656633576 013133 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "sleep.h"
#include
static bool ATTR_NOWARN_UNUSED_RESULT
sleep_timespec(const struct timespec *ts_sleep, bool interruptible)
{
struct timespec ts_remain = *ts_sleep;
while (nanosleep(&ts_remain, &ts_remain) < 0) {
if (errno != EINTR)
i_fatal("nanosleep(): %m");
if (interruptible)
return FALSE;
}
return TRUE;
}
void i_sleep_usecs(unsigned long long usecs)
{
struct timespec ts_sleep;
ts_sleep.tv_sec = (time_t)(usecs / 1000000);
ts_sleep.tv_nsec = (long)(usecs % 1000000) * 1000;
sleep_timespec(&ts_sleep, FALSE);
}
void i_sleep_msecs(unsigned int msecs)
{
struct timespec ts_sleep;
ts_sleep.tv_sec = (time_t)(msecs / 1000);
ts_sleep.tv_nsec = (long)(msecs % 1000) * 1000000;
sleep_timespec(&ts_sleep, FALSE);
}
void i_sleep_secs(time_t secs)
{
struct timespec ts_sleep;
ts_sleep.tv_sec = secs;
ts_sleep.tv_nsec = 0;
sleep_timespec(&ts_sleep, FALSE);
}
bool i_sleep_intr_usecs(unsigned long long usecs)
{
struct timespec ts_sleep;
ts_sleep.tv_sec = (time_t)(usecs / 1000000);
ts_sleep.tv_nsec = (long)(usecs % 1000000) * 1000;
return sleep_timespec(&ts_sleep, TRUE);
}
bool i_sleep_intr_msecs(unsigned int msecs)
{
struct timespec ts_sleep;
ts_sleep.tv_sec = (time_t)(msecs / 1000);
ts_sleep.tv_nsec = (long)(msecs % 1000) * 1000000;
return sleep_timespec(&ts_sleep, TRUE);
}
bool i_sleep_intr_secs(time_t secs)
{
struct timespec ts_sleep;
ts_sleep.tv_sec = secs;
ts_sleep.tv_nsec = 0;
return sleep_timespec(&ts_sleep, TRUE);
}
dovecot-2.3.21.1/src/lib/test-file-cache.c 0000644 0000000 0000000 00000021515 14656633576 014757 0000000 0000000 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "istream.h"
#include "ostream.h"
#include "file-cache.h"
#include
#include
#include
#include
#include
#include
#define TEST_FILENAME ".test_file_cache"
static void test_file_cache_read(void)
{
test_begin("file_cache_read");
/* create a file */
struct ostream *os = o_stream_create_file(TEST_FILENAME, 0, 0600, 0);
o_stream_nsend_str(os, "initial data\n");
test_assert(o_stream_finish(os) == 1);
o_stream_destroy(&os);
int fd = open(TEST_FILENAME, O_RDONLY);
i_assert(fd > -1);
struct file_cache *cache = file_cache_new_path(fd, TEST_FILENAME);
/* this should be 0 before read */
size_t size;
const unsigned char *map = file_cache_get_map(cache, &size);
test_assert(map == NULL);
test_assert(size == 0);
test_assert(map == NULL);
test_assert(file_cache_read(cache, 0, 13) == 13);
map = file_cache_get_map(cache, &size);
test_assert(map != NULL && size == 13 && memcmp(map, "initial data\n", 13) == 0);
file_cache_free(&cache);
i_close_fd(&fd);
i_unlink(TEST_FILENAME);
test_end();
}
static void test_file_cache_write_read(void)
{
test_begin("file_cache_write_read");
/* create a file */
struct ostream *os = o_stream_create_file(TEST_FILENAME, 0, 0600, 0);
o_stream_nsend_str(os, "initial data\n");
test_assert(o_stream_finish(os) == 1);
o_stream_destroy(&os);
int fd = open(TEST_FILENAME, O_RDONLY);
i_assert(fd > -1);
struct file_cache *cache = file_cache_new_path(fd, TEST_FILENAME);
/* this should be 0 before read */
size_t size;
const unsigned char *map = file_cache_get_map(cache, &size);
test_assert(map == NULL);
test_assert(size == 0);
test_assert(map == NULL);
test_assert(file_cache_read(cache, 0, 13) == 13);
file_cache_write(cache, "updated data\n", 13, 0);
map = file_cache_get_map(cache, &size);
test_assert(map != NULL && size == 13 && memcmp(map, "updated data\n", 13) == 0);
file_cache_free(&cache);
i_close_fd(&fd);
struct istream *is = i_stream_create_file(TEST_FILENAME, SIZE_MAX);
const unsigned char *data;
test_assert(i_stream_read_more(is, &data, &size) > 0 && size == 13);
test_assert(map != NULL && size == 13 && memcmp(data, "initial data\n", 13) == 0);
i_stream_destroy(&is);
i_unlink(TEST_FILENAME);
test_end();
}
static void test_file_cache_read_invalidate(void)
{
test_begin("file_cache_read_invalidate");
/* create a file */
struct ostream *os = o_stream_create_file(TEST_FILENAME, 0, 0600, 0);
o_stream_nsend_str(os, "initial data\n");
test_assert(o_stream_finish(os) == 1);
o_stream_destroy(&os);
int fd = open(TEST_FILENAME, O_RDONLY);
i_assert(fd > -1);
struct file_cache *cache = file_cache_new_path(fd, TEST_FILENAME);
/* this should be 0 before read */
size_t size;
test_assert(file_cache_read(cache, 0, 13) == 13);
const unsigned char *map = file_cache_get_map(cache, &size);
test_assert(map != NULL && size == 13 && memcmp(map, "initial data\n", 13) == 0);
/* update file */
os = o_stream_create_file(TEST_FILENAME, 0, 0600, 0);
o_stream_nsend_str(os, "updated data\n");
test_assert(o_stream_finish(os) == 1);
o_stream_destroy(&os);
map = file_cache_get_map(cache, &size);
test_assert(map != NULL && size == 13 && memcmp(map, "initial data\n", 13) == 0);
/* invalidate cache */
file_cache_invalidate(cache, 0, size);
test_assert(file_cache_read(cache, 0, 13) == 13);
map = file_cache_get_map(cache, &size);
test_assert(size == 13);
test_assert(map != NULL && size == 13 && memcmp(map, "updated data\n", 13) == 0);
file_cache_free(&cache);
i_close_fd(&fd);
i_unlink(TEST_FILENAME);
test_end();
}
static void test_file_cache_multipage(void)
{
test_begin("file_cache_multipage");
size_t page_size = getpagesize();
struct ostream *os = o_stream_create_file(TEST_FILENAME, 0, 0600, 0);
size_t total_size = 0;
for (size_t i = 0; i < page_size * 3 + 100; i += 12) {
o_stream_nsend_str(os, "initial data");
total_size += 12;
}
test_assert(o_stream_finish(os) == 1);
o_stream_destroy(&os);
int fd = open(TEST_FILENAME, O_RDONLY);
i_assert(fd > -1);
struct file_cache *cache = file_cache_new_path(fd, TEST_FILENAME);
/* read everything to memory page at a time */
test_assert(file_cache_read(cache, 0, page_size) == (ssize_t)page_size);
test_assert(file_cache_read(cache, page_size, page_size) ==
(ssize_t)page_size);
test_assert(file_cache_read(cache, page_size*2, page_size) ==
(ssize_t)page_size);
test_assert(file_cache_read(cache, page_size*3, page_size) ==
(ssize_t)total_size-(ssize_t)page_size*3);
size_t size;
const unsigned char *map = file_cache_get_map(cache, &size);
test_assert(size == total_size);
test_assert(map != NULL);
/* write-read-invalidate-read */
for(size_t i = 0; i < page_size * 3; i+= page_size / 3) {
char orig[13];
const char *ptr = CONST_PTR_OFFSET(map, i);
memcpy(orig, ptr, 12);
orig[12] = '\0';
file_cache_write(cache, "updated data", 12, i);
map = file_cache_get_map(cache, &size);
ptr = CONST_PTR_OFFSET(map, i);
test_assert(strncmp(ptr, "updated data", 12) == 0);
/* invalidate cache */
file_cache_invalidate(cache, i, 12);
/* check that it's back what it was */
test_assert(file_cache_read(cache, i, 12) == 12);
map = file_cache_get_map(cache, &size);
ptr = CONST_PTR_OFFSET(map, i);
test_assert(strncmp(ptr, orig, 12) == 0);
}
file_cache_free(&cache);
i_close_fd(&fd);
i_unlink(TEST_FILENAME);
test_end();
}
static void test_file_cache_anon(void)
{
/* file-cache should work as anonymous cache for small files */
test_begin("file_cache_anon");
test_assert(access(TEST_FILENAME, F_OK) == -1 && errno == ENOENT);
struct file_cache *cache = file_cache_new_path(-1, TEST_FILENAME);
test_assert(file_cache_set_size(cache, 1024) == 0);
file_cache_write(cache, "initial data", 12, 0);
size_t size;
const unsigned char *map = file_cache_get_map(cache, &size);
test_assert(map != NULL && size == 12 && memcmp(map, "initial data", 12) == 0);
file_cache_free(&cache);
i_unlink_if_exists(TEST_FILENAME);
test_end();
}
static void test_file_cache_switch_fd(void)
{
test_begin("file_cache_switch_fd");
test_assert(access(TEST_FILENAME, F_OK) == -1 && errno == ENOENT);
struct file_cache *cache = file_cache_new_path(-1, TEST_FILENAME);
test_assert(file_cache_set_size(cache, 13) == 0);
file_cache_write(cache, "initial data\n", 13, 0);
/* create a file */
struct ostream *os = o_stream_create_file(TEST_FILENAME, 0, 0600, 0);
o_stream_nsend_str(os, "updated data\n");
test_assert(o_stream_finish(os) == 1);
o_stream_destroy(&os);
int fd = open(TEST_FILENAME, O_RDONLY);
i_assert(fd > -1);
/* map should be invalidated and updated data read
from given file */
file_cache_set_fd(cache, fd);
test_assert(file_cache_read(cache, 0, 13) == 13);
size_t size;
const unsigned char *map = file_cache_get_map(cache, &size);
test_assert(map != NULL && size == 13 && memcmp(map, "updated data\n", 13) == 0);
file_cache_free(&cache);
i_close_fd(&fd);
i_unlink(TEST_FILENAME);
test_end();
}
static void test_file_cache_errors(void)
{
test_begin("file_cache_errors");
size_t page_size = getpagesize();
test_assert(access(TEST_FILENAME, F_OK) == -1 && errno == ENOENT);
int fd = open(TEST_FILENAME, O_RDONLY);
struct file_cache *cache = file_cache_new_path(fd, TEST_FILENAME);
size_t size;
/* file does not exist and we try large enough mapping */
test_expect_error_string("fstat(.test_file_cache) failed: "
"Bad file descriptor");
test_assert(file_cache_read(cache, 0, 2*1024*1024) == -1);
const unsigned char *map = file_cache_get_map(cache, &size);
test_assert(size == 0);
test_assert(map == NULL);
/* temporarily set a small memory limit to make mmap attempt fail */
struct rlimit rl_cur;
test_assert(getrlimit(RLIMIT_AS, &rl_cur) == 0);
struct rlimit rl_new = {
.rlim_cur = 1,
.rlim_max = rl_cur.rlim_max
};
const char *errstr =
t_strdup_printf("mmap_anon(.test_file_cache, %zu) failed: "
"Cannot allocate memory", page_size);
test_assert(setrlimit(RLIMIT_AS, &rl_new) == 0);
test_expect_error_string(errstr);
test_assert(file_cache_set_size(cache, 1024) == -1);
test_assert(setrlimit(RLIMIT_AS, &rl_cur) == 0);
/* same for mremap */
errstr = t_strdup_printf("mremap_anon(.test_file_cache, %zu) failed: "
"Cannot allocate memory", page_size*2);
test_assert(file_cache_set_size(cache, 1) == 0);
test_assert(setrlimit(RLIMIT_AS, &rl_new) == 0);
test_expect_error_string(errstr);
test_assert(file_cache_set_size(cache, page_size*2) == -1);
test_assert(setrlimit(RLIMIT_AS, &rl_cur) == 0);
file_cache_free(&cache);
i_close_fd(&fd);
i_unlink_if_exists(TEST_FILENAME);
test_end();
}
void test_file_cache(void)
{
test_file_cache_read();
test_file_cache_write_read();
test_file_cache_read_invalidate();
test_file_cache_multipage();
test_file_cache_anon();
test_file_cache_switch_fd();
test_file_cache_errors();
}
dovecot-2.3.21.1/src/lib/hostpid.c 0000644 0000000 0000000 00000003003 14656633576 013464 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "hostpid.h"
#include
#include
#define HOSTNAME_DISALLOWED_CHARS "/\r\n\t"
const char *my_hostname = NULL;
const char *my_pid = NULL;
static char *my_hostname_dup = NULL;
static char *my_domain = NULL;
void hostpid_init(void)
{
static char pid[MAX_INT_STRLEN];
char hostname[256];
const char *value;
/* allow calling hostpid_init() multiple times to reset hostname */
i_free_and_null(my_hostname_dup);
i_free_and_null(my_domain);
value = getenv(MY_HOSTNAME_ENV);
if (value == NULL) {
if (gethostname(hostname, sizeof(hostname)-1) < 0)
i_fatal("gethostname() failed: %m");
hostname[sizeof(hostname)-1] = '\0';
value = hostname;
}
if (value[0] == '\0' ||
strcspn(value, HOSTNAME_DISALLOWED_CHARS) != strlen(value))
i_fatal("Invalid system hostname: '%s'", value);
my_hostname_dup = i_strdup(value);
my_hostname = my_hostname_dup;
i_snprintf(pid, sizeof(pid), "%lld", (long long)getpid());
my_pid = pid;
}
void hostpid_deinit(void)
{
i_free(my_hostname_dup);
i_free(my_domain);
}
const char *my_hostdomain(void)
{
struct hostent *hent;
const char *name;
if (my_domain == NULL) {
name = getenv(MY_HOSTDOMAIN_ENV);
if (name == NULL) {
hent = gethostbyname(my_hostname);
name = hent != NULL ? hent->h_name : NULL;
if (name == NULL) {
/* failed, use just the hostname */
name = my_hostname;
}
}
my_domain = i_strdup(name);
}
return my_domain;
}
dovecot-2.3.21.1/src/lib/json-parser.c 0000644 0000000 0000000 00000050533 14656633576 014267 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "istream.h"
#include "hex-dec.h"
#include "unichar.h"
#include "istream-jsonstr.h"
#include "json-parser.h"
enum json_state {
JSON_STATE_ROOT = 0,
JSON_STATE_OBJECT_OPEN,
JSON_STATE_OBJECT_KEY,
JSON_STATE_OBJECT_COLON,
JSON_STATE_OBJECT_VALUE,
JSON_STATE_OBJECT_SKIP_STRING,
JSON_STATE_OBJECT_NEXT,
JSON_STATE_ARRAY_OPEN,
JSON_STATE_ARRAY_VALUE,
JSON_STATE_ARRAY_SKIP_STRING,
JSON_STATE_ARRAY_NEXT,
JSON_STATE_ARRAY_NEXT_SKIP,
JSON_STATE_VALUE,
JSON_STATE_DONE
};
struct json_parser {
pool_t pool;
struct istream *input;
uoff_t highwater_offset;
enum json_parser_flags flags;
const unsigned char *start, *end, *data;
const char *error;
string_t *value;
struct istream *strinput;
enum json_state state;
ARRAY(enum json_state) nesting;
unsigned int nested_skip_count;
bool skipping;
bool seen_eof;
};
static int json_parser_read_more(struct json_parser *parser)
{
uoff_t cur_highwater = parser->input->v_offset +
i_stream_get_data_size(parser->input);
size_t size;
ssize_t ret;
i_assert(parser->highwater_offset <= cur_highwater);
if (parser->error != NULL)
return -1;
if (parser->highwater_offset == cur_highwater) {
ret = i_stream_read(parser->input);
if (ret == -2) {
parser->error = "Token too large";
return -1;
}
if (ret < 0 && !parser->seen_eof &&
i_stream_get_data_size(parser->input) > 0 &&
parser->input->stream_errno == 0) {
/* call it once more to finish any pending number */
parser->seen_eof = TRUE;
} else if (ret <= 0) {
return ret;
} else {
cur_highwater = parser->input->v_offset +
i_stream_get_data_size(parser->input);
i_assert(parser->highwater_offset < cur_highwater);
parser->highwater_offset = cur_highwater;
}
}
parser->start = parser->data = i_stream_get_data(parser->input, &size);
parser->end = parser->start + size;
i_assert(size > 0);
return 1;
}
static void json_parser_update_input_pos(struct json_parser *parser)
{
size_t size;
if (parser->data == parser->start)
return;
i_stream_skip(parser->input, parser->data - parser->start);
parser->start = parser->data = i_stream_get_data(parser->input, &size);
parser->end = parser->start + size;
if (size > 0) {
/* we skipped over some data and there's still data left.
no need to read() the next time. */
parser->highwater_offset = 0;
} else {
parser->highwater_offset = parser->input->v_offset;
}
}
struct json_parser *json_parser_init(struct istream *input)
{
return json_parser_init_flags(input, 0);
}
struct json_parser *json_parser_init_flags(struct istream *input,
enum json_parser_flags flags)
{
struct json_parser *parser;
pool_t pool = pool_alloconly_create("json parser",
sizeof(struct json_parser)+64);
parser = p_new(pool, struct json_parser, 1);
parser->pool = pool;
parser->input = input;
parser->flags = flags;
parser->value = str_new(default_pool, 128);
i_array_init(&parser->nesting, 8);
i_stream_ref(input);
if ((flags & JSON_PARSER_NO_ROOT_OBJECT) != 0)
parser->state = JSON_STATE_VALUE;
return parser;
}
int json_parser_deinit(struct json_parser **_parser, const char **error_r)
{
struct json_parser *parser = *_parser;
*_parser = NULL;
if (parser->error != NULL) {
/* actual parser error */
*error_r = t_strdup(parser->error);
} else if (parser->input->stream_errno != 0) {
*error_r = t_strdup_printf("read(%s) failed: %s",
i_stream_get_name(parser->input),
i_stream_get_error(parser->input));
} else if (parser->data == parser->end &&
!i_stream_have_bytes_left(parser->input) &&
parser->state != JSON_STATE_DONE) {
*error_r = "Missing '}'";
} else {
*error_r = NULL;
}
i_stream_unref(&parser->input);
array_free(&parser->nesting);
str_free(&parser->value);
pool_unref(&parser->pool);
return *error_r != NULL ? -1 : 0;
}
static bool json_parse_whitespace(struct json_parser *parser)
{
for (; parser->data != parser->end; parser->data++) {
switch (*parser->data) {
case ' ':
case '\t':
case '\r':
case '\n':
break;
default:
json_parser_update_input_pos(parser);
return TRUE;
}
}
json_parser_update_input_pos(parser);
return FALSE;
}
static int json_skip_string(struct json_parser *parser)
{
for (; parser->data != parser->end; parser->data++) {
if (*parser->data == '"') {
parser->data++;
json_parser_update_input_pos(parser);
return 1;
}
if (*parser->data == '\\') {
parser->data++;
if (parser->data == parser->end)
break;
switch (*parser->data) {
case '"':
case '\\':
case '/':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
break;
case 'u':
if (parser->end - parser->data < 4) {
parser->data = parser->end;
return -1;
}
parser->data += 3;
break;
default:
parser->error = "Invalid escape string";
return -1;
}
}
}
json_parser_update_input_pos(parser);
return 0;
}
static int json_parse_unicode_escape(struct json_parser *parser)
{
char chbuf[5] = {0};
unichar_t chr, hi_surg;
parser->data++;
if (parser->end - parser->data < 4) {
/* wait for more data */
parser->data = parser->end;
return 0;
}
memcpy(chbuf, parser->data, 4);
if (str_to_uint32_hex(chbuf, &chr) < 0) {
parser->error = "Invalid unicode escape seen";
return -1;
}
if (UTF16_VALID_HIGH_SURROGATE(chr)) {
/* possible surrogate pair */
hi_surg = chr;
chr = 0;
parser->data += 4;
if (parser->data >= parser->end) {
/* wait for more data */
parser->data = parser->end;
return 0;
}
if ((parser->end - parser->data) < 2) {
if (parser->data[0] == '\\') {
/* wait for more data */
parser->data = parser->end;
return 0;
}
/* error */
}
if ((parser->end - parser->data) < 6) {
if (parser->data[0] == '\\' &&
parser->data[1] == 'u') {
/* wait for more data */
parser->data = parser->end;
return 0;
}
/* error */
} else {
memcpy(chbuf, &parser->data[2], 4);
if (str_to_uint32_hex(chbuf, &chr) < 0) {
parser->error = "Invalid unicode escape seen";
return -1;
}
}
if (parser->data[0] != '\\' || parser->data[1] != 'u' ||
!UTF16_VALID_LOW_SURROGATE(chr)) {
parser->error = p_strdup_printf(parser->pool,
"High surrogate 0x%04x seen, "
"but not followed by low surrogate", hi_surg);
return -1;
}
chr = uni_join_surrogate(hi_surg, chr);
parser->data += 2;
}
if (!uni_is_valid_ucs4(chr)) {
parser->error = p_strdup_printf(parser->pool,
"Invalid unicode character U+%04x", chr);
return -1;
}
if (chr == 0) {
parser->error = "\\u0000 not supported in strings";
return -1;
}
uni_ucs4_to_utf8_c(chr, parser->value);
parser->data += 3;
return 1;
}
static int json_parse_string(struct json_parser *parser, bool allow_skip,
const char **value_r)
{
int ret;
if (*parser->data != '"')
return -1;
parser->data++;
if (parser->skipping && allow_skip) {
*value_r = NULL;
return json_skip_string(parser);
}
str_truncate(parser->value, 0);
for (; parser->data != parser->end; parser->data++) {
if (*parser->data == '"') {
parser->data++;
*value_r = str_c(parser->value);
return 1;
}
switch (*parser->data) {
case '\\':
if (++parser->data == parser->end)
return 0;
switch (*parser->data) {
case '"':
case '\\':
case '/':
str_append_c(parser->value, *parser->data);
break;
case 'b':
str_append_c(parser->value, '\b');
break;
case 'f':
str_append_c(parser->value, '\f');
break;
case 'n':
str_append_c(parser->value, '\n');
break;
case 'r':
str_append_c(parser->value, '\r');
break;
case 't':
str_append_c(parser->value, '\t');
break;
case 'u':
if ((ret=json_parse_unicode_escape(parser)) <= 0)
return ret;
break;
default:
parser->error = "Invalid escape string";
return -1;
}
break;
case '\0':
parser->error = "NULs not supported in strings";
return -1;
default:
str_append_c(parser->value, *parser->data);
break;
}
}
return 0;
}
static int
json_parse_digits(struct json_parser *parser)
{
if (parser->data == parser->end)
return 0;
if (*parser->data < '0' || *parser->data > '9')
return -1;
while (parser->data != parser->end &&
*parser->data >= '0' && *parser->data <= '9')
str_append_c(parser->value, *parser->data++);
return 1;
}
static int json_parse_int(struct json_parser *parser)
{
int ret;
if (*parser->data == '-') {
str_append_c(parser->value, *parser->data++);
if (parser->data == parser->end)
return 0;
}
if (*parser->data == '0')
str_append_c(parser->value, *parser->data++);
else {
if ((ret = json_parse_digits(parser)) <= 0)
return ret;
}
return 1;
}
static int json_parse_number(struct json_parser *parser, const char **value_r)
{
int ret;
str_truncate(parser->value, 0);
if ((ret = json_parse_int(parser)) <= 0)
return ret;
if (parser->data != parser->end && *parser->data == '.') {
/* frac */
str_append_c(parser->value, *parser->data++);
if ((ret = json_parse_digits(parser)) <= 0)
return ret;
}
if (parser->data != parser->end &&
(*parser->data == 'e' || *parser->data == 'E')) {
/* exp */
str_append_c(parser->value, *parser->data++);
if (parser->data == parser->end)
return 0;
if (*parser->data == '+' || *parser->data == '-')
str_append_c(parser->value, *parser->data++);
if ((ret = json_parse_digits(parser)) <= 0)
return ret;
}
if (parser->data == parser->end && !parser->input->eof)
return 0;
*value_r = str_c(parser->value);
return 1;
}
static int json_parse_atom(struct json_parser *parser, const char *atom)
{
size_t avail, len = strlen(atom);
avail = parser->end - parser->data;
if (avail < len) {
if (memcmp(parser->data, atom, avail) != 0)
return -1;
/* everything matches so far, but we need more data */
parser->data += avail;
return 0;
}
if (memcmp(parser->data, atom, len) != 0)
return -1;
parser->data += len;
return 1;
}
static int json_parse_denest(struct json_parser *parser)
{
const enum json_state *nested_states;
unsigned count;
parser->data++;
json_parser_update_input_pos(parser);
nested_states = array_get(&parser->nesting, &count);
i_assert(count > 0);
if (count == 1) {
/* closing root */
parser->state = JSON_STATE_DONE;
if ((parser->flags & JSON_PARSER_NO_ROOT_OBJECT) == 0)
return 0;
/* we want to return the ending "]" or "}" to caller */
return 1;
}
/* closing a nested object */
parser->state = nested_states[count-2] == JSON_STATE_OBJECT_OPEN ?
JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
array_delete(&parser->nesting, count-1, 1);
if (parser->nested_skip_count > 0) {
parser->nested_skip_count--;
return 0;
}
return 1;
}
static int
json_parse_close_object(struct json_parser *parser, enum json_type *type_r)
{
if (json_parse_denest(parser) == 0)
return 0;
*type_r = JSON_TYPE_OBJECT_END;
return 1;
}
static int
json_parse_close_array(struct json_parser *parser, enum json_type *type_r)
{
if (json_parse_denest(parser) == 0)
return 0;
*type_r = JSON_TYPE_ARRAY_END;
return 1;
}
static void json_parser_object_open(struct json_parser *parser)
{
parser->data++;
parser->state = JSON_STATE_OBJECT_OPEN;
array_push_back(&parser->nesting, &parser->state);
json_parser_update_input_pos(parser);
}
static int
json_try_parse_next(struct json_parser *parser, enum json_type *type_r,
const char **value_r)
{
bool skipping = parser->skipping;
int ret;
if (!json_parse_whitespace(parser))
return -1;
switch (parser->state) {
case JSON_STATE_ROOT:
if (*parser->data != '{') {
parser->error = "Object doesn't begin with '{'";
return -1;
}
json_parser_object_open(parser);
return 0;
case JSON_STATE_OBJECT_VALUE:
case JSON_STATE_ARRAY_VALUE:
case JSON_STATE_VALUE:
if (*parser->data == '{') {
json_parser_object_open(parser);
if (parser->skipping) {
parser->nested_skip_count++;
return 0;
}
*type_r = JSON_TYPE_OBJECT;
return 1;
} else if (*parser->data == '[') {
parser->data++;
parser->state = JSON_STATE_ARRAY_OPEN;
array_push_back(&parser->nesting, &parser->state);
json_parser_update_input_pos(parser);
if (parser->skipping) {
parser->nested_skip_count++;
return 0;
}
*type_r = JSON_TYPE_ARRAY;
return 1;
}
if ((ret = json_parse_string(parser, TRUE, value_r)) >= 0) {
*type_r = JSON_TYPE_STRING;
} else if ((ret = json_parse_number(parser, value_r)) >= 0) {
*type_r = JSON_TYPE_NUMBER;
} else if ((ret = json_parse_atom(parser, "true")) >= 0) {
*type_r = JSON_TYPE_TRUE;
*value_r = "true";
} else if ((ret = json_parse_atom(parser, "false")) >= 0) {
*type_r = JSON_TYPE_FALSE;
*value_r = "false";
} else if ((ret = json_parse_atom(parser, "null")) >= 0) {
*type_r = JSON_TYPE_NULL;
*value_r = NULL;
} else {
if (parser->error == NULL)
parser->error = "Invalid data as value";
return -1;
}
if (ret == 0) {
i_assert(parser->data == parser->end);
if (parser->skipping && *type_r == JSON_TYPE_STRING) {
/* a large string that we want to skip over. */
json_parser_update_input_pos(parser);
parser->state = parser->state == JSON_STATE_OBJECT_VALUE ?
JSON_STATE_OBJECT_SKIP_STRING :
JSON_STATE_ARRAY_SKIP_STRING;
return 0;
}
return -1;
}
switch (parser->state) {
case JSON_STATE_OBJECT_VALUE:
parser->state = JSON_STATE_OBJECT_NEXT;
break;
case JSON_STATE_ARRAY_VALUE:
parser->state = JSON_STATE_ARRAY_NEXT;
break;
case JSON_STATE_VALUE:
parser->state = JSON_STATE_DONE;
break;
default:
i_unreached();
}
break;
case JSON_STATE_OBJECT_OPEN:
if (*parser->data == '}')
return json_parse_close_object(parser, type_r);
parser->state = JSON_STATE_OBJECT_KEY;
/* fall through */
case JSON_STATE_OBJECT_KEY:
if (json_parse_string(parser, FALSE, value_r) <= 0) {
parser->error = "Expected string as object key";
return -1;
}
*type_r = JSON_TYPE_OBJECT_KEY;
parser->state = JSON_STATE_OBJECT_COLON;
break;
case JSON_STATE_OBJECT_COLON:
if (*parser->data != ':') {
parser->error = "Expected ':' after key";
return -1;
}
parser->data++;
parser->state = JSON_STATE_OBJECT_VALUE;
json_parser_update_input_pos(parser);
return 0;
case JSON_STATE_OBJECT_NEXT:
if (parser->skipping && parser->nested_skip_count == 0) {
/* we skipped over the previous value */
parser->skipping = FALSE;
}
if (*parser->data == '}')
return json_parse_close_object(parser, type_r);
if (*parser->data != ',') {
parser->error = "Expected ',' or '}' after object value";
return -1;
}
parser->state = JSON_STATE_OBJECT_KEY;
parser->data++;
json_parser_update_input_pos(parser);
return 0;
case JSON_STATE_ARRAY_OPEN:
if (*parser->data == ']')
return json_parse_close_array(parser, type_r);
parser->state = JSON_STATE_ARRAY_VALUE;
return 0;
case JSON_STATE_ARRAY_NEXT:
if (parser->skipping && parser->nested_skip_count == 0) {
/* we skipped over the previous value */
parser->skipping = FALSE;
}
/* fall through */
case JSON_STATE_ARRAY_NEXT_SKIP:
if (*parser->data == ']')
return json_parse_close_array(parser, type_r);
if (*parser->data != ',') {
parser->error = "Expected ',' or '}' after array value";
return -1;
}
parser->state = JSON_STATE_ARRAY_VALUE;
parser->data++;
json_parser_update_input_pos(parser);
return 0;
case JSON_STATE_OBJECT_SKIP_STRING:
case JSON_STATE_ARRAY_SKIP_STRING:
if (json_skip_string(parser) <= 0)
return -1;
parser->state = parser->state == JSON_STATE_OBJECT_SKIP_STRING ?
JSON_STATE_OBJECT_NEXT : JSON_STATE_ARRAY_NEXT;
return 0;
case JSON_STATE_DONE:
parser->error = "Unexpected data at the end";
return -1;
}
json_parser_update_input_pos(parser);
return skipping ? 0 : 1;
}
int json_parse_next(struct json_parser *parser, enum json_type *type_r,
const char **value_r)
{
int ret;
i_assert(parser->strinput == NULL);
*value_r = NULL;
while ((ret = json_parser_read_more(parser)) > 0) {
while ((ret = json_try_parse_next(parser, type_r, value_r)) == 0)
;
if (ret > 0)
break;
if (parser->data != parser->end)
return -1;
/* parsing probably failed because there wasn't enough input.
reset the error and try reading more. */
parser->error = NULL;
parser->highwater_offset = parser->input->v_offset +
i_stream_get_data_size(parser->input);
}
return ret;
}
void json_parse_skip_next(struct json_parser *parser)
{
i_assert(!parser->skipping);
i_assert(parser->strinput == NULL);
i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
parser->state == JSON_STATE_OBJECT_VALUE ||
parser->state == JSON_STATE_ARRAY_VALUE ||
parser->state == JSON_STATE_ARRAY_NEXT);
parser->skipping = TRUE;
if (parser->state == JSON_STATE_ARRAY_NEXT)
parser->state = JSON_STATE_ARRAY_NEXT_SKIP;
}
void json_parse_skip(struct json_parser *parser)
{
i_assert(!parser->skipping);
i_assert(parser->strinput == NULL);
i_assert(parser->state == JSON_STATE_OBJECT_NEXT ||
parser->state == JSON_STATE_OBJECT_OPEN ||
parser->state == JSON_STATE_ARRAY_NEXT ||
parser->state == JSON_STATE_ARRAY_OPEN);
if (parser->state == JSON_STATE_OBJECT_OPEN ||
parser->state == JSON_STATE_ARRAY_OPEN)
parser->nested_skip_count++;
parser->skipping = TRUE;
if (parser->state == JSON_STATE_ARRAY_NEXT)
parser->state = JSON_STATE_ARRAY_NEXT_SKIP;
}
static void json_strinput_destroyed(struct json_parser *parser)
{
i_assert(parser->strinput != NULL);
parser->strinput = NULL;
}
static int
json_try_parse_stream_start(struct json_parser *parser,
struct istream **input_r)
{
if (!json_parse_whitespace(parser))
return -1;
if (parser->state == JSON_STATE_OBJECT_COLON) {
if (*parser->data != ':') {
parser->error = "Expected ':' after key";
return -1;
}
parser->data++;
parser->state = JSON_STATE_OBJECT_VALUE;
if (!json_parse_whitespace(parser))
return -1;
}
if (*parser->data != '"')
return -1;
parser->data++;
json_parser_update_input_pos(parser);
parser->state = parser->state == JSON_STATE_OBJECT_VALUE ?
JSON_STATE_OBJECT_SKIP_STRING : JSON_STATE_ARRAY_SKIP_STRING;
parser->strinput = i_stream_create_jsonstr(parser->input);
i_stream_add_destroy_callback(parser->strinput,
json_strinput_destroyed, parser);
*input_r = parser->strinput;
return 0;
}
int json_parse_next_stream(struct json_parser *parser,
struct istream **input_r)
{
int ret;
i_assert(!parser->skipping);
i_assert(parser->strinput == NULL);
i_assert(parser->state == JSON_STATE_OBJECT_COLON ||
parser->state == JSON_STATE_OBJECT_VALUE ||
parser->state == JSON_STATE_ARRAY_VALUE);
*input_r = NULL;
while ((ret = json_parser_read_more(parser)) > 0) {
if (json_try_parse_stream_start(parser, input_r) == 0)
break;
if (parser->data != parser->end)
return -1;
/* parsing probably failed because there wasn't enough input.
reset the error and try reading more. */
parser->error = NULL;
parser->highwater_offset = parser->input->v_offset +
i_stream_get_data_size(parser->input);
}
return ret;
}
static void json_append_escaped_char(string_t *dest, unsigned char src)
{
switch (src) {
case '\b':
str_append(dest, "\\b");
break;
case '\f':
str_append(dest, "\\f");
break;
case '\n':
str_append(dest, "\\n");
break;
case '\r':
str_append(dest, "\\r");
break;
case '\t':
str_append(dest, "\\t");
break;
case '"':
str_append(dest, "\\\"");
break;
case '\\':
str_append(dest, "\\\\");
break;
default:
if (src < 0x20 || src >= 0x80)
str_printfa(dest, "\\u%04x", src);
else
str_append_c(dest, src);
break;
}
}
void json_append_escaped_ucs4(string_t *dest, unichar_t chr)
{
if (chr < 0x80)
json_append_escaped_char(dest, (unsigned char)chr);
else if (chr == 0x2028 || chr == 0x2029)
str_printfa(dest, "\\u%04x", chr);
else
uni_ucs4_to_utf8_c(chr, dest);
}
void ostream_escaped_json_format(string_t *dest, unsigned char src)
{
json_append_escaped_char(dest, src);
}
void json_append_escaped(string_t *dest, const char *src)
{
json_append_escaped_data(dest, (const unsigned char*)src, strlen(src));
}
void json_append_escaped_data(string_t *dest, const unsigned char *src, size_t size)
{
size_t i;
int bytes = 0;
unichar_t chr;
for (i = 0; i < size;) {
bytes = uni_utf8_get_char_n(src+i, size-i, &chr);
if (bytes > 0 && uni_is_valid_ucs4(chr)) {
json_append_escaped_ucs4(dest, chr);
i += bytes;
} else {
str_append_data(dest, UNICODE_REPLACEMENT_CHAR_UTF8,
UTF8_REPLACEMENT_CHAR_LEN);
i++;
}
}
}
dovecot-2.3.21.1/src/lib/lib.h 0000644 0000000 0000000 00000007223 14656633576 012575 0000000 0000000 #ifndef LIB_H
#define LIB_H
/* default lib includes */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/* default system includes - keep these at minimum.. */
#include /* Solaris defines NULL wrong unless this is used */
#include
#include /* strcmp() etc. */
#ifdef HAVE_STRINGS_H
# include /* strcasecmp() etc. */
#endif
#include /* va_list is used everywhere */
#include /* INT_MAX, etc. */
#include /* error checking is good */
#include /* many other includes want this */
#include /* PRI* macros */
#ifdef HAVE_STDINT_H
# include /* C99 int types, we mostly need uintmax_t */
#endif
#include "compat.h"
#include "macros.h"
#include "failures.h"
#include "malloc-overflow.h"
#include "data-stack.h"
#include "mempool.h"
#include "imem.h"
#include "byteorder.h"
#include "fd-util.h"
typedef struct buffer buffer_t;
typedef struct buffer string_t;
struct istream;
struct ostream;
typedef void lib_atexit_callback_t(void);
#include "array-decl.h" /* ARRAY*()s may exist in any header */
#include "bits.h"
#include "hash-decl.h" /* HASH_TABLE*()s may exist in any header */
#include "strfuncs.h"
#include "strnum.h"
#include "event-log.h"
#define LIB_ATEXIT_PRIORITY_HIGH -10
#define LIB_ATEXIT_PRIORITY_DEFAULT 0
#define LIB_ATEXIT_PRIORITY_LOW 10
/* /dev/null opened as O_WRONLY. Opened at lib_init(), so it can be accessed
also inside chroots. */
extern int dev_null_fd;
/* Call unlink(). If it fails, log an error including the source filename
and line number. */
int i_unlink(const char *path, const char *source_fname,
unsigned int source_linenum);
#define i_unlink(path) i_unlink(path, __FILE__, __LINE__)
/* Same as i_unlink(), but don't log an error if errno=ENOENT. Returns 1 on
unlink() success, 0 if errno=ENOENT, -1 on other errors. */
int i_unlink_if_exists(const char *path, const char *source_fname,
unsigned int source_linenum);
#define i_unlink_if_exists(path) i_unlink_if_exists(path, __FILE__, __LINE__)
/* Reset getopt() so it can be used for the next args. */
void i_getopt_reset(void);
/* Call the given callback at the beginning of lib_deinit(). The main
difference to atexit() is that liblib's memory allocation and logging
functions are still available. Also if lib_atexit() is called multiple times
to the same callback, it's added only once. */
void lib_atexit(lib_atexit_callback_t *callback);
/* Specify the order in which the callback is called. Lowest numbered
priorities are called first. lib_atexit() is called with priority=0. */
void lib_atexit_priority(lib_atexit_callback_t *callback, int priority);
/* Manually run the atexit callbacks. lib_deinit() also does this if not
explicitly called. */
void lib_atexit_run(void);
/* Unless this or lib_deinit() is called, any unexpected exit() will result
in abort(). This can be helpful in catching unexpected exits. */
void lib_set_clean_exit(bool set);
/* Same as lib_set_clean_exit(TRUE) followed by exit(status). */
void lib_exit(int status) ATTR_NORETURN;
void lib_init(void);
bool lib_is_initialized(void);
void lib_deinit(void);
uint32_t i_rand(void);
/* Returns a random integer < upper_bound. */
uint32_t i_rand_limit(uint32_t upper_bound);
static inline unsigned short i_rand_ushort(void)
{
return i_rand_limit(USHRT_MAX + 1);
}
static inline unsigned char i_rand_uchar(void)
{
return i_rand_limit(UCHAR_MAX + 1);
}
/* Returns a random integer >= min_val, and <= max_val. */
static inline uint32_t i_rand_minmax(uint32_t min_val, uint32_t max_val)
{
i_assert(min_val <= max_val);
return min_val + i_rand_limit(max_val - min_val + 1);
}
#endif
dovecot-2.3.21.1/src/lib/istream-crlf.h 0000644 0000000 0000000 00000000357 14656633576 014420 0000000 0000000 #ifndef ISTREAM_CRLF_H
#define ISTREAM_CRLF_H
/* Read all linefeeds as CRLF */
struct istream *i_stream_create_crlf(struct istream *input);
/* Read all linefeeds as LF */
struct istream *i_stream_create_lf(struct istream *input);
#endif
dovecot-2.3.21.1/src/lib/test-istream-concat.c 0000644 0000000 0000000 00000016045 14656633576 015712 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "istream-private.h"
#include "istream-concat.h"
#include
#include
#define TEST_MAX_ISTREAM_COUNT 10
#define TEST_MAX_ISTREAM_SIZE 1024
#define TEST_MAX_BUFFER_SIZE 128
static void test_istream_concat_one(unsigned int buffer_size)
{
static const char *input_string = "xyz";
#define STREAM_COUNT 5
#define STREAM_BYTES 3
struct istream *streams[STREAM_COUNT+1];
struct istream *input;
const unsigned char *data;
size_t size;
unsigned int i, j;
for (i = 0; i < STREAM_COUNT; i++) {
streams[i] = test_istream_create(input_string);
test_istream_set_allow_eof(streams[i], TRUE);
test_istream_set_size(streams[i], 0);
}
streams[i] = NULL;
input = i_stream_create_concat(streams);
for (i = 0; i/STREAM_BYTES < STREAM_COUNT; i++) {
test_istream_set_size(streams[i/STREAM_BYTES], (i%STREAM_BYTES) + 1);
test_assert(i_stream_read(input) == 1);
if (i < buffer_size) {
data = i_stream_get_data(input, &size);
test_assert(size == i+1);
} else {
i_stream_skip(input, 1);
data = i_stream_get_data(input, &size);
test_assert(size == buffer_size);
}
for (j = 0; j < size; j++) {
test_assert((char)data[j] == input_string[(input->v_offset + j) % STREAM_BYTES]);
}
test_assert(i_stream_read(input) <= 0);
}
test_assert(i_stream_read(input) == -1);
i_stream_skip(input, i_stream_get_data_size(input));
i_stream_unref(&input);
for (i = 0; i < STREAM_COUNT; i++) {
test_assert(streams[i]->eof && streams[i]->stream_errno == 0);
i_stream_unref(&streams[i]);
}
}
static bool test_istream_concat_random(void)
{
struct istream **streams, *concat, **limits = NULL;
const unsigned char *data;
unsigned char *w_data;
size_t size = 0;
unsigned int i, j, offset, stream_count, data_len, simult;
stream_count = i_rand_minmax(2, TEST_MAX_ISTREAM_COUNT + 2 - 1);
streams = t_new(struct istream *, stream_count + 1);
for (i = 0, offset = 0; i < stream_count; i++) {
data_len = i_rand_minmax(1, TEST_MAX_ISTREAM_SIZE);
w_data = t_malloc_no0(data_len);
for (j = 0; j < data_len; j++)
w_data[j] = (offset++) & 0xff;
streams[i] = test_istream_create_data(w_data, data_len);
test_istream_set_allow_eof(streams[i], TRUE);
}
streams[i] = NULL;
i_assert(offset > 0);
concat = i_stream_create_concat(streams);
i_stream_set_max_buffer_size(concat, TEST_MAX_BUFFER_SIZE);
simult = i_rand_limit(TEST_MAX_ISTREAM_COUNT);
if (simult > 0) {
limits = t_new(struct istream *, simult);
for (i = 0; i < simult; i++)
limits[i] = i_stream_create_limit(concat, UOFF_T_MAX);
}
for (i = 0; i < 1000; i++) {
struct istream *input = (simult == 0) ? concat : limits[i_rand_limit(simult)];
if (i_rand_limit(3) == 0) {
i_stream_seek(input, i_rand_limit(offset));
} else {
ssize_t ret = i_stream_read(input);
size = i_stream_get_data_size(input);
if (ret == -2) {
test_assert(size >= TEST_MAX_BUFFER_SIZE);
} else if (input->v_offset + size != offset) {
test_assert(ret > 0);
test_assert(input->v_offset + ret <= offset);
i_stream_skip(input, i_rand_limit(ret));
data = i_stream_get_data(input, &size);
for (j = 0; j < size; j++) {
test_assert(data[j] == (input->v_offset + j) % 256);
}
}
}
if (test_has_failed())
break;
}
for (i = 0; i < stream_count; i++)
i_stream_unref(&streams[i]);
for (i = 0; i < simult; i++)
i_stream_unref(&limits[i]);
i_stream_unref(&concat);
return !test_has_failed();
}
static void test_istream_concat_seek_end(void)
{
test_begin("istream concat seek end");
struct istream *streams[] = {
test_istream_create("s1"),
test_istream_create("s2"),
NULL
};
struct istream *input = i_stream_create_concat(streams);
i_stream_unref(&streams[0]);
i_stream_unref(&streams[1]);
i_stream_seek(input, 4);
test_assert(i_stream_read(input) == -1);
i_stream_unref(&input);
test_end();
}
static void test_istream_concat_early_end(void)
{
struct istream *input, *streams[2];
test_begin("istream concat early end");
streams[0] = test_istream_create("stream");
test_istream_set_size(streams[0], 3);
test_istream_set_allow_eof(streams[0], FALSE);
streams[1] = NULL;
input = i_stream_create_concat(streams);
test_assert(i_stream_read(input) == 3);
test_istream_set_size(streams[0], 5);
test_assert(i_stream_read(input) == 2);
i_stream_skip(input, 5);
i_stream_unref(&input);
test_assert(streams[0]->v_offset == 5);
i_stream_unref(&streams[0]);
test_end();
}
static void test_istream_concat_snapshot(void)
{
struct istream *input;
const unsigned char *data;
size_t size;
test_begin("istream concat snapshot");
struct istream *test_istreams[] = {
test_istream_create("abcdefghijklmnopqrst"),
test_istream_create("ABCDEFGHIJKLMNOPQRSTUVWXY"),
test_istream_create("!\"#$%&'()*+,-./01234567890:;<="),
NULL
};
input = i_stream_create_concat(test_istreams);
for (unsigned int i = 0; test_istreams[i] != NULL; i++) {
struct istream *tmp_istream = test_istreams[i];
i_stream_unref(&tmp_istream);
}
test_istream_set_size(test_istreams[0], 20);
test_istream_set_size(test_istreams[1], 0);
test_istream_set_size(test_istreams[2], 0);
/* first stream */
test_istream_set_allow_eof(test_istreams[0], FALSE);
test_assert(i_stream_read_data(input, &data, &size, 0) == 1);
test_assert(size == 20);
test_assert(memcmp(data, "abcdefghijklmnopqrst", 20) == 0);
/* partially skip */
i_stream_skip(input, 12);
/* second stream */
test_assert(i_stream_read_data(input, &data, &size, 10) == 0);
test_assert(size == 8);
test_istream_set_allow_eof(test_istreams[0], TRUE);
test_istream_set_size(test_istreams[0], 0);
test_assert(i_stream_read_data(input, &data, &size, 10) == 0);
test_assert(size == 8);
test_istream_set_size(test_istreams[1], 10);
test_assert(i_stream_read_data(input, &data, &size, 10) == 1);
test_assert(size == 18);
test_istream_set_allow_eof(test_istreams[1], FALSE);
test_assert(i_stream_read(input) == 0);
test_istream_set_size(test_istreams[1], 25);
test_istream_set_allow_eof(test_istreams[1], TRUE);
test_assert(i_stream_read_data(input, &data, &size, 30) == 1);
test_assert(size == 33);
test_assert(memcmp(data, "mnopqrst"
"ABCDEFGHIJKLMNOPQRSTUVWXY", 33) == 0);
/* partially skip */
i_stream_skip(input, 12);
/* third stream */
test_istream_set_size(test_istreams[2], 0);
test_assert(i_stream_read(input) == 0);
test_istream_set_size(test_istreams[2], 30);
test_assert(i_stream_read_data(input, &data, &size, 25) == 1);
test_assert(size == 51);
test_assert(memcmp(data, "EFGHIJKLMNOPQRSTUVWXY"
"!\"#$%&'()*+,-./01234567890:;<=", 51) == 0);
i_stream_unref(&input);
test_end();
}
void test_istream_concat(void)
{
unsigned int i;
test_begin("istream concat");
for (i = 1; i < STREAM_BYTES*STREAM_COUNT; i++) {
test_istream_concat_one(i);
}
test_end();
test_begin("istream concat random");
for (i = 0; i < 100; i++) T_BEGIN {
if(!test_istream_concat_random())
i = 101; /* don't break a T_BEGIN */
} T_END;
test_end();
test_istream_concat_seek_end();
test_istream_concat_early_end();
test_istream_concat_snapshot();
}
dovecot-2.3.21.1/src/lib/test-printf-format-fix.c 0000644 0000000 0000000 00000010066 14656633576 016352 0000000 0000000 /* Copyright (c) 2001-2018 Dovecot authors, see the included COPYING file */
/* Unit tests for printf-format-fix helper */
#include "test-lib.h"
#include "printf-format-fix.h"
#include
struct format_fix_rewrites {
const char *input;
const char *output;
size_t length;
};
static void test_unchanged()
{
static const char *tests[] = {
"Hello world",
"Embedded %%, %u, %f, %s, etc. are OK",
"Allow %#0- +s flags",
"duplicate flags in different args %0-123s %0-123s",
"Minimum length %9999s",
"Minimum length parameter %*s",
"Precision %.9999s",
"Precision %1.9999s",
"Precision parameter %1.*s %.*s",
"Floating precisions such as %.0f %0.4f %-4.0f",
"Length modifiers %hd %hhd %ld %lld %Lg %jd %zd %td",
"Specifiers %s %u %d %c %i %x %X %p %o %e %E %f %F %g %G %a %A",
"%%doesn't cause confusion in %%m and %%n",
};
unsigned int i;
test_begin("printf_format_fix(safe)");
for (i = 0; i < N_ELEMENTS(tests); ++i) {
size_t len;
T_BEGIN {
test_assert_idx(printf_format_fix(tests[i])
== tests[i], i);
test_assert_idx(printf_format_fix_get_len(tests[i], &len)
== tests[i], i);
test_assert_idx(len == strlen(tests[i]), i);
} T_END;
}
test_end();
}
static void test_ok_changes()
{
static const char *tests[] = {
"OK to have a trailing %m",
"%m can appear at the start too",
"Even %m in the middle with a confusing %%m elsewhere is OK",
};
unsigned int i;
const char *needle;
unsigned int needlen;
int old_errno = errno;
test_begin("printf_format_fix(rewrites)");
errno = EINVAL;
needle = strerror(errno);
i_assert(needle != NULL);
needlen = strlen(needle);
for (i = 0; i < N_ELEMENTS(tests); ++i) {
size_t len;
char const *chgd;
char const *insert;
unsigned int offs;
T_BEGIN {
chgd = printf_format_fix(tests[i]);
test_assert_idx(chgd != tests[i], i);
insert = strstr(chgd, needle);
test_assert_idx(insert != NULL, i);
offs = insert - chgd;
test_assert_idx(memcmp(chgd, tests[i], offs) == 0, i);
test_assert_idx(memcmp(chgd+offs, needle, needlen) == 0, i);
test_assert_idx(strcmp(chgd+offs+needlen, tests[i]+offs+2) == 0, i);
chgd = printf_format_fix_get_len(tests[i], &len);
test_assert_idx(chgd != tests[i], i);
test_assert_idx(len == strlen(chgd), i);
insert = strstr(chgd, needle);
test_assert_idx(insert != NULL, i);
offs = insert - chgd;
test_assert_idx(memcmp(chgd, tests[i], offs) == 0, i);
test_assert_idx(memcmp(chgd+offs, needle, needlen) == 0, i);
test_assert_idx(memcmp(chgd+offs+needlen, tests[i]+offs+2, len-needlen-offs) == 0, i);
} T_END;
}
errno = old_errno;
test_end();
}
void test_printf_format_fix()
{
test_unchanged();
test_ok_changes();
}
/* Want to test the panics too? go for it! */
enum fatal_test_state fatal_printf_format_fix(unsigned int stage)
{
static const struct {
const char *format;
const char *expected_fatal;
} fatals[] = {
{ "no no no %n's", "%n modifier used" },
{ "no no no %-1234567890123n's with extra stuff", "Too large minimum field width" },
{ "%m allowed once, but not twice: %m", "%m used twice" },
{ "%m must not obscure a later %n", "%n modifier used" },
{ "definitely can't have a tailing %", "Missing % specifier" },
{ "Evil %**%n", "Unsupported 0x2a specifier" },
{ "Evil %*#%99999$s", "Unsupported 0x23 specifier" },
{ "No weird %% with %0%", "Unsupported 0x25 specifier" },
{ "No duplicate modifiers %00s", "Duplicate % flag '0'" },
{ "Minimum length can't be too long %10000s", "Too large minimum field width" },
{ "Minimum length doesn't support %*1$s", "Unsupported 0x31 specifier" },
{ "Precision can't be too long %.10000s", "Too large precision" },
{ "Precision can't be too long %1.10000s", "Too large precision" },
{ "Precision doesn't support %1.-1s", "Unsupported 0x2d specifier" },
};
if(stage >= N_ELEMENTS(fatals)) {
test_end();
return FATAL_TEST_FINISHED;
}
if(stage == 0)
test_begin("fatal_printf_format_fix");
/* let's crash! */
test_expect_fatal_string(fatals[stage].expected_fatal);
(void)printf_format_fix(fatals[stage].format);
return FATAL_TEST_FAILURE;
}
dovecot-2.3.21.1/src/lib/test-utc-mktime.c 0000644 0000000 0000000 00000003250 14656633576 015052 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "utc-mktime.h"
struct test_utc_mktime {
int year, month, day, hour, min, sec;
time_t out;
};
void test_utc_mktime(void)
{
static const struct test_utc_mktime tests[] = {
#ifdef TIME_T_SIGNED
{ 1969, 12, 31, 23, 59, 59, -1 },
{ 1901, 12, 13, 20, 45, 53, -2147483647 },
#endif
#if (TIME_T_MAX_BITS > 32 || !defined(TIME_T_SIGNED))
{ 2106, 2, 7, 6, 28, 15, 4294967295 },
{ 2038, 1, 19, 3, 14, 8, 2147483648 },
#endif
{ 2007, 11, 7, 1, 7, 20, 1194397640 },
{ 1970, 1, 1, 0, 0, 0, 0 },
{ 2038, 1, 19, 3, 14, 7, 2147483647 },
{ INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, -1 },
#if TIME_T_MAX_BITS > 32
{ 2106, 2, 7, 6, 28, 16, 4294967296 },
#endif
/* June leap second */
{ 2015, 6, 30, 23, 59, 59, 1435708799 },
{ 2015, 6, 30, 23, 59, 60, 1435708799 },
{ 2015, 7, 1, 0, 0, 0, 1435708800 },
/* Invalid leap second */
{ 2017, 1, 24, 16, 40, 60, 1485276059 },
/* Dec leap second */
{ 2016, 12, 31, 23, 59, 59, 1483228799 },
{ 2016, 12, 31, 23, 59, 60, 1483228799 },
{ 2017, 1, 1, 0, 0, 0, 1483228800 },
};
struct tm tm;
unsigned int i;
time_t t;
bool success;
for (i = 0; i < N_ELEMENTS(tests); i++) {
const struct test_utc_mktime *test = &tests[i];
i_zero(&tm);
tm.tm_year = test->year - 1900;
tm.tm_mon = test->month - 1;
tm.tm_mday = test->day;
tm.tm_hour = test->hour;
tm.tm_min = test->min;
tm.tm_sec = test->sec;
t = utc_mktime(&tm);
success = t == test->out;
test_out_reason(t_strdup_printf("utc_mktime(%d)", i), success,
success ? NULL : t_strdup_printf("%ld != %ld",
(long)t, (long)test->out));
}
}
dovecot-2.3.21.1/src/lib/randgen.h 0000644 0000000 0000000 00000000635 14656633576 013445 0000000 0000000 #ifndef RANDGEN_H
#define RANDGEN_H
/* Fill given buffer with semi-strong randomness */
void random_fill(void *buf, size_t size);
/* may be called multiple times,
and are called by default in lib_init */
void random_init(void);
void random_deinit(void);
#ifdef DEBUG
/* Debug helper to make random tests reproduceable. 0=got seed, -1=failure. */
int rand_get_last_seed(unsigned int *seed_r);
#endif
#endif
dovecot-2.3.21.1/src/lib/test-env-util.c 0000644 0000000 0000000 00000005071 14656633576 014541 0000000 0000000 /* Copyright (c) 2021 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "env-util.h"
void test_env_util(void)
{
test_begin("env util");
env_put("ENVUTIL_BACKUP", "saved");
struct env_backup *backup = env_backup_save();
/* test env_clean() */
env_clean();
char ***env = env_get_environ_p();
test_assert(*env == NULL || **env == NULL);
test_assert(getenv("ENVUTIL_BACKUP") == NULL);
/* test env_put_array() */
const char *add_env[] = { "a=1", "b=1", "c=1", "d=1", NULL };
env_put_array(add_env);
test_assert_strcmp(getenv("a"), "1");
test_assert_strcmp(getenv("b"), "1");
test_assert_strcmp(getenv("c"), "1");
test_assert_strcmp(getenv("d"), "1");
test_assert(getenv("e") == NULL);
const char *add_env2[] = { "b=", "e=2", NULL };
env_put_array(add_env2);
test_assert_strcmp(getenv("a"), "1");
test_assert_strcmp(getenv("b"), "");
test_assert_strcmp(getenv("c"), "1");
test_assert_strcmp(getenv("d"), "1");
test_assert_strcmp(getenv("e"), "2");
/* test env_clean_except() */
const char *preserve_env[] = { "a", "c", NULL };
env_clean_except(preserve_env);
test_assert_strcmp(getenv("a"), "1");
test_assert(getenv("b") == NULL);
test_assert_strcmp(getenv("c"), "1");
test_assert(getenv("d") == NULL);
test_assert(*env != NULL &&
(null_strcmp((*env)[0], "a=1") == 0 ||
null_strcmp((*env)[0], "c=1") == 0));
test_assert(*env != NULL &&
(null_strcmp((*env)[1], "a=1") == 0 ||
null_strcmp((*env)[1], "c=1") == 0));
/* test env_remove() */
env_remove("a");
test_assert(getenv("a") == NULL);
test_assert(getenv("c") != NULL);
env_remove("a");
test_assert(getenv("a") == NULL);
test_assert(getenv("c") != NULL);
env_remove("c");
test_assert(getenv("c") == NULL);
test_assert(*env == NULL || **env == NULL);
/* test restoring */
env_backup_restore(backup);
test_assert_strcmp(getenv("ENVUTIL_BACKUP"), "saved");
env_put("ENVUTIL_BACKUP", "overwrite");
test_assert_strcmp(getenv("ENVUTIL_BACKUP"), "overwrite");
/* test restoring again */
env_backup_restore(backup);
test_assert_strcmp(getenv("ENVUTIL_BACKUP"), "saved");
env_backup_free(&backup);
test_end();
}
enum fatal_test_state fatal_env_util(unsigned int stage)
{
switch (stage) {
case 0:
test_begin("env util fatals");
test_expect_fatal_string("strchr(name, '=') == NULL");
env_put("key=bad", "value");
return FATAL_TEST_FAILURE;
case 1:
test_expect_fatal_string("value != NULL");
const char *const envs[] = { "key", NULL };
env_put_array(envs);
return FATAL_TEST_FAILURE;
default:
test_end();
return FATAL_TEST_FINISHED;
}
}
dovecot-2.3.21.1/src/lib/process-title.c 0000644 0000000 0000000 00000011477 14656633576 014625 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "env-util.h"
#include "process-title.h"
#ifdef HAVE_LIBBSD
#include
#else
#include /* FreeBSD */
#endif
static char *process_name = NULL;
static char *current_process_title;
static unsigned int process_title_counter = 0;
#ifdef HAVE_SETPROCTITLE
# undef PROCTITLE_HACK
#endif
#ifdef PROCTITLE_HACK
#ifdef DEBUG
/* if there are problems with this approach, try to make sure we notice it */
# define PROCTITLE_CLEAR_CHAR 0xab
#else
/* There are always race conditions when updating the process title. ps might
read a partially written title. Try to at least minimize this by using NUL
as the fill character, so ps won't show a large number of 0xab chars. */
# define PROCTITLE_CLEAR_CHAR 0
#endif
static char *process_title;
static size_t process_title_len, process_title_clean_pos;
static void *argv_memblock, *environ_memblock;
static void proctitle_hack_init(char *argv[], char *env[])
{
char *last;
unsigned int i;
bool clear_env;
i_assert(argv[0] != NULL);
/* find the last argv or environment string. it should always be the
last string in environ, but don't rely on it. this is what openssh
does, so hopefully it's safe enough. */
last = argv[0] + strlen(argv[0]) + 1;
for (i = 1; argv[i] != NULL; i++) {
if (argv[i] == last)
last = argv[i] + strlen(argv[i]) + 1;
}
if (env[0] == NULL)
clear_env = FALSE;
else {
clear_env = last == env[0];
for (i = 0; env[i] != NULL; i++) {
if (env[i] == last)
last = env[i] + strlen(env[i]) + 1;
}
}
process_title = argv[0];
process_title_len = last - argv[0];
if (clear_env) {
memset(env[0], PROCTITLE_CLEAR_CHAR, last - env[0]);
process_title_clean_pos = env[0] - process_title;
} else {
process_title_clean_pos = 0;
}
}
static char **argv_dup(char *old_argv[], void **memblock_r)
{
/* @UNSAFE */
void *memblock, *memblock_end;
char **new_argv;
unsigned int i, count;
size_t len, memblock_len = 0;
for (count = 0; old_argv[count] != NULL; count++)
memblock_len += strlen(old_argv[count]) + 1;
memblock_len += sizeof(char *) * (count + 1);
memblock = malloc(memblock_len);
if (memblock == NULL)
i_fatal_status(FATAL_OUTOFMEM, "malloc() failed: %m");
*memblock_r = memblock;
memblock_end = PTR_OFFSET(memblock, memblock_len);
new_argv = memblock;
memblock = PTR_OFFSET(memblock, sizeof(char *) * (count + 1));
for (i = 0; i < count; i++) {
new_argv[i] = memblock;
len = strlen(old_argv[i]) + 1;
memcpy(memblock, old_argv[i], len);
memblock = PTR_OFFSET(memblock, len);
}
i_assert(memblock == memblock_end);
new_argv[i] = NULL;
return new_argv;
}
static void proctitle_hack_set(const char *title)
{
size_t len = strlen(title);
/* OS X wants two NULs */
if (len >= process_title_len-1)
len = process_title_len - 2;
memcpy(process_title, title, len);
process_title[len++] = '\0';
process_title[len++] = '\0';
if (len < process_title_clean_pos) {
memset(process_title + len, PROCTITLE_CLEAR_CHAR,
process_title_clean_pos - len);
process_title_clean_pos = len;
} else if (process_title_clean_pos != 0) {
process_title_clean_pos = len;
}
}
#endif
void process_title_init(int argc ATTR_UNUSED, char **argv[])
{
#ifdef PROCTITLE_HACK
char ***environ_p = env_get_environ_p();
char **orig_argv = *argv;
char **orig_environ = *environ_p;
*argv = argv_dup(orig_argv, &argv_memblock);
*environ_p = argv_dup(orig_environ, &environ_memblock);
proctitle_hack_init(orig_argv, orig_environ);
#endif
#ifdef HAVE_LIBBSD
setproctitle_init(argc, *argv, *env_get_environ_p());
#endif
process_name = (*argv)[0];
}
void process_title_set(const char *title)
{
i_assert(process_name != NULL);
process_title_counter++;
i_free(current_process_title);
current_process_title = i_strdup(title);
#ifdef HAVE_SETPROCTITLE
if (title == NULL)
setproctitle(NULL);
else
setproctitle("%s", title);
#elif defined(PROCTITLE_HACK)
T_BEGIN {
proctitle_hack_set(t_strconcat(process_name, " ", title, NULL));
} T_END;
#endif
}
const char *process_title_get(void)
{
return current_process_title;
}
unsigned int process_title_get_counter(void)
{
return process_title_counter;
}
void process_title_deinit(void)
{
#ifdef PROCTITLE_HACK
char ***environ_p = env_get_environ_p();
free(argv_memblock);
free(environ_memblock);
/* Environment is no longer usable. Make sure we won't crash in case
some library's deinit function still calls getenv(). This code was
mainly added because of GNUTLS where we don't really care about the
getenv() call.
Alternatively we could remove the free() calls above, but that would
annoy memory leak checking tools. Also we could attempt to restore
the environ_p to its original state, but that's a bit complicated. */
*environ_p = NULL;
#endif
i_free(current_process_title);
}
dovecot-2.3.21.1/src/lib/istream-concat.c 0000644 0000000 0000000 00000027575 14656633576 014747 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "memarea.h"
#include "istream-private.h"
#include "istream-concat.h"
struct concat_istream {
struct istream_private istream;
struct istream **input, *cur_input;
uoff_t *input_size;
unsigned int input_count;
unsigned int cur_idx, unknown_size_idx;
size_t prev_stream_left, prev_stream_skip, prev_skip;
};
static void i_stream_concat_skip(struct concat_istream *cstream);
static void i_stream_concat_close(struct iostream_private *stream,
bool close_parent)
{
struct concat_istream *cstream =
container_of(stream, struct concat_istream, istream.iostream);
i_assert(cstream->cur_input == cstream->input[cstream->cur_idx]);
unsigned int i;
if (cstream->istream.istream.stream_errno == 0) {
/* get the parent streams to the wanted offset */
(void)i_stream_concat_skip(cstream);
}
if (close_parent) {
for (i = 0; i < cstream->input_count; i++)
i_stream_close(cstream->input[i]);
}
}
static void i_stream_concat_destroy(struct iostream_private *stream)
{
struct concat_istream *cstream =
container_of(stream, struct concat_istream, istream.iostream);
i_assert(cstream->cur_input == cstream->input[cstream->cur_idx]);
unsigned int i;
for (i = 0; i < cstream->input_count; i++)
i_stream_unref(&cstream->input[i]);
i_free(cstream->input);
i_free(cstream->input_size);
i_stream_free_buffer(&cstream->istream);
}
static void
i_stream_concat_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
struct concat_istream *cstream =
container_of(stream, struct concat_istream, istream.iostream);
i_assert(cstream->cur_input == cstream->input[cstream->cur_idx]);
unsigned int i;
cstream->istream.max_buffer_size = max_size;
for (i = 0; i < cstream->input_count; i++)
i_stream_set_max_buffer_size(cstream->input[i], max_size);
}
static void i_stream_concat_read_next(struct concat_istream *cstream)
{
struct istream *prev_input = cstream->cur_input;
const unsigned char *data;
size_t data_size, size;
i_assert(cstream->cur_input->eof);
if (cstream->prev_stream_skip != 0) {
i_stream_skip(cstream->input[cstream->cur_idx-1], cstream->prev_stream_skip);
cstream->prev_stream_skip = 0;
}
data = i_stream_get_data(cstream->cur_input, &data_size);
cstream->cur_idx++;
cstream->cur_input = cstream->input[cstream->cur_idx];
i_stream_seek(cstream->cur_input, 0);
if (cstream->prev_stream_left > 0 || cstream->istream.pos == 0) {
/* all the pending data is already in w_buffer */
cstream->prev_stream_skip = data_size;
cstream->prev_stream_left += data_size;
i_assert(cstream->prev_stream_left ==
cstream->istream.pos - cstream->istream.skip);
return;
}
i_assert(cstream->prev_stream_skip == 0);
/* we already verified that the data size is less than the
maximum buffer size */
cstream->istream.skip = 0;
cstream->istream.pos = 0;
if (data_size > 0) {
if (cstream->istream.memarea != NULL &&
memarea_get_refcount(cstream->istream.memarea) > 1)
i_stream_memarea_detach(&cstream->istream);
if (!i_stream_try_alloc(&cstream->istream, data_size, &size))
i_unreached();
i_assert(size >= data_size);
}
cstream->prev_stream_left = data_size;
memcpy(cstream->istream.w_buffer, data, data_size);
i_stream_skip(prev_input, data_size);
cstream->istream.skip = 0;
cstream->istream.pos = data_size;
}
static void i_stream_concat_skip(struct concat_istream *cstream)
{
struct istream_private *stream = &cstream->istream;
size_t bytes_skipped;
i_assert(stream->skip >= cstream->prev_skip);
bytes_skipped = stream->skip - cstream->prev_skip;
if (cstream->prev_stream_left == 0) {
/* no need to worry about buffers, skip everything */
} else if (bytes_skipped < cstream->prev_stream_left) {
/* we're still skipping inside buffer */
cstream->prev_stream_left -= bytes_skipped;
bytes_skipped = 0;
} else {
/* done with the buffer */
i_stream_skip(cstream->input[cstream->cur_idx-1], cstream->prev_stream_skip);
cstream->prev_stream_skip = 0;
bytes_skipped -= cstream->prev_stream_left;
cstream->prev_stream_left = 0;
}
if (bytes_skipped > 0) {
i_assert(stream->buffer != NULL);
stream->pos -= bytes_skipped;
stream->skip -= bytes_skipped;
stream->buffer += bytes_skipped;
}
cstream->prev_skip = stream->skip;
i_stream_skip(cstream->cur_input, bytes_skipped);
}
static ssize_t i_stream_concat_read(struct istream_private *stream)
{
struct concat_istream *cstream =
container_of(stream, struct concat_istream, istream);
i_assert(cstream->cur_input == cstream->input[cstream->cur_idx]);
const unsigned char *data;
size_t size, data_size, cur_data_pos, new_pos;
size_t new_bytes_count;
ssize_t ret;
bool last_stream;
i_assert(cstream->cur_input != NULL);
i_stream_concat_skip(cstream);
i_assert(stream->pos >= stream->skip + cstream->prev_stream_left);
cur_data_pos = stream->pos - (stream->skip + cstream->prev_stream_left);
data = i_stream_get_data(cstream->cur_input, &data_size);
if (data_size > cur_data_pos)
ret = 0;
else {
/* need to read more - NOTE: Can't use i_stream_read_memarea()
here, because our stream->buffer may point to the parent
istream. Implementing explicit snapshot function to avoid
this isn't easy for seekable concat-istreams, because due to
seeking it's not necessarily the cur_input that needs to be
snapshotted. */
i_assert(cur_data_pos == data_size);
ret = i_stream_read(cstream->cur_input);
if (ret == -2 || ret == 0)
return ret;
if (ret == -1 && cstream->cur_input->stream_errno != 0) {
io_stream_set_error(&cstream->istream.iostream,
"read(%s) failed: %s",
i_stream_get_name(cstream->cur_input),
i_stream_get_error(cstream->cur_input));
stream->istream.stream_errno =
cstream->cur_input->stream_errno;
return -1;
}
/* we either read something or we're at EOF */
last_stream = cstream->cur_idx+1 >= cstream->input_count;
if (ret == -1 && !last_stream) {
if (stream->pos - stream->skip >= i_stream_get_max_buffer_size(&stream->istream))
return -2;
i_stream_concat_read_next(cstream);
cstream->prev_skip = stream->skip;
return i_stream_concat_read(stream);
}
stream->istream.eof = cstream->cur_input->eof && last_stream;
i_assert(ret != -1 || stream->istream.eof);
data = i_stream_get_data(cstream->cur_input, &data_size);
}
if (data_size == cur_data_pos) {
/* nothing new read - preserve the buffer as it was */
i_assert(ret == 0 || ret == -1);
return ret;
}
if (cstream->prev_stream_left == 0) {
/* we can point directly to the current stream's buffers */
stream->buffer = data;
stream->pos -= stream->skip;
stream->skip = 0;
new_pos = data_size;
} else {
/* we still have some of the previous stream left. merge the
new data with it. */
i_assert(data_size > cur_data_pos);
new_bytes_count = data_size - cur_data_pos;
if (!i_stream_try_alloc(stream, new_bytes_count, &size)) {
stream->buffer = stream->w_buffer;
return -2;
}
stream->buffer = stream->w_buffer;
/* we'll copy all the new input to w_buffer. if we skip over
prev_stream_left bytes, the next read will switch to
pointing to cur_input's data directly. */
if (new_bytes_count > size)
new_bytes_count = size;
memcpy(stream->w_buffer + stream->pos,
data + cur_data_pos, new_bytes_count);
new_pos = stream->pos + new_bytes_count;
}
i_assert(new_pos > stream->pos);
ret = (ssize_t)(new_pos - stream->pos);
stream->pos = new_pos;
cstream->prev_skip = stream->skip;
return ret;
}
static int
find_v_offset(struct concat_istream *cstream, uoff_t *v_offset,
unsigned int *idx_r)
{
const struct stat *st;
unsigned int i;
for (i = 0; i < cstream->input_count; i++) {
if (*v_offset == 0) {
/* seek to beginning of this stream */
break;
}
if (i == cstream->unknown_size_idx) {
/* we'll need to figure out this stream's size */
if (i_stream_stat(cstream->input[i], TRUE, &st) < 0) {
io_stream_set_error(&cstream->istream.iostream,
"stat(%s) failed: %s",
i_stream_get_name(cstream->input[i]),
i_stream_get_error(cstream->input[i]));
i_error("istream-concat: stat(%s) failed: %s",
i_stream_get_name(cstream->input[i]),
i_stream_get_error(cstream->input[i]));
cstream->istream.istream.stream_errno =
cstream->input[i]->stream_errno;
return -1;
}
/* @UNSAFE */
cstream->input_size[i] = st->st_size;
cstream->unknown_size_idx = i + 1;
}
if (*v_offset < cstream->input_size[i])
break;
*v_offset -= cstream->input_size[i];
}
*idx_r = i;
return 0;
}
static void i_stream_concat_seek(struct istream_private *stream,
uoff_t v_offset, bool mark ATTR_UNUSED)
{
struct concat_istream *cstream =
container_of(stream, struct concat_istream, istream);
i_assert(cstream->cur_input == cstream->input[cstream->cur_idx]);
stream->istream.v_offset = v_offset;
stream->skip = stream->pos = 0;
cstream->prev_stream_left = 0;
cstream->prev_stream_skip = 0;
cstream->prev_skip = 0;
if (find_v_offset(cstream, &v_offset, &cstream->cur_idx) < 0) {
/* failed */
stream->istream.stream_errno = EINVAL;
return;
}
if (cstream->cur_idx < cstream->input_count)
cstream->cur_input = cstream->input[cstream->cur_idx];
else {
/* we allow seeking to EOF, but not past it. */
if (v_offset != 0) {
io_stream_set_error(&cstream->istream.iostream,
"Seeking past EOF by %"PRIuUOFF_T" bytes", v_offset);
cstream->istream.istream.stream_errno = EINVAL;
return;
}
i_assert(cstream->cur_idx > 0);
/* Position ourselves at the EOF of the last actual stream. */
cstream->cur_idx--;
cstream->cur_input = cstream->input[cstream->cur_idx];
v_offset = cstream->input_size[cstream->cur_idx];
}
i_stream_seek(cstream->cur_input, v_offset);
}
static int
i_stream_concat_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
{
struct concat_istream *cstream =
container_of(stream, struct concat_istream, istream);
i_assert(cstream->cur_input == cstream->input[cstream->cur_idx]);
uoff_t v_offset = UOFF_T_MAX;
unsigned int i, cur_idx;
/* make sure we have all sizes */
if (find_v_offset(cstream, &v_offset, &cur_idx) < 0)
return -1;
stream->statbuf.st_size = 0;
for (i = 0; i < cstream->unknown_size_idx; i++)
stream->statbuf.st_size += cstream->input_size[i];
return 0;
}
struct istream *i_stream_create_concat(struct istream *input[])
{
struct concat_istream *cstream;
unsigned int count;
size_t max_buffer_size = 0;
bool blocking = TRUE, seekable = TRUE;
/* if any of the streams isn't blocking or seekable, set ourself also
nonblocking/nonseekable */
for (count = 0; input[count] != NULL; count++) {
size_t cur_max = i_stream_get_max_buffer_size(input[count]);
i_assert(cur_max != 0);
if (cur_max != SIZE_MAX && cur_max > max_buffer_size)
max_buffer_size = cur_max;
if (!input[count]->blocking)
blocking = FALSE;
if (!input[count]->seekable)
seekable = FALSE;
i_stream_ref(input[count]);
}
i_assert(count != 0);
if (max_buffer_size == 0)
max_buffer_size = SIZE_MAX;
if (max_buffer_size < I_STREAM_MIN_SIZE)
max_buffer_size = I_STREAM_MIN_SIZE;
cstream = i_new(struct concat_istream, 1);
cstream->input_count = count;
cstream->input = p_memdup(default_pool, input, sizeof(*input) * count);
cstream->input_size = i_new(uoff_t, count);
cstream->cur_input = cstream->input[0];
i_stream_seek(cstream->cur_input, 0);
cstream->istream.iostream.close = i_stream_concat_close;
cstream->istream.iostream.destroy = i_stream_concat_destroy;
cstream->istream.iostream.set_max_buffer_size =
i_stream_concat_set_max_buffer_size;
cstream->istream.max_buffer_size = max_buffer_size;
cstream->istream.read = i_stream_concat_read;
cstream->istream.seek = i_stream_concat_seek;
cstream->istream.stat = i_stream_concat_stat;
cstream->istream.istream.readable_fd = FALSE;
cstream->istream.istream.blocking = blocking;
cstream->istream.istream.seekable = seekable;
return i_stream_create(&cstream->istream, NULL, -1, 0);
}
dovecot-2.3.21.1/src/lib/sha3.h 0000644 0000000 0000000 00000006005 14656633576 012662 0000000 0000000 /*
* FIPS 180-2 SHA-224/256/384/512 implementation
* Last update: 02/02/2007
* Issue date: 04/30/2005
*
* Copyright (C) 2005, 2007 Olivier Gay
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef SHA3_H
#define SHA3_H
#include "hash-method.h"
#include "sha-common.h"
#define SHA3_KECCAK_SPONGE_WORDS \
(((1600)/8/*bits to byte*/)/sizeof(uint64_t))
struct sha3_ctx {
uint64_t saved; /* the portion of the input message that we
* didn't consume yet */
union { /* Keccak's state */
uint64_t s[SHA3_KECCAK_SPONGE_WORDS];
uint8_t sb[SHA3_KECCAK_SPONGE_WORDS * 8];
};
unsigned byteIndex; /* 0..7--the next byte after the set one
* (starts from 0; 0--none are buffered) */
unsigned wordIndex; /* 0..24--the next word to integrate input
* (starts from 0) */
unsigned capacityWords; /* the double size of the hash output in
* words (e.g. 16 for Keccak 512) */
};
void sha3_256_init(void *context);
void sha3_256_result(void *context,
unsigned char digest[STATIC_ARRAY SHA256_RESULTLEN]);
void sha3_256_get_digest(const void *data, size_t size,
unsigned char digest[STATIC_ARRAY SHA256_RESULTLEN]);
void sha3_512_init(void *context);
void sha3_512_result(void *context,
unsigned char digest[STATIC_ARRAY SHA512_RESULTLEN]);
void sha3_512_get_digest(const void *data, size_t size,
unsigned char digest[STATIC_ARRAY SHA512_RESULTLEN]);
void sha3_loop(void *context, const void *data, size_t len);
extern const struct hash_method hash_method_sha3_256;
extern const struct hash_method hash_method_sha3_512;
#endif
dovecot-2.3.21.1/src/lib/uri-util.c 0000644 0000000 0000000 00000077356 14656633576 013612 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "net.h"
#include "uri-util.h"
#include
/* [URI-GEN] RFC3986 Appendix A:
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
absolute-URI = scheme ":" hier-part [ "?" query ]
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
URI-reference = URI / relative-ref
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
relative-part = "//" authority path-abempty
/ path-absolute
/ path-noscheme
/ path-empty
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
authority = [ userinfo "@" ] host [ ":" port ]
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
host = IP-literal / IPv4address / reg-name
port = *DIGIT
IP-literal = "[" ( IPv6address / IPvFuture ) "]"
IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
IPv6address = 6( h16 ":" ) ls32
/ "::" 5( h16 ":" ) ls32
/ [ h16 ] "::" 4( h16 ":" ) ls32
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
/ [ *4( h16 ":" ) h16 ] "::" ls32
/ [ *5( h16 ":" ) h16 ] "::" h16
/ [ *6( h16 ":" ) h16 ] "::"
h16 = 1*4HEXDIG
ls32 = ( h16 ":" h16 ) / IPv4address
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dec-octet = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
reg-name = *( unreserved / pct-encoded / sub-delims )
path = path-abempty ; begins with "/" or is empty
/ path-absolute ; begins with "/" but not "//"
/ path-noscheme ; begins with a non-colon segment
/ path-rootless ; begins with a segment
/ path-empty ; zero characters
path-abempty = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
path-empty = 0
segment = *pchar
segment-nz = 1*pchar
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
; non-zero-length segment without any colon ":"
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
query = *( pchar / "/" / "?" )
fragment = *( pchar / "/" / "?" )
pct-encoded = "%" HEXDIG HEXDIG
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
*/
#define URI_MAX_SCHEME_NAME_LEN 64
/* Character lookup table
*
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" [bit0]
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "=" [bit1]
* gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" [bit2]
* pchar = unreserved / sub-delims / ":" / "@" [bit0|bit1|bit3]
* 'pfchar' = unreserved / sub-delims / ":" / "@" / "/"
* [bit0|bit1|bit3|bit5]
* 'uchar' = unreserved / sub-delims / ":" [bit0|bit1|bit4]
* 'qchar' = pchar / "/" / "?" [bit0|bit1|bit3|bit5|bit6]
*
*/
#define CHAR_MASK_UNRESERVED (1<<0)
#define CHAR_MASK_SUB_DELIMS (1<<1)
#define CHAR_MASK_PCHAR ((1<<0)|(1<<1)|(1<<3))
#define CHAR_MASK_PFCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5))
#define CHAR_MASK_UCHAR ((1<<0)|(1<<1)|(1<<4))
#define CHAR_MASK_QCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<6))
#define CHAR_MASK_UNRESERVED_PATH ((1<<0)|(1<<5))
static unsigned const char _uri_char_lookup[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10
0, 2, 0, 4, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 1, 36, // 20
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 2, 0, 2, 0, 68, // 30
12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, 4, 0, 1, // 50
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 70
};
static inline int _decode_hex_digit(const unsigned char digit)
{
switch (digit) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return digit - '0';
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
return digit - 'a' + 0x0a;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
return digit - 'A' + 0x0A;
}
return -1;
}
static int
uri_parse_pct_encoded_data(struct uri_parser *parser,
const unsigned char **p, const unsigned char *pend,
unsigned char *ch_r) ATTR_NULL(3)
{
int value;
if (**p != '%' || (pend != NULL && *p >= pend))
return 0;
*p += 1;
if (**p == 0 || *(*p+1) == 0 || (pend != NULL && *p+1 >= pend)) {
parser->error = "Unexpected URI boundary after '%'";
return -1;
}
if ((value = _decode_hex_digit(**p)) < 0) {
parser->error = p_strdup_printf(parser->pool,
"Expecting hex digit after '%%', but found '%c'", **p);
return -1;
}
*ch_r = (value & 0x0f) << 4;
*p += 1;
if ((value = _decode_hex_digit(**p)) < 0) {
parser->error = p_strdup_printf(parser->pool,
"Expecting hex digit after '%%%c', but found '%c'", *((*p)-1), **p);
return -1;
}
*ch_r |= (value & 0x0f);
*p += 1;
if (!parser->allow_pct_nul && *ch_r == '\0') {
parser->error =
"Percent encoding is not allowed to encode NUL character";
return -1;
}
return 1;
}
int uri_parse_pct_encoded(struct uri_parser *parser,
unsigned char *ch_r)
{
return uri_parse_pct_encoded_data
(parser, &parser->cur, parser->end, ch_r);
}
static int
uri_parse_unreserved_char(struct uri_parser *parser, unsigned char *ch_r)
{
if ((*parser->cur & 0x80) != 0)
return 0;
if ((_uri_char_lookup[*parser->cur] & CHAR_MASK_UNRESERVED) != 0) {
*ch_r = *parser->cur;
parser->cur++;
return 1;
}
return 0;
}
int uri_parse_unreserved(struct uri_parser *parser, string_t *part)
{
int len = 0;
while (parser->cur < parser->end) {
int ret;
unsigned char ch = 0;
if ((ret = uri_parse_unreserved_char(parser, &ch)) < 0)
return -1;
if (ret == 0)
break;
if (part != NULL)
str_append_c(part, ch);
len++;
}
return len > 0 ? 1 : 0;
}
int uri_parse_unreserved_pct(struct uri_parser *parser, string_t *part)
{
int len = 0;
while (parser->cur < parser->end) {
int ret;
unsigned char ch = 0;
if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
return -1;
else if (ret == 0 &&
(ret=uri_parse_unreserved_char(parser, &ch)) < 0)
return -1;
if (ret == 0)
break;
if (part != NULL)
str_append_c(part, ch);
len++;
}
return len > 0 ? 1 : 0;
}
bool uri_data_decode(struct uri_parser *parser, const char *data,
const char *until, const char **decoded_r)
{
const unsigned char *p = (const unsigned char *)data;
const unsigned char *pend = (const unsigned char *)until;
string_t *decoded;
int ret;
if (pend == NULL) {
/* NULL means unlimited; solely rely on '\0' */
pend = (const unsigned char *)SIZE_MAX;
}
if (p >= pend || *p == '\0') {
if (decoded_r != NULL)
*decoded_r = "";
return TRUE;
}
decoded = uri_parser_get_tmpbuf(parser, 256);
while (p < pend && *p != '\0') {
unsigned char ch;
if ((ret=uri_parse_pct_encoded_data
(parser, &p, NULL, &ch)) != 0) {
if (ret < 0)
return FALSE;
str_append_c(decoded, ch);
} else {
str_append_c(decoded, *p);
p++;
}
}
if (decoded_r != NULL)
*decoded_r = p_strdup(parser->pool, str_c(decoded));
return TRUE;
}
int uri_parse_scheme(struct uri_parser *parser, const char **scheme_r)
{
const unsigned char *first = parser->cur;
size_t len = 1;
/* RFC 3968:
* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
*/
if (parser->cur >= parser->end || !i_isalpha(*parser->cur))
return 0;
parser->cur++;
while (len < URI_MAX_SCHEME_NAME_LEN &&
parser->cur < parser->end) {
if (!i_isalnum(*parser->cur) &&
*parser->cur != '+' && *parser->cur != '-' &&
*parser->cur != '.')
break;
parser->cur++;
len++;
}
if (parser->cur >= parser->end || *parser->cur != ':') {
parser->error = "Invalid URI scheme";
return -1;
}
if (scheme_r != NULL)
*scheme_r = t_strndup(first, parser->cur - first);
parser->cur++;
return 1;
}
int uri_cut_scheme(const char **uri_p, const char **scheme_r)
{
struct uri_parser parser;
uri_parser_init(&parser, NULL, *uri_p);
if (uri_parse_scheme(&parser, scheme_r) <= 0)
return -1;
*uri_p = (const char *)parser.cur;
return 0;
}
static int
uri_parse_dec_octet(struct uri_parser *parser, string_t *literal,
uint8_t *octet_r) ATTR_NULL(2)
{
unsigned int octet = 0;
int count = 0;
/* RFC 3986:
*
* dec-octet = DIGIT ; 0-9
* / %x31-39 DIGIT ; 10-99
* / "1" 2DIGIT ; 100-199
* / "2" %x30-34 DIGIT ; 200-249
* / "25" %x30-35 ; 250-255
*/
while (parser->cur < parser->end && i_isdigit(*parser->cur)) {
octet = octet * 10 + (parser->cur[0] - '0');
if (octet > 255)
return -1;
if (literal != NULL)
str_append_c(literal, *parser->cur);
parser->cur++;
count++;
}
if (count > 0) {
*octet_r = octet;
return 1;
}
return 0;
}
static int
uri_parse_ipv4address(struct uri_parser *parser, string_t *literal,
struct in_addr *ip4_r) ATTR_NULL(2,3)
{
uint8_t octet;
uint32_t ip = 0;
int ret;
int i;
/* RFC 3986:
*
* IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
*/
if ((ret = uri_parse_dec_octet(parser, literal, &octet)) <= 0)
return ret;
ip = octet;
for (i = 0; i < 3 && parser->cur < parser->end; i++) {
if (*parser->cur != '.')
return -1;
if (literal != NULL)
str_append_c(literal, '.');
parser->cur++;
if (uri_parse_dec_octet(parser, literal, &octet) <= 0)
return -1;
ip = (ip << 8) + octet;
}
if (ip4_r != NULL)
ip4_r->s_addr = htonl(ip);
return 1;
}
static int
uri_do_parse_reg_name(struct uri_parser *parser,
string_t *reg_name) ATTR_NULL(2)
{
/* RFC 3986:
*
* reg-name = *( unreserved / pct-encoded / sub-delims )
*/
while (parser->cur < parser->end) {
int ret;
unsigned char c;
/* unreserved / pct-encoded */
if ((ret=uri_parse_pct_encoded(parser, &c)) < 0)
return -1;
else if (ret == 0 &&
(ret=uri_parse_unreserved_char(parser, &c)) < 0)
return -1;
if (ret > 0) {
if (reg_name != NULL)
str_append_c(reg_name, c);
continue;
}
/* sub-delims */
c = *parser->cur;
if ((c & 0x80) == 0 && (_uri_char_lookup[c] & CHAR_MASK_SUB_DELIMS) != 0) {
if (reg_name != NULL)
str_append_c(reg_name, *parser->cur);
parser->cur++;
continue;
}
break;
}
return 0;
}
int uri_parse_reg_name(struct uri_parser *parser,
const char **reg_name_r)
{
string_t *reg_name = NULL;
int ret;
if (reg_name_r != NULL)
reg_name = uri_parser_get_tmpbuf(parser, 256);
if ((ret=uri_do_parse_reg_name(parser, reg_name)) <= 0)
return ret;
if (reg_name_r != NULL)
*reg_name_r = str_c(reg_name);
return 1;
}
static int uri_do_parse_host_name(struct uri_parser *parser,
string_t *host_name) ATTR_NULL(2)
{
const unsigned char *first, *part;
int ret;
/* RFC 3986, Section 3.2.2:
A registered name intended for lookup in the DNS uses the syntax
defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123].
Such a name consists of a sequence of domain labels separated by ".",
each domain label starting and ending with an alphanumeric character
and possibly also containing "-" characters. The rightmost domain
label of a fully qualified domain name in DNS may be followed by a
single "." and should be if it is necessary to distinguish between
the complete domain name and some local domain.
RFC 2396, Section 3.2.2 (old URI specification):
hostname = *( domainlabel "." ) toplabel [ "." ]
domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
toplabel = alpha | alpha *( alphanum | "-" ) alphanum
The description in RFC 3986 is more liberal, so:
hostname = *( domainlabel "." ) domainlabel [ "." ]
domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
We also support percent encoding in spirit of the generic reg-name,
even though this should explicitly not be used according to the RFC.
It is, however, not strictly forbidden (unlike older RFC), so we
support it.
*/
first = part = parser->cur;
for (;;) {
const unsigned char *offset;
unsigned char ch, pch;
/* alphanum */
offset = parser->cur;
ch = pch = *parser->cur;
if (parser->cur >= parser->end)
break;
if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0) {
return -1;
} else if (ret > 0) {
if (!i_isalnum(ch))
return -1;
if (host_name != NULL)
str_append_c(host_name, ch);
part = parser->cur;
} else {
if (!i_isalnum(*parser->cur))
break;
parser->cur++;
}
if (parser->cur < parser->end) {
/* *( alphanum | "-" ) alphanum */
do {
offset = parser->cur;
if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0) {
return -1;
} else if (ret > 0) {
if (!i_isalnum(ch) && ch != '-')
break;
if (host_name != NULL) {
if (offset > part)
str_append_data(host_name, part, offset - part);
str_append_c(host_name, ch);
}
part = parser->cur;
} else {
ch = *parser->cur;
if (!i_isalnum(ch) && ch != '-')
break;
parser->cur++;
}
pch = ch;
} while (parser->cur < parser->end);
if (!i_isalnum(pch)) {
parser->error = "Invalid domain label in hostname";
return -1;
}
}
if (host_name != NULL && parser->cur > part)
str_append_data(host_name, part, parser->cur - part);
/* "." */
if (parser->cur >= parser->end || ch != '.')
break;
if (host_name != NULL)
str_append_c(host_name, '.');
if (parser->cur == offset)
parser->cur++;
part = parser->cur;
}
if (parser->cur == first)
return 0;
/* remove trailing '.' */
if (host_name != NULL) {
const char *name = str_c(host_name);
i_assert(str_len(host_name) > 0);
if (name[str_len(host_name)-1] == '.')
str_truncate(host_name, str_len(host_name)-1);
}
return 1;
}
int uri_parse_host_name(struct uri_parser *parser,
const char **host_name_r)
{
string_t *host_name = NULL;
int ret;
if (host_name_r != NULL)
host_name = uri_parser_get_tmpbuf(parser, 256);
if ((ret=uri_do_parse_host_name(parser, host_name)) <= 0)
return ret;
if (host_name_r != NULL)
*host_name_r = str_c(host_name);
return 1;
}
static int
uri_parse_ip_literal(struct uri_parser *parser, string_t *literal,
struct in6_addr *ip6_r) ATTR_NULL(2,3)
{
const unsigned char *p;
const char *address;
struct in6_addr ip6;
/* IP-literal = "[" ( IPv6address / IPvFuture ) "]"
* IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
* IPv6address = ; Syntax not relevant: parsed using inet_pton()
*/
/* "[" already verified */
/* Scan for end of address */
for (p = parser->cur+1; p < parser->end; p++) {
if (*p == ']')
break;
}
if (p >= parser->end || *p != ']') {
parser->error = "Expecting ']' at end of IP-literal";
return -1;
}
if (literal != NULL)
str_append_data(literal, parser->cur, p-parser->cur+1);
address = t_strdup_until(parser->cur+1, p);
parser->cur = p + 1;
if (*address == '\0') {
parser->error = "Empty IPv6 host address";
return -1;
}
if (*address == 'v') {
parser->error = p_strdup_printf(parser->pool,
"Future IP host address '%s' not supported", address);
return -1;
}
if (inet_pton(AF_INET6, address, &ip6) <= 0) {
parser->error = p_strdup_printf(parser->pool,
"Invalid IPv6 host address '%s'", address);
return -1;
}
if (ip6_r != NULL)
*ip6_r = ip6;
return 1;
}
static int
uri_do_parse_host(struct uri_parser *parser,
struct uri_host *host, bool host_name)
ATTR_NULL(2)
{
const unsigned char *preserve;
struct in_addr ip4;
struct in6_addr ip6;
string_t *literal = NULL;
int ret;
/* RFC 3986:
*
* host = IP-literal / IPv4address / reg-name
*/
if (host != NULL)
i_zero(host);
literal = uri_parser_get_tmpbuf(parser, 256);
/* IP-literal / */
if (parser->cur < parser->end && *parser->cur == '[') {
if (uri_parse_ip_literal(parser, literal, &ip6) <= 0)
return -1;
if (host != NULL) {
host->name = p_strdup(parser->pool, str_c(literal));;
host->ip.family = AF_INET6;
host->ip.u.ip6 = ip6;
}
return 1;
}
/* IPv4address /
*
* If it fails to parse, we try to parse it as a reg-name
*/
preserve = parser->cur;
if ((ret = uri_parse_ipv4address(parser, literal, &ip4)) > 0) {
if (host != NULL) {
host->name = p_strdup(parser->pool, str_c(literal));
host->ip.family = AF_INET;
host->ip.u.ip4 = ip4;
}
return ret;
}
parser->cur = preserve;
str_truncate(literal, 0);
/* reg-name */
if (host_name) {
if (uri_do_parse_host_name(parser, literal) < 0)
return -1;
} else if (uri_do_parse_reg_name(parser, literal) < 0)
return -1;
if (host != NULL)
host->name = p_strdup(parser->pool, str_c(literal));
return 0;
}
int uri_parse_host(struct uri_parser *parser,
struct uri_host *host)
{
return uri_do_parse_host(parser, host, TRUE);
}
static int
uri_parse_port(struct uri_parser *parser,
struct uri_authority *auth) ATTR_NULL(2)
{
const unsigned char *first;
in_port_t port;
/* RFC 3986:
*
* port = *DIGIT
*/
first = parser->cur;
while (parser->cur < parser->end && i_isdigit(*parser->cur))
parser->cur++;
if (parser->cur == first)
return 0;
if (net_str2port(t_strdup_until(first, parser->cur), &port) < 0) {
parser->error = "Invalid port number";
return -1;
}
if (auth != NULL)
auth->port = port;
return 1;
}
static int
uri_do_parse_authority(struct uri_parser *parser,
struct uri_authority *auth, bool host_name) ATTR_NULL(2)
{
const unsigned char *p;
int ret;
/*
* authority = [ userinfo "@" ] host [ ":" port ]
*/
if (auth != NULL)
i_zero(auth);
/* Scan ahead to check whether there is a [userinfo "@"] uri component */
for (p = parser->cur; p < parser->end; p++){
/* refuse 8bit characters */
if ((*p & 0x80) != 0)
break;
/* break at first delimiter */
if (*p != '%' && (_uri_char_lookup[*p] & CHAR_MASK_UCHAR) == 0)
break;
}
/* Extract userinfo */
if (p < parser->end && *p == '@') {
if (auth != NULL)
auth->enc_userinfo = p_strdup_until(parser->pool, parser->cur, p);
parser->cur = p+1;
}
/* host */
if (uri_do_parse_host(parser,
(auth == NULL ? NULL : &auth->host), host_name) < 0)
return -1;
if (parser->cur == parser->end)
return 1;
switch (*parser->cur) {
case ':': case '/': case '?': case '#':
break;
default:
parser->error = "Invalid host identifier";
return -1;
}
/* [":" port] */
if (*parser->cur == ':') {
parser->cur++;
if ((ret = uri_parse_port(parser, auth)) < 0)
return ret;
if (parser->cur == parser->end)
return 1;
switch (*parser->cur) {
case '/': case '?': case '#':
break;
default:
parser->error = "Invalid host port";
return -1;
}
}
return 1;
}
static int
uri_do_parse_slashslash_authority(struct uri_parser *parser,
struct uri_authority *auth, bool host_name)
ATTR_NULL(2)
{
/* "//" authority */
if ((parser->end - parser->cur) <= 2 || parser->cur[0] != '/' ||
parser->cur[1] != '/')
return 0;
parser->cur += 2;
return uri_do_parse_authority(parser, auth, host_name);
}
int uri_parse_authority(struct uri_parser *parser,
struct uri_authority *auth)
{
return uri_do_parse_authority(parser, auth, FALSE);
}
int uri_parse_slashslash_authority(struct uri_parser *parser,
struct uri_authority *auth)
{
return uri_do_parse_slashslash_authority(parser, auth, FALSE);
}
int uri_parse_host_authority(struct uri_parser *parser,
struct uri_authority *auth)
{
return uri_do_parse_authority(parser, auth, TRUE);
}
int uri_parse_slashslash_host_authority(struct uri_parser *parser,
struct uri_authority *auth)
{
return uri_do_parse_slashslash_authority(parser, auth, TRUE);
}
int uri_parse_path_segment(struct uri_parser *parser, const char **segment_r)
{
const unsigned char *first = parser->cur;
int ret;
while (parser->cur < parser->end) {
if (*parser->cur == '%') {
unsigned char ch = 0;
if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
return -1;
if (ret > 0)
continue;
}
if ((*parser->cur & 0x80) != 0 ||
(_uri_char_lookup[*parser->cur] & CHAR_MASK_PCHAR) == 0)
break;
parser->cur++;
}
if (parser->cur < parser->end &&
*parser->cur != '/' && *parser->cur != '?' && *parser->cur != '#' ) {
parser->error =
"Path component contains invalid character";
return -1;
}
if (first == parser->cur)
return 0;
if (segment_r != NULL)
*segment_r = p_strdup_until(parser->pool, first, parser->cur);
return 1;
}
int uri_parse_path(struct uri_parser *parser,
int *relative_r, const char *const **path_r)
{
const unsigned char *pbegin = parser->cur;
ARRAY_TYPE(const_string) segments;
const char *segment = NULL;
unsigned int count;
int relative = 1;
int ret;
count = 0;
if (path_r != NULL)
p_array_init(&segments, parser->pool, 16);
else
i_zero(&segments);
/* check for a leading '/' and indicate absolute path
when it is present
*/
if (parser->cur < parser->end && *parser->cur == '/') {
parser->cur++;
relative = 0;
}
/* parse first segment */
if ((ret = uri_parse_path_segment(parser, &segment)) < 0)
return -1;
for (;;) {
if (ret > 0) {
/* strip dot segments */
if (segment[0] == '.') {
if (segment[1] == '.') {
if (segment[2] == '\0') {
/* '..' -> skip and... */
segment = NULL;
/* ... pop last segment (if any) */
if (count > 0) {
if (path_r != NULL) {
i_assert(count == array_count(&segments));
array_delete(&segments, count-1, 1);
}
count--;
} else if ( relative > 0 ) {
relative++;
}
}
} else if (segment[1] == '\0') {
/* '.' -> skip */
segment = NULL;
}
}
} else {
segment = "";
}
if (segment != NULL) {
if (path_r != NULL)
array_push_back(&segments, &segment);
count++;
}
if (parser->cur >= parser->end || *parser->cur != '/')
break;
parser->cur++;
/* parse next path segment */
if ((ret = uri_parse_path_segment(parser, &segment)) < 0)
return -1;
}
if (relative_r != NULL)
*relative_r = relative;
if (path_r != NULL)
*path_r = NULL;
if (parser->cur == pbegin) {
/* path part of URI is empty */
return 0;
}
if (path_r != NULL) {
/* special treatment for a trailing '..' or '.' */
if (segment == NULL) {
segment = "";
array_push_back(&segments, &segment);
}
array_append_zero(&segments);
*path_r = array_get(&segments, &count);
}
if (parser->cur < parser->end &&
*parser->cur != '?' && *parser->cur != '#') {
parser->error = "Path component contains invalid character";
return -1;
}
return 1;
}
int uri_parse_query(struct uri_parser *parser, const char **query_r)
{
const unsigned char *first = parser->cur;
int ret;
/* RFC 3986:
*
* URI = { ... } [ "?" query ] { ... }
* query = *( pchar / "/" / "?" )
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
*/
if (parser->cur >= parser->end || *parser->cur != '?')
return 0;
parser->cur++;
while (parser->cur < parser->end) {
if (*parser->cur == '%') {
unsigned char ch = 0;
if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
return -1;
if (ret > 0)
continue;
}
if ((*parser->cur & 0x80) != 0 ||
(_uri_char_lookup[*parser->cur] & CHAR_MASK_QCHAR) == 0)
break;
parser->cur++;
}
if (parser->cur < parser->end && *parser->cur != '#') {
parser->error = "Query component contains invalid character";
return -1;
}
if (query_r != NULL)
*query_r = p_strdup_until(parser->pool, first+1, parser->cur);
return 1;
}
int uri_parse_fragment(struct uri_parser *parser, const char **fragment_r)
{
const unsigned char *first = parser->cur;
int ret;
/* RFC 3986:
*
* URI = { ... } [ "#" fragment ]
* fragment = *( pchar / "/" / "?" )
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
*/
if (parser->cur >= parser->end || *parser->cur != '#')
return 0;
parser->cur++;
while (parser->cur < parser->end) {
if (*parser->cur == '%') {
unsigned char ch = 0;
if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
return -1;
if (ret > 0)
continue;
}
if ((*parser->cur & 0x80) != 0 ||
(_uri_char_lookup[*parser->cur] & CHAR_MASK_QCHAR) == 0)
break;
parser->cur++;
}
if (parser->cur < parser->end) {
parser->error = "Fragment component contains invalid character";
return -1;
}
if (fragment_r != NULL)
*fragment_r = p_strdup_until(parser->pool, first+1, parser->cur);
return 1;
}
void uri_parser_init_data(struct uri_parser *parser,
pool_t pool, const unsigned char *data, size_t size)
{
i_zero(parser);
parser->pool = pool;
parser->begin = parser->cur = data;
parser->end = data + size;
}
void uri_parser_init(struct uri_parser *parser,
pool_t pool, const char *uri)
{
uri_parser_init_data
(parser, pool, (const unsigned char *)uri, strlen(uri));
}
string_t *uri_parser_get_tmpbuf(struct uri_parser *parser, size_t size)
{
if (parser->tmpbuf == NULL)
parser->tmpbuf = str_new(parser->pool, size);
else
str_truncate(parser->tmpbuf, 0);
return parser->tmpbuf;
}
int uri_parse_absolute_generic(struct uri_parser *parser,
enum uri_parse_flags flags)
{
int relative, aret, ret = 0;
/*
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
path-abempty = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-rootless = segment-nz *( "/" segment )
path-empty = 0
segment = *pchar
segment-nz = 1*pchar
*/
/* scheme ":" */
if ((flags & URI_PARSE_SCHEME_EXTERNAL) == 0 &&
(ret=uri_parse_scheme(parser, NULL)) <= 0) {
if (ret == 0)
parser->error = "Missing scheme";
return -1;
}
/* "//" authority */
if ((aret=uri_parse_slashslash_authority
(parser, NULL)) < 0)
return -1;
/* path-absolute / path-rootless / path-empty */
if (aret == 0) {
ret = uri_parse_path(parser, &relative, NULL);
/* path-abempty */
} else if (parser->cur < parser->end && *parser->cur == '/') {
ret = uri_parse_path(parser, &relative, NULL);
i_assert(ret <= 0 || relative == 0);
}
if (ret < 0)
return -1;
/* [ "?" query ] */
if (uri_parse_query(parser, NULL) < 0)
return -1;
/* [ "#" fragment ] */
if ((ret=uri_parse_fragment(parser, NULL)) < 0)
return ret;
if (ret > 0 && (flags & URI_PARSE_ALLOW_FRAGMENT_PART) == 0) {
parser->error = "Fragment part not allowed";
return -1;
}
i_assert(parser->cur == parser->end);
return 0;
}
/*
* Generic URI manipulation
*/
void uri_host_copy(pool_t pool, struct uri_host *dest,
const struct uri_host *src)
{
const char *host_name = src->name;
/* create host name literal if caller is lazy */
if (host_name == NULL && src->ip.family != 0) {
host_name = net_ip2addr(&src->ip);
i_assert(*host_name != '\0');
}
*dest = *src;
dest->name = p_strdup(pool, host_name);
}
/*
* Check generic URI
*/
int uri_check_data(const unsigned char *data, size_t size,
enum uri_parse_flags flags, const char **error_r)
{
struct uri_parser parser;
int ret;
i_zero(&parser);
parser.pool = pool_datastack_create();
parser.begin = parser.cur = data;
parser.end = data + size;
ret = uri_parse_absolute_generic(&parser, flags);
*error_r = parser.error;
return ret;
}
int uri_check(const char *uri, enum uri_parse_flags flags,
const char **error_r)
{
return uri_check_data
((const unsigned char *)uri, strlen(uri), flags, error_r);
}
/*
* Generic URI construction
*/
void uri_data_encode(string_t *out,
const unsigned char esc_table[256],
unsigned char esc_mask, const char *esc_extra,
const char *data)
{
const unsigned char *pbegin, *p;
pbegin = p = (const unsigned char *)data;
while (*p != '\0') {
if ((*p & 0x80) != 0 || (esc_table[*p] & esc_mask) == 0 ||
(esc_extra != NULL && strchr(esc_extra, (char)*p) != NULL)) {
if ((p - pbegin) > 0)
str_append_data(out, pbegin, p - pbegin);
str_printfa(out, "%%%02x", *p);
p++;
pbegin = p;
} else {
p++;
}
}
if ((p - pbegin) > 0)
str_append_data(out, pbegin, p - pbegin);
}
void uri_append_scheme(string_t *out, const char *scheme)
{
str_append(out, scheme);
str_append_c(out, ':');
}
void uri_append_user_data(string_t *out, const char *esc,
const char *data)
{
uri_data_encode(out, _uri_char_lookup, CHAR_MASK_UCHAR, esc, data);
}
void uri_append_userinfo(string_t *out, const char *userinfo)
{
uri_append_user_data(out, NULL, userinfo);
str_append_c(out, '@');
}
void uri_append_host_name(string_t *out, const char *name)
{
uri_data_encode(out, _uri_char_lookup,
CHAR_MASK_UNRESERVED | CHAR_MASK_SUB_DELIMS, NULL, name);
}
void uri_append_host_ip(string_t *out, const struct ip_addr *host_ip)
{
const char *addr = net_ip2addr(host_ip);
i_assert(host_ip->family != 0);
if (host_ip->family == AF_INET) {
str_append(out, addr);
return;
}
i_assert(host_ip->family == AF_INET6);
str_append_c(out, '[');
str_append(out, addr);
str_append_c(out, ']');
}
void uri_append_host(string_t *out, const struct uri_host *host)
{
if (host->name != NULL) {
/* assume IPv6 literal if starts with '['; avoid encoding */
if (*host->name == '[')
str_append(out, host->name);
else
uri_append_host_name(out, host->name);
} else
uri_append_host_ip(out, &host->ip);
}
void uri_append_port(string_t *out, in_port_t port)
{
if (port != 0)
str_printfa(out, ":%u", port);
}
void uri_append_path_segment_data(string_t *out, const char *esc,
const char *data)
{
uri_data_encode(out, _uri_char_lookup, CHAR_MASK_PCHAR, esc, data);
}
void uri_append_path_segment(string_t *out, const char *segment)
{
str_append_c(out, '/');
if (*segment != '\0')
uri_append_path_data(out, NULL, segment);
}
void uri_append_path_data(string_t *out, const char *esc,
const char *data)
{
uri_data_encode(out, _uri_char_lookup, CHAR_MASK_PFCHAR, esc, data);
}
void uri_append_path(string_t *out, const char *path)
{
str_append_c(out, '/');
if (*path != '\0')
uri_append_path_data(out, NULL, path);
}
void uri_append_query_data(string_t *out, const char *esc,
const char *data)
{
uri_data_encode(out, _uri_char_lookup, CHAR_MASK_QCHAR, esc, data);
}
void uri_append_query(string_t *out, const char *query)
{
str_append_c(out, '?');
if (*query != '\0')
uri_append_query_data(out, NULL, query);
}
void uri_append_fragment_data(string_t *out, const char *esc,
const char *data)
{
uri_data_encode(out, _uri_char_lookup, CHAR_MASK_QCHAR, esc, data);
}
void uri_append_fragment(string_t *out, const char *fragment)
{
str_append_c(out, '#');
if (*fragment != '\0')
uri_append_fragment_data(out, NULL, fragment);
}
void uri_append_unreserved(string_t *out, const char *data)
{
uri_data_encode(out, _uri_char_lookup, CHAR_MASK_UNRESERVED,
NULL, data);
}
void uri_append_unreserved_path(string_t *out, const char *data)
{
uri_data_encode(out, _uri_char_lookup, CHAR_MASK_UNRESERVED_PATH,
NULL, data);
}
dovecot-2.3.21.1/src/lib/process-stat.c 0000644 0000000 0000000 00000015671 14656633576 014457 0000000 0000000 /* Copyright (c) 2008-2021 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "process-stat.h"
#include "time-util.h"
#include
#include
#include
#include
#include
#include
#include
#define PROC_STAT_PATH "/proc/self/stat"
#define PROC_STATUS_PATH "/proc/self/status"
#define PROC_IO_PATH "/proc/self/io"
static const uint64_t stat_undefined = 0xFFFFFFFFFFFFFFFF;
struct key_val {
const char *key;
uint64_t *value;
unsigned int idx;
};
static int parse_field(const char *line, struct key_val *field)
{
if (str_begins(line, field->key))
return str_to_uint64(line + strlen(field->key), field->value);
return -1;
}
static void buffer_parse(const char *buf, struct key_val *fields)
{
const char *const *tmp;
tmp = t_strsplit(buf, "\n");
unsigned int tmp_count = str_array_length(tmp);
for (; fields->key != NULL; fields++) {
if (fields->idx >= tmp_count ||
parse_field(tmp[fields->idx], fields) < 0)
*fields->value = stat_undefined;
}
}
static int open_fd(const char *path, struct event *event)
{
int fd;
uid_t uid;
fd = open(path, O_RDONLY);
if (fd == -1 && errno == EACCES) {
uid = geteuid();
/* kludge: if we're running with permissions temporarily
dropped, get them temporarily back so we can open
/proc/self/io. */
if (seteuid(0) == 0) {
fd = open(path, O_RDONLY);
if (seteuid(uid) < 0)
i_fatal("seteuid(%s) failed", dec2str(uid));
}
errno = EACCES;
}
if (fd == -1) {
if (errno == ENOENT || errno == EACCES)
e_debug(event, "open(%s) failed: %m", path);
else
e_error(event, "open(%s) failed: %m", path);
}
return fd;
}
static int
read_file(int fd, const char *path, char *buf_r, size_t buf_size, struct event *event)
{
ssize_t ret;
ret = read(fd, buf_r, buf_size);
if (ret <= 0) {
if (ret == -1)
e_error(event, "read(%s) failed: %m", path);
else
e_error(event, "read(%s) returned EOF", path);
} else if (ret == (ssize_t)buf_size) {
e_error(event, "%s is larger than expected", path);
buf_r[buf_size - 1] = '\0';
} else {
buf_r[ret] = '\0';
}
i_close_fd(&fd);
return ret <= 0 ? -1 : 0;
}
static int parse_key_val_file(const char *path,
struct key_val *fields,
struct event *event)
{
char buf[2048];
int fd;
fd = open_fd(path, event);
if (fd == -1 || read_file(fd, path, buf, sizeof(buf), event) < 0) {
for (; fields->key != NULL; fields++)
*fields->value = stat_undefined;
return -1;
}
buffer_parse(buf, fields);
return 0;
}
static int parse_proc_io(struct process_stat *stat_r, struct event *event)
{
struct key_val fields[] = {
{ "rchar: ", &stat_r->rchar, 0 },
{ "wchar: ", &stat_r->wchar, 1 },
{ "syscr: ", &stat_r->syscr, 2 },
{ "syscw: ", &stat_r->syscw, 3 },
{ NULL, NULL, 0 },
};
if (stat_r->proc_io_failed ||
parse_key_val_file(PROC_IO_PATH, fields, event) < 0) {
stat_r->proc_io_failed = TRUE;
return -1;
}
return 0;
}
static int parse_proc_status(struct process_stat *stat_r, struct event *event)
{
struct key_val fields [] = {
{ "voluntary_ctxt_switches:\t", &stat_r->vol_cs, 53 },
{ "nonvoluntary_ctxt_switches:\t", &stat_r->invol_cs, 54 },
{ NULL, NULL, 0 },
};
if (stat_r->proc_status_failed ||
parse_key_val_file(PROC_STATUS_PATH, fields, event) < 0) {
stat_r->proc_status_failed = TRUE;
return -1;
}
return 0;
}
static int stat_get_rusage(struct process_stat *stat_r)
{
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) < 0)
return -1;
stat_r->utime = timeval_to_usecs(&usage.ru_utime);
stat_r->stime = timeval_to_usecs(&usage.ru_stime);
stat_r->minor_faults = usage.ru_minflt;
stat_r->major_faults = usage.ru_majflt;
stat_r->vol_cs = usage.ru_nvcsw;
stat_r->invol_cs = usage.ru_nivcsw;
return 0;
}
static int parse_stat_file(struct process_stat *stat_r, struct event *event)
{
int fd = -1;
char buf[1024];
unsigned int i;
const char *const *tmp;
struct {
uint64_t *value;
unsigned int idx;
} fields[] = {
{ &stat_r->minor_faults, 9 },
{ &stat_r->major_faults, 11 },
{ &stat_r->utime, 13 },
{ &stat_r->stime, 14 },
{ &stat_r->vsz, 22 },
{ &stat_r->rss, 23 },
};
if (!stat_r->proc_stat_failed)
fd = open_fd(PROC_STAT_PATH, event);
if (fd == -1) {
stat_r->proc_stat_failed = TRUE;
/* vsz and rss are not provided by getrusage(), setting to undefined */
stat_r->vsz = stat_undefined;
stat_r->rss = stat_undefined;
if (stat_r->rusage_failed)
return -1;
if (stat_get_rusage(stat_r) < 0) {
e_error(event, "getrusage() failed: %m");
stat_r->rusage_failed = TRUE;
return -1;
}
return 0;
}
if (read_file(fd, PROC_STAT_PATH, buf, sizeof(buf), event) < 0) {
stat_r->proc_stat_failed = TRUE;
return -1;
}
tmp = t_strsplit(buf, " ");
unsigned int tmp_count = str_array_length(tmp);
for (i = 0; i < N_ELEMENTS(fields); i++) {
if (fields[i].idx >= tmp_count ||
str_to_uint64(tmp[fields[i].idx], fields[i].value) < 0)
*fields[i].value = stat_undefined;
}
/* rss is provided in pages, convert to bytes */
stat_r->rss *= sysconf(_SC_PAGESIZE);
return 0;
}
static int parse_all_stats(struct process_stat *stat_r, struct event *event)
{
bool has_fields = FALSE;
if (parse_stat_file(stat_r, event) == 0)
has_fields = TRUE;
if (parse_proc_io(stat_r, event) == 0)
has_fields = TRUE;
if ((!stat_r->proc_stat_failed || stat_r->rusage_failed) &&
parse_proc_status(stat_r, event) == 0)
has_fields = TRUE;
if (has_fields)
return 0;
return -1;
}
void process_stat_read_start(struct process_stat *stat_r, struct event *event)
{
i_zero(stat_r);
(void)parse_all_stats(stat_r, event);
}
void process_stat_read_finish(struct process_stat *stat, struct event *event)
{
unsigned int i;
struct process_stat new_stat;
i_zero(&new_stat);
new_stat.proc_io_failed = stat->proc_io_failed;
new_stat.proc_status_failed = stat->proc_status_failed;
new_stat.proc_stat_failed = stat->proc_stat_failed;
new_stat.rusage_failed = stat->rusage_failed;
if (parse_all_stats(&new_stat, event) < 0) {
i_zero(stat);
return;
}
stat->vsz = new_stat.vsz == stat_undefined ? 0 : new_stat.vsz;
stat->rss = new_stat.rss == stat_undefined ? 0 : new_stat.rss;
unsigned int cumulative_field_offsets[] = {
offsetof(struct process_stat, utime),
offsetof(struct process_stat, stime),
offsetof(struct process_stat, minor_faults),
offsetof(struct process_stat, major_faults),
offsetof(struct process_stat, vol_cs),
offsetof(struct process_stat, invol_cs),
offsetof(struct process_stat, rchar),
offsetof(struct process_stat, wchar),
offsetof(struct process_stat, syscr),
offsetof(struct process_stat, syscw),
};
for (i = 0; i < N_ELEMENTS(cumulative_field_offsets); i++) {
uint64_t *old_value = PTR_OFFSET(stat, cumulative_field_offsets[i]);
uint64_t *new_value = PTR_OFFSET(&new_stat, cumulative_field_offsets[i]);
if (*old_value == stat_undefined || *new_value == stat_undefined)
*old_value = 0;
else
*old_value = *new_value > *old_value ?
(*new_value - *old_value) : 0;
}
}
dovecot-2.3.21.1/src/lib/hook-build.h 0000644 0000000 0000000 00000001204 14656633576 014055 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#ifndef HOOK_BUILD_H
#define HOOK_BUILD_H 1
struct hook_build_context;
struct hook_stack;
/* Initialize new hook building context, vfuncs should point to
the functions table that is being manipulated, and size should be
the size of this table. */
struct hook_build_context *hook_build_init(void (**vfuncs)(), size_t size);
/* This is called after a hook may have updated vfuncs */
void hook_build_update(struct hook_build_context *ctx, void *_vlast);
/* Free memory used by build context */
void hook_build_deinit(struct hook_build_context **_ctx);
#endif
dovecot-2.3.21.1/src/lib/ostream-rawlog.h 0000644 0000000 0000000 00000000611 14656633576 014764 0000000 0000000 #ifndef OSTREAM_RAWLOG_H
#define OSTREAM_RAWLOG_H
#include "iostream-rawlog.h"
struct ostream *
o_stream_create_rawlog(struct ostream *output, const char *rawlog_path,
int rawlog_fd, enum iostream_rawlog_flags flags);
struct ostream *
o_stream_create_rawlog_from_stream(struct ostream *output,
struct ostream *rawlog_output,
enum iostream_rawlog_flags flags);
#endif
dovecot-2.3.21.1/src/lib/mmap-util.c 0000644 0000000 0000000 00000002336 14656633576 013727 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "mmap-util.h"
#include
void *mmap_file(int fd, size_t *length, int prot)
{
struct stat st;
if (fstat(fd, &st) < 0)
return MAP_FAILED;
#if OFF_T_MAX > SSIZE_T_MAX
if (st.st_size > SSIZE_T_MAX) {
/* too large file to map into memory */
errno = EFBIG;
return MAP_FAILED;
}
#endif
*length = (size_t)st.st_size;
if (*length == 0)
return NULL;
i_assert(*length > 0 && *length < SSIZE_T_MAX);
return mmap(NULL, *length, prot, MAP_SHARED, fd, 0);
}
void *mmap_ro_file(int fd, size_t *length)
{
return mmap_file(fd, length, PROT_READ);
}
void *mmap_rw_file(int fd, size_t *length)
{
return mmap_file(fd, length, PROT_READ | PROT_WRITE);
}
#undef madvise
int my_madvise(void *start ATTR_UNUSED, size_t length ATTR_UNUSED,
int advice ATTR_UNUSED)
{
#ifdef HAVE_MADVISE
/* Ignore ENOSYS errors, which happen if the kernel hasn't implemented
the syscall even if libc has. */
if (madvise(start, length, advice) < 0 && errno != ENOSYS)
return -1;
#endif
return 0;
}
size_t mmap_get_page_size(void)
{
static size_t size = 0;
if (size != 0)
return size;
size = getpagesize();
return size;
}
dovecot-2.3.21.1/src/lib/eacces-error.h 0000644 0000000 0000000 00000001073 14656633576 014376 0000000 0000000 #ifndef EACCES_ERROR_H
#define EACCES_ERROR_H
/* Return a user-friendly error message for EACCES failures. */
const char *eacces_error_get(const char *func, const char *path);
const char *eacces_error_get_creating(const char *func, const char *path);
/* Return a user-friendly error message for fchown() or chown() EPERM
failures when only the group is being changed. gid_origin specifies why
exactly this group is being used. */
const char *eperm_error_get_chgrp(const char *func, const char *path,
gid_t gid, const char *gid_origin)
ATTR_NULL(4);
#endif
dovecot-2.3.21.1/src/lib/istream-rawlog.c 0000644 0000000 0000000 00000007144 14656633576 014761 0000000 0000000 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ostream.h"
#include "iostream-rawlog-private.h"
#include "istream-private.h"
#include "istream-rawlog.h"
struct rawlog_istream {
struct istream_private istream;
struct rawlog_iostream riostream;
};
static void i_stream_rawlog_close(struct iostream_private *stream,
bool close_parent)
{
struct rawlog_istream *rstream =
container_of(stream, struct rawlog_istream, istream.iostream);
iostream_rawlog_close(&rstream->riostream);
if (close_parent)
i_stream_close(rstream->istream.parent);
}
static void i_stream_rawlog_destroy(struct iostream_private *stream)
{
struct rawlog_istream *rstream =
container_of(stream, struct rawlog_istream, istream.iostream);
uoff_t v_offset;
v_offset = rstream->istream.parent_start_offset +
rstream->istream.istream.v_offset;
if (rstream->istream.parent->seekable ||
v_offset > rstream->istream.parent->v_offset) {
/* get to same position in parent stream */
i_stream_seek(rstream->istream.parent, v_offset);
}
}
static ssize_t i_stream_rawlog_read(struct istream_private *stream)
{
struct rawlog_istream *rstream =
container_of(stream, struct rawlog_istream, istream);
ssize_t ret;
size_t pos;
i_stream_seek(stream->parent, rstream->istream.parent_start_offset +
stream->istream.v_offset);
stream->pos -= stream->skip;
stream->skip = 0;
stream->buffer = i_stream_get_data(stream->parent, &pos);
if (pos > stream->pos)
ret = 0;
else do {
ret = i_stream_read_memarea(stream->parent);
stream->istream.stream_errno = stream->parent->stream_errno;
stream->istream.eof = stream->parent->eof;
stream->buffer = i_stream_get_data(stream->parent, &pos);
} while (pos <= stream->pos && ret > 0);
if (ret == -2)
return -2;
if (pos <= stream->pos)
ret = ret == 0 ? 0 : -1;
else {
ret = (ssize_t)(pos - stream->pos);
iostream_rawlog_write(&rstream->riostream,
stream->buffer + stream->pos, ret);
}
stream->pos = pos;
i_assert(ret != -1 || stream->istream.eof ||
stream->istream.stream_errno != 0);
return ret;
}
struct istream *
i_stream_create_rawlog(struct istream *input, const char *rawlog_path,
int rawlog_fd, enum iostream_rawlog_flags flags)
{
struct ostream *rawlog_output;
bool autoclose_fd = (flags & IOSTREAM_RAWLOG_FLAG_AUTOCLOSE) != 0;
i_assert(rawlog_path != NULL);
i_assert(rawlog_fd != -1);
rawlog_output = autoclose_fd ?
o_stream_create_fd_autoclose(&rawlog_fd, 0) :
o_stream_create_fd(rawlog_fd, 0);
o_stream_set_name(rawlog_output,
t_strdup_printf("rawlog(%s)", rawlog_path));
return i_stream_create_rawlog_from_stream(input, rawlog_output, flags);
}
struct istream *
i_stream_create_rawlog_from_stream(struct istream *input,
struct ostream *rawlog_output,
enum iostream_rawlog_flags flags)
{
struct rawlog_istream *rstream;
rstream = i_new(struct rawlog_istream, 1);
rstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
rstream->istream.stream_size_passthrough = TRUE;
rstream->riostream.rawlog_output = rawlog_output;
iostream_rawlog_init(&rstream->riostream, flags, TRUE);
rstream->istream.read = i_stream_rawlog_read;
rstream->istream.iostream.close = i_stream_rawlog_close;
rstream->istream.iostream.destroy = i_stream_rawlog_destroy;
rstream->istream.istream.readable_fd = input->readable_fd;
rstream->istream.istream.blocking = input->blocking;
rstream->istream.istream.seekable = input->seekable;
return i_stream_create(&rstream->istream, input,
i_stream_get_fd(input), 0);
}
dovecot-2.3.21.1/src/lib/ostream-private.h 0000644 0000000 0000000 00000004565 14656633576 015157 0000000 0000000 #ifndef OSTREAM_PRIVATE_H
#define OSTREAM_PRIVATE_H
#include "ostream.h"
#include "iostream-private.h"
struct ostream_private {
/* inheritance: */
struct iostream_private iostream;
/* methods: */
void (*cork)(struct ostream_private *stream, bool set);
int (*flush)(struct ostream_private *stream);
void (*set_flush_callback)(struct ostream_private *stream,
stream_flush_callback_t *callback,
void *context);
void (*flush_pending)(struct ostream_private *stream, bool set);
size_t (*get_buffer_used_size)(const struct ostream_private *stream);
size_t (*get_buffer_avail_size)(const struct ostream_private *stream);
int (*seek)(struct ostream_private *stream, uoff_t offset);
ssize_t (*sendv)(struct ostream_private *stream,
const struct const_iovec *iov,
unsigned int iov_count);
int (*write_at)(struct ostream_private *stream,
const void *data, size_t size, uoff_t offset);
enum ostream_send_istream_result
(*send_istream)(struct ostream_private *outstream,
struct istream *instream);
void (*switch_ioloop_to)(struct ostream_private *stream,
struct ioloop *ioloop);
/* data: */
struct ostream ostream;
size_t max_buffer_size;
struct ostream *parent; /* for filter streams */
int fd;
struct timeval last_write_timeval;
stream_flush_callback_t *callback;
void *context;
bool corked:1;
bool finished:1;
bool closing:1;
bool last_errors_not_checked:1;
bool error_handling_disabled:1;
bool noverflow:1;
bool finish_also_parent:1;
bool finish_via_child:1;
};
struct ostream *
o_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
ATTR_NULL(2);
enum ostream_send_istream_result
io_stream_copy(struct ostream *outstream, struct istream *instream);
void o_stream_copy_error_from_parent(struct ostream_private *_stream);
/* This should be called before sending data to parent stream. It makes sure
that the parent stream's output buffer doesn't become too large.
Returns 1 if more data can be safely added, 0 if not, -1 if error. */
int o_stream_flush_parent_if_needed(struct ostream_private *_stream);
/* Call this in flush() handler to flush the parent stream. It will call
either o_stream_flush() or o_stream_finish() depending on whether this
stream is already finished. If the parent fails, its error will be also
copied to this stream. */
int o_stream_flush_parent(struct ostream_private *_stream);
#endif
dovecot-2.3.21.1/src/lib/istream-chain.c 0000644 0000000 0000000 00000024051 14656633576 014544 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "llist.h"
#include "memarea.h"
#include "istream-private.h"
#include "istream-chain.h"
struct chain_istream;
struct istream_chain_link {
struct istream_chain_link *prev, *next;
struct istream *stream;
bool eof;
};
struct istream_chain {
struct istream_chain_link *head, *tail;
struct chain_istream *stream;
};
struct chain_istream {
struct istream_private istream;
/* how much of the previous link's stream still exists at the
beginning of our buffer. skipping through this should point to
the beginning of the current link's stream. */
size_t prev_stream_left;
size_t prev_skip;
struct istream_chain chain;
};
static void ATTR_NULL(2)
i_stream_chain_append_internal(struct istream_chain *chain,
struct istream *stream)
{
struct istream_chain_link *link;
if (stream == NULL && chain->tail != NULL && chain->tail->stream == NULL)
return;
link = i_new(struct istream_chain_link, 1);
link->stream = stream;
link->eof = stream == NULL;
if (stream != NULL)
i_stream_ref(stream);
if (chain->head == NULL && stream != NULL) {
i_stream_set_max_buffer_size(stream,
chain->stream->istream.max_buffer_size);
}
DLLIST2_APPEND(&chain->head, &chain->tail, link);
/* if io_add_istream() has been added to this chain stream, notify
the callback that we have more data available. */
if (stream != NULL)
i_stream_set_input_pending(stream, TRUE);
}
void i_stream_chain_append(struct istream_chain *chain, struct istream *stream)
{
i_stream_chain_append_internal(chain, stream);
}
void i_stream_chain_append_eof(struct istream_chain *chain)
{
i_stream_chain_append_internal(chain, NULL);
}
static void
i_stream_chain_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
struct chain_istream *cstream =
container_of(stream, struct chain_istream, istream.iostream);
struct istream_chain_link *link = cstream->chain.head;
cstream->istream.max_buffer_size = max_size;
while (link != NULL) {
if (link->stream != NULL)
i_stream_set_max_buffer_size(link->stream, max_size);
link = link->next;
}
}
static void i_stream_chain_destroy(struct iostream_private *stream)
{
struct chain_istream *cstream =
container_of(stream, struct chain_istream, istream.iostream);
struct istream_chain_link *link = cstream->chain.head;
while (link != NULL) {
struct istream_chain_link *next = link->next;
i_stream_unref(&link->stream);
i_free(link);
link = next;
}
i_stream_free_buffer(&cstream->istream);
}
static void i_stream_chain_read_next(struct chain_istream *cstream)
{
struct istream_chain_link *link = cstream->chain.head;
struct istream *prev_input;
const unsigned char *data;
size_t data_size, cur_data_pos;
i_assert(link != NULL && link->stream != NULL);
i_assert(link->stream->eof);
prev_input = link->stream;
data = i_stream_get_data(prev_input, &data_size);
DLLIST2_REMOVE(&cstream->chain.head, &cstream->chain.tail, link);
i_free(link);
/* a) we have more streams, b) we have EOF, c) we need to wait
for more streams */
link = cstream->chain.head;
if (link != NULL && link->stream != NULL)
i_stream_seek(link->stream, 0);
if (cstream->prev_stream_left > 0) {
/* we've already buffered some of the prev_input. continue
appending the rest to it. if it's already at EOF, there's
nothing more to append. */
cur_data_pos = cstream->istream.pos -
(cstream->istream.skip + cstream->prev_stream_left);
i_assert(cur_data_pos <= data_size);
data += cur_data_pos;
data_size -= cur_data_pos;
/* the stream has now become "previous", so its contents in
buffer are now part of prev_stream_left. */
cstream->prev_stream_left += cur_data_pos;
} else {
cstream->istream.pos = 0;
cstream->istream.skip = 0;
cstream->prev_stream_left = 0;
}
if (data_size > 0) {
if (cstream->istream.memarea != NULL &&
memarea_get_refcount(cstream->istream.memarea) > 1)
i_stream_memarea_detach(&cstream->istream);
memcpy(i_stream_alloc(&cstream->istream, data_size),
data, data_size);
cstream->istream.pos += data_size;
cstream->prev_stream_left += data_size;
}
i_stream_skip(prev_input, i_stream_get_data_size(prev_input));
i_stream_unref(&prev_input);
}
static bool i_stream_chain_skip(struct chain_istream *cstream)
{
struct istream_private *stream = &cstream->istream;
struct istream_chain_link *link = cstream->chain.head;
size_t bytes_skipped;
i_assert(stream->skip >= cstream->prev_skip);
bytes_skipped = stream->skip - cstream->prev_skip;
if (cstream->prev_stream_left == 0) {
/* no need to worry about buffers, skip everything */
} else if (bytes_skipped < cstream->prev_stream_left) {
/* we're still skipping inside buffer */
cstream->prev_stream_left -= bytes_skipped;
bytes_skipped = 0;
} else {
/* done with the buffer */
bytes_skipped -= cstream->prev_stream_left;
cstream->prev_stream_left = 0;
}
if (bytes_skipped > 0) {
i_assert(stream->buffer != NULL);
stream->pos -= bytes_skipped;
stream->skip -= bytes_skipped;
stream->buffer += bytes_skipped;
}
cstream->prev_skip = stream->skip;
if (link == NULL || link->eof) {
i_assert(bytes_skipped == 0);
return FALSE;
}
i_stream_skip(link->stream, bytes_skipped);
return TRUE;
}
static ssize_t i_stream_chain_read(struct istream_private *stream)
{
struct chain_istream *cstream =
container_of(stream, struct chain_istream, istream);
struct istream_chain_link *link = cstream->chain.head;
const unsigned char *data;
size_t data_size, cur_data_pos, new_pos;
size_t new_bytes_count;
ssize_t ret;
if (link != NULL && link->eof) {
stream->istream.eof = TRUE;
return -1;
}
if (!i_stream_chain_skip(cstream))
return 0;
i_assert(link != NULL);
i_assert(stream->pos >= stream->skip + cstream->prev_stream_left);
cur_data_pos = stream->pos - (stream->skip + cstream->prev_stream_left);
data = i_stream_get_data(link->stream, &data_size);
if (data_size > cur_data_pos)
ret = 0;
else {
/* need to read more */
i_assert(cur_data_pos == data_size);
ret = i_stream_read_memarea(link->stream);
if (ret == -2 || ret == 0)
return ret;
if (ret == -1) {
if (link->stream->stream_errno != 0) {
io_stream_set_error(&stream->iostream,
"read(%s) failed: %s",
i_stream_get_name(link->stream),
i_stream_get_error(link->stream));
stream->istream.stream_errno =
link->stream->stream_errno;
return -1;
}
/* EOF of this stream, go to next stream */
i_stream_chain_read_next(cstream);
cstream->prev_skip = stream->skip;
return i_stream_chain_read(stream);
}
/* we read something */
data = i_stream_get_data(link->stream, &data_size);
}
if (data_size == cur_data_pos) {
/* nothing new read - preserve the buffer as it was */
i_assert(ret == 0 || ret == -1);
return ret;
}
if (cstream->prev_stream_left == 0) {
/* we can point directly to the current stream's buffers */
stream->buffer = data;
stream->pos -= stream->skip;
stream->skip = 0;
new_pos = data_size;
} else {
/* we still have some of the previous stream left. merge the
new data with it. */
i_assert(data_size > cur_data_pos);
new_bytes_count = data_size - cur_data_pos;
memcpy(i_stream_alloc(stream, new_bytes_count),
data + cur_data_pos, new_bytes_count);
stream->buffer = stream->w_buffer;
new_pos = stream->pos + new_bytes_count;
}
i_assert(new_pos > stream->pos);
ret = (ssize_t)(new_pos - stream->pos);
stream->pos = new_pos;
cstream->prev_skip = stream->skip;
return ret;
}
static void i_stream_chain_close(struct iostream_private *stream,
bool close_parent)
{
struct chain_istream *cstream =
container_of(stream, struct chain_istream, istream.iostream);
/* seek to the correct position in parent stream in case it didn't
end with EOF */
(void)i_stream_chain_skip(cstream);
if (close_parent) {
struct istream_chain_link *link = cstream->chain.head;
while (link != NULL) {
i_stream_close(link->stream);
link = link->next;
}
}
}
static struct istream_snapshot *
i_stream_chain_snapshot(struct istream_private *stream,
struct istream_snapshot *prev_snapshot)
{
if (stream->buffer == stream->w_buffer) {
/* Two or more istreams have been combined. Snapshot the
w_buffer's contents that contains their data. */
i_assert(stream->memarea != NULL);
return i_stream_default_snapshot(stream, prev_snapshot);
}
/* Individual istreams are being read. Snapshot the istream directly. */
struct chain_istream *cstream =
container_of(stream, struct chain_istream, istream);
struct istream_chain_link *link = cstream->chain.head;
if (link == NULL || link->stream == NULL)
return prev_snapshot;
struct istream_private *_link_stream = link->stream->real_stream;
struct istream_snapshot *snapshot = i_new(struct istream_snapshot, 1);
snapshot->prev_snapshot =
_link_stream->snapshot(_link_stream, prev_snapshot);
if (snapshot->prev_snapshot == prev_snapshot) {
/* The link stream didn't implement snapshotting in any way.
This could cause trouble if the link stream is freed while
it's still referred to in this snapshot. Fix this by
referencing the link istream. Normally avoid doing this,
since the extra references can cause unexpected problems. */
snapshot->istream = link->stream;
i_stream_ref(snapshot->istream);
}
return snapshot;
}
struct istream *i_stream_create_chain(struct istream_chain **chain_r,
size_t max_buffer_size)
{
struct chain_istream *cstream;
cstream = i_new(struct chain_istream, 1);
cstream->chain.stream = cstream;
cstream->istream.max_buffer_size = max_buffer_size;
cstream->istream.iostream.close = i_stream_chain_close;
cstream->istream.iostream.destroy = i_stream_chain_destroy;
cstream->istream.iostream.set_max_buffer_size =
i_stream_chain_set_max_buffer_size;
cstream->istream.read = i_stream_chain_read;
cstream->istream.snapshot = i_stream_chain_snapshot;
cstream->istream.istream.readable_fd = FALSE;
cstream->istream.istream.blocking = FALSE;
cstream->istream.istream.seekable = FALSE;
*chain_r = &cstream->chain;
return i_stream_create(&cstream->istream, NULL, -1, 0);
}
dovecot-2.3.21.1/src/lib/test-byteorder.c 0000644 0000000 0000000 00000013526 14656633576 015001 0000000 0000000 /*
* Copyright (c) 2016-2017 Josef 'Jeff' Sipek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "test-lib.h"
#include "byteorder.h"
struct bswap_run {
uint64_t in;
uint8_t out8;
uint16_t out16;
uint32_t out32;
uint64_t out64;
};
static const struct bswap_run runs[] = {
{
.in = 0,
.out8 = 0,
.out16 = 0,
.out32 = 0,
.out64 = 0,
},
{
.in = 0xffffffffffffffff,
.out8 = 0xff,
.out16 = 0xffff,
.out32 = 0xffffffff,
.out64 = 0xffffffffffffffff,
},
{
.in = 0x123456789abcdef0,
.out8 = 0xf0,
.out16 = 0xf0de,
.out32 = 0xf0debc9a,
.out64 = 0xf0debc9a78563412,
},
{
.in = 0x8080808080808080,
.out8 = 0x80,
.out16 = 0x8080,
.out32 = 0x80808080,
.out64 = 0x8080808080808080,
},
};
#define CHECK(iter, size, in, exp) \
do { \
uint##size##_t got = i_bswap_##size(in); \
\
test_begin(t_strdup_printf("byteorder - bswap " \
"(size:%-2u iter:%u)", \
size, iter)); \
test_assert(got == exp); \
test_end(); \
} while (0)
static void __test(int iter, const struct bswap_run *run)
{
CHECK(iter, 8, run->in & 0xff, run->out8);
CHECK(iter, 16, run->in & 0xffff, run->out16);
CHECK(iter, 32, run->in & 0xffffffff, run->out32);
CHECK(iter, 64, run->in, run->out64);
}
static void test_bswap(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(runs) ; i++)
__test(i, &runs[i]);
}
struct unaligned_run {
uint8_t in[8];
/* outputs */
uint8_t be8;
uint16_t be16;
uint32_t be32;
uint64_t be64;
uint8_t le8;
uint16_t le16;
uint32_t le32;
uint64_t le64;
#ifdef WORDS_BIGENDIAN
#define cpu8 be8
#define cpu16 be16
#define cpu32 be32
#define cpu64 be64
#else
#define cpu8 le8
#define cpu16 le16
#define cpu32 le32
#define cpu64 le64
#endif
};
static const struct unaligned_run uruns[] = {
{
.in = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
},
.be8 = 0,
.be16 = 0,
.be32 = 0,
.be64 = 0,
.le8 = 0,
.le16 = 0,
.le32 = 0,
.le64 = 0,
},
{
.in = {
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
},
.be8 = 0xff,
.be16 = 0xffff,
.be32 = 0xffffffff,
.be64 = 0xffffffffffffffff,
.le8 = 0xff,
.le16 = 0xffff,
.le32 = 0xffffffff,
.le64 = 0xffffffffffffffff,
},
{
.in = {
0x12, 0x34, 0x56, 0x78,
0x9a, 0xbc, 0xde, 0xf0,
},
.be8 = 0x12,
.be16 = 0x1234,
.be32 = 0x12345678,
.be64 = 0x123456789abcdef0,
.le8 = 0x12,
.le16 = 0x3412,
.le32 = 0x78563412,
.le64 = 0xf0debc9a78563412,
},
{
.in = {
0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80,
},
.be8 = 0x80,
.be16 = 0x8080,
.be32 = 0x80808080,
.be64 = 0x8080808080808080,
.le8 = 0x80,
.le16 = 0x8080,
.le32 = 0x80808080,
.le64 = 0x8080808080808080,
},
};
#define __CHECK_READ(iter, size, pfx, in, fxn, exp) \
do { \
uint##size##_t got = fxn(in); \
\
test_begin(t_strdup_printf("byteorder - unaligned read "\
"(%-3s size:%-2u iter:%u)", \
pfx, size, iter)); \
test_assert(got == exp); \
test_end(); \
} while (0)
#define CHECK_READ(iter, size, in, be_exp, le_exp, cpu_exp) \
do { \
__CHECK_READ(iter, size, "BE", in, \
be##size##_to_cpu_unaligned, be_exp); \
__CHECK_READ(iter, size, "LE", in, \
le##size##_to_cpu_unaligned, le_exp); \
__CHECK_READ(iter, size, "CPU", in, \
cpu##size##_to_cpu_unaligned, cpu_exp); \
} while (0)
static void __test_read(int iter, const struct unaligned_run *run)
{
CHECK_READ(iter, 8, run->in, run->be8, run->le8, run->cpu8);
CHECK_READ(iter, 16, run->in, run->be16, run->le16, run->cpu16);
CHECK_READ(iter, 32, run->in, run->be32, run->le32, run->cpu32);
CHECK_READ(iter, 64, run->in, run->be64, run->le64, run->cpu64);
}
#define __CHECK_WRITE(iter, size, pfx, in, fxn, exp) \
do { \
uint8_t got[size / 8]; \
\
fxn(in, got); \
\
test_begin(t_strdup_printf("byteorder - unaligned write "\
"(%-3s size:%-2u iter:%u)", \
pfx, size, iter)); \
test_assert(memcmp(got, exp, sizeof(got)) == 0); \
test_end(); \
} while (0)
#define CHECK_WRITE(iter, size, out, be_in, le_in) \
do { \
__CHECK_WRITE(iter, size, "BE", be_in, \
cpu##size##_to_be_unaligned, out); \
__CHECK_WRITE(iter, size, "LE", le_in, \
cpu##size##_to_le_unaligned, out); \
} while (0)
static void __test_write(int iter, const struct unaligned_run *run)
{
CHECK_WRITE(iter, 8, run->in, run->be8, run->le8);
CHECK_WRITE(iter, 16, run->in, run->be16, run->le16);
CHECK_WRITE(iter, 32, run->in, run->be32, run->le32);
CHECK_WRITE(iter, 64, run->in, run->be64, run->le64);
}
static void test_unaligned(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(uruns) ; i++)
__test_read(i, &uruns[i]);
for (i = 0; i < N_ELEMENTS(uruns) ; i++)
__test_write(i, &uruns[i]);
}
void test_byteorder(void)
{
test_bswap();
test_unaligned();
}
dovecot-2.3.21.1/src/lib/log-throttle.h 0000644 0000000 0000000 00000002257 14656633576 014455 0000000 0000000 #ifndef LOG_THROTTLE_H
#define LOG_THROTTLE_H
struct log_throttle_settings {
/* Start throttling after we reach this many log events/interval. */
unsigned int throttle_at_max_per_interval;
/* Throttling continues until there's only this many or below
log events/interval. */
unsigned int unthrottle_at_max_per_interval;
/* Interval unit in milliseconds. The throttled-callback is also called
at this interval. Default (0) is 1000 milliseconds. */
unsigned int interval_msecs;
};
typedef void
log_throttle_callback_t(unsigned int new_events_count, void *context);
struct log_throttle *
log_throttle_init(const struct log_throttle_settings *set,
log_throttle_callback_t *callback, void *context);
#define log_throttle_init(set, callback, context) \
log_throttle_init(set - \
CALLBACK_TYPECHECK(callback, void (*)(unsigned int, typeof(context))), \
(log_throttle_callback_t *)callback, context)
void log_throttle_deinit(struct log_throttle **throttle);
/* Increase event count. Returns TRUE if the event should be logged,
FALSE if it's throttled. ioloop_timeval is used to determine the current
time. */
bool log_throttle_accept(struct log_throttle *throttle);
#endif
dovecot-2.3.21.1/src/lib/test-lib-signals.c 0000644 0000000 0000000 00000012720 14656633576 015201 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "time-util.h"
#include "ioloop.h"
#include "lib-signals.h"
#include
#include
struct test_context_delayed {
bool timed_out:1;
bool signal_handled:1;
};
static void
kill_timeout(struct test_context_delayed *tctx ATTR_UNUSED)
{
if (kill(getpid(), SIGALRM) < 0)
i_fatal("Failed to send signal: %m");
}
static void
test_timeout(struct test_context_delayed *tctx)
{
tctx->timed_out = TRUE;
io_loop_stop(current_ioloop);
}
static void
signal_handler_delayed(const siginfo_t *si ATTR_UNUSED,
void *context ATTR_UNUSED)
{
struct test_context_delayed *tctx =
(struct test_context_delayed *)context;
tctx->signal_handled = TRUE;
io_loop_stop(current_ioloop);
}
static void
test_lib_signals_delayed(void)
{
struct test_context_delayed tctx;
struct timeout *to_kill, *to_test;
struct ioloop *ioloop;
test_begin("lib-signals delayed - init lib-signals first");
i_zero(&tctx);
lib_signals_init();
lib_signals_set_handler(SIGALRM,
LIBSIG_FLAGS_SAFE | LIBSIG_FLAG_IOLOOP_AUTOMOVE,
signal_handler_delayed, &tctx);
ioloop = io_loop_create();
to_kill = timeout_add_short(200, kill_timeout, &tctx);
to_test = timeout_add_short(400, test_timeout, &tctx);
io_loop_run(ioloop);
timeout_remove(&to_kill);
timeout_remove(&to_test);
io_loop_destroy(&ioloop);
lib_signals_deinit();
test_assert(!tctx.timed_out);
test_assert(tctx.signal_handled);
test_end();
test_begin("lib-signals delayed - init ioloop first");
i_zero(&tctx);
ioloop = io_loop_create();
lib_signals_init();
lib_signals_set_handler(SIGALRM,
LIBSIG_FLAGS_SAFE | LIBSIG_FLAG_IOLOOP_AUTOMOVE,
signal_handler_delayed, &tctx);
to_kill = timeout_add_short(200, kill_timeout, &tctx);
to_test = timeout_add_short(400, test_timeout, &tctx);
io_loop_run(ioloop);
timeout_remove(&to_kill);
timeout_remove(&to_test);
lib_signals_deinit();
io_loop_destroy(&ioloop);
test_assert(!tctx.timed_out);
test_assert(tctx.signal_handled);
test_end();
}
static void
test_lib_signals_delayed_nested_ioloop(void)
{
struct test_context_delayed tctx;
struct timeout *to_kill, *to_test;
struct ioloop *ioloop1, *ioloop2;
test_begin("lib-signals delayed in nested ioloop");
i_zero(&tctx);
lib_signals_init();
lib_signals_set_handler(SIGALRM,
LIBSIG_FLAGS_SAFE | LIBSIG_FLAG_IOLOOP_AUTOMOVE,
signal_handler_delayed, &tctx);
/* briefly run outer ioloop */
ioloop1 = io_loop_create();
to_test = timeout_add_short(100, test_timeout, &tctx);
io_loop_run(ioloop1);
timeout_remove(&to_test);
test_assert(tctx.timed_out);
test_assert(!tctx.signal_handled);
tctx.timed_out = FALSE;
/* run inner ioloop, which triggers the signal */
ioloop2 = io_loop_create();
to_kill = timeout_add_short(200, kill_timeout, &tctx);
to_test = timeout_add_short(400, test_timeout, &tctx);
io_loop_run(ioloop2);
timeout_remove(&to_kill);
timeout_remove(&to_test);
io_loop_destroy(&ioloop2);
io_loop_destroy(&ioloop1);
lib_signals_deinit();
test_assert(!tctx.timed_out);
test_assert(tctx.signal_handled);
test_end();
}
static void
test_lib_signals_delayed_no_ioloop_automove(void)
{
struct test_context_delayed tctx;
struct timeout *to_kill, *to_test;
struct ioloop *ioloop1, *ioloop2;
test_begin("lib-signals delayed with NO_IOLOOP_AUTOMOVE - unmoved");
i_zero(&tctx);
ioloop1 = io_loop_create();
lib_signals_init();
lib_signals_set_handler(SIGALRM, LIBSIG_FLAGS_SAFE,
signal_handler_delayed, &tctx);
/* briefly run outer ioloop */
to_test = timeout_add_short(100, test_timeout, &tctx);
io_loop_run(ioloop1);
timeout_remove(&to_test);
test_assert(tctx.timed_out);
test_assert(!tctx.signal_handled);
tctx.timed_out = FALSE;
/* run inner ioloop, which triggers the signal but musn't handle it */
ioloop2 = io_loop_create();
to_kill = timeout_add_short(200, kill_timeout, &tctx);
to_test = timeout_add_short(400, test_timeout, &tctx);
io_loop_run(ioloop2);
test_assert(tctx.timed_out);
test_assert(!tctx.signal_handled);
tctx.timed_out = FALSE;
timeout_remove(&to_kill);
timeout_remove(&to_test);
io_loop_destroy(&ioloop2);
/* run outer ioloop once more */
to_test = timeout_add_short(100, test_timeout, &tctx);
io_loop_run(ioloop1);
timeout_remove(&to_test);
lib_signals_deinit();
io_loop_destroy(&ioloop1);
test_assert(!tctx.timed_out);
test_assert(tctx.signal_handled);
test_end();
test_begin("lib-signals delayed with NO_IOLOOP_AUTOMOVE - moved");
i_zero(&tctx);
ioloop1 = io_loop_create();
lib_signals_init();
lib_signals_set_handler(SIGALRM, LIBSIG_FLAGS_SAFE,
signal_handler_delayed, &tctx);
/* briefly run outer ioloop */
to_test = timeout_add_short(100, test_timeout, &tctx);
io_loop_run(ioloop1);
timeout_remove(&to_test);
test_assert(tctx.timed_out);
test_assert(!tctx.signal_handled);
tctx.timed_out = FALSE;
/* run inner ioloop, which triggers the signal */
ioloop2 = io_loop_create();
lib_signals_switch_ioloop(SIGALRM,
signal_handler_delayed, &tctx);
to_kill = timeout_add_short(200, kill_timeout, &tctx);
to_test = timeout_add_short(400, test_timeout, &tctx);
io_loop_run(ioloop2);
test_assert(!tctx.timed_out);
test_assert(tctx.signal_handled);
timeout_remove(&to_kill);
timeout_remove(&to_test);
io_loop_destroy(&ioloop2);
lib_signals_deinit();
io_loop_destroy(&ioloop1);
test_end();
}
void test_lib_signals(void)
{
test_lib_signals_delayed();
test_lib_signals_delayed_nested_ioloop();
test_lib_signals_delayed_no_ioloop_automove();
}
dovecot-2.3.21.1/src/lib/sendfile-util.c 0000644 0000000 0000000 00000006200 14656633576 014560 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
/* kludge a bit to remove _FILE_OFFSET_BITS definition from config.h.
It's required to be able to include sys/sendfile.h with Linux. */
#include "config.h"
#undef HAVE_CONFIG_H
#ifdef HAVE_LINUX_SENDFILE
# undef _FILE_OFFSET_BITS
#endif
#include "lib.h"
#include "sendfile-util.h"
#ifdef HAVE_LINUX_SENDFILE
#include
ssize_t safe_sendfile(int out_fd, int in_fd, uoff_t *offset, size_t count)
{
/* REMEMBER: uoff_t and off_t may not be of same size. */
off_t safe_offset;
ssize_t ret;
i_assert(count > 0);
/* make sure given offset fits into off_t */
if (sizeof(off_t) * CHAR_BIT == 32) {
/* 32bit off_t */
if (*offset >= 2147483647L) {
errno = EINVAL;
return -1;
}
if (count > 2147483647L - *offset)
count = 2147483647L - *offset;
} else {
/* they're most likely the same size. if not, fix this
code later */
i_assert(sizeof(off_t) == sizeof(uoff_t));
if (*offset >= OFF_T_MAX) {
errno = EINVAL;
return -1;
}
if (count > OFF_T_MAX - *offset)
count = OFF_T_MAX - *offset;
}
safe_offset = (off_t)*offset;
ret = sendfile(out_fd, in_fd, &safe_offset, count);
/* ret=0 : trying to read past EOF */
*offset = (uoff_t)safe_offset;
return ret;
}
#elif defined(HAVE_FREEBSD_SENDFILE)
#include
#include
ssize_t safe_sendfile(int out_fd, int in_fd, uoff_t *offset, size_t count)
{
struct sf_hdtr hdtr;
off_t sbytes;
int ret;
/* if count=0 is passed to sendfile(), it sends everything
from in_fd until EOF. We don't want that. */
i_assert(count > 0);
i_assert(count <= SSIZE_T_MAX);
i_zero(&hdtr);
ret = sendfile(in_fd, out_fd, *offset, count, &hdtr, &sbytes, 0);
*offset += sbytes;
if (ret == 0 || (ret < 0 && errno == EAGAIN && sbytes > 0))
return (ssize_t)sbytes;
else {
if (errno == ENOTSOCK) {
/* out_fd wasn't a socket. behave as if sendfile()
wasn't supported at all. */
errno = EINVAL;
}
return -1;
}
}
#elif defined (HAVE_SOLARIS_SENDFILE)
#include
#include "net.h"
ssize_t safe_sendfile(int out_fd, int in_fd, uoff_t *offset, size_t count)
{
ssize_t ret;
off_t s_offset;
i_assert(count > 0);
i_assert(count <= SSIZE_T_MAX);
/* NOTE: if outfd is not a socket, some Solaris versions will
kernel panic */
s_offset = (off_t)*offset;
ret = sendfile(out_fd, in_fd, &s_offset, count);
if (ret < 0) {
/* if remote is gone, EPIPE is returned */
if (errno == EINVAL) {
/* most likely trying to read past EOF */
ret = 0;
} else if (errno == EAFNOSUPPORT || errno == EOPNOTSUPP) {
/* not supported, return Linux-like EINVAL so caller
sees only consistent errnos. */
errno = EINVAL;
} else if (s_offset != (off_t)*offset) {
/* some data was sent, return it */
i_assert(s_offset > (off_t)*offset);
ret = s_offset - (off_t)*offset;
}
}
*offset = (uoff_t)s_offset;
i_assert(ret < 0 || (size_t)ret <= count);
return ret;
}
#else
ssize_t safe_sendfile(int out_fd ATTR_UNUSED, int in_fd ATTR_UNUSED,
uoff_t *offset ATTR_UNUSED,
size_t count ATTR_UNUSED)
{
errno = EINVAL;
return -1;
}
#endif
dovecot-2.3.21.1/src/lib/istream-private.h 0000644 0000000 0000000 00000012367 14656633576 015150 0000000 0000000 #ifndef ISTREAM_PRIVATE_H
#define ISTREAM_PRIVATE_H
#include "istream.h"
#include "iostream-private.h"
#define I_STREAM_MIN_SIZE IO_BLOCK_SIZE
struct io;
struct istream_private {
/* inheritance: */
struct iostream_private iostream;
/* methods: */
ssize_t (*read)(struct istream_private *stream);
void (*seek)(struct istream_private *stream,
uoff_t v_offset, bool mark);
void (*sync)(struct istream_private *stream);
int (*stat)(struct istream_private *stream, bool exact);
int (*get_size)(struct istream_private *stream, bool exact, uoff_t *size_r);
void (*switch_ioloop_to)(struct istream_private *stream,
struct ioloop *ioloop);
struct istream_snapshot *
(*snapshot)(struct istream_private *stream,
struct istream_snapshot *prev_snapshot);
/* data: */
struct istream istream;
int fd;
uoff_t start_offset;
struct stat statbuf;
/* added by io_add_istream() -> i_stream_set_io() */
struct io *io;
const unsigned char *buffer;
unsigned char *w_buffer; /* may be NULL */
size_t buffer_size, max_buffer_size, init_buffer_size, data_limit;
size_t skip, pos;
/* If seeking backwards within the buffer, the next read() will
return again pos..high_pos */
size_t high_pos;
struct istream *parent; /* for filter streams */
uoff_t parent_start_offset;
/* Initially UOFF_T_MAX. Otherwise it's the exact known stream size,
which can be used by stat() / get_size(). */
uoff_t cached_stream_size;
/* parent stream's expected offset is kept here. i_stream_read()
always seeks parent stream to here before calling read(). */
uoff_t parent_expected_offset;
struct memarea *memarea;
struct istream_snapshot *prev_snapshot;
/* increased every time the stream is changed (e.g. seek, read).
this way streams can check if their parent streams have been
accessed behind them. */
unsigned int access_counter;
/* Timestamp when read() last returned >0 */
struct timeval last_read_timeval;
string_t *line_str; /* for i_stream_next_line() if w_buffer == NULL */
bool line_crlf:1;
bool return_nolf_line:1;
bool stream_size_passthrough:1; /* stream is parent's size */
bool nonpersistent_buffers:1;
bool io_pending:1;
};
struct istream_snapshot {
struct istream_snapshot *prev_snapshot;
struct memarea *old_memarea;
struct istream *istream;
void (*free)(struct istream_snapshot *snapshot);
};
enum istream_create_flag {
/* The stream guarantees that the buffer pointer stays valid when it
returns <= 0. */
ISTREAM_CREATE_FLAG_NOOP_SNAPSHOT = 0x01,
};
struct istream * ATTR_NOWARN_UNUSED_RESULT
i_stream_create(struct istream_private *stream, struct istream *parent, int fd,
enum istream_create_flag flags) ATTR_NULL(2);
/* Initialize parent lazily after i_stream_create() has already been called. */
void i_stream_init_parent(struct istream_private *_stream,
struct istream *parent);
void i_stream_compress(struct istream_private *stream);
void i_stream_grow_buffer(struct istream_private *stream, size_t bytes);
bool ATTR_NOWARN_UNUSED_RESULT
i_stream_try_alloc(struct istream_private *stream,
size_t wanted_size, size_t *size_r);
/* Like i_stream_try_alloc(), but compress only if it's the only way to get
more space. This can be useful when stream is marked with
i_stream_seek_mark() */
bool ATTR_NOWARN_UNUSED_RESULT
i_stream_try_alloc_avoid_compress(struct istream_private *stream,
size_t wanted_size, size_t *size_r);
void *i_stream_alloc(struct istream_private *stream, size_t size);
/* Detach istream from its current memarea. This unreferences the memarea and
resets the w_buffer to empty. This can be used to make sure i_stream_*alloc()
won't return a pointer to memory referenced to in a snapshot. */
void i_stream_memarea_detach(struct istream_private *stream);
/* Free memory allocated by i_stream_*alloc() */
void i_stream_free_buffer(struct istream_private *stream);
ssize_t i_stream_read_copy_from_parent(struct istream *istream);
void i_stream_default_seek_nonseekable(struct istream_private *stream,
uoff_t v_offset, bool mark);
/* Returns FALSE if seeking must be done by starting from the beginning.
The caller is then expected to reset the stream and call this function
again, which should work then. If TRUE is returned, the seek was either
successfully done or stream_errno is set. */
bool i_stream_nonseekable_try_seek(struct istream_private *stream,
uoff_t v_offset);
/* Default snapshot handling: use memarea if it exists, otherwise snapshot
parent stream. */
struct istream_snapshot *
i_stream_default_snapshot(struct istream_private *stream,
struct istream_snapshot *prev_snapshot);
void i_stream_snapshot_free(struct istream_snapshot **snapshot);
struct istream *i_stream_get_root_io(struct istream *stream);
void i_stream_set_io(struct istream *stream, struct io *io);
void i_stream_unset_io(struct istream *stream, struct io *io);
/* Filter istreams should be calling this instead of i_stream_read() to avoid
unnecessarily referencing memareas. After this call any pointers to the
parent istream's content must be considered as potentially invalid and have
to be updated, even if the return value is <=0. */
ssize_t i_stream_read_memarea(struct istream *stream);
int i_stream_read_more_memarea(struct istream *stream,
const unsigned char **data_r, size_t *size_r);
#endif
dovecot-2.3.21.1/src/lib/test-istream-base64-encoder.c 0000644 0000000 0000000 00000015222 14656633576 017140 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "str.h"
#include "istream-private.h"
#include "istream-base64.h"
struct base64_istream_test {
const char *input;
unsigned int chars_per_line;
bool crlf;
const char *output;
};
static const struct base64_istream_test base64_tests[] = {
{ "", 80, FALSE, "" },
{ "1", 80, FALSE, "MQ==" },
{ "12", 80, FALSE, "MTI=" },
{ "123", 80, FALSE, "MTIz" },
{ "1234", 80, FALSE, "MTIzNA==" },
{ "12345", 80, FALSE, "MTIzNDU=" },
{ "hello world", 80, FALSE, "aGVsbG8gd29ybGQ=" },
{ "hello world", 4, FALSE, "aGVs\nbG8g\nd29y\nbGQ=" },
{ "hello world", 4, TRUE, "aGVs\r\nbG8g\r\nd29y\r\nbGQ=" },
{ "hello worlds", 80, FALSE, "aGVsbG8gd29ybGRz" },
{ "hello worlds", 4, FALSE, "aGVs\nbG8g\nd29y\nbGRz" },
{ "hello worlds", 4, TRUE, "aGVs\r\nbG8g\r\nd29y\r\nbGRz" },
{ "hell world", 80, FALSE, "aGVsbCB3b3JsZA==" },
{ "hell world", 4, FALSE, "aGVs\nbCB3\nb3Js\nZA==" },
{ "hell world", 4, TRUE, "aGVs\r\nbCB3\r\nb3Js\r\nZA==" },
{ "hello to the world!!", 80, FALSE,
"aGVsbG8gdG8gdGhlIHdvcmxkISE=" },
{ "hello to the world!!", 8, FALSE,
"aGVsbG8g\ndG8gdGhl\nIHdvcmxk\nISE=" },
{ "hello to the world!!", 8, TRUE,
"aGVsbG8g\r\ndG8gdGhl\r\nIHdvcmxk\r\nISE=" },
{ "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e", 80, FALSE,
"0JPQvtCy0L7RgNGPzIHRgiwg0YfRgtC+INC60YPRgCDQtNC+0Y/MgdGCLg==" },
};
static const struct base64_istream_test base64url_tests[] = {
{ "", 80, FALSE, "" },
{ "1", 80, FALSE, "MQ==" },
{ "12", 80, FALSE, "MTI=" },
{ "123", 80, FALSE, "MTIz" },
{ "1234", 80, FALSE, "MTIzNA==" },
{ "12345", 80, FALSE, "MTIzNDU=" },
{ "hello world", 80, FALSE, "aGVsbG8gd29ybGQ=" },
{ "hello world", 4, FALSE, "aGVs\nbG8g\nd29y\nbGQ=" },
{ "hello world", 4, TRUE, "aGVs\r\nbG8g\r\nd29y\r\nbGQ=" },
{ "hello worlds", 80, FALSE, "aGVsbG8gd29ybGRz" },
{ "hello worlds", 4, FALSE, "aGVs\nbG8g\nd29y\nbGRz" },
{ "hello worlds", 4, TRUE, "aGVs\r\nbG8g\r\nd29y\r\nbGRz" },
{ "hell world", 80, FALSE, "aGVsbCB3b3JsZA==" },
{ "hell world", 4, FALSE, "aGVs\nbCB3\nb3Js\nZA==" },
{ "hell world", 4, TRUE, "aGVs\r\nbCB3\r\nb3Js\r\nZA==" },
{ "hello to the world!!", 80, FALSE,
"aGVsbG8gdG8gdGhlIHdvcmxkISE=" },
{ "hello to the world!!", 8, FALSE,
"aGVsbG8g\ndG8gdGhl\nIHdvcmxk\nISE=" },
{ "hello to the world!!", 8, TRUE,
"aGVsbG8g\r\ndG8gdGhl\r\nIHdvcmxk\r\nISE=" },
{ "\xd0\x93\xd0\xbe\xd0\xb2\xd0\xbe\xd1\x80\xd1\x8f\xcc"
"\x81\xd1\x82\x2c\x20\xd1\x87\xd1\x82\xd0\xbe\x20\xd0"
"\xba\xd1\x83\xd1\x80\x20\xd0\xb4\xd0\xbe\xd1\x8f\xcc"
"\x81\xd1\x82\x2e", 80, FALSE,
"0JPQvtCy0L7RgNGPzIHRgiwg0YfRgtC-INC60YPRgCDQtNC-0Y_MgdGCLg==" },
};
static const char *hello = "hello world";
static void encode_test(unsigned int text_len,
struct istream *input, struct istream *input_data,
const char *output)
{
unsigned int i;
const unsigned char *data;
uoff_t stream_size;
size_t size;
ssize_t ret;
for (i = 1; i <= text_len; i++) {
test_istream_set_size(input_data, i);
while ((ret = i_stream_read(input)) > 0) ;
test_assert(ret == 0);
}
test_istream_set_allow_eof(input_data, TRUE);
while ((ret = i_stream_read(input)) > 0) ;
test_assert(ret == -1);
data = i_stream_get_data(input, &size);
test_assert(size == strlen(output) && memcmp(data, output, size) == 0);
ret = i_stream_get_size(input, TRUE, &stream_size);
test_assert(ret > 0);
test_assert(size == stream_size);
}
static void
encode_base64_test(const char *text, unsigned int chars_per_line,
bool crlf, const char *output)
{
unsigned int text_len = strlen(text);
struct istream *input, *input_data;
input_data = test_istream_create_data(text, text_len);
test_istream_set_allow_eof(input_data, FALSE);
input = i_stream_create_base64_encoder(input_data, chars_per_line,
crlf);
encode_test(text_len, input, input_data, output);
i_stream_unref(&input);
i_stream_unref(&input_data);
}
static void
encode_base64url_test(const char *text, unsigned int chars_per_line,
bool crlf, const char *output)
{
unsigned int text_len = strlen(text);
struct istream *input, *input_data;
input_data = test_istream_create_data(text, text_len);
test_istream_set_allow_eof(input_data, FALSE);
input = i_stream_create_base64url_encoder(input_data, chars_per_line,
crlf);
encode_test(text_len, input, input_data, output);
i_stream_unref(&input);
i_stream_unref(&input_data);
}
static void
test_encoder_seek(struct istream *input, const char *textout)
{
unsigned int offset, len = strlen(textout);
const unsigned char *data;
size_t size;
ssize_t ret;
while (i_stream_read(input) > 0) ;
i_stream_skip(input, i_stream_get_data_size(input));
for (offset = 0; offset < len; offset++) {
i_stream_seek(input, offset);
while ((ret = i_stream_read(input)) > 0) ;
test_assert(ret == -1);
data = i_stream_get_data(input, &size);
test_assert(size == len-offset);
test_assert(memcmp(data, textout+offset, size) == 0);
i_stream_skip(input, size);
}
}
static void
test_istream_base64_encoder_seek(const char *textin, const char *textout)
{
struct istream *input, *input_data;
input_data = i_stream_create_from_data(textin, strlen(textin));
input = i_stream_create_base64_encoder(input_data, 4, TRUE);
test_encoder_seek(input, textout);
i_stream_unref(&input);
i_stream_unref(&input_data);
}
static void
test_istream_base64url_encoder_seek(const char *textin, const char *textout)
{
struct istream *input, *input_data;
input_data = i_stream_create_from_data(textin, strlen(textin));
input = i_stream_create_base64url_encoder(input_data, 4, TRUE);
test_encoder_seek(input, textout);
i_stream_unref(&input);
i_stream_unref(&input_data);
}
void test_istream_base64_encoder(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(base64_tests); i++) {
const struct base64_istream_test *test = &base64_tests[i];
test_begin(t_strdup_printf(
"istream base64 encoder %u", i+1));
encode_base64_test(test->input, test->chars_per_line,
test->crlf, test->output);
test_end();
}
for (i = 0; i < N_ELEMENTS(base64url_tests); i++) {
const struct base64_istream_test *test = &base64url_tests[i];
test_begin(t_strdup_printf(
"istream base64url encoder %u", i+1));
encode_base64url_test(test->input, test->chars_per_line,
test->crlf, test->output);
test_end();
}
test_begin("istream base64 encoder seek");
test_istream_base64_encoder_seek(
hello, "aGVs\r\nbG8g\r\nd29y\r\nbGQ=");
test_end();
test_begin("istream base64url encoder seek");
test_istream_base64url_encoder_seek(
hello, "aGVs\r\nbG8g\r\nd29y\r\nbGQ=");
test_end();
}
dovecot-2.3.21.1/src/lib/istream-multiplex.c 0000644 0000000 0000000 00000020365 14656633576 015511 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "istream-private.h"
#include "istream-multiplex.h"
/* all multiplex packets are [1 byte cid][4 byte length][data] */
struct multiplex_istream;
struct multiplex_ichannel {
struct istream_private istream;
struct multiplex_istream *mstream;
uint8_t cid;
size_t pending_pos;
bool closed:1;
};
struct multiplex_istream {
struct istream *parent;
/* channel 0 is main channel */
uint8_t cur_channel;
unsigned int remain;
size_t bufsize;
ARRAY(struct multiplex_ichannel *) channels;
bool blocking:1;
};
static ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream);
static struct multiplex_ichannel *
get_channel(struct multiplex_istream *mstream, uint8_t cid)
{
struct multiplex_ichannel *channel;
i_assert(mstream != NULL);
array_foreach_elem(&mstream->channels, channel) {
if (channel != NULL && channel->cid == cid)
return channel;
}
return NULL;
}
static void propagate_error(struct multiplex_istream *mstream, int stream_errno)
{
struct multiplex_ichannel *channel;
array_foreach_elem(&mstream->channels, channel)
if (channel != NULL)
channel->istream.istream.stream_errno = stream_errno;
}
static void propagate_eof(struct multiplex_istream *mstream)
{
struct multiplex_ichannel *channel;
array_foreach_elem(&mstream->channels, channel) {
if (channel == NULL)
continue;
channel->istream.istream.eof = TRUE;
if (mstream->remain > 0) {
channel->istream.istream.stream_errno = EPIPE;
io_stream_set_error(&channel->istream.iostream,
"Unexpected EOF - %u bytes remaining in packet",
mstream->remain);
}
}
}
static ssize_t
i_stream_multiplex_read(struct multiplex_istream *mstream,
struct multiplex_ichannel *req_channel)
{
const unsigned char *data;
size_t len = 0, used, wanted, avail;
ssize_t ret, got = 0;
if (mstream->parent == NULL) {
req_channel->istream.istream.eof = TRUE;
return -1;
}
(void)i_stream_get_data(mstream->parent, &len);
if (len == 0 && mstream->parent->closed) {
req_channel->istream.istream.eof = TRUE;
return -1;
}
if (((mstream->remain > 0 && len == 0) ||
(mstream->remain == 0 && len < 5)) &&
(ret = i_stream_read_memarea(mstream->parent)) <= 0) {
propagate_error(mstream, mstream->parent->stream_errno);
if (mstream->parent->eof)
propagate_eof(mstream);
return ret;
}
for(;;) {
data = i_stream_get_data(mstream->parent, &len);
if (len == 0) {
if (got == 0 && mstream->blocking) {
/* can't return 0 with blocking istreams,
so try again from the beginning. */
return i_stream_multiplex_read(mstream, req_channel);
}
break;
}
if (mstream->remain > 0) {
struct multiplex_ichannel *channel =
get_channel(mstream, mstream->cur_channel);
wanted = I_MIN(len, mstream->remain);
/* is it open? */
if (channel != NULL && !channel->closed) {
struct istream_private *stream = &channel->istream;
stream->pos += channel->pending_pos;
bool alloc_ret = i_stream_try_alloc(stream, wanted, &avail);
stream->pos -= channel->pending_pos;
if (!alloc_ret) {
i_stream_set_input_pending(&stream->istream, TRUE);
if (channel->cid != req_channel->cid)
return 0;
if (got > 0)
break;
return -2;
}
used = I_MIN(wanted, avail);
/* dump into buffer */
if (channel->cid != req_channel->cid) {
i_assert(stream->pos + channel->pending_pos + used <= stream->buffer_size);
memcpy(stream->w_buffer + stream->pos + channel->pending_pos,
data, used);
channel->pending_pos += used;
i_stream_set_input_pending(&stream->istream, TRUE);
} else {
i_assert(stream->pos + used <= stream->buffer_size);
memcpy(stream->w_buffer + stream->pos, data, used);
stream->pos += used;
got += used;
}
} else {
used = wanted;
}
mstream->remain -= used;
i_stream_skip(mstream->parent, used);
/* see if there is more to read */
continue;
}
if (mstream->remain == 0) {
/* need more data */
if (len < 5) {
ret = i_stream_multiplex_ichannel_read(&req_channel->istream);
if (ret > 0)
got += ret;
break;
}
/* channel ID */
mstream->cur_channel = data[0];
/* data length */
mstream->remain = be32_to_cpu_unaligned(data+1);
i_stream_skip(mstream->parent, 5);
}
}
propagate_error(mstream, mstream->parent->stream_errno);
if (mstream->parent->eof)
propagate_eof(mstream);
return got;
}
static ssize_t i_stream_multiplex_ichannel_read(struct istream_private *stream)
{
struct multiplex_ichannel *channel =
container_of(stream, struct multiplex_ichannel, istream);
/* if previous multiplex read dumped data for us
actually serve it here. */
if (channel->pending_pos > 0) {
ssize_t ret = channel->pending_pos;
stream->pos += channel->pending_pos;
channel->pending_pos = 0;
return ret;
}
return i_stream_multiplex_read(channel->mstream, channel);
}
static void
i_stream_multiplex_ichannel_switch_ioloop_to(struct istream_private *stream,
struct ioloop *ioloop)
{
struct multiplex_ichannel *channel =
container_of(stream, struct multiplex_ichannel, istream);
i_stream_switch_ioloop_to(channel->mstream->parent, ioloop);
}
static void
i_stream_multiplex_ichannel_close(struct iostream_private *stream, bool close_parent)
{
struct multiplex_ichannel *arr_channel;
struct multiplex_ichannel *channel =
container_of(stream, struct multiplex_ichannel,
istream.iostream);
channel->closed = TRUE;
if (close_parent) {
array_foreach_elem(&channel->mstream->channels, arr_channel)
if (arr_channel != NULL && !arr_channel->closed)
return;
i_stream_close(channel->mstream->parent);
}
}
static void i_stream_multiplex_try_destroy(struct multiplex_istream *mstream)
{
struct multiplex_ichannel *channel;
/* can't do anything until they are all closed */
array_foreach_elem(&mstream->channels, channel)
if (channel != NULL)
return;
i_stream_unref(&mstream->parent);
array_free(&mstream->channels);
i_free(mstream);
}
static void i_stream_multiplex_ichannel_destroy(struct iostream_private *stream)
{
struct multiplex_ichannel **channelp;
struct multiplex_ichannel *channel =
container_of(stream, struct multiplex_ichannel,
istream.iostream);
i_stream_multiplex_ichannel_close(stream, TRUE);
i_stream_free_buffer(&channel->istream);
array_foreach_modifiable(&channel->mstream->channels, channelp) {
if (*channelp == channel) {
*channelp = NULL;
break;
}
}
i_stream_multiplex_try_destroy(channel->mstream);
}
static struct istream *
i_stream_add_channel_real(struct multiplex_istream *mstream, uint8_t cid)
{
struct multiplex_ichannel *channel = i_new(struct multiplex_ichannel, 1);
channel->cid = cid;
channel->mstream = mstream;
channel->istream.read = i_stream_multiplex_ichannel_read;
channel->istream.switch_ioloop_to = i_stream_multiplex_ichannel_switch_ioloop_to;
channel->istream.iostream.close = i_stream_multiplex_ichannel_close;
channel->istream.iostream.destroy = i_stream_multiplex_ichannel_destroy;
channel->istream.max_buffer_size = mstream->bufsize;
channel->istream.istream.blocking = mstream->blocking;
if (cid == 0)
channel->istream.fd = i_stream_get_fd(mstream->parent);
else
channel->istream.fd = -1;
array_push_back(&channel->mstream->channels, &channel);
return i_stream_create(&channel->istream, NULL, channel->istream.fd, 0);
}
struct istream *i_stream_multiplex_add_channel(struct istream *stream, uint8_t cid)
{
struct multiplex_ichannel *chan =
container_of(stream->real_stream,
struct multiplex_ichannel, istream);
i_assert(get_channel(chan->mstream, cid) == NULL);
return i_stream_add_channel_real(chan->mstream, cid);
}
struct istream *i_stream_create_multiplex(struct istream *parent, size_t bufsize)
{
struct multiplex_istream *mstream;
mstream = i_new(struct multiplex_istream, 1);
mstream->parent = parent;
mstream->bufsize = bufsize;
mstream->blocking = parent->blocking;
i_array_init(&mstream->channels, 8);
i_stream_ref(parent);
return i_stream_add_channel_real(mstream, 0);
}
uint8_t i_stream_multiplex_get_channel_id(struct istream *stream)
{
struct multiplex_ichannel *channel =
container_of(stream->real_stream,
struct multiplex_ichannel, istream);
return channel->cid;
}
dovecot-2.3.21.1/src/lib/Makefile.in 0000644 0000000 0000000 00001070020 14656633611 013705 0000000 0000000 # Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
noinst_PROGRAMS = $(am__EXEEXT_1)
subdir = src/lib
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
$(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
$(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
$(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
$(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
$(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
$(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
$(top_srcdir)/m4/flexible_array_member.m4 \
$(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
$(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
$(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
$(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
$(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
$(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
$(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
$(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
$(top_srcdir)/m4/pr_set_dumpable.m4 \
$(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
$(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
$(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
$(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
$(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
$(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
$(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
$(top_srcdir)/m4/typeof_dev_t.m4 \
$(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
$(top_srcdir)/m4/want_apparmor.m4 \
$(top_srcdir)/m4/want_bsdauth.m4 \
$(top_srcdir)/m4/want_bzlib.m4 \
$(top_srcdir)/m4/want_cassandra.m4 \
$(top_srcdir)/m4/want_cdb.m4 \
$(top_srcdir)/m4/want_checkpassword.m4 \
$(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
$(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
$(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
$(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
$(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
$(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
$(top_srcdir)/m4/want_prefetch.m4 \
$(top_srcdir)/m4/want_shadow.m4 \
$(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
$(top_srcdir)/m4/want_sqlite.m4 \
$(top_srcdir)/m4/want_stemmer.m4 \
$(top_srcdir)/m4/want_systemd.m4 \
$(top_srcdir)/m4/want_textcat.m4 \
$(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
$(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
$(pkginc_lib_HEADERS) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = test-lib$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
LTLIBRARIES = $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 =
liblib_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_liblib_la_OBJECTS = array.lo aqueue.lo askpass.lo \
backtrace-string.lo base32.lo base64.lo bits.lo \
bsearch-insert-pos.lo buffer.lo buffer-istream.lo \
child-wait.lo compat.lo connection.lo cpu-limit.lo crc32.lo \
data-stack.lo eacces-error.lo env-util.lo event-filter.lo \
event-filter-lexer.lo event-filter-parser.lo event-log.lo \
execv-const.lo failures.lo fd-util.lo fdatasync-path.lo \
fdpass.lo file-cache.lo file-create-locked.lo file-copy.lo \
file-dotlock.lo file-lock.lo file-set-size.lo guid.lo hash.lo \
hash-format.lo hash-method.lo hash2.lo hex-binary.lo \
hex-dec.lo hmac.lo hmac-cram-md5.lo home-expand.lo \
hook-build.lo hostpid.lo imem.lo ipwd.lo iostream.lo \
iostream-pump.lo iostream-proxy.lo iostream-rawlog.lo \
iostream-temp.lo iso8601-date.lo istream.lo \
istream-base64-decoder.lo istream-base64-encoder.lo \
istream-callback.lo istream-chain.lo istream-concat.lo \
istream-crlf.lo istream-data.lo istream-failure-at.lo \
istream-file.lo istream-hash.lo istream-jsonstr.lo \
istream-limit.lo istream-multiplex.lo istream-rawlog.lo \
istream-seekable.lo istream-sized.lo istream-tee.lo \
istream-try.lo istream-timeout.lo istream-unix.lo ioloop.lo \
ioloop-iolist.lo ioloop-notify-none.lo ioloop-notify-fd.lo \
ioloop-notify-inotify.lo ioloop-notify-kqueue.lo \
ioloop-poll.lo ioloop-select.lo ioloop-epoll.lo \
ioloop-kqueue.lo json-parser.lo json-tree.lo lib.lo \
lib-event.lo lib-signals.lo log-throttle.lo md4.lo md5.lo \
memarea.lo mempool.lo mempool-allocfree.lo \
mempool-alloconly.lo mempool-datastack.lo mempool-system.lo \
mempool-unsafe-datastack.lo mkdir-parents.lo mmap-anon.lo \
mmap-util.lo module-dir.lo mountpoint.lo net.lo \
nfs-workarounds.lo numpack.lo ostream.lo ostream-buffer.lo \
ostream-failure-at.lo ostream-file.lo ostream-hash.lo \
ostream-multiplex.lo ostream-null.lo ostream-rawlog.lo \
ostream-unix.lo ostream-wrapper.lo path-util.lo pkcs5.lo \
primes.lo printf-format-fix.lo process-stat.lo \
process-title.lo priorityq.lo randgen.lo rand.lo read-full.lo \
restrict-access.lo restrict-process-size.lo safe-memset.lo \
safe-mkdir.lo safe-mkstemp.lo sendfile-util.lo \
seq-range-array.lo seq-set-builder.lo sha1.lo sha2.lo sha3.lo \
sleep.lo sort.lo stats-dist.lo str.lo str-find.lo \
str-sanitize.lo str-table.lo strescape.lo strfuncs.lo \
strnum.lo time-util.lo unix-socket-create.lo \
unlink-directory.lo unlink-old-files.lo unichar.lo uri-util.lo \
utc-offset.lo utc-mktime.lo var-expand.lo var-expand-if.lo \
wildcard-match.lo write-full.lo
liblib_la_OBJECTS = $(am_liblib_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am_test_lib_OBJECTS = test_lib-test-lib.$(OBJEXT) \
test_lib-test-array.$(OBJEXT) test_lib-test-aqueue.$(OBJEXT) \
test_lib-test-backtrace.$(OBJEXT) \
test_lib-test-base32.$(OBJEXT) test_lib-test-base64.$(OBJEXT) \
test_lib-test-bits.$(OBJEXT) \
test_lib-test-bsearch-insert-pos.$(OBJEXT) \
test_lib-test-buffer.$(OBJEXT) \
test_lib-test-buffer-istream.$(OBJEXT) \
test_lib-test-byteorder.$(OBJEXT) \
test_lib-test-connection.$(OBJEXT) \
test_lib-test-crc32.$(OBJEXT) \
test_lib-test-cpu-limit.$(OBJEXT) \
test_lib-test-data-stack.$(OBJEXT) \
test_lib-test-env-util.$(OBJEXT) \
test_lib-test-event-category-register.$(OBJEXT) \
test_lib-test-event-filter.$(OBJEXT) \
test_lib-test-event-filter-expr.$(OBJEXT) \
test_lib-test-event-filter-merge.$(OBJEXT) \
test_lib-test-event-filter-parser.$(OBJEXT) \
test_lib-test-event-flatten.$(OBJEXT) \
test_lib-test-event-log.$(OBJEXT) \
test_lib-test-failures.$(OBJEXT) \
test_lib-test-fd-util.$(OBJEXT) \
test_lib-test-file-cache.$(OBJEXT) \
test_lib-test-file-create-locked.$(OBJEXT) \
test_lib-test-guid.$(OBJEXT) test_lib-test-hash.$(OBJEXT) \
test_lib-test-hash-format.$(OBJEXT) \
test_lib-test-hash-method.$(OBJEXT) \
test_lib-test-hmac.$(OBJEXT) \
test_lib-test-hex-binary.$(OBJEXT) \
test_lib-test-imem.$(OBJEXT) test_lib-test-ioloop.$(OBJEXT) \
test_lib-test-iso8601-date.$(OBJEXT) \
test_lib-test-iostream-pump.$(OBJEXT) \
test_lib-test-iostream-proxy.$(OBJEXT) \
test_lib-test-iostream-temp.$(OBJEXT) \
test_lib-test-istream.$(OBJEXT) \
test_lib-test-istream-base64-decoder.$(OBJEXT) \
test_lib-test-istream-base64-encoder.$(OBJEXT) \
test_lib-test-istream-chain.$(OBJEXT) \
test_lib-test-istream-concat.$(OBJEXT) \
test_lib-test-istream-crlf.$(OBJEXT) \
test_lib-test-istream-failure-at.$(OBJEXT) \
test_lib-test-istream-jsonstr.$(OBJEXT) \
test_lib-test-istream-multiplex.$(OBJEXT) \
test_lib-test-istream-seekable.$(OBJEXT) \
test_lib-test-istream-sized.$(OBJEXT) \
test_lib-test-istream-tee.$(OBJEXT) \
test_lib-test-istream-try.$(OBJEXT) \
test_lib-test-istream-unix.$(OBJEXT) \
test_lib-test-json-parser.$(OBJEXT) \
test_lib-test-json-tree.$(OBJEXT) \
test_lib-test-lib-event.$(OBJEXT) \
test_lib-test-lib-signals.$(OBJEXT) \
test_lib-test-llist.$(OBJEXT) \
test_lib-test-log-throttle.$(OBJEXT) \
test_lib-test-macros.$(OBJEXT) \
test_lib-test-malloc-overflow.$(OBJEXT) \
test_lib-test-memarea.$(OBJEXT) \
test_lib-test-mempool.$(OBJEXT) \
test_lib-test-mempool-allocfree.$(OBJEXT) \
test_lib-test-mempool-alloconly.$(OBJEXT) \
test_lib-test-pkcs5.$(OBJEXT) test_lib-test-net.$(OBJEXT) \
test_lib-test-numpack.$(OBJEXT) \
test_lib-test-ostream-buffer.$(OBJEXT) \
test_lib-test-ostream-failure-at.$(OBJEXT) \
test_lib-test-ostream-file.$(OBJEXT) \
test_lib-test-ostream-multiplex.$(OBJEXT) \
test_lib-test-multiplex.$(OBJEXT) \
test_lib-test-path-util.$(OBJEXT) \
test_lib-test-primes.$(OBJEXT) \
test_lib-test-printf-format-fix.$(OBJEXT) \
test_lib-test-priorityq.$(OBJEXT) \
test_lib-test-random.$(OBJEXT) \
test_lib-test-seq-range-array.$(OBJEXT) \
test_lib-test-seq-set-builder.$(OBJEXT) \
test_lib-test-stats-dist.$(OBJEXT) test_lib-test-str.$(OBJEXT) \
test_lib-test-strescape.$(OBJEXT) \
test_lib-test-strfuncs.$(OBJEXT) \
test_lib-test-strnum.$(OBJEXT) \
test_lib-test-str-find.$(OBJEXT) \
test_lib-test-str-sanitize.$(OBJEXT) \
test_lib-test-str-table.$(OBJEXT) \
test_lib-test-time-util.$(OBJEXT) \
test_lib-test-unichar.$(OBJEXT) \
test_lib-test-utc-mktime.$(OBJEXT) test_lib-test-uri.$(OBJEXT) \
test_lib-test-var-expand.$(OBJEXT) \
test_lib-test-wildcard-match.$(OBJEXT)
test_lib_OBJECTS = $(am_test_lib_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/aqueue.Plo ./$(DEPDIR)/array.Plo \
./$(DEPDIR)/askpass.Plo ./$(DEPDIR)/backtrace-string.Plo \
./$(DEPDIR)/base32.Plo ./$(DEPDIR)/base64.Plo \
./$(DEPDIR)/bits.Plo ./$(DEPDIR)/bsearch-insert-pos.Plo \
./$(DEPDIR)/buffer-istream.Plo ./$(DEPDIR)/buffer.Plo \
./$(DEPDIR)/child-wait.Plo ./$(DEPDIR)/compat.Plo \
./$(DEPDIR)/connection.Plo ./$(DEPDIR)/cpu-limit.Plo \
./$(DEPDIR)/crc32.Plo ./$(DEPDIR)/data-stack.Plo \
./$(DEPDIR)/eacces-error.Plo ./$(DEPDIR)/env-util.Plo \
./$(DEPDIR)/event-filter-lexer.Plo \
./$(DEPDIR)/event-filter-parser.Plo \
./$(DEPDIR)/event-filter.Plo ./$(DEPDIR)/event-log.Plo \
./$(DEPDIR)/execv-const.Plo ./$(DEPDIR)/failures.Plo \
./$(DEPDIR)/fd-util.Plo ./$(DEPDIR)/fdatasync-path.Plo \
./$(DEPDIR)/fdpass.Plo ./$(DEPDIR)/file-cache.Plo \
./$(DEPDIR)/file-copy.Plo ./$(DEPDIR)/file-create-locked.Plo \
./$(DEPDIR)/file-dotlock.Plo ./$(DEPDIR)/file-lock.Plo \
./$(DEPDIR)/file-set-size.Plo ./$(DEPDIR)/guid.Plo \
./$(DEPDIR)/hash-format.Plo ./$(DEPDIR)/hash-method.Plo \
./$(DEPDIR)/hash.Plo ./$(DEPDIR)/hash2.Plo \
./$(DEPDIR)/hex-binary.Plo ./$(DEPDIR)/hex-dec.Plo \
./$(DEPDIR)/hmac-cram-md5.Plo ./$(DEPDIR)/hmac.Plo \
./$(DEPDIR)/home-expand.Plo ./$(DEPDIR)/hook-build.Plo \
./$(DEPDIR)/hostpid.Plo ./$(DEPDIR)/imem.Plo \
./$(DEPDIR)/ioloop-epoll.Plo ./$(DEPDIR)/ioloop-iolist.Plo \
./$(DEPDIR)/ioloop-kqueue.Plo ./$(DEPDIR)/ioloop-notify-fd.Plo \
./$(DEPDIR)/ioloop-notify-inotify.Plo \
./$(DEPDIR)/ioloop-notify-kqueue.Plo \
./$(DEPDIR)/ioloop-notify-none.Plo ./$(DEPDIR)/ioloop-poll.Plo \
./$(DEPDIR)/ioloop-select.Plo ./$(DEPDIR)/ioloop.Plo \
./$(DEPDIR)/iostream-proxy.Plo ./$(DEPDIR)/iostream-pump.Plo \
./$(DEPDIR)/iostream-rawlog.Plo ./$(DEPDIR)/iostream-temp.Plo \
./$(DEPDIR)/iostream.Plo ./$(DEPDIR)/ipwd.Plo \
./$(DEPDIR)/iso8601-date.Plo \
./$(DEPDIR)/istream-base64-decoder.Plo \
./$(DEPDIR)/istream-base64-encoder.Plo \
./$(DEPDIR)/istream-callback.Plo ./$(DEPDIR)/istream-chain.Plo \
./$(DEPDIR)/istream-concat.Plo ./$(DEPDIR)/istream-crlf.Plo \
./$(DEPDIR)/istream-data.Plo \
./$(DEPDIR)/istream-failure-at.Plo \
./$(DEPDIR)/istream-file.Plo ./$(DEPDIR)/istream-hash.Plo \
./$(DEPDIR)/istream-jsonstr.Plo ./$(DEPDIR)/istream-limit.Plo \
./$(DEPDIR)/istream-multiplex.Plo \
./$(DEPDIR)/istream-rawlog.Plo \
./$(DEPDIR)/istream-seekable.Plo ./$(DEPDIR)/istream-sized.Plo \
./$(DEPDIR)/istream-tee.Plo ./$(DEPDIR)/istream-timeout.Plo \
./$(DEPDIR)/istream-try.Plo ./$(DEPDIR)/istream-unix.Plo \
./$(DEPDIR)/istream.Plo ./$(DEPDIR)/json-parser.Plo \
./$(DEPDIR)/json-tree.Plo ./$(DEPDIR)/lib-event.Plo \
./$(DEPDIR)/lib-signals.Plo ./$(DEPDIR)/lib.Plo \
./$(DEPDIR)/log-throttle.Plo ./$(DEPDIR)/md4.Plo \
./$(DEPDIR)/md5.Plo ./$(DEPDIR)/memarea.Plo \
./$(DEPDIR)/mempool-allocfree.Plo \
./$(DEPDIR)/mempool-alloconly.Plo \
./$(DEPDIR)/mempool-datastack.Plo \
./$(DEPDIR)/mempool-system.Plo \
./$(DEPDIR)/mempool-unsafe-datastack.Plo \
./$(DEPDIR)/mempool.Plo ./$(DEPDIR)/mkdir-parents.Plo \
./$(DEPDIR)/mmap-anon.Plo ./$(DEPDIR)/mmap-util.Plo \
./$(DEPDIR)/module-dir.Plo ./$(DEPDIR)/mountpoint.Plo \
./$(DEPDIR)/net.Plo ./$(DEPDIR)/nfs-workarounds.Plo \
./$(DEPDIR)/numpack.Plo ./$(DEPDIR)/ostream-buffer.Plo \
./$(DEPDIR)/ostream-failure-at.Plo \
./$(DEPDIR)/ostream-file.Plo ./$(DEPDIR)/ostream-hash.Plo \
./$(DEPDIR)/ostream-multiplex.Plo ./$(DEPDIR)/ostream-null.Plo \
./$(DEPDIR)/ostream-rawlog.Plo ./$(DEPDIR)/ostream-unix.Plo \
./$(DEPDIR)/ostream-wrapper.Plo ./$(DEPDIR)/ostream.Plo \
./$(DEPDIR)/path-util.Plo ./$(DEPDIR)/pkcs5.Plo \
./$(DEPDIR)/primes.Plo ./$(DEPDIR)/printf-format-fix.Plo \
./$(DEPDIR)/priorityq.Plo ./$(DEPDIR)/process-stat.Plo \
./$(DEPDIR)/process-title.Plo ./$(DEPDIR)/rand.Plo \
./$(DEPDIR)/randgen.Plo ./$(DEPDIR)/read-full.Plo \
./$(DEPDIR)/restrict-access.Plo \
./$(DEPDIR)/restrict-process-size.Plo \
./$(DEPDIR)/safe-memset.Plo ./$(DEPDIR)/safe-mkdir.Plo \
./$(DEPDIR)/safe-mkstemp.Plo ./$(DEPDIR)/sendfile-util.Plo \
./$(DEPDIR)/seq-range-array.Plo \
./$(DEPDIR)/seq-set-builder.Plo ./$(DEPDIR)/sha1.Plo \
./$(DEPDIR)/sha2.Plo ./$(DEPDIR)/sha3.Plo \
./$(DEPDIR)/sleep.Plo ./$(DEPDIR)/sort.Plo \
./$(DEPDIR)/stats-dist.Plo ./$(DEPDIR)/str-find.Plo \
./$(DEPDIR)/str-sanitize.Plo ./$(DEPDIR)/str-table.Plo \
./$(DEPDIR)/str.Plo ./$(DEPDIR)/strescape.Plo \
./$(DEPDIR)/strfuncs.Plo ./$(DEPDIR)/strnum.Plo \
./$(DEPDIR)/test_lib-test-aqueue.Po \
./$(DEPDIR)/test_lib-test-array.Po \
./$(DEPDIR)/test_lib-test-backtrace.Po \
./$(DEPDIR)/test_lib-test-base32.Po \
./$(DEPDIR)/test_lib-test-base64.Po \
./$(DEPDIR)/test_lib-test-bits.Po \
./$(DEPDIR)/test_lib-test-bsearch-insert-pos.Po \
./$(DEPDIR)/test_lib-test-buffer-istream.Po \
./$(DEPDIR)/test_lib-test-buffer.Po \
./$(DEPDIR)/test_lib-test-byteorder.Po \
./$(DEPDIR)/test_lib-test-connection.Po \
./$(DEPDIR)/test_lib-test-cpu-limit.Po \
./$(DEPDIR)/test_lib-test-crc32.Po \
./$(DEPDIR)/test_lib-test-data-stack.Po \
./$(DEPDIR)/test_lib-test-env-util.Po \
./$(DEPDIR)/test_lib-test-event-category-register.Po \
./$(DEPDIR)/test_lib-test-event-filter-expr.Po \
./$(DEPDIR)/test_lib-test-event-filter-merge.Po \
./$(DEPDIR)/test_lib-test-event-filter-parser.Po \
./$(DEPDIR)/test_lib-test-event-filter.Po \
./$(DEPDIR)/test_lib-test-event-flatten.Po \
./$(DEPDIR)/test_lib-test-event-log.Po \
./$(DEPDIR)/test_lib-test-failures.Po \
./$(DEPDIR)/test_lib-test-fd-util.Po \
./$(DEPDIR)/test_lib-test-file-cache.Po \
./$(DEPDIR)/test_lib-test-file-create-locked.Po \
./$(DEPDIR)/test_lib-test-guid.Po \
./$(DEPDIR)/test_lib-test-hash-format.Po \
./$(DEPDIR)/test_lib-test-hash-method.Po \
./$(DEPDIR)/test_lib-test-hash.Po \
./$(DEPDIR)/test_lib-test-hex-binary.Po \
./$(DEPDIR)/test_lib-test-hmac.Po \
./$(DEPDIR)/test_lib-test-imem.Po \
./$(DEPDIR)/test_lib-test-ioloop.Po \
./$(DEPDIR)/test_lib-test-iostream-proxy.Po \
./$(DEPDIR)/test_lib-test-iostream-pump.Po \
./$(DEPDIR)/test_lib-test-iostream-temp.Po \
./$(DEPDIR)/test_lib-test-iso8601-date.Po \
./$(DEPDIR)/test_lib-test-istream-base64-decoder.Po \
./$(DEPDIR)/test_lib-test-istream-base64-encoder.Po \
./$(DEPDIR)/test_lib-test-istream-chain.Po \
./$(DEPDIR)/test_lib-test-istream-concat.Po \
./$(DEPDIR)/test_lib-test-istream-crlf.Po \
./$(DEPDIR)/test_lib-test-istream-failure-at.Po \
./$(DEPDIR)/test_lib-test-istream-jsonstr.Po \
./$(DEPDIR)/test_lib-test-istream-multiplex.Po \
./$(DEPDIR)/test_lib-test-istream-seekable.Po \
./$(DEPDIR)/test_lib-test-istream-sized.Po \
./$(DEPDIR)/test_lib-test-istream-tee.Po \
./$(DEPDIR)/test_lib-test-istream-try.Po \
./$(DEPDIR)/test_lib-test-istream-unix.Po \
./$(DEPDIR)/test_lib-test-istream.Po \
./$(DEPDIR)/test_lib-test-json-parser.Po \
./$(DEPDIR)/test_lib-test-json-tree.Po \
./$(DEPDIR)/test_lib-test-lib-event.Po \
./$(DEPDIR)/test_lib-test-lib-signals.Po \
./$(DEPDIR)/test_lib-test-lib.Po \
./$(DEPDIR)/test_lib-test-llist.Po \
./$(DEPDIR)/test_lib-test-log-throttle.Po \
./$(DEPDIR)/test_lib-test-macros.Po \
./$(DEPDIR)/test_lib-test-malloc-overflow.Po \
./$(DEPDIR)/test_lib-test-memarea.Po \
./$(DEPDIR)/test_lib-test-mempool-allocfree.Po \
./$(DEPDIR)/test_lib-test-mempool-alloconly.Po \
./$(DEPDIR)/test_lib-test-mempool.Po \
./$(DEPDIR)/test_lib-test-multiplex.Po \
./$(DEPDIR)/test_lib-test-net.Po \
./$(DEPDIR)/test_lib-test-numpack.Po \
./$(DEPDIR)/test_lib-test-ostream-buffer.Po \
./$(DEPDIR)/test_lib-test-ostream-failure-at.Po \
./$(DEPDIR)/test_lib-test-ostream-file.Po \
./$(DEPDIR)/test_lib-test-ostream-multiplex.Po \
./$(DEPDIR)/test_lib-test-path-util.Po \
./$(DEPDIR)/test_lib-test-pkcs5.Po \
./$(DEPDIR)/test_lib-test-primes.Po \
./$(DEPDIR)/test_lib-test-printf-format-fix.Po \
./$(DEPDIR)/test_lib-test-priorityq.Po \
./$(DEPDIR)/test_lib-test-random.Po \
./$(DEPDIR)/test_lib-test-seq-range-array.Po \
./$(DEPDIR)/test_lib-test-seq-set-builder.Po \
./$(DEPDIR)/test_lib-test-stats-dist.Po \
./$(DEPDIR)/test_lib-test-str-find.Po \
./$(DEPDIR)/test_lib-test-str-sanitize.Po \
./$(DEPDIR)/test_lib-test-str-table.Po \
./$(DEPDIR)/test_lib-test-str.Po \
./$(DEPDIR)/test_lib-test-strescape.Po \
./$(DEPDIR)/test_lib-test-strfuncs.Po \
./$(DEPDIR)/test_lib-test-strnum.Po \
./$(DEPDIR)/test_lib-test-time-util.Po \
./$(DEPDIR)/test_lib-test-unichar.Po \
./$(DEPDIR)/test_lib-test-uri.Po \
./$(DEPDIR)/test_lib-test-utc-mktime.Po \
./$(DEPDIR)/test_lib-test-var-expand.Po \
./$(DEPDIR)/test_lib-test-wildcard-match.Po \
./$(DEPDIR)/time-util.Plo ./$(DEPDIR)/unichar.Plo \
./$(DEPDIR)/unix-socket-create.Plo \
./$(DEPDIR)/unlink-directory.Plo \
./$(DEPDIR)/unlink-old-files.Plo ./$(DEPDIR)/uri-util.Plo \
./$(DEPDIR)/utc-mktime.Plo ./$(DEPDIR)/utc-offset.Plo \
./$(DEPDIR)/var-expand-if.Plo ./$(DEPDIR)/var-expand.Plo \
./$(DEPDIR)/wildcard-match.Plo ./$(DEPDIR)/write-full.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
AM_V_LEX = $(am__v_LEX_@AM_V@)
am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@)
am__v_LEX_0 = @echo " LEX " $@;
am__v_LEX_1 =
YLWRAP = $(top_srcdir)/ylwrap
@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
-e s/c++$$/h++/ -e s/c$$/h/
YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
AM_V_YACC = $(am__v_YACC_@AM_V@)
am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
am__v_YACC_0 = @echo " YACC " $@;
am__v_YACC_1 =
SOURCES = $(liblib_la_SOURCES) $(test_lib_SOURCES)
DIST_SOURCES = $(liblib_la_SOURCES) $(test_lib_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(pkginc_libdir)"
HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
$(top_srcdir)/ylwrap event-filter-lexer.c \
event-filter-parser.c
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTH_CFLAGS = @AUTH_CFLAGS@
AUTH_LIBS = @AUTH_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BINARY_CFLAGS = @BINARY_CFLAGS@
BINARY_LDFLAGS = @BINARY_LDFLAGS@
BISON = @BISON@
CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
CASSANDRA_LIBS = @CASSANDRA_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CDB_LIBS = @CDB_LIBS@
CFLAGS = @CFLAGS@
CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
CLUCENE_LIBS = @CLUCENE_LIBS@
COMPRESS_LIBS = @COMPRESS_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPT_LIBS = @CRYPT_LIBS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DICT_LIBS = @DICT_LIBS@
DLLIB = @DLLIB@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FLEX = @FLEX@
FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KRB5CONFIG = @KRB5CONFIG@
KRB5_CFLAGS = @KRB5_CFLAGS@
KRB5_LIBS = @KRB5_LIBS@
LD = @LD@
LDAP_LIBS = @LDAP_LIBS@
LDFLAGS = @LDFLAGS@
LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
LIBCAP = @LIBCAP@
LIBDOVECOT = @LIBDOVECOT@
LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
LIBICONV = @LIBICONV@
LIBICU_CFLAGS = @LIBICU_CFLAGS@
LIBICU_LIBS = @LIBICU_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
LIBTOOL = @LIBTOOL@
LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
LIBWRAP_LIBS = @LIBWRAP_LIBS@
LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBICONV = @LTLIBICONV@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODULE_LIBS = @MODULE_LIBS@
MODULE_SUFFIX = @MODULE_SUFFIX@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LIBS = @MYSQL_LIBS@
NM = @NM@
NMEDIT = @NMEDIT@
NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PANDOC = @PANDOC@
PATH_SEPARATOR = @PATH_SEPARATOR@
PGSQL_CFLAGS = @PGSQL_CFLAGS@
PGSQL_LIBS = @PGSQL_LIBS@
PG_CONFIG = @PG_CONFIG@
PIE_CFLAGS = @PIE_CFLAGS@
PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
QUOTA_LIBS = @QUOTA_LIBS@
RANLIB = @RANLIB@
RELRO_LDFLAGS = @RELRO_LDFLAGS@
RPCGEN = @RPCGEN@
RUN_TEST = @RUN_TEST@
SED = @SED@
SETTING_FILES = @SETTING_FILES@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SQL_CFLAGS = @SQL_CFLAGS@
SQL_LIBS = @SQL_LIBS@
SSL_CFLAGS = @SSL_CFLAGS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
SYSTEMD_LIBS = @SYSTEMD_LIBS@
VALGRIND = @VALGRIND@
VERSION = @VERSION@
ZSTD_CFLAGS = @ZSTD_CFLAGS@
ZSTD_LIBS = @ZSTD_LIBS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
dict_drivers = @dict_drivers@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
moduledir = @moduledir@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
rundir = @rundir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sql_drivers = @sql_drivers@
srcdir = @srcdir@
ssldir = @ssldir@
statedir = @statedir@
sysconfdir = @sysconfdir@
systemdservicetype = @systemdservicetype@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = \
$(LIBUNWIND_CFLAGS)
noinst_LTLIBRARIES = liblib.la
BUILT_SOURCES = $(srcdir)/unicodemap.c \
event-filter-lexer.c \
event-filter-parser.c \
event-filter-parser.h
EXTRA_DIST = unicodemap.c unicodemap.pl UnicodeData.txt
# Squelch autoconf error about using .[ly] sources but not defining $(LEX)
# and $(YACC). Using false here avoids accidental use.
LEX = /bin/false
YACC = /bin/false
liblib_la_LIBADD = $(LIBUNWIND_LIBS)
liblib_la_SOURCES = \
array.c \
aqueue.c \
askpass.c \
backtrace-string.c \
base32.c \
base64.c \
bits.c \
bsearch-insert-pos.c \
buffer.c \
buffer-istream.c \
child-wait.c \
compat.c \
connection.c \
cpu-limit.c \
crc32.c \
data-stack.c \
eacces-error.c \
env-util.c \
event-filter.c \
event-filter-lexer.l \
event-filter-parser.y \
event-log.c \
execv-const.c \
failures.c \
fd-util.c \
fdatasync-path.c \
fdpass.c \
file-cache.c \
file-create-locked.c \
file-copy.c \
file-dotlock.c \
file-lock.c \
file-set-size.c \
guid.c \
hash.c \
hash-format.c \
hash-method.c \
hash2.c \
hex-binary.c \
hex-dec.c \
hmac.c \
hmac-cram-md5.c \
home-expand.c \
hook-build.c \
hostpid.c \
imem.c \
ipwd.c \
iostream.c \
iostream-pump.c \
iostream-proxy.c \
iostream-rawlog.c \
iostream-temp.c \
iso8601-date.c \
istream.c \
istream-base64-decoder.c \
istream-base64-encoder.c \
istream-callback.c \
istream-chain.c \
istream-concat.c \
istream-crlf.c \
istream-data.c \
istream-failure-at.c \
istream-file.c \
istream-hash.c \
istream-jsonstr.c \
istream-limit.c \
istream-multiplex.c \
istream-rawlog.c \
istream-seekable.c \
istream-sized.c \
istream-tee.c \
istream-try.c \
istream-timeout.c \
istream-unix.c \
ioloop.c \
ioloop-iolist.c \
ioloop-notify-none.c \
ioloop-notify-fd.c \
ioloop-notify-inotify.c \
ioloop-notify-kqueue.c \
ioloop-poll.c \
ioloop-select.c \
ioloop-epoll.c \
ioloop-kqueue.c \
json-parser.c \
json-tree.c \
lib.c \
lib-event.c \
lib-signals.c \
log-throttle.c \
md4.c \
md5.c \
memarea.c \
mempool.c \
mempool-allocfree.c \
mempool-alloconly.c \
mempool-datastack.c \
mempool-system.c \
mempool-unsafe-datastack.c \
mkdir-parents.c \
mmap-anon.c \
mmap-util.c \
module-dir.c \
mountpoint.c \
net.c \
nfs-workarounds.c \
numpack.c \
ostream.c \
ostream-buffer.c \
ostream-failure-at.c \
ostream-file.c \
ostream-hash.c \
ostream-multiplex.c \
ostream-null.c \
ostream-rawlog.c \
ostream-unix.c \
ostream-wrapper.c \
path-util.c \
pkcs5.c \
primes.c \
printf-format-fix.c \
process-stat.c \
process-title.c \
priorityq.c \
randgen.c \
rand.c \
read-full.c \
restrict-access.c \
restrict-process-size.c \
safe-memset.c \
safe-mkdir.c \
safe-mkstemp.c \
sendfile-util.c \
seq-range-array.c \
seq-set-builder.c \
sha1.c \
sha2.c \
sha3.c \
sleep.c \
sort.c \
stats-dist.c \
str.c \
str-find.c \
str-sanitize.c \
str-table.c \
strescape.c \
strfuncs.c \
strnum.c \
time-util.c \
unix-socket-create.c \
unlink-directory.c \
unlink-old-files.c \
unichar.c \
uri-util.c \
utc-offset.c \
utc-mktime.c \
var-expand.c \
var-expand-if.c \
wildcard-match.c \
write-full.c
headers = \
aqueue.h \
array.h \
array-decl.h \
askpass.h \
backtrace-string.h \
base32.h \
base64.h \
bits.h \
bsearch-insert-pos.h \
buffer.h \
byteorder.h \
child-wait.h \
compat.h \
connection.h \
cpu-limit.h \
crc32.h \
data-stack.h \
eacces-error.h \
env-util.h \
event-filter.h \
event-filter-parser.h \
event-filter-private.h \
event-log.h \
execv-const.h \
failures.h \
failures-private.h \
fd-util.h \
fdatasync-path.h \
fdpass.h \
file-cache.h \
file-create-locked.h \
file-copy.h \
file-dotlock.h \
file-lock.h \
file-set-size.h \
fsync-mode.h \
guid.h \
hash.h \
hash-decl.h \
hash-format.h \
hash-method.h \
hash2.h \
hex-binary.h \
hex-dec.h \
hmac.h \
hmac-cram-md5.h \
home-expand.h \
hook-build.h \
hostpid.h \
imem.h \
ipwd.h \
iostream.h \
iostream-private.h \
iostream-pump.h \
iostream-proxy.h \
iostream-rawlog.h \
iostream-rawlog-private.h \
iostream-temp.h \
iso8601-date.h \
istream.h \
istream-base64.h \
istream-callback.h \
istream-chain.h \
istream-concat.h \
istream-crlf.h \
istream-failure-at.h \
istream-file-private.h \
istream-hash.h \
istream-jsonstr.h \
istream-multiplex.h \
istream-private.h \
istream-rawlog.h \
istream-seekable.h \
istream-sized.h \
istream-tee.h \
istream-try.h \
istream-timeout.h \
istream-unix.h \
ioloop.h \
ioloop-iolist.h \
ioloop-private.h \
ioloop-notify-fd.h \
json-parser.h \
json-tree.h \
lib.h \
lib-event.h \
lib-event-private.h \
lib-signals.h \
llist.h \
log-throttle.h \
macros.h \
md4.h \
md5.h \
malloc-overflow.h \
memarea.h \
mempool.h \
mkdir-parents.h \
mmap-util.h \
module-context.h \
module-dir.h \
mountpoint.h \
net.h \
nfs-workarounds.h \
numpack.h \
ostream.h \
ostream-failure-at.h \
ostream-file-private.h \
ostream-hash.h \
ostream-multiplex.h \
ostream-private.h \
ostream-null.h \
ostream-rawlog.h \
ostream-unix.h \
ostream-wrapper.h \
path-util.h \
pkcs5.h \
primes.h \
printf-format-fix.h \
process-stat.h \
process-title.h \
priorityq.h \
randgen.h \
read-full.h \
restrict-access.h \
restrict-process-size.h \
safe-memset.h \
safe-mkdir.h \
safe-mkstemp.h \
sendfile-util.h \
seq-range-array.h \
seq-set-builder.h \
sha-common.h \
sha1.h \
sha2.h \
sha3.h \
sleep.h \
sort.h \
stats-dist.h \
str.h \
str-find.h \
str-sanitize.h \
str-table.h \
strescape.h \
strfuncs.h \
strnum.h \
time-util.h \
unix-socket-create.h \
unlink-directory.h \
unlink-old-files.h \
unichar.h \
uri-util.h \
utc-offset.h \
utc-mktime.h \
var-expand.h \
var-expand-private.h \
wildcard-match.h \
write-full.h
test_programs = test-lib
test_lib_CPPFLAGS = \
-I$(top_srcdir)/src/lib-test
test_libs = \
../lib-test/libtest.la \
liblib.la
test_lib_SOURCES = \
test-lib.c \
test-array.c \
test-aqueue.c \
test-backtrace.c \
test-base32.c \
test-base64.c \
test-bits.c \
test-bsearch-insert-pos.c \
test-buffer.c \
test-buffer-istream.c \
test-byteorder.c \
test-connection.c \
test-crc32.c \
test-cpu-limit.c \
test-data-stack.c \
test-env-util.c \
test-event-category-register.c \
test-event-filter.c \
test-event-filter-expr.c \
test-event-filter-merge.c \
test-event-filter-parser.c \
test-event-flatten.c \
test-event-log.c \
test-failures.c \
test-fd-util.c \
test-file-cache.c \
test-file-create-locked.c \
test-guid.c \
test-hash.c \
test-hash-format.c \
test-hash-method.c \
test-hmac.c \
test-hex-binary.c \
test-imem.c \
test-ioloop.c \
test-iso8601-date.c \
test-iostream-pump.c \
test-iostream-proxy.c \
test-iostream-temp.c \
test-istream.c \
test-istream-base64-decoder.c \
test-istream-base64-encoder.c \
test-istream-chain.c \
test-istream-concat.c \
test-istream-crlf.c \
test-istream-failure-at.c \
test-istream-jsonstr.c \
test-istream-multiplex.c \
test-istream-seekable.c \
test-istream-sized.c \
test-istream-tee.c \
test-istream-try.c \
test-istream-unix.c \
test-json-parser.c \
test-json-tree.c \
test-lib-event.c \
test-lib-signals.c \
test-llist.c \
test-log-throttle.c \
test-macros.c \
test-malloc-overflow.c \
test-memarea.c \
test-mempool.c \
test-mempool-allocfree.c \
test-mempool-alloconly.c \
test-pkcs5.c \
test-net.c \
test-numpack.c \
test-ostream-buffer.c \
test-ostream-failure-at.c \
test-ostream-file.c \
test-ostream-multiplex.c \
test-multiplex.c \
test-path-util.c \
test-primes.c \
test-printf-format-fix.c \
test-priorityq.c \
test-random.c \
test-seq-range-array.c \
test-seq-set-builder.c \
test-stats-dist.c \
test-str.c \
test-strescape.c \
test-strfuncs.c \
test-strnum.c \
test-str-find.c \
test-str-sanitize.c \
test-str-table.c \
test-time-util.c \
test-unichar.c \
test-utc-mktime.c \
test-uri.c \
test-var-expand.c \
test-wildcard-match.c
test_headers = \
test-lib.h \
test-lib.inc
test_lib_LDADD = $(test_libs) -lm
test_lib_DEPENDENCIES = $(test_libs)
pkginc_libdir = $(pkgincludedir)
pkginc_lib_HEADERS = $(headers)
noinst_HEADERS = $(test_headers)
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .l .lo .o .obj .y
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/lib/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstPROGRAMS:
@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
liblib.la: $(liblib_la_OBJECTS) $(liblib_la_DEPENDENCIES) $(EXTRA_liblib_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(liblib_la_OBJECTS) $(liblib_la_LIBADD) $(LIBS)
test-lib$(EXEEXT): $(test_lib_OBJECTS) $(test_lib_DEPENDENCIES) $(EXTRA_test_lib_DEPENDENCIES)
@rm -f test-lib$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(test_lib_OBJECTS) $(test_lib_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aqueue.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/askpass.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backtrace-string.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bits.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bsearch-insert-pos.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer-istream.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/child-wait.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compat.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu-limit.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc32.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-stack.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eacces-error.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/env-util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-filter-lexer.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-filter-parser.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-filter.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event-log.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execv-const.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/failures.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fd-util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdatasync-path.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdpass.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file-cache.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file-copy.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file-create-locked.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file-dotlock.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file-lock.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file-set-size.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/guid.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-format.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-method.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash2.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hex-binary.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hex-dec.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac-cram-md5.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/home-expand.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hook-build.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostpid.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imem.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-epoll.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-iolist.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-kqueue.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-notify-fd.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-notify-inotify.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-notify-kqueue.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-notify-none.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-poll.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop-select.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioloop.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iostream-proxy.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iostream-pump.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iostream-rawlog.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iostream-temp.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iostream.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipwd.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iso8601-date.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-base64-decoder.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-base64-encoder.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-callback.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-chain.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-concat.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-crlf.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-data.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-failure-at.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-file.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-hash.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-jsonstr.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-limit.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-multiplex.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-rawlog.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-seekable.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-sized.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-tee.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-timeout.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-try.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream-unix.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/istream.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json-parser.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json-tree.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib-event.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib-signals.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log-throttle.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md4.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memarea.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempool-allocfree.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempool-alloconly.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempool-datastack.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempool-system.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempool-unsafe-datastack.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempool.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkdir-parents.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmap-anon.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmap-util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module-dir.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mountpoint.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfs-workarounds.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numpack.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-buffer.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-failure-at.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-file.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-hash.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-multiplex.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-null.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-rawlog.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-unix.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream-wrapper.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ostream.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs5.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/primes.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printf-format-fix.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/priorityq.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process-stat.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process-title.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rand.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/randgen.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read-full.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/restrict-access.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/restrict-process-size.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safe-memset.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safe-mkdir.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safe-mkstemp.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sendfile-util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq-range-array.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq-set-builder.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha2.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha3.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sleep.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sort.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-dist.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-find.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-sanitize.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-table.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strescape.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strfuncs.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnum.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-aqueue.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-array.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-backtrace.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-base32.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-base64.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-bits.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-bsearch-insert-pos.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-buffer-istream.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-buffer.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-byteorder.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-connection.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-cpu-limit.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-crc32.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-data-stack.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-env-util.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-event-category-register.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-event-filter-expr.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-event-filter-merge.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-event-filter-parser.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-event-filter.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-event-flatten.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-event-log.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-failures.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-fd-util.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-file-cache.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-file-create-locked.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-guid.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-hash-format.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-hash-method.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-hash.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-hex-binary.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-hmac.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-imem.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-ioloop.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-iostream-proxy.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-iostream-pump.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-iostream-temp.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-iso8601-date.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-base64-decoder.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-base64-encoder.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-chain.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-concat.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-crlf.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-failure-at.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-jsonstr.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-multiplex.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-seekable.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-sized.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-tee.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-try.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream-unix.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-istream.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-json-parser.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-json-tree.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-lib-event.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-lib-signals.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-lib.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-llist.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-log-throttle.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-macros.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-malloc-overflow.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-memarea.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-mempool-allocfree.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-mempool-alloconly.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-mempool.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-multiplex.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-net.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-numpack.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-ostream-buffer.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-ostream-failure-at.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-ostream-file.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-ostream-multiplex.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-path-util.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-pkcs5.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-primes.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-printf-format-fix.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-priorityq.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-random.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-seq-range-array.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-seq-set-builder.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-stats-dist.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-str-find.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-str-sanitize.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-str-table.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-str.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-strescape.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-strfuncs.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-strnum.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-time-util.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-unichar.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-uri.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-utc-mktime.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-var-expand.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lib-test-wildcard-match.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time-util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unichar.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix-socket-create.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unlink-directory.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unlink-old-files.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uri-util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utc-mktime.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utc-offset.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/var-expand-if.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/var-expand.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wildcard-match.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write-full.Plo@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
test_lib-test-lib.o: test-lib.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-lib.o -MD -MP -MF $(DEPDIR)/test_lib-test-lib.Tpo -c -o test_lib-test-lib.o `test -f 'test-lib.c' || echo '$(srcdir)/'`test-lib.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-lib.Tpo $(DEPDIR)/test_lib-test-lib.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lib.c' object='test_lib-test-lib.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-lib.o `test -f 'test-lib.c' || echo '$(srcdir)/'`test-lib.c
test_lib-test-lib.obj: test-lib.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-lib.obj -MD -MP -MF $(DEPDIR)/test_lib-test-lib.Tpo -c -o test_lib-test-lib.obj `if test -f 'test-lib.c'; then $(CYGPATH_W) 'test-lib.c'; else $(CYGPATH_W) '$(srcdir)/test-lib.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-lib.Tpo $(DEPDIR)/test_lib-test-lib.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lib.c' object='test_lib-test-lib.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-lib.obj `if test -f 'test-lib.c'; then $(CYGPATH_W) 'test-lib.c'; else $(CYGPATH_W) '$(srcdir)/test-lib.c'; fi`
test_lib-test-array.o: test-array.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-array.o -MD -MP -MF $(DEPDIR)/test_lib-test-array.Tpo -c -o test_lib-test-array.o `test -f 'test-array.c' || echo '$(srcdir)/'`test-array.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-array.Tpo $(DEPDIR)/test_lib-test-array.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-array.c' object='test_lib-test-array.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-array.o `test -f 'test-array.c' || echo '$(srcdir)/'`test-array.c
test_lib-test-array.obj: test-array.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-array.obj -MD -MP -MF $(DEPDIR)/test_lib-test-array.Tpo -c -o test_lib-test-array.obj `if test -f 'test-array.c'; then $(CYGPATH_W) 'test-array.c'; else $(CYGPATH_W) '$(srcdir)/test-array.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-array.Tpo $(DEPDIR)/test_lib-test-array.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-array.c' object='test_lib-test-array.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-array.obj `if test -f 'test-array.c'; then $(CYGPATH_W) 'test-array.c'; else $(CYGPATH_W) '$(srcdir)/test-array.c'; fi`
test_lib-test-aqueue.o: test-aqueue.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-aqueue.o -MD -MP -MF $(DEPDIR)/test_lib-test-aqueue.Tpo -c -o test_lib-test-aqueue.o `test -f 'test-aqueue.c' || echo '$(srcdir)/'`test-aqueue.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-aqueue.Tpo $(DEPDIR)/test_lib-test-aqueue.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-aqueue.c' object='test_lib-test-aqueue.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-aqueue.o `test -f 'test-aqueue.c' || echo '$(srcdir)/'`test-aqueue.c
test_lib-test-aqueue.obj: test-aqueue.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-aqueue.obj -MD -MP -MF $(DEPDIR)/test_lib-test-aqueue.Tpo -c -o test_lib-test-aqueue.obj `if test -f 'test-aqueue.c'; then $(CYGPATH_W) 'test-aqueue.c'; else $(CYGPATH_W) '$(srcdir)/test-aqueue.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-aqueue.Tpo $(DEPDIR)/test_lib-test-aqueue.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-aqueue.c' object='test_lib-test-aqueue.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-aqueue.obj `if test -f 'test-aqueue.c'; then $(CYGPATH_W) 'test-aqueue.c'; else $(CYGPATH_W) '$(srcdir)/test-aqueue.c'; fi`
test_lib-test-backtrace.o: test-backtrace.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-backtrace.o -MD -MP -MF $(DEPDIR)/test_lib-test-backtrace.Tpo -c -o test_lib-test-backtrace.o `test -f 'test-backtrace.c' || echo '$(srcdir)/'`test-backtrace.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-backtrace.Tpo $(DEPDIR)/test_lib-test-backtrace.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-backtrace.c' object='test_lib-test-backtrace.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-backtrace.o `test -f 'test-backtrace.c' || echo '$(srcdir)/'`test-backtrace.c
test_lib-test-backtrace.obj: test-backtrace.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-backtrace.obj -MD -MP -MF $(DEPDIR)/test_lib-test-backtrace.Tpo -c -o test_lib-test-backtrace.obj `if test -f 'test-backtrace.c'; then $(CYGPATH_W) 'test-backtrace.c'; else $(CYGPATH_W) '$(srcdir)/test-backtrace.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-backtrace.Tpo $(DEPDIR)/test_lib-test-backtrace.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-backtrace.c' object='test_lib-test-backtrace.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-backtrace.obj `if test -f 'test-backtrace.c'; then $(CYGPATH_W) 'test-backtrace.c'; else $(CYGPATH_W) '$(srcdir)/test-backtrace.c'; fi`
test_lib-test-base32.o: test-base32.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-base32.o -MD -MP -MF $(DEPDIR)/test_lib-test-base32.Tpo -c -o test_lib-test-base32.o `test -f 'test-base32.c' || echo '$(srcdir)/'`test-base32.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-base32.Tpo $(DEPDIR)/test_lib-test-base32.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-base32.c' object='test_lib-test-base32.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-base32.o `test -f 'test-base32.c' || echo '$(srcdir)/'`test-base32.c
test_lib-test-base32.obj: test-base32.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-base32.obj -MD -MP -MF $(DEPDIR)/test_lib-test-base32.Tpo -c -o test_lib-test-base32.obj `if test -f 'test-base32.c'; then $(CYGPATH_W) 'test-base32.c'; else $(CYGPATH_W) '$(srcdir)/test-base32.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-base32.Tpo $(DEPDIR)/test_lib-test-base32.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-base32.c' object='test_lib-test-base32.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-base32.obj `if test -f 'test-base32.c'; then $(CYGPATH_W) 'test-base32.c'; else $(CYGPATH_W) '$(srcdir)/test-base32.c'; fi`
test_lib-test-base64.o: test-base64.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-base64.o -MD -MP -MF $(DEPDIR)/test_lib-test-base64.Tpo -c -o test_lib-test-base64.o `test -f 'test-base64.c' || echo '$(srcdir)/'`test-base64.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-base64.Tpo $(DEPDIR)/test_lib-test-base64.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-base64.c' object='test_lib-test-base64.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-base64.o `test -f 'test-base64.c' || echo '$(srcdir)/'`test-base64.c
test_lib-test-base64.obj: test-base64.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-base64.obj -MD -MP -MF $(DEPDIR)/test_lib-test-base64.Tpo -c -o test_lib-test-base64.obj `if test -f 'test-base64.c'; then $(CYGPATH_W) 'test-base64.c'; else $(CYGPATH_W) '$(srcdir)/test-base64.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-base64.Tpo $(DEPDIR)/test_lib-test-base64.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-base64.c' object='test_lib-test-base64.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-base64.obj `if test -f 'test-base64.c'; then $(CYGPATH_W) 'test-base64.c'; else $(CYGPATH_W) '$(srcdir)/test-base64.c'; fi`
test_lib-test-bits.o: test-bits.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-bits.o -MD -MP -MF $(DEPDIR)/test_lib-test-bits.Tpo -c -o test_lib-test-bits.o `test -f 'test-bits.c' || echo '$(srcdir)/'`test-bits.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-bits.Tpo $(DEPDIR)/test_lib-test-bits.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-bits.c' object='test_lib-test-bits.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-bits.o `test -f 'test-bits.c' || echo '$(srcdir)/'`test-bits.c
test_lib-test-bits.obj: test-bits.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-bits.obj -MD -MP -MF $(DEPDIR)/test_lib-test-bits.Tpo -c -o test_lib-test-bits.obj `if test -f 'test-bits.c'; then $(CYGPATH_W) 'test-bits.c'; else $(CYGPATH_W) '$(srcdir)/test-bits.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-bits.Tpo $(DEPDIR)/test_lib-test-bits.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-bits.c' object='test_lib-test-bits.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-bits.obj `if test -f 'test-bits.c'; then $(CYGPATH_W) 'test-bits.c'; else $(CYGPATH_W) '$(srcdir)/test-bits.c'; fi`
test_lib-test-bsearch-insert-pos.o: test-bsearch-insert-pos.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-bsearch-insert-pos.o -MD -MP -MF $(DEPDIR)/test_lib-test-bsearch-insert-pos.Tpo -c -o test_lib-test-bsearch-insert-pos.o `test -f 'test-bsearch-insert-pos.c' || echo '$(srcdir)/'`test-bsearch-insert-pos.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-bsearch-insert-pos.Tpo $(DEPDIR)/test_lib-test-bsearch-insert-pos.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-bsearch-insert-pos.c' object='test_lib-test-bsearch-insert-pos.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-bsearch-insert-pos.o `test -f 'test-bsearch-insert-pos.c' || echo '$(srcdir)/'`test-bsearch-insert-pos.c
test_lib-test-bsearch-insert-pos.obj: test-bsearch-insert-pos.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-bsearch-insert-pos.obj -MD -MP -MF $(DEPDIR)/test_lib-test-bsearch-insert-pos.Tpo -c -o test_lib-test-bsearch-insert-pos.obj `if test -f 'test-bsearch-insert-pos.c'; then $(CYGPATH_W) 'test-bsearch-insert-pos.c'; else $(CYGPATH_W) '$(srcdir)/test-bsearch-insert-pos.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-bsearch-insert-pos.Tpo $(DEPDIR)/test_lib-test-bsearch-insert-pos.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-bsearch-insert-pos.c' object='test_lib-test-bsearch-insert-pos.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-bsearch-insert-pos.obj `if test -f 'test-bsearch-insert-pos.c'; then $(CYGPATH_W) 'test-bsearch-insert-pos.c'; else $(CYGPATH_W) '$(srcdir)/test-bsearch-insert-pos.c'; fi`
test_lib-test-buffer.o: test-buffer.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-buffer.o -MD -MP -MF $(DEPDIR)/test_lib-test-buffer.Tpo -c -o test_lib-test-buffer.o `test -f 'test-buffer.c' || echo '$(srcdir)/'`test-buffer.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-buffer.Tpo $(DEPDIR)/test_lib-test-buffer.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-buffer.c' object='test_lib-test-buffer.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-buffer.o `test -f 'test-buffer.c' || echo '$(srcdir)/'`test-buffer.c
test_lib-test-buffer.obj: test-buffer.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-buffer.obj -MD -MP -MF $(DEPDIR)/test_lib-test-buffer.Tpo -c -o test_lib-test-buffer.obj `if test -f 'test-buffer.c'; then $(CYGPATH_W) 'test-buffer.c'; else $(CYGPATH_W) '$(srcdir)/test-buffer.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-buffer.Tpo $(DEPDIR)/test_lib-test-buffer.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-buffer.c' object='test_lib-test-buffer.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-buffer.obj `if test -f 'test-buffer.c'; then $(CYGPATH_W) 'test-buffer.c'; else $(CYGPATH_W) '$(srcdir)/test-buffer.c'; fi`
test_lib-test-buffer-istream.o: test-buffer-istream.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-buffer-istream.o -MD -MP -MF $(DEPDIR)/test_lib-test-buffer-istream.Tpo -c -o test_lib-test-buffer-istream.o `test -f 'test-buffer-istream.c' || echo '$(srcdir)/'`test-buffer-istream.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-buffer-istream.Tpo $(DEPDIR)/test_lib-test-buffer-istream.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-buffer-istream.c' object='test_lib-test-buffer-istream.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-buffer-istream.o `test -f 'test-buffer-istream.c' || echo '$(srcdir)/'`test-buffer-istream.c
test_lib-test-buffer-istream.obj: test-buffer-istream.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-buffer-istream.obj -MD -MP -MF $(DEPDIR)/test_lib-test-buffer-istream.Tpo -c -o test_lib-test-buffer-istream.obj `if test -f 'test-buffer-istream.c'; then $(CYGPATH_W) 'test-buffer-istream.c'; else $(CYGPATH_W) '$(srcdir)/test-buffer-istream.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-buffer-istream.Tpo $(DEPDIR)/test_lib-test-buffer-istream.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-buffer-istream.c' object='test_lib-test-buffer-istream.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-buffer-istream.obj `if test -f 'test-buffer-istream.c'; then $(CYGPATH_W) 'test-buffer-istream.c'; else $(CYGPATH_W) '$(srcdir)/test-buffer-istream.c'; fi`
test_lib-test-byteorder.o: test-byteorder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-byteorder.o -MD -MP -MF $(DEPDIR)/test_lib-test-byteorder.Tpo -c -o test_lib-test-byteorder.o `test -f 'test-byteorder.c' || echo '$(srcdir)/'`test-byteorder.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-byteorder.Tpo $(DEPDIR)/test_lib-test-byteorder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-byteorder.c' object='test_lib-test-byteorder.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-byteorder.o `test -f 'test-byteorder.c' || echo '$(srcdir)/'`test-byteorder.c
test_lib-test-byteorder.obj: test-byteorder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-byteorder.obj -MD -MP -MF $(DEPDIR)/test_lib-test-byteorder.Tpo -c -o test_lib-test-byteorder.obj `if test -f 'test-byteorder.c'; then $(CYGPATH_W) 'test-byteorder.c'; else $(CYGPATH_W) '$(srcdir)/test-byteorder.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-byteorder.Tpo $(DEPDIR)/test_lib-test-byteorder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-byteorder.c' object='test_lib-test-byteorder.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-byteorder.obj `if test -f 'test-byteorder.c'; then $(CYGPATH_W) 'test-byteorder.c'; else $(CYGPATH_W) '$(srcdir)/test-byteorder.c'; fi`
test_lib-test-connection.o: test-connection.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-connection.o -MD -MP -MF $(DEPDIR)/test_lib-test-connection.Tpo -c -o test_lib-test-connection.o `test -f 'test-connection.c' || echo '$(srcdir)/'`test-connection.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-connection.Tpo $(DEPDIR)/test_lib-test-connection.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-connection.c' object='test_lib-test-connection.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-connection.o `test -f 'test-connection.c' || echo '$(srcdir)/'`test-connection.c
test_lib-test-connection.obj: test-connection.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-connection.obj -MD -MP -MF $(DEPDIR)/test_lib-test-connection.Tpo -c -o test_lib-test-connection.obj `if test -f 'test-connection.c'; then $(CYGPATH_W) 'test-connection.c'; else $(CYGPATH_W) '$(srcdir)/test-connection.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-connection.Tpo $(DEPDIR)/test_lib-test-connection.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-connection.c' object='test_lib-test-connection.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-connection.obj `if test -f 'test-connection.c'; then $(CYGPATH_W) 'test-connection.c'; else $(CYGPATH_W) '$(srcdir)/test-connection.c'; fi`
test_lib-test-crc32.o: test-crc32.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-crc32.o -MD -MP -MF $(DEPDIR)/test_lib-test-crc32.Tpo -c -o test_lib-test-crc32.o `test -f 'test-crc32.c' || echo '$(srcdir)/'`test-crc32.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-crc32.Tpo $(DEPDIR)/test_lib-test-crc32.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-crc32.c' object='test_lib-test-crc32.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-crc32.o `test -f 'test-crc32.c' || echo '$(srcdir)/'`test-crc32.c
test_lib-test-crc32.obj: test-crc32.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-crc32.obj -MD -MP -MF $(DEPDIR)/test_lib-test-crc32.Tpo -c -o test_lib-test-crc32.obj `if test -f 'test-crc32.c'; then $(CYGPATH_W) 'test-crc32.c'; else $(CYGPATH_W) '$(srcdir)/test-crc32.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-crc32.Tpo $(DEPDIR)/test_lib-test-crc32.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-crc32.c' object='test_lib-test-crc32.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-crc32.obj `if test -f 'test-crc32.c'; then $(CYGPATH_W) 'test-crc32.c'; else $(CYGPATH_W) '$(srcdir)/test-crc32.c'; fi`
test_lib-test-cpu-limit.o: test-cpu-limit.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-cpu-limit.o -MD -MP -MF $(DEPDIR)/test_lib-test-cpu-limit.Tpo -c -o test_lib-test-cpu-limit.o `test -f 'test-cpu-limit.c' || echo '$(srcdir)/'`test-cpu-limit.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-cpu-limit.Tpo $(DEPDIR)/test_lib-test-cpu-limit.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-cpu-limit.c' object='test_lib-test-cpu-limit.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-cpu-limit.o `test -f 'test-cpu-limit.c' || echo '$(srcdir)/'`test-cpu-limit.c
test_lib-test-cpu-limit.obj: test-cpu-limit.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-cpu-limit.obj -MD -MP -MF $(DEPDIR)/test_lib-test-cpu-limit.Tpo -c -o test_lib-test-cpu-limit.obj `if test -f 'test-cpu-limit.c'; then $(CYGPATH_W) 'test-cpu-limit.c'; else $(CYGPATH_W) '$(srcdir)/test-cpu-limit.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-cpu-limit.Tpo $(DEPDIR)/test_lib-test-cpu-limit.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-cpu-limit.c' object='test_lib-test-cpu-limit.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-cpu-limit.obj `if test -f 'test-cpu-limit.c'; then $(CYGPATH_W) 'test-cpu-limit.c'; else $(CYGPATH_W) '$(srcdir)/test-cpu-limit.c'; fi`
test_lib-test-data-stack.o: test-data-stack.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-data-stack.o -MD -MP -MF $(DEPDIR)/test_lib-test-data-stack.Tpo -c -o test_lib-test-data-stack.o `test -f 'test-data-stack.c' || echo '$(srcdir)/'`test-data-stack.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-data-stack.Tpo $(DEPDIR)/test_lib-test-data-stack.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-data-stack.c' object='test_lib-test-data-stack.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-data-stack.o `test -f 'test-data-stack.c' || echo '$(srcdir)/'`test-data-stack.c
test_lib-test-data-stack.obj: test-data-stack.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-data-stack.obj -MD -MP -MF $(DEPDIR)/test_lib-test-data-stack.Tpo -c -o test_lib-test-data-stack.obj `if test -f 'test-data-stack.c'; then $(CYGPATH_W) 'test-data-stack.c'; else $(CYGPATH_W) '$(srcdir)/test-data-stack.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-data-stack.Tpo $(DEPDIR)/test_lib-test-data-stack.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-data-stack.c' object='test_lib-test-data-stack.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-data-stack.obj `if test -f 'test-data-stack.c'; then $(CYGPATH_W) 'test-data-stack.c'; else $(CYGPATH_W) '$(srcdir)/test-data-stack.c'; fi`
test_lib-test-env-util.o: test-env-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-env-util.o -MD -MP -MF $(DEPDIR)/test_lib-test-env-util.Tpo -c -o test_lib-test-env-util.o `test -f 'test-env-util.c' || echo '$(srcdir)/'`test-env-util.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-env-util.Tpo $(DEPDIR)/test_lib-test-env-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-env-util.c' object='test_lib-test-env-util.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-env-util.o `test -f 'test-env-util.c' || echo '$(srcdir)/'`test-env-util.c
test_lib-test-env-util.obj: test-env-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-env-util.obj -MD -MP -MF $(DEPDIR)/test_lib-test-env-util.Tpo -c -o test_lib-test-env-util.obj `if test -f 'test-env-util.c'; then $(CYGPATH_W) 'test-env-util.c'; else $(CYGPATH_W) '$(srcdir)/test-env-util.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-env-util.Tpo $(DEPDIR)/test_lib-test-env-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-env-util.c' object='test_lib-test-env-util.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-env-util.obj `if test -f 'test-env-util.c'; then $(CYGPATH_W) 'test-env-util.c'; else $(CYGPATH_W) '$(srcdir)/test-env-util.c'; fi`
test_lib-test-event-category-register.o: test-event-category-register.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-category-register.o -MD -MP -MF $(DEPDIR)/test_lib-test-event-category-register.Tpo -c -o test_lib-test-event-category-register.o `test -f 'test-event-category-register.c' || echo '$(srcdir)/'`test-event-category-register.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-category-register.Tpo $(DEPDIR)/test_lib-test-event-category-register.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-category-register.c' object='test_lib-test-event-category-register.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-category-register.o `test -f 'test-event-category-register.c' || echo '$(srcdir)/'`test-event-category-register.c
test_lib-test-event-category-register.obj: test-event-category-register.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-category-register.obj -MD -MP -MF $(DEPDIR)/test_lib-test-event-category-register.Tpo -c -o test_lib-test-event-category-register.obj `if test -f 'test-event-category-register.c'; then $(CYGPATH_W) 'test-event-category-register.c'; else $(CYGPATH_W) '$(srcdir)/test-event-category-register.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-category-register.Tpo $(DEPDIR)/test_lib-test-event-category-register.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-category-register.c' object='test_lib-test-event-category-register.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-category-register.obj `if test -f 'test-event-category-register.c'; then $(CYGPATH_W) 'test-event-category-register.c'; else $(CYGPATH_W) '$(srcdir)/test-event-category-register.c'; fi`
test_lib-test-event-filter.o: test-event-filter.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter.o -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter.Tpo -c -o test_lib-test-event-filter.o `test -f 'test-event-filter.c' || echo '$(srcdir)/'`test-event-filter.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter.Tpo $(DEPDIR)/test_lib-test-event-filter.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter.c' object='test_lib-test-event-filter.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter.o `test -f 'test-event-filter.c' || echo '$(srcdir)/'`test-event-filter.c
test_lib-test-event-filter.obj: test-event-filter.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter.obj -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter.Tpo -c -o test_lib-test-event-filter.obj `if test -f 'test-event-filter.c'; then $(CYGPATH_W) 'test-event-filter.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter.Tpo $(DEPDIR)/test_lib-test-event-filter.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter.c' object='test_lib-test-event-filter.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter.obj `if test -f 'test-event-filter.c'; then $(CYGPATH_W) 'test-event-filter.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter.c'; fi`
test_lib-test-event-filter-expr.o: test-event-filter-expr.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter-expr.o -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter-expr.Tpo -c -o test_lib-test-event-filter-expr.o `test -f 'test-event-filter-expr.c' || echo '$(srcdir)/'`test-event-filter-expr.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter-expr.Tpo $(DEPDIR)/test_lib-test-event-filter-expr.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter-expr.c' object='test_lib-test-event-filter-expr.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter-expr.o `test -f 'test-event-filter-expr.c' || echo '$(srcdir)/'`test-event-filter-expr.c
test_lib-test-event-filter-expr.obj: test-event-filter-expr.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter-expr.obj -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter-expr.Tpo -c -o test_lib-test-event-filter-expr.obj `if test -f 'test-event-filter-expr.c'; then $(CYGPATH_W) 'test-event-filter-expr.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter-expr.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter-expr.Tpo $(DEPDIR)/test_lib-test-event-filter-expr.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter-expr.c' object='test_lib-test-event-filter-expr.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter-expr.obj `if test -f 'test-event-filter-expr.c'; then $(CYGPATH_W) 'test-event-filter-expr.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter-expr.c'; fi`
test_lib-test-event-filter-merge.o: test-event-filter-merge.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter-merge.o -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter-merge.Tpo -c -o test_lib-test-event-filter-merge.o `test -f 'test-event-filter-merge.c' || echo '$(srcdir)/'`test-event-filter-merge.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter-merge.Tpo $(DEPDIR)/test_lib-test-event-filter-merge.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter-merge.c' object='test_lib-test-event-filter-merge.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter-merge.o `test -f 'test-event-filter-merge.c' || echo '$(srcdir)/'`test-event-filter-merge.c
test_lib-test-event-filter-merge.obj: test-event-filter-merge.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter-merge.obj -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter-merge.Tpo -c -o test_lib-test-event-filter-merge.obj `if test -f 'test-event-filter-merge.c'; then $(CYGPATH_W) 'test-event-filter-merge.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter-merge.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter-merge.Tpo $(DEPDIR)/test_lib-test-event-filter-merge.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter-merge.c' object='test_lib-test-event-filter-merge.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter-merge.obj `if test -f 'test-event-filter-merge.c'; then $(CYGPATH_W) 'test-event-filter-merge.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter-merge.c'; fi`
test_lib-test-event-filter-parser.o: test-event-filter-parser.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter-parser.o -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter-parser.Tpo -c -o test_lib-test-event-filter-parser.o `test -f 'test-event-filter-parser.c' || echo '$(srcdir)/'`test-event-filter-parser.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter-parser.Tpo $(DEPDIR)/test_lib-test-event-filter-parser.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter-parser.c' object='test_lib-test-event-filter-parser.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter-parser.o `test -f 'test-event-filter-parser.c' || echo '$(srcdir)/'`test-event-filter-parser.c
test_lib-test-event-filter-parser.obj: test-event-filter-parser.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-filter-parser.obj -MD -MP -MF $(DEPDIR)/test_lib-test-event-filter-parser.Tpo -c -o test_lib-test-event-filter-parser.obj `if test -f 'test-event-filter-parser.c'; then $(CYGPATH_W) 'test-event-filter-parser.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter-parser.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-filter-parser.Tpo $(DEPDIR)/test_lib-test-event-filter-parser.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-filter-parser.c' object='test_lib-test-event-filter-parser.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-filter-parser.obj `if test -f 'test-event-filter-parser.c'; then $(CYGPATH_W) 'test-event-filter-parser.c'; else $(CYGPATH_W) '$(srcdir)/test-event-filter-parser.c'; fi`
test_lib-test-event-flatten.o: test-event-flatten.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-flatten.o -MD -MP -MF $(DEPDIR)/test_lib-test-event-flatten.Tpo -c -o test_lib-test-event-flatten.o `test -f 'test-event-flatten.c' || echo '$(srcdir)/'`test-event-flatten.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-flatten.Tpo $(DEPDIR)/test_lib-test-event-flatten.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-flatten.c' object='test_lib-test-event-flatten.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-flatten.o `test -f 'test-event-flatten.c' || echo '$(srcdir)/'`test-event-flatten.c
test_lib-test-event-flatten.obj: test-event-flatten.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-flatten.obj -MD -MP -MF $(DEPDIR)/test_lib-test-event-flatten.Tpo -c -o test_lib-test-event-flatten.obj `if test -f 'test-event-flatten.c'; then $(CYGPATH_W) 'test-event-flatten.c'; else $(CYGPATH_W) '$(srcdir)/test-event-flatten.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-flatten.Tpo $(DEPDIR)/test_lib-test-event-flatten.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-flatten.c' object='test_lib-test-event-flatten.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-flatten.obj `if test -f 'test-event-flatten.c'; then $(CYGPATH_W) 'test-event-flatten.c'; else $(CYGPATH_W) '$(srcdir)/test-event-flatten.c'; fi`
test_lib-test-event-log.o: test-event-log.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-log.o -MD -MP -MF $(DEPDIR)/test_lib-test-event-log.Tpo -c -o test_lib-test-event-log.o `test -f 'test-event-log.c' || echo '$(srcdir)/'`test-event-log.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-log.Tpo $(DEPDIR)/test_lib-test-event-log.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-log.c' object='test_lib-test-event-log.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-log.o `test -f 'test-event-log.c' || echo '$(srcdir)/'`test-event-log.c
test_lib-test-event-log.obj: test-event-log.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-event-log.obj -MD -MP -MF $(DEPDIR)/test_lib-test-event-log.Tpo -c -o test_lib-test-event-log.obj `if test -f 'test-event-log.c'; then $(CYGPATH_W) 'test-event-log.c'; else $(CYGPATH_W) '$(srcdir)/test-event-log.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-event-log.Tpo $(DEPDIR)/test_lib-test-event-log.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-event-log.c' object='test_lib-test-event-log.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-event-log.obj `if test -f 'test-event-log.c'; then $(CYGPATH_W) 'test-event-log.c'; else $(CYGPATH_W) '$(srcdir)/test-event-log.c'; fi`
test_lib-test-failures.o: test-failures.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-failures.o -MD -MP -MF $(DEPDIR)/test_lib-test-failures.Tpo -c -o test_lib-test-failures.o `test -f 'test-failures.c' || echo '$(srcdir)/'`test-failures.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-failures.Tpo $(DEPDIR)/test_lib-test-failures.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-failures.c' object='test_lib-test-failures.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-failures.o `test -f 'test-failures.c' || echo '$(srcdir)/'`test-failures.c
test_lib-test-failures.obj: test-failures.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-failures.obj -MD -MP -MF $(DEPDIR)/test_lib-test-failures.Tpo -c -o test_lib-test-failures.obj `if test -f 'test-failures.c'; then $(CYGPATH_W) 'test-failures.c'; else $(CYGPATH_W) '$(srcdir)/test-failures.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-failures.Tpo $(DEPDIR)/test_lib-test-failures.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-failures.c' object='test_lib-test-failures.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-failures.obj `if test -f 'test-failures.c'; then $(CYGPATH_W) 'test-failures.c'; else $(CYGPATH_W) '$(srcdir)/test-failures.c'; fi`
test_lib-test-fd-util.o: test-fd-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-fd-util.o -MD -MP -MF $(DEPDIR)/test_lib-test-fd-util.Tpo -c -o test_lib-test-fd-util.o `test -f 'test-fd-util.c' || echo '$(srcdir)/'`test-fd-util.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-fd-util.Tpo $(DEPDIR)/test_lib-test-fd-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-fd-util.c' object='test_lib-test-fd-util.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-fd-util.o `test -f 'test-fd-util.c' || echo '$(srcdir)/'`test-fd-util.c
test_lib-test-fd-util.obj: test-fd-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-fd-util.obj -MD -MP -MF $(DEPDIR)/test_lib-test-fd-util.Tpo -c -o test_lib-test-fd-util.obj `if test -f 'test-fd-util.c'; then $(CYGPATH_W) 'test-fd-util.c'; else $(CYGPATH_W) '$(srcdir)/test-fd-util.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-fd-util.Tpo $(DEPDIR)/test_lib-test-fd-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-fd-util.c' object='test_lib-test-fd-util.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-fd-util.obj `if test -f 'test-fd-util.c'; then $(CYGPATH_W) 'test-fd-util.c'; else $(CYGPATH_W) '$(srcdir)/test-fd-util.c'; fi`
test_lib-test-file-cache.o: test-file-cache.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-file-cache.o -MD -MP -MF $(DEPDIR)/test_lib-test-file-cache.Tpo -c -o test_lib-test-file-cache.o `test -f 'test-file-cache.c' || echo '$(srcdir)/'`test-file-cache.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-file-cache.Tpo $(DEPDIR)/test_lib-test-file-cache.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-file-cache.c' object='test_lib-test-file-cache.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-file-cache.o `test -f 'test-file-cache.c' || echo '$(srcdir)/'`test-file-cache.c
test_lib-test-file-cache.obj: test-file-cache.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-file-cache.obj -MD -MP -MF $(DEPDIR)/test_lib-test-file-cache.Tpo -c -o test_lib-test-file-cache.obj `if test -f 'test-file-cache.c'; then $(CYGPATH_W) 'test-file-cache.c'; else $(CYGPATH_W) '$(srcdir)/test-file-cache.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-file-cache.Tpo $(DEPDIR)/test_lib-test-file-cache.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-file-cache.c' object='test_lib-test-file-cache.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-file-cache.obj `if test -f 'test-file-cache.c'; then $(CYGPATH_W) 'test-file-cache.c'; else $(CYGPATH_W) '$(srcdir)/test-file-cache.c'; fi`
test_lib-test-file-create-locked.o: test-file-create-locked.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-file-create-locked.o -MD -MP -MF $(DEPDIR)/test_lib-test-file-create-locked.Tpo -c -o test_lib-test-file-create-locked.o `test -f 'test-file-create-locked.c' || echo '$(srcdir)/'`test-file-create-locked.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-file-create-locked.Tpo $(DEPDIR)/test_lib-test-file-create-locked.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-file-create-locked.c' object='test_lib-test-file-create-locked.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-file-create-locked.o `test -f 'test-file-create-locked.c' || echo '$(srcdir)/'`test-file-create-locked.c
test_lib-test-file-create-locked.obj: test-file-create-locked.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-file-create-locked.obj -MD -MP -MF $(DEPDIR)/test_lib-test-file-create-locked.Tpo -c -o test_lib-test-file-create-locked.obj `if test -f 'test-file-create-locked.c'; then $(CYGPATH_W) 'test-file-create-locked.c'; else $(CYGPATH_W) '$(srcdir)/test-file-create-locked.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-file-create-locked.Tpo $(DEPDIR)/test_lib-test-file-create-locked.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-file-create-locked.c' object='test_lib-test-file-create-locked.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-file-create-locked.obj `if test -f 'test-file-create-locked.c'; then $(CYGPATH_W) 'test-file-create-locked.c'; else $(CYGPATH_W) '$(srcdir)/test-file-create-locked.c'; fi`
test_lib-test-guid.o: test-guid.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-guid.o -MD -MP -MF $(DEPDIR)/test_lib-test-guid.Tpo -c -o test_lib-test-guid.o `test -f 'test-guid.c' || echo '$(srcdir)/'`test-guid.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-guid.Tpo $(DEPDIR)/test_lib-test-guid.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-guid.c' object='test_lib-test-guid.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-guid.o `test -f 'test-guid.c' || echo '$(srcdir)/'`test-guid.c
test_lib-test-guid.obj: test-guid.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-guid.obj -MD -MP -MF $(DEPDIR)/test_lib-test-guid.Tpo -c -o test_lib-test-guid.obj `if test -f 'test-guid.c'; then $(CYGPATH_W) 'test-guid.c'; else $(CYGPATH_W) '$(srcdir)/test-guid.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-guid.Tpo $(DEPDIR)/test_lib-test-guid.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-guid.c' object='test_lib-test-guid.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-guid.obj `if test -f 'test-guid.c'; then $(CYGPATH_W) 'test-guid.c'; else $(CYGPATH_W) '$(srcdir)/test-guid.c'; fi`
test_lib-test-hash.o: test-hash.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hash.o -MD -MP -MF $(DEPDIR)/test_lib-test-hash.Tpo -c -o test_lib-test-hash.o `test -f 'test-hash.c' || echo '$(srcdir)/'`test-hash.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hash.Tpo $(DEPDIR)/test_lib-test-hash.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hash.c' object='test_lib-test-hash.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hash.o `test -f 'test-hash.c' || echo '$(srcdir)/'`test-hash.c
test_lib-test-hash.obj: test-hash.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hash.obj -MD -MP -MF $(DEPDIR)/test_lib-test-hash.Tpo -c -o test_lib-test-hash.obj `if test -f 'test-hash.c'; then $(CYGPATH_W) 'test-hash.c'; else $(CYGPATH_W) '$(srcdir)/test-hash.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hash.Tpo $(DEPDIR)/test_lib-test-hash.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hash.c' object='test_lib-test-hash.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hash.obj `if test -f 'test-hash.c'; then $(CYGPATH_W) 'test-hash.c'; else $(CYGPATH_W) '$(srcdir)/test-hash.c'; fi`
test_lib-test-hash-format.o: test-hash-format.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hash-format.o -MD -MP -MF $(DEPDIR)/test_lib-test-hash-format.Tpo -c -o test_lib-test-hash-format.o `test -f 'test-hash-format.c' || echo '$(srcdir)/'`test-hash-format.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hash-format.Tpo $(DEPDIR)/test_lib-test-hash-format.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hash-format.c' object='test_lib-test-hash-format.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hash-format.o `test -f 'test-hash-format.c' || echo '$(srcdir)/'`test-hash-format.c
test_lib-test-hash-format.obj: test-hash-format.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hash-format.obj -MD -MP -MF $(DEPDIR)/test_lib-test-hash-format.Tpo -c -o test_lib-test-hash-format.obj `if test -f 'test-hash-format.c'; then $(CYGPATH_W) 'test-hash-format.c'; else $(CYGPATH_W) '$(srcdir)/test-hash-format.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hash-format.Tpo $(DEPDIR)/test_lib-test-hash-format.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hash-format.c' object='test_lib-test-hash-format.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hash-format.obj `if test -f 'test-hash-format.c'; then $(CYGPATH_W) 'test-hash-format.c'; else $(CYGPATH_W) '$(srcdir)/test-hash-format.c'; fi`
test_lib-test-hash-method.o: test-hash-method.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hash-method.o -MD -MP -MF $(DEPDIR)/test_lib-test-hash-method.Tpo -c -o test_lib-test-hash-method.o `test -f 'test-hash-method.c' || echo '$(srcdir)/'`test-hash-method.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hash-method.Tpo $(DEPDIR)/test_lib-test-hash-method.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hash-method.c' object='test_lib-test-hash-method.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hash-method.o `test -f 'test-hash-method.c' || echo '$(srcdir)/'`test-hash-method.c
test_lib-test-hash-method.obj: test-hash-method.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hash-method.obj -MD -MP -MF $(DEPDIR)/test_lib-test-hash-method.Tpo -c -o test_lib-test-hash-method.obj `if test -f 'test-hash-method.c'; then $(CYGPATH_W) 'test-hash-method.c'; else $(CYGPATH_W) '$(srcdir)/test-hash-method.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hash-method.Tpo $(DEPDIR)/test_lib-test-hash-method.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hash-method.c' object='test_lib-test-hash-method.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hash-method.obj `if test -f 'test-hash-method.c'; then $(CYGPATH_W) 'test-hash-method.c'; else $(CYGPATH_W) '$(srcdir)/test-hash-method.c'; fi`
test_lib-test-hmac.o: test-hmac.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hmac.o -MD -MP -MF $(DEPDIR)/test_lib-test-hmac.Tpo -c -o test_lib-test-hmac.o `test -f 'test-hmac.c' || echo '$(srcdir)/'`test-hmac.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hmac.Tpo $(DEPDIR)/test_lib-test-hmac.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hmac.c' object='test_lib-test-hmac.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hmac.o `test -f 'test-hmac.c' || echo '$(srcdir)/'`test-hmac.c
test_lib-test-hmac.obj: test-hmac.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hmac.obj -MD -MP -MF $(DEPDIR)/test_lib-test-hmac.Tpo -c -o test_lib-test-hmac.obj `if test -f 'test-hmac.c'; then $(CYGPATH_W) 'test-hmac.c'; else $(CYGPATH_W) '$(srcdir)/test-hmac.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hmac.Tpo $(DEPDIR)/test_lib-test-hmac.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hmac.c' object='test_lib-test-hmac.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hmac.obj `if test -f 'test-hmac.c'; then $(CYGPATH_W) 'test-hmac.c'; else $(CYGPATH_W) '$(srcdir)/test-hmac.c'; fi`
test_lib-test-hex-binary.o: test-hex-binary.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hex-binary.o -MD -MP -MF $(DEPDIR)/test_lib-test-hex-binary.Tpo -c -o test_lib-test-hex-binary.o `test -f 'test-hex-binary.c' || echo '$(srcdir)/'`test-hex-binary.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hex-binary.Tpo $(DEPDIR)/test_lib-test-hex-binary.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hex-binary.c' object='test_lib-test-hex-binary.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hex-binary.o `test -f 'test-hex-binary.c' || echo '$(srcdir)/'`test-hex-binary.c
test_lib-test-hex-binary.obj: test-hex-binary.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-hex-binary.obj -MD -MP -MF $(DEPDIR)/test_lib-test-hex-binary.Tpo -c -o test_lib-test-hex-binary.obj `if test -f 'test-hex-binary.c'; then $(CYGPATH_W) 'test-hex-binary.c'; else $(CYGPATH_W) '$(srcdir)/test-hex-binary.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-hex-binary.Tpo $(DEPDIR)/test_lib-test-hex-binary.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-hex-binary.c' object='test_lib-test-hex-binary.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-hex-binary.obj `if test -f 'test-hex-binary.c'; then $(CYGPATH_W) 'test-hex-binary.c'; else $(CYGPATH_W) '$(srcdir)/test-hex-binary.c'; fi`
test_lib-test-imem.o: test-imem.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-imem.o -MD -MP -MF $(DEPDIR)/test_lib-test-imem.Tpo -c -o test_lib-test-imem.o `test -f 'test-imem.c' || echo '$(srcdir)/'`test-imem.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-imem.Tpo $(DEPDIR)/test_lib-test-imem.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-imem.c' object='test_lib-test-imem.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-imem.o `test -f 'test-imem.c' || echo '$(srcdir)/'`test-imem.c
test_lib-test-imem.obj: test-imem.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-imem.obj -MD -MP -MF $(DEPDIR)/test_lib-test-imem.Tpo -c -o test_lib-test-imem.obj `if test -f 'test-imem.c'; then $(CYGPATH_W) 'test-imem.c'; else $(CYGPATH_W) '$(srcdir)/test-imem.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-imem.Tpo $(DEPDIR)/test_lib-test-imem.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-imem.c' object='test_lib-test-imem.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-imem.obj `if test -f 'test-imem.c'; then $(CYGPATH_W) 'test-imem.c'; else $(CYGPATH_W) '$(srcdir)/test-imem.c'; fi`
test_lib-test-ioloop.o: test-ioloop.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ioloop.o -MD -MP -MF $(DEPDIR)/test_lib-test-ioloop.Tpo -c -o test_lib-test-ioloop.o `test -f 'test-ioloop.c' || echo '$(srcdir)/'`test-ioloop.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ioloop.Tpo $(DEPDIR)/test_lib-test-ioloop.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ioloop.c' object='test_lib-test-ioloop.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ioloop.o `test -f 'test-ioloop.c' || echo '$(srcdir)/'`test-ioloop.c
test_lib-test-ioloop.obj: test-ioloop.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ioloop.obj -MD -MP -MF $(DEPDIR)/test_lib-test-ioloop.Tpo -c -o test_lib-test-ioloop.obj `if test -f 'test-ioloop.c'; then $(CYGPATH_W) 'test-ioloop.c'; else $(CYGPATH_W) '$(srcdir)/test-ioloop.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ioloop.Tpo $(DEPDIR)/test_lib-test-ioloop.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ioloop.c' object='test_lib-test-ioloop.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ioloop.obj `if test -f 'test-ioloop.c'; then $(CYGPATH_W) 'test-ioloop.c'; else $(CYGPATH_W) '$(srcdir)/test-ioloop.c'; fi`
test_lib-test-iso8601-date.o: test-iso8601-date.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iso8601-date.o -MD -MP -MF $(DEPDIR)/test_lib-test-iso8601-date.Tpo -c -o test_lib-test-iso8601-date.o `test -f 'test-iso8601-date.c' || echo '$(srcdir)/'`test-iso8601-date.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iso8601-date.Tpo $(DEPDIR)/test_lib-test-iso8601-date.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iso8601-date.c' object='test_lib-test-iso8601-date.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iso8601-date.o `test -f 'test-iso8601-date.c' || echo '$(srcdir)/'`test-iso8601-date.c
test_lib-test-iso8601-date.obj: test-iso8601-date.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iso8601-date.obj -MD -MP -MF $(DEPDIR)/test_lib-test-iso8601-date.Tpo -c -o test_lib-test-iso8601-date.obj `if test -f 'test-iso8601-date.c'; then $(CYGPATH_W) 'test-iso8601-date.c'; else $(CYGPATH_W) '$(srcdir)/test-iso8601-date.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iso8601-date.Tpo $(DEPDIR)/test_lib-test-iso8601-date.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iso8601-date.c' object='test_lib-test-iso8601-date.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iso8601-date.obj `if test -f 'test-iso8601-date.c'; then $(CYGPATH_W) 'test-iso8601-date.c'; else $(CYGPATH_W) '$(srcdir)/test-iso8601-date.c'; fi`
test_lib-test-iostream-pump.o: test-iostream-pump.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iostream-pump.o -MD -MP -MF $(DEPDIR)/test_lib-test-iostream-pump.Tpo -c -o test_lib-test-iostream-pump.o `test -f 'test-iostream-pump.c' || echo '$(srcdir)/'`test-iostream-pump.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iostream-pump.Tpo $(DEPDIR)/test_lib-test-iostream-pump.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iostream-pump.c' object='test_lib-test-iostream-pump.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iostream-pump.o `test -f 'test-iostream-pump.c' || echo '$(srcdir)/'`test-iostream-pump.c
test_lib-test-iostream-pump.obj: test-iostream-pump.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iostream-pump.obj -MD -MP -MF $(DEPDIR)/test_lib-test-iostream-pump.Tpo -c -o test_lib-test-iostream-pump.obj `if test -f 'test-iostream-pump.c'; then $(CYGPATH_W) 'test-iostream-pump.c'; else $(CYGPATH_W) '$(srcdir)/test-iostream-pump.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iostream-pump.Tpo $(DEPDIR)/test_lib-test-iostream-pump.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iostream-pump.c' object='test_lib-test-iostream-pump.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iostream-pump.obj `if test -f 'test-iostream-pump.c'; then $(CYGPATH_W) 'test-iostream-pump.c'; else $(CYGPATH_W) '$(srcdir)/test-iostream-pump.c'; fi`
test_lib-test-iostream-proxy.o: test-iostream-proxy.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iostream-proxy.o -MD -MP -MF $(DEPDIR)/test_lib-test-iostream-proxy.Tpo -c -o test_lib-test-iostream-proxy.o `test -f 'test-iostream-proxy.c' || echo '$(srcdir)/'`test-iostream-proxy.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iostream-proxy.Tpo $(DEPDIR)/test_lib-test-iostream-proxy.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iostream-proxy.c' object='test_lib-test-iostream-proxy.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iostream-proxy.o `test -f 'test-iostream-proxy.c' || echo '$(srcdir)/'`test-iostream-proxy.c
test_lib-test-iostream-proxy.obj: test-iostream-proxy.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iostream-proxy.obj -MD -MP -MF $(DEPDIR)/test_lib-test-iostream-proxy.Tpo -c -o test_lib-test-iostream-proxy.obj `if test -f 'test-iostream-proxy.c'; then $(CYGPATH_W) 'test-iostream-proxy.c'; else $(CYGPATH_W) '$(srcdir)/test-iostream-proxy.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iostream-proxy.Tpo $(DEPDIR)/test_lib-test-iostream-proxy.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iostream-proxy.c' object='test_lib-test-iostream-proxy.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iostream-proxy.obj `if test -f 'test-iostream-proxy.c'; then $(CYGPATH_W) 'test-iostream-proxy.c'; else $(CYGPATH_W) '$(srcdir)/test-iostream-proxy.c'; fi`
test_lib-test-iostream-temp.o: test-iostream-temp.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iostream-temp.o -MD -MP -MF $(DEPDIR)/test_lib-test-iostream-temp.Tpo -c -o test_lib-test-iostream-temp.o `test -f 'test-iostream-temp.c' || echo '$(srcdir)/'`test-iostream-temp.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iostream-temp.Tpo $(DEPDIR)/test_lib-test-iostream-temp.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iostream-temp.c' object='test_lib-test-iostream-temp.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iostream-temp.o `test -f 'test-iostream-temp.c' || echo '$(srcdir)/'`test-iostream-temp.c
test_lib-test-iostream-temp.obj: test-iostream-temp.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-iostream-temp.obj -MD -MP -MF $(DEPDIR)/test_lib-test-iostream-temp.Tpo -c -o test_lib-test-iostream-temp.obj `if test -f 'test-iostream-temp.c'; then $(CYGPATH_W) 'test-iostream-temp.c'; else $(CYGPATH_W) '$(srcdir)/test-iostream-temp.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-iostream-temp.Tpo $(DEPDIR)/test_lib-test-iostream-temp.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-iostream-temp.c' object='test_lib-test-iostream-temp.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-iostream-temp.obj `if test -f 'test-iostream-temp.c'; then $(CYGPATH_W) 'test-iostream-temp.c'; else $(CYGPATH_W) '$(srcdir)/test-iostream-temp.c'; fi`
test_lib-test-istream.o: test-istream.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream.Tpo -c -o test_lib-test-istream.o `test -f 'test-istream.c' || echo '$(srcdir)/'`test-istream.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream.Tpo $(DEPDIR)/test_lib-test-istream.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream.c' object='test_lib-test-istream.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream.o `test -f 'test-istream.c' || echo '$(srcdir)/'`test-istream.c
test_lib-test-istream.obj: test-istream.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream.Tpo -c -o test_lib-test-istream.obj `if test -f 'test-istream.c'; then $(CYGPATH_W) 'test-istream.c'; else $(CYGPATH_W) '$(srcdir)/test-istream.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream.Tpo $(DEPDIR)/test_lib-test-istream.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream.c' object='test_lib-test-istream.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream.obj `if test -f 'test-istream.c'; then $(CYGPATH_W) 'test-istream.c'; else $(CYGPATH_W) '$(srcdir)/test-istream.c'; fi`
test_lib-test-istream-base64-decoder.o: test-istream-base64-decoder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-base64-decoder.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-base64-decoder.Tpo -c -o test_lib-test-istream-base64-decoder.o `test -f 'test-istream-base64-decoder.c' || echo '$(srcdir)/'`test-istream-base64-decoder.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-base64-decoder.Tpo $(DEPDIR)/test_lib-test-istream-base64-decoder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-base64-decoder.c' object='test_lib-test-istream-base64-decoder.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-base64-decoder.o `test -f 'test-istream-base64-decoder.c' || echo '$(srcdir)/'`test-istream-base64-decoder.c
test_lib-test-istream-base64-decoder.obj: test-istream-base64-decoder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-base64-decoder.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-base64-decoder.Tpo -c -o test_lib-test-istream-base64-decoder.obj `if test -f 'test-istream-base64-decoder.c'; then $(CYGPATH_W) 'test-istream-base64-decoder.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-base64-decoder.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-base64-decoder.Tpo $(DEPDIR)/test_lib-test-istream-base64-decoder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-base64-decoder.c' object='test_lib-test-istream-base64-decoder.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-base64-decoder.obj `if test -f 'test-istream-base64-decoder.c'; then $(CYGPATH_W) 'test-istream-base64-decoder.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-base64-decoder.c'; fi`
test_lib-test-istream-base64-encoder.o: test-istream-base64-encoder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-base64-encoder.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-base64-encoder.Tpo -c -o test_lib-test-istream-base64-encoder.o `test -f 'test-istream-base64-encoder.c' || echo '$(srcdir)/'`test-istream-base64-encoder.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-base64-encoder.Tpo $(DEPDIR)/test_lib-test-istream-base64-encoder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-base64-encoder.c' object='test_lib-test-istream-base64-encoder.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-base64-encoder.o `test -f 'test-istream-base64-encoder.c' || echo '$(srcdir)/'`test-istream-base64-encoder.c
test_lib-test-istream-base64-encoder.obj: test-istream-base64-encoder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-base64-encoder.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-base64-encoder.Tpo -c -o test_lib-test-istream-base64-encoder.obj `if test -f 'test-istream-base64-encoder.c'; then $(CYGPATH_W) 'test-istream-base64-encoder.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-base64-encoder.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-base64-encoder.Tpo $(DEPDIR)/test_lib-test-istream-base64-encoder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-base64-encoder.c' object='test_lib-test-istream-base64-encoder.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-base64-encoder.obj `if test -f 'test-istream-base64-encoder.c'; then $(CYGPATH_W) 'test-istream-base64-encoder.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-base64-encoder.c'; fi`
test_lib-test-istream-chain.o: test-istream-chain.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-chain.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-chain.Tpo -c -o test_lib-test-istream-chain.o `test -f 'test-istream-chain.c' || echo '$(srcdir)/'`test-istream-chain.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-chain.Tpo $(DEPDIR)/test_lib-test-istream-chain.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-chain.c' object='test_lib-test-istream-chain.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-chain.o `test -f 'test-istream-chain.c' || echo '$(srcdir)/'`test-istream-chain.c
test_lib-test-istream-chain.obj: test-istream-chain.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-chain.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-chain.Tpo -c -o test_lib-test-istream-chain.obj `if test -f 'test-istream-chain.c'; then $(CYGPATH_W) 'test-istream-chain.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-chain.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-chain.Tpo $(DEPDIR)/test_lib-test-istream-chain.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-chain.c' object='test_lib-test-istream-chain.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-chain.obj `if test -f 'test-istream-chain.c'; then $(CYGPATH_W) 'test-istream-chain.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-chain.c'; fi`
test_lib-test-istream-concat.o: test-istream-concat.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-concat.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-concat.Tpo -c -o test_lib-test-istream-concat.o `test -f 'test-istream-concat.c' || echo '$(srcdir)/'`test-istream-concat.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-concat.Tpo $(DEPDIR)/test_lib-test-istream-concat.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-concat.c' object='test_lib-test-istream-concat.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-concat.o `test -f 'test-istream-concat.c' || echo '$(srcdir)/'`test-istream-concat.c
test_lib-test-istream-concat.obj: test-istream-concat.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-concat.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-concat.Tpo -c -o test_lib-test-istream-concat.obj `if test -f 'test-istream-concat.c'; then $(CYGPATH_W) 'test-istream-concat.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-concat.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-concat.Tpo $(DEPDIR)/test_lib-test-istream-concat.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-concat.c' object='test_lib-test-istream-concat.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-concat.obj `if test -f 'test-istream-concat.c'; then $(CYGPATH_W) 'test-istream-concat.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-concat.c'; fi`
test_lib-test-istream-crlf.o: test-istream-crlf.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-crlf.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-crlf.Tpo -c -o test_lib-test-istream-crlf.o `test -f 'test-istream-crlf.c' || echo '$(srcdir)/'`test-istream-crlf.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-crlf.Tpo $(DEPDIR)/test_lib-test-istream-crlf.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-crlf.c' object='test_lib-test-istream-crlf.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-crlf.o `test -f 'test-istream-crlf.c' || echo '$(srcdir)/'`test-istream-crlf.c
test_lib-test-istream-crlf.obj: test-istream-crlf.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-crlf.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-crlf.Tpo -c -o test_lib-test-istream-crlf.obj `if test -f 'test-istream-crlf.c'; then $(CYGPATH_W) 'test-istream-crlf.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-crlf.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-crlf.Tpo $(DEPDIR)/test_lib-test-istream-crlf.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-crlf.c' object='test_lib-test-istream-crlf.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-crlf.obj `if test -f 'test-istream-crlf.c'; then $(CYGPATH_W) 'test-istream-crlf.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-crlf.c'; fi`
test_lib-test-istream-failure-at.o: test-istream-failure-at.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-failure-at.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-failure-at.Tpo -c -o test_lib-test-istream-failure-at.o `test -f 'test-istream-failure-at.c' || echo '$(srcdir)/'`test-istream-failure-at.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-failure-at.Tpo $(DEPDIR)/test_lib-test-istream-failure-at.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-failure-at.c' object='test_lib-test-istream-failure-at.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-failure-at.o `test -f 'test-istream-failure-at.c' || echo '$(srcdir)/'`test-istream-failure-at.c
test_lib-test-istream-failure-at.obj: test-istream-failure-at.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-failure-at.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-failure-at.Tpo -c -o test_lib-test-istream-failure-at.obj `if test -f 'test-istream-failure-at.c'; then $(CYGPATH_W) 'test-istream-failure-at.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-failure-at.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-failure-at.Tpo $(DEPDIR)/test_lib-test-istream-failure-at.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-failure-at.c' object='test_lib-test-istream-failure-at.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-failure-at.obj `if test -f 'test-istream-failure-at.c'; then $(CYGPATH_W) 'test-istream-failure-at.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-failure-at.c'; fi`
test_lib-test-istream-jsonstr.o: test-istream-jsonstr.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-jsonstr.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-jsonstr.Tpo -c -o test_lib-test-istream-jsonstr.o `test -f 'test-istream-jsonstr.c' || echo '$(srcdir)/'`test-istream-jsonstr.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-jsonstr.Tpo $(DEPDIR)/test_lib-test-istream-jsonstr.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-jsonstr.c' object='test_lib-test-istream-jsonstr.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-jsonstr.o `test -f 'test-istream-jsonstr.c' || echo '$(srcdir)/'`test-istream-jsonstr.c
test_lib-test-istream-jsonstr.obj: test-istream-jsonstr.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-jsonstr.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-jsonstr.Tpo -c -o test_lib-test-istream-jsonstr.obj `if test -f 'test-istream-jsonstr.c'; then $(CYGPATH_W) 'test-istream-jsonstr.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-jsonstr.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-jsonstr.Tpo $(DEPDIR)/test_lib-test-istream-jsonstr.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-jsonstr.c' object='test_lib-test-istream-jsonstr.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-jsonstr.obj `if test -f 'test-istream-jsonstr.c'; then $(CYGPATH_W) 'test-istream-jsonstr.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-jsonstr.c'; fi`
test_lib-test-istream-multiplex.o: test-istream-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-multiplex.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-multiplex.Tpo -c -o test_lib-test-istream-multiplex.o `test -f 'test-istream-multiplex.c' || echo '$(srcdir)/'`test-istream-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-multiplex.Tpo $(DEPDIR)/test_lib-test-istream-multiplex.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-multiplex.c' object='test_lib-test-istream-multiplex.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-multiplex.o `test -f 'test-istream-multiplex.c' || echo '$(srcdir)/'`test-istream-multiplex.c
test_lib-test-istream-multiplex.obj: test-istream-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-multiplex.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-multiplex.Tpo -c -o test_lib-test-istream-multiplex.obj `if test -f 'test-istream-multiplex.c'; then $(CYGPATH_W) 'test-istream-multiplex.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-multiplex.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-multiplex.Tpo $(DEPDIR)/test_lib-test-istream-multiplex.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-multiplex.c' object='test_lib-test-istream-multiplex.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-multiplex.obj `if test -f 'test-istream-multiplex.c'; then $(CYGPATH_W) 'test-istream-multiplex.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-multiplex.c'; fi`
test_lib-test-istream-seekable.o: test-istream-seekable.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-seekable.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-seekable.Tpo -c -o test_lib-test-istream-seekable.o `test -f 'test-istream-seekable.c' || echo '$(srcdir)/'`test-istream-seekable.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-seekable.Tpo $(DEPDIR)/test_lib-test-istream-seekable.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-seekable.c' object='test_lib-test-istream-seekable.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-seekable.o `test -f 'test-istream-seekable.c' || echo '$(srcdir)/'`test-istream-seekable.c
test_lib-test-istream-seekable.obj: test-istream-seekable.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-seekable.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-seekable.Tpo -c -o test_lib-test-istream-seekable.obj `if test -f 'test-istream-seekable.c'; then $(CYGPATH_W) 'test-istream-seekable.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-seekable.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-seekable.Tpo $(DEPDIR)/test_lib-test-istream-seekable.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-seekable.c' object='test_lib-test-istream-seekable.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-seekable.obj `if test -f 'test-istream-seekable.c'; then $(CYGPATH_W) 'test-istream-seekable.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-seekable.c'; fi`
test_lib-test-istream-sized.o: test-istream-sized.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-sized.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-sized.Tpo -c -o test_lib-test-istream-sized.o `test -f 'test-istream-sized.c' || echo '$(srcdir)/'`test-istream-sized.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-sized.Tpo $(DEPDIR)/test_lib-test-istream-sized.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-sized.c' object='test_lib-test-istream-sized.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-sized.o `test -f 'test-istream-sized.c' || echo '$(srcdir)/'`test-istream-sized.c
test_lib-test-istream-sized.obj: test-istream-sized.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-sized.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-sized.Tpo -c -o test_lib-test-istream-sized.obj `if test -f 'test-istream-sized.c'; then $(CYGPATH_W) 'test-istream-sized.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-sized.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-sized.Tpo $(DEPDIR)/test_lib-test-istream-sized.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-sized.c' object='test_lib-test-istream-sized.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-sized.obj `if test -f 'test-istream-sized.c'; then $(CYGPATH_W) 'test-istream-sized.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-sized.c'; fi`
test_lib-test-istream-tee.o: test-istream-tee.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-tee.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-tee.Tpo -c -o test_lib-test-istream-tee.o `test -f 'test-istream-tee.c' || echo '$(srcdir)/'`test-istream-tee.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-tee.Tpo $(DEPDIR)/test_lib-test-istream-tee.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-tee.c' object='test_lib-test-istream-tee.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-tee.o `test -f 'test-istream-tee.c' || echo '$(srcdir)/'`test-istream-tee.c
test_lib-test-istream-tee.obj: test-istream-tee.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-tee.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-tee.Tpo -c -o test_lib-test-istream-tee.obj `if test -f 'test-istream-tee.c'; then $(CYGPATH_W) 'test-istream-tee.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-tee.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-tee.Tpo $(DEPDIR)/test_lib-test-istream-tee.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-tee.c' object='test_lib-test-istream-tee.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-tee.obj `if test -f 'test-istream-tee.c'; then $(CYGPATH_W) 'test-istream-tee.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-tee.c'; fi`
test_lib-test-istream-try.o: test-istream-try.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-try.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-try.Tpo -c -o test_lib-test-istream-try.o `test -f 'test-istream-try.c' || echo '$(srcdir)/'`test-istream-try.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-try.Tpo $(DEPDIR)/test_lib-test-istream-try.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-try.c' object='test_lib-test-istream-try.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-try.o `test -f 'test-istream-try.c' || echo '$(srcdir)/'`test-istream-try.c
test_lib-test-istream-try.obj: test-istream-try.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-try.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-try.Tpo -c -o test_lib-test-istream-try.obj `if test -f 'test-istream-try.c'; then $(CYGPATH_W) 'test-istream-try.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-try.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-try.Tpo $(DEPDIR)/test_lib-test-istream-try.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-try.c' object='test_lib-test-istream-try.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-try.obj `if test -f 'test-istream-try.c'; then $(CYGPATH_W) 'test-istream-try.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-try.c'; fi`
test_lib-test-istream-unix.o: test-istream-unix.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-unix.o -MD -MP -MF $(DEPDIR)/test_lib-test-istream-unix.Tpo -c -o test_lib-test-istream-unix.o `test -f 'test-istream-unix.c' || echo '$(srcdir)/'`test-istream-unix.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-unix.Tpo $(DEPDIR)/test_lib-test-istream-unix.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-unix.c' object='test_lib-test-istream-unix.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-unix.o `test -f 'test-istream-unix.c' || echo '$(srcdir)/'`test-istream-unix.c
test_lib-test-istream-unix.obj: test-istream-unix.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-istream-unix.obj -MD -MP -MF $(DEPDIR)/test_lib-test-istream-unix.Tpo -c -o test_lib-test-istream-unix.obj `if test -f 'test-istream-unix.c'; then $(CYGPATH_W) 'test-istream-unix.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-unix.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-istream-unix.Tpo $(DEPDIR)/test_lib-test-istream-unix.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-istream-unix.c' object='test_lib-test-istream-unix.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-istream-unix.obj `if test -f 'test-istream-unix.c'; then $(CYGPATH_W) 'test-istream-unix.c'; else $(CYGPATH_W) '$(srcdir)/test-istream-unix.c'; fi`
test_lib-test-json-parser.o: test-json-parser.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-json-parser.o -MD -MP -MF $(DEPDIR)/test_lib-test-json-parser.Tpo -c -o test_lib-test-json-parser.o `test -f 'test-json-parser.c' || echo '$(srcdir)/'`test-json-parser.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-json-parser.Tpo $(DEPDIR)/test_lib-test-json-parser.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-json-parser.c' object='test_lib-test-json-parser.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-json-parser.o `test -f 'test-json-parser.c' || echo '$(srcdir)/'`test-json-parser.c
test_lib-test-json-parser.obj: test-json-parser.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-json-parser.obj -MD -MP -MF $(DEPDIR)/test_lib-test-json-parser.Tpo -c -o test_lib-test-json-parser.obj `if test -f 'test-json-parser.c'; then $(CYGPATH_W) 'test-json-parser.c'; else $(CYGPATH_W) '$(srcdir)/test-json-parser.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-json-parser.Tpo $(DEPDIR)/test_lib-test-json-parser.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-json-parser.c' object='test_lib-test-json-parser.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-json-parser.obj `if test -f 'test-json-parser.c'; then $(CYGPATH_W) 'test-json-parser.c'; else $(CYGPATH_W) '$(srcdir)/test-json-parser.c'; fi`
test_lib-test-json-tree.o: test-json-tree.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-json-tree.o -MD -MP -MF $(DEPDIR)/test_lib-test-json-tree.Tpo -c -o test_lib-test-json-tree.o `test -f 'test-json-tree.c' || echo '$(srcdir)/'`test-json-tree.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-json-tree.Tpo $(DEPDIR)/test_lib-test-json-tree.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-json-tree.c' object='test_lib-test-json-tree.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-json-tree.o `test -f 'test-json-tree.c' || echo '$(srcdir)/'`test-json-tree.c
test_lib-test-json-tree.obj: test-json-tree.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-json-tree.obj -MD -MP -MF $(DEPDIR)/test_lib-test-json-tree.Tpo -c -o test_lib-test-json-tree.obj `if test -f 'test-json-tree.c'; then $(CYGPATH_W) 'test-json-tree.c'; else $(CYGPATH_W) '$(srcdir)/test-json-tree.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-json-tree.Tpo $(DEPDIR)/test_lib-test-json-tree.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-json-tree.c' object='test_lib-test-json-tree.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-json-tree.obj `if test -f 'test-json-tree.c'; then $(CYGPATH_W) 'test-json-tree.c'; else $(CYGPATH_W) '$(srcdir)/test-json-tree.c'; fi`
test_lib-test-lib-event.o: test-lib-event.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-lib-event.o -MD -MP -MF $(DEPDIR)/test_lib-test-lib-event.Tpo -c -o test_lib-test-lib-event.o `test -f 'test-lib-event.c' || echo '$(srcdir)/'`test-lib-event.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-lib-event.Tpo $(DEPDIR)/test_lib-test-lib-event.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lib-event.c' object='test_lib-test-lib-event.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-lib-event.o `test -f 'test-lib-event.c' || echo '$(srcdir)/'`test-lib-event.c
test_lib-test-lib-event.obj: test-lib-event.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-lib-event.obj -MD -MP -MF $(DEPDIR)/test_lib-test-lib-event.Tpo -c -o test_lib-test-lib-event.obj `if test -f 'test-lib-event.c'; then $(CYGPATH_W) 'test-lib-event.c'; else $(CYGPATH_W) '$(srcdir)/test-lib-event.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-lib-event.Tpo $(DEPDIR)/test_lib-test-lib-event.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lib-event.c' object='test_lib-test-lib-event.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-lib-event.obj `if test -f 'test-lib-event.c'; then $(CYGPATH_W) 'test-lib-event.c'; else $(CYGPATH_W) '$(srcdir)/test-lib-event.c'; fi`
test_lib-test-lib-signals.o: test-lib-signals.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-lib-signals.o -MD -MP -MF $(DEPDIR)/test_lib-test-lib-signals.Tpo -c -o test_lib-test-lib-signals.o `test -f 'test-lib-signals.c' || echo '$(srcdir)/'`test-lib-signals.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-lib-signals.Tpo $(DEPDIR)/test_lib-test-lib-signals.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lib-signals.c' object='test_lib-test-lib-signals.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-lib-signals.o `test -f 'test-lib-signals.c' || echo '$(srcdir)/'`test-lib-signals.c
test_lib-test-lib-signals.obj: test-lib-signals.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-lib-signals.obj -MD -MP -MF $(DEPDIR)/test_lib-test-lib-signals.Tpo -c -o test_lib-test-lib-signals.obj `if test -f 'test-lib-signals.c'; then $(CYGPATH_W) 'test-lib-signals.c'; else $(CYGPATH_W) '$(srcdir)/test-lib-signals.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-lib-signals.Tpo $(DEPDIR)/test_lib-test-lib-signals.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lib-signals.c' object='test_lib-test-lib-signals.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-lib-signals.obj `if test -f 'test-lib-signals.c'; then $(CYGPATH_W) 'test-lib-signals.c'; else $(CYGPATH_W) '$(srcdir)/test-lib-signals.c'; fi`
test_lib-test-llist.o: test-llist.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-llist.o -MD -MP -MF $(DEPDIR)/test_lib-test-llist.Tpo -c -o test_lib-test-llist.o `test -f 'test-llist.c' || echo '$(srcdir)/'`test-llist.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-llist.Tpo $(DEPDIR)/test_lib-test-llist.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-llist.c' object='test_lib-test-llist.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-llist.o `test -f 'test-llist.c' || echo '$(srcdir)/'`test-llist.c
test_lib-test-llist.obj: test-llist.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-llist.obj -MD -MP -MF $(DEPDIR)/test_lib-test-llist.Tpo -c -o test_lib-test-llist.obj `if test -f 'test-llist.c'; then $(CYGPATH_W) 'test-llist.c'; else $(CYGPATH_W) '$(srcdir)/test-llist.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-llist.Tpo $(DEPDIR)/test_lib-test-llist.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-llist.c' object='test_lib-test-llist.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-llist.obj `if test -f 'test-llist.c'; then $(CYGPATH_W) 'test-llist.c'; else $(CYGPATH_W) '$(srcdir)/test-llist.c'; fi`
test_lib-test-log-throttle.o: test-log-throttle.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-log-throttle.o -MD -MP -MF $(DEPDIR)/test_lib-test-log-throttle.Tpo -c -o test_lib-test-log-throttle.o `test -f 'test-log-throttle.c' || echo '$(srcdir)/'`test-log-throttle.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-log-throttle.Tpo $(DEPDIR)/test_lib-test-log-throttle.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-log-throttle.c' object='test_lib-test-log-throttle.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-log-throttle.o `test -f 'test-log-throttle.c' || echo '$(srcdir)/'`test-log-throttle.c
test_lib-test-log-throttle.obj: test-log-throttle.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-log-throttle.obj -MD -MP -MF $(DEPDIR)/test_lib-test-log-throttle.Tpo -c -o test_lib-test-log-throttle.obj `if test -f 'test-log-throttle.c'; then $(CYGPATH_W) 'test-log-throttle.c'; else $(CYGPATH_W) '$(srcdir)/test-log-throttle.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-log-throttle.Tpo $(DEPDIR)/test_lib-test-log-throttle.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-log-throttle.c' object='test_lib-test-log-throttle.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-log-throttle.obj `if test -f 'test-log-throttle.c'; then $(CYGPATH_W) 'test-log-throttle.c'; else $(CYGPATH_W) '$(srcdir)/test-log-throttle.c'; fi`
test_lib-test-macros.o: test-macros.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-macros.o -MD -MP -MF $(DEPDIR)/test_lib-test-macros.Tpo -c -o test_lib-test-macros.o `test -f 'test-macros.c' || echo '$(srcdir)/'`test-macros.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-macros.Tpo $(DEPDIR)/test_lib-test-macros.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-macros.c' object='test_lib-test-macros.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-macros.o `test -f 'test-macros.c' || echo '$(srcdir)/'`test-macros.c
test_lib-test-macros.obj: test-macros.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-macros.obj -MD -MP -MF $(DEPDIR)/test_lib-test-macros.Tpo -c -o test_lib-test-macros.obj `if test -f 'test-macros.c'; then $(CYGPATH_W) 'test-macros.c'; else $(CYGPATH_W) '$(srcdir)/test-macros.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-macros.Tpo $(DEPDIR)/test_lib-test-macros.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-macros.c' object='test_lib-test-macros.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-macros.obj `if test -f 'test-macros.c'; then $(CYGPATH_W) 'test-macros.c'; else $(CYGPATH_W) '$(srcdir)/test-macros.c'; fi`
test_lib-test-malloc-overflow.o: test-malloc-overflow.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-malloc-overflow.o -MD -MP -MF $(DEPDIR)/test_lib-test-malloc-overflow.Tpo -c -o test_lib-test-malloc-overflow.o `test -f 'test-malloc-overflow.c' || echo '$(srcdir)/'`test-malloc-overflow.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-malloc-overflow.Tpo $(DEPDIR)/test_lib-test-malloc-overflow.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-malloc-overflow.c' object='test_lib-test-malloc-overflow.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-malloc-overflow.o `test -f 'test-malloc-overflow.c' || echo '$(srcdir)/'`test-malloc-overflow.c
test_lib-test-malloc-overflow.obj: test-malloc-overflow.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-malloc-overflow.obj -MD -MP -MF $(DEPDIR)/test_lib-test-malloc-overflow.Tpo -c -o test_lib-test-malloc-overflow.obj `if test -f 'test-malloc-overflow.c'; then $(CYGPATH_W) 'test-malloc-overflow.c'; else $(CYGPATH_W) '$(srcdir)/test-malloc-overflow.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-malloc-overflow.Tpo $(DEPDIR)/test_lib-test-malloc-overflow.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-malloc-overflow.c' object='test_lib-test-malloc-overflow.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-malloc-overflow.obj `if test -f 'test-malloc-overflow.c'; then $(CYGPATH_W) 'test-malloc-overflow.c'; else $(CYGPATH_W) '$(srcdir)/test-malloc-overflow.c'; fi`
test_lib-test-memarea.o: test-memarea.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-memarea.o -MD -MP -MF $(DEPDIR)/test_lib-test-memarea.Tpo -c -o test_lib-test-memarea.o `test -f 'test-memarea.c' || echo '$(srcdir)/'`test-memarea.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-memarea.Tpo $(DEPDIR)/test_lib-test-memarea.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-memarea.c' object='test_lib-test-memarea.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-memarea.o `test -f 'test-memarea.c' || echo '$(srcdir)/'`test-memarea.c
test_lib-test-memarea.obj: test-memarea.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-memarea.obj -MD -MP -MF $(DEPDIR)/test_lib-test-memarea.Tpo -c -o test_lib-test-memarea.obj `if test -f 'test-memarea.c'; then $(CYGPATH_W) 'test-memarea.c'; else $(CYGPATH_W) '$(srcdir)/test-memarea.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-memarea.Tpo $(DEPDIR)/test_lib-test-memarea.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-memarea.c' object='test_lib-test-memarea.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-memarea.obj `if test -f 'test-memarea.c'; then $(CYGPATH_W) 'test-memarea.c'; else $(CYGPATH_W) '$(srcdir)/test-memarea.c'; fi`
test_lib-test-mempool.o: test-mempool.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-mempool.o -MD -MP -MF $(DEPDIR)/test_lib-test-mempool.Tpo -c -o test_lib-test-mempool.o `test -f 'test-mempool.c' || echo '$(srcdir)/'`test-mempool.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-mempool.Tpo $(DEPDIR)/test_lib-test-mempool.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-mempool.c' object='test_lib-test-mempool.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-mempool.o `test -f 'test-mempool.c' || echo '$(srcdir)/'`test-mempool.c
test_lib-test-mempool.obj: test-mempool.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-mempool.obj -MD -MP -MF $(DEPDIR)/test_lib-test-mempool.Tpo -c -o test_lib-test-mempool.obj `if test -f 'test-mempool.c'; then $(CYGPATH_W) 'test-mempool.c'; else $(CYGPATH_W) '$(srcdir)/test-mempool.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-mempool.Tpo $(DEPDIR)/test_lib-test-mempool.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-mempool.c' object='test_lib-test-mempool.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-mempool.obj `if test -f 'test-mempool.c'; then $(CYGPATH_W) 'test-mempool.c'; else $(CYGPATH_W) '$(srcdir)/test-mempool.c'; fi`
test_lib-test-mempool-allocfree.o: test-mempool-allocfree.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-mempool-allocfree.o -MD -MP -MF $(DEPDIR)/test_lib-test-mempool-allocfree.Tpo -c -o test_lib-test-mempool-allocfree.o `test -f 'test-mempool-allocfree.c' || echo '$(srcdir)/'`test-mempool-allocfree.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-mempool-allocfree.Tpo $(DEPDIR)/test_lib-test-mempool-allocfree.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-mempool-allocfree.c' object='test_lib-test-mempool-allocfree.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-mempool-allocfree.o `test -f 'test-mempool-allocfree.c' || echo '$(srcdir)/'`test-mempool-allocfree.c
test_lib-test-mempool-allocfree.obj: test-mempool-allocfree.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-mempool-allocfree.obj -MD -MP -MF $(DEPDIR)/test_lib-test-mempool-allocfree.Tpo -c -o test_lib-test-mempool-allocfree.obj `if test -f 'test-mempool-allocfree.c'; then $(CYGPATH_W) 'test-mempool-allocfree.c'; else $(CYGPATH_W) '$(srcdir)/test-mempool-allocfree.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-mempool-allocfree.Tpo $(DEPDIR)/test_lib-test-mempool-allocfree.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-mempool-allocfree.c' object='test_lib-test-mempool-allocfree.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-mempool-allocfree.obj `if test -f 'test-mempool-allocfree.c'; then $(CYGPATH_W) 'test-mempool-allocfree.c'; else $(CYGPATH_W) '$(srcdir)/test-mempool-allocfree.c'; fi`
test_lib-test-mempool-alloconly.o: test-mempool-alloconly.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-mempool-alloconly.o -MD -MP -MF $(DEPDIR)/test_lib-test-mempool-alloconly.Tpo -c -o test_lib-test-mempool-alloconly.o `test -f 'test-mempool-alloconly.c' || echo '$(srcdir)/'`test-mempool-alloconly.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-mempool-alloconly.Tpo $(DEPDIR)/test_lib-test-mempool-alloconly.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-mempool-alloconly.c' object='test_lib-test-mempool-alloconly.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-mempool-alloconly.o `test -f 'test-mempool-alloconly.c' || echo '$(srcdir)/'`test-mempool-alloconly.c
test_lib-test-mempool-alloconly.obj: test-mempool-alloconly.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-mempool-alloconly.obj -MD -MP -MF $(DEPDIR)/test_lib-test-mempool-alloconly.Tpo -c -o test_lib-test-mempool-alloconly.obj `if test -f 'test-mempool-alloconly.c'; then $(CYGPATH_W) 'test-mempool-alloconly.c'; else $(CYGPATH_W) '$(srcdir)/test-mempool-alloconly.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-mempool-alloconly.Tpo $(DEPDIR)/test_lib-test-mempool-alloconly.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-mempool-alloconly.c' object='test_lib-test-mempool-alloconly.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-mempool-alloconly.obj `if test -f 'test-mempool-alloconly.c'; then $(CYGPATH_W) 'test-mempool-alloconly.c'; else $(CYGPATH_W) '$(srcdir)/test-mempool-alloconly.c'; fi`
test_lib-test-pkcs5.o: test-pkcs5.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-pkcs5.o -MD -MP -MF $(DEPDIR)/test_lib-test-pkcs5.Tpo -c -o test_lib-test-pkcs5.o `test -f 'test-pkcs5.c' || echo '$(srcdir)/'`test-pkcs5.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-pkcs5.Tpo $(DEPDIR)/test_lib-test-pkcs5.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-pkcs5.c' object='test_lib-test-pkcs5.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-pkcs5.o `test -f 'test-pkcs5.c' || echo '$(srcdir)/'`test-pkcs5.c
test_lib-test-pkcs5.obj: test-pkcs5.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-pkcs5.obj -MD -MP -MF $(DEPDIR)/test_lib-test-pkcs5.Tpo -c -o test_lib-test-pkcs5.obj `if test -f 'test-pkcs5.c'; then $(CYGPATH_W) 'test-pkcs5.c'; else $(CYGPATH_W) '$(srcdir)/test-pkcs5.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-pkcs5.Tpo $(DEPDIR)/test_lib-test-pkcs5.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-pkcs5.c' object='test_lib-test-pkcs5.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-pkcs5.obj `if test -f 'test-pkcs5.c'; then $(CYGPATH_W) 'test-pkcs5.c'; else $(CYGPATH_W) '$(srcdir)/test-pkcs5.c'; fi`
test_lib-test-net.o: test-net.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-net.o -MD -MP -MF $(DEPDIR)/test_lib-test-net.Tpo -c -o test_lib-test-net.o `test -f 'test-net.c' || echo '$(srcdir)/'`test-net.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-net.Tpo $(DEPDIR)/test_lib-test-net.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-net.c' object='test_lib-test-net.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-net.o `test -f 'test-net.c' || echo '$(srcdir)/'`test-net.c
test_lib-test-net.obj: test-net.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-net.obj -MD -MP -MF $(DEPDIR)/test_lib-test-net.Tpo -c -o test_lib-test-net.obj `if test -f 'test-net.c'; then $(CYGPATH_W) 'test-net.c'; else $(CYGPATH_W) '$(srcdir)/test-net.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-net.Tpo $(DEPDIR)/test_lib-test-net.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-net.c' object='test_lib-test-net.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-net.obj `if test -f 'test-net.c'; then $(CYGPATH_W) 'test-net.c'; else $(CYGPATH_W) '$(srcdir)/test-net.c'; fi`
test_lib-test-numpack.o: test-numpack.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-numpack.o -MD -MP -MF $(DEPDIR)/test_lib-test-numpack.Tpo -c -o test_lib-test-numpack.o `test -f 'test-numpack.c' || echo '$(srcdir)/'`test-numpack.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-numpack.Tpo $(DEPDIR)/test_lib-test-numpack.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-numpack.c' object='test_lib-test-numpack.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-numpack.o `test -f 'test-numpack.c' || echo '$(srcdir)/'`test-numpack.c
test_lib-test-numpack.obj: test-numpack.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-numpack.obj -MD -MP -MF $(DEPDIR)/test_lib-test-numpack.Tpo -c -o test_lib-test-numpack.obj `if test -f 'test-numpack.c'; then $(CYGPATH_W) 'test-numpack.c'; else $(CYGPATH_W) '$(srcdir)/test-numpack.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-numpack.Tpo $(DEPDIR)/test_lib-test-numpack.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-numpack.c' object='test_lib-test-numpack.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-numpack.obj `if test -f 'test-numpack.c'; then $(CYGPATH_W) 'test-numpack.c'; else $(CYGPATH_W) '$(srcdir)/test-numpack.c'; fi`
test_lib-test-ostream-buffer.o: test-ostream-buffer.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-buffer.o -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-buffer.Tpo -c -o test_lib-test-ostream-buffer.o `test -f 'test-ostream-buffer.c' || echo '$(srcdir)/'`test-ostream-buffer.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-buffer.Tpo $(DEPDIR)/test_lib-test-ostream-buffer.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-buffer.c' object='test_lib-test-ostream-buffer.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-buffer.o `test -f 'test-ostream-buffer.c' || echo '$(srcdir)/'`test-ostream-buffer.c
test_lib-test-ostream-buffer.obj: test-ostream-buffer.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-buffer.obj -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-buffer.Tpo -c -o test_lib-test-ostream-buffer.obj `if test -f 'test-ostream-buffer.c'; then $(CYGPATH_W) 'test-ostream-buffer.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-buffer.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-buffer.Tpo $(DEPDIR)/test_lib-test-ostream-buffer.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-buffer.c' object='test_lib-test-ostream-buffer.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-buffer.obj `if test -f 'test-ostream-buffer.c'; then $(CYGPATH_W) 'test-ostream-buffer.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-buffer.c'; fi`
test_lib-test-ostream-failure-at.o: test-ostream-failure-at.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-failure-at.o -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-failure-at.Tpo -c -o test_lib-test-ostream-failure-at.o `test -f 'test-ostream-failure-at.c' || echo '$(srcdir)/'`test-ostream-failure-at.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-failure-at.Tpo $(DEPDIR)/test_lib-test-ostream-failure-at.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-failure-at.c' object='test_lib-test-ostream-failure-at.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-failure-at.o `test -f 'test-ostream-failure-at.c' || echo '$(srcdir)/'`test-ostream-failure-at.c
test_lib-test-ostream-failure-at.obj: test-ostream-failure-at.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-failure-at.obj -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-failure-at.Tpo -c -o test_lib-test-ostream-failure-at.obj `if test -f 'test-ostream-failure-at.c'; then $(CYGPATH_W) 'test-ostream-failure-at.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-failure-at.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-failure-at.Tpo $(DEPDIR)/test_lib-test-ostream-failure-at.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-failure-at.c' object='test_lib-test-ostream-failure-at.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-failure-at.obj `if test -f 'test-ostream-failure-at.c'; then $(CYGPATH_W) 'test-ostream-failure-at.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-failure-at.c'; fi`
test_lib-test-ostream-file.o: test-ostream-file.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-file.o -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-file.Tpo -c -o test_lib-test-ostream-file.o `test -f 'test-ostream-file.c' || echo '$(srcdir)/'`test-ostream-file.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-file.Tpo $(DEPDIR)/test_lib-test-ostream-file.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-file.c' object='test_lib-test-ostream-file.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-file.o `test -f 'test-ostream-file.c' || echo '$(srcdir)/'`test-ostream-file.c
test_lib-test-ostream-file.obj: test-ostream-file.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-file.obj -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-file.Tpo -c -o test_lib-test-ostream-file.obj `if test -f 'test-ostream-file.c'; then $(CYGPATH_W) 'test-ostream-file.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-file.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-file.Tpo $(DEPDIR)/test_lib-test-ostream-file.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-file.c' object='test_lib-test-ostream-file.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-file.obj `if test -f 'test-ostream-file.c'; then $(CYGPATH_W) 'test-ostream-file.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-file.c'; fi`
test_lib-test-ostream-multiplex.o: test-ostream-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-multiplex.o -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-multiplex.Tpo -c -o test_lib-test-ostream-multiplex.o `test -f 'test-ostream-multiplex.c' || echo '$(srcdir)/'`test-ostream-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-multiplex.Tpo $(DEPDIR)/test_lib-test-ostream-multiplex.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-multiplex.c' object='test_lib-test-ostream-multiplex.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-multiplex.o `test -f 'test-ostream-multiplex.c' || echo '$(srcdir)/'`test-ostream-multiplex.c
test_lib-test-ostream-multiplex.obj: test-ostream-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-ostream-multiplex.obj -MD -MP -MF $(DEPDIR)/test_lib-test-ostream-multiplex.Tpo -c -o test_lib-test-ostream-multiplex.obj `if test -f 'test-ostream-multiplex.c'; then $(CYGPATH_W) 'test-ostream-multiplex.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-multiplex.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-ostream-multiplex.Tpo $(DEPDIR)/test_lib-test-ostream-multiplex.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-ostream-multiplex.c' object='test_lib-test-ostream-multiplex.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-ostream-multiplex.obj `if test -f 'test-ostream-multiplex.c'; then $(CYGPATH_W) 'test-ostream-multiplex.c'; else $(CYGPATH_W) '$(srcdir)/test-ostream-multiplex.c'; fi`
test_lib-test-multiplex.o: test-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-multiplex.o -MD -MP -MF $(DEPDIR)/test_lib-test-multiplex.Tpo -c -o test_lib-test-multiplex.o `test -f 'test-multiplex.c' || echo '$(srcdir)/'`test-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-multiplex.Tpo $(DEPDIR)/test_lib-test-multiplex.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-multiplex.c' object='test_lib-test-multiplex.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-multiplex.o `test -f 'test-multiplex.c' || echo '$(srcdir)/'`test-multiplex.c
test_lib-test-multiplex.obj: test-multiplex.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-multiplex.obj -MD -MP -MF $(DEPDIR)/test_lib-test-multiplex.Tpo -c -o test_lib-test-multiplex.obj `if test -f 'test-multiplex.c'; then $(CYGPATH_W) 'test-multiplex.c'; else $(CYGPATH_W) '$(srcdir)/test-multiplex.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-multiplex.Tpo $(DEPDIR)/test_lib-test-multiplex.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-multiplex.c' object='test_lib-test-multiplex.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-multiplex.obj `if test -f 'test-multiplex.c'; then $(CYGPATH_W) 'test-multiplex.c'; else $(CYGPATH_W) '$(srcdir)/test-multiplex.c'; fi`
test_lib-test-path-util.o: test-path-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-path-util.o -MD -MP -MF $(DEPDIR)/test_lib-test-path-util.Tpo -c -o test_lib-test-path-util.o `test -f 'test-path-util.c' || echo '$(srcdir)/'`test-path-util.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-path-util.Tpo $(DEPDIR)/test_lib-test-path-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-path-util.c' object='test_lib-test-path-util.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-path-util.o `test -f 'test-path-util.c' || echo '$(srcdir)/'`test-path-util.c
test_lib-test-path-util.obj: test-path-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-path-util.obj -MD -MP -MF $(DEPDIR)/test_lib-test-path-util.Tpo -c -o test_lib-test-path-util.obj `if test -f 'test-path-util.c'; then $(CYGPATH_W) 'test-path-util.c'; else $(CYGPATH_W) '$(srcdir)/test-path-util.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-path-util.Tpo $(DEPDIR)/test_lib-test-path-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-path-util.c' object='test_lib-test-path-util.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-path-util.obj `if test -f 'test-path-util.c'; then $(CYGPATH_W) 'test-path-util.c'; else $(CYGPATH_W) '$(srcdir)/test-path-util.c'; fi`
test_lib-test-primes.o: test-primes.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-primes.o -MD -MP -MF $(DEPDIR)/test_lib-test-primes.Tpo -c -o test_lib-test-primes.o `test -f 'test-primes.c' || echo '$(srcdir)/'`test-primes.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-primes.Tpo $(DEPDIR)/test_lib-test-primes.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-primes.c' object='test_lib-test-primes.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-primes.o `test -f 'test-primes.c' || echo '$(srcdir)/'`test-primes.c
test_lib-test-primes.obj: test-primes.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-primes.obj -MD -MP -MF $(DEPDIR)/test_lib-test-primes.Tpo -c -o test_lib-test-primes.obj `if test -f 'test-primes.c'; then $(CYGPATH_W) 'test-primes.c'; else $(CYGPATH_W) '$(srcdir)/test-primes.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-primes.Tpo $(DEPDIR)/test_lib-test-primes.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-primes.c' object='test_lib-test-primes.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-primes.obj `if test -f 'test-primes.c'; then $(CYGPATH_W) 'test-primes.c'; else $(CYGPATH_W) '$(srcdir)/test-primes.c'; fi`
test_lib-test-printf-format-fix.o: test-printf-format-fix.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-printf-format-fix.o -MD -MP -MF $(DEPDIR)/test_lib-test-printf-format-fix.Tpo -c -o test_lib-test-printf-format-fix.o `test -f 'test-printf-format-fix.c' || echo '$(srcdir)/'`test-printf-format-fix.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-printf-format-fix.Tpo $(DEPDIR)/test_lib-test-printf-format-fix.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-printf-format-fix.c' object='test_lib-test-printf-format-fix.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-printf-format-fix.o `test -f 'test-printf-format-fix.c' || echo '$(srcdir)/'`test-printf-format-fix.c
test_lib-test-printf-format-fix.obj: test-printf-format-fix.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-printf-format-fix.obj -MD -MP -MF $(DEPDIR)/test_lib-test-printf-format-fix.Tpo -c -o test_lib-test-printf-format-fix.obj `if test -f 'test-printf-format-fix.c'; then $(CYGPATH_W) 'test-printf-format-fix.c'; else $(CYGPATH_W) '$(srcdir)/test-printf-format-fix.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-printf-format-fix.Tpo $(DEPDIR)/test_lib-test-printf-format-fix.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-printf-format-fix.c' object='test_lib-test-printf-format-fix.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-printf-format-fix.obj `if test -f 'test-printf-format-fix.c'; then $(CYGPATH_W) 'test-printf-format-fix.c'; else $(CYGPATH_W) '$(srcdir)/test-printf-format-fix.c'; fi`
test_lib-test-priorityq.o: test-priorityq.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-priorityq.o -MD -MP -MF $(DEPDIR)/test_lib-test-priorityq.Tpo -c -o test_lib-test-priorityq.o `test -f 'test-priorityq.c' || echo '$(srcdir)/'`test-priorityq.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-priorityq.Tpo $(DEPDIR)/test_lib-test-priorityq.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-priorityq.c' object='test_lib-test-priorityq.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-priorityq.o `test -f 'test-priorityq.c' || echo '$(srcdir)/'`test-priorityq.c
test_lib-test-priorityq.obj: test-priorityq.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-priorityq.obj -MD -MP -MF $(DEPDIR)/test_lib-test-priorityq.Tpo -c -o test_lib-test-priorityq.obj `if test -f 'test-priorityq.c'; then $(CYGPATH_W) 'test-priorityq.c'; else $(CYGPATH_W) '$(srcdir)/test-priorityq.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-priorityq.Tpo $(DEPDIR)/test_lib-test-priorityq.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-priorityq.c' object='test_lib-test-priorityq.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-priorityq.obj `if test -f 'test-priorityq.c'; then $(CYGPATH_W) 'test-priorityq.c'; else $(CYGPATH_W) '$(srcdir)/test-priorityq.c'; fi`
test_lib-test-random.o: test-random.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-random.o -MD -MP -MF $(DEPDIR)/test_lib-test-random.Tpo -c -o test_lib-test-random.o `test -f 'test-random.c' || echo '$(srcdir)/'`test-random.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-random.Tpo $(DEPDIR)/test_lib-test-random.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-random.c' object='test_lib-test-random.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-random.o `test -f 'test-random.c' || echo '$(srcdir)/'`test-random.c
test_lib-test-random.obj: test-random.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-random.obj -MD -MP -MF $(DEPDIR)/test_lib-test-random.Tpo -c -o test_lib-test-random.obj `if test -f 'test-random.c'; then $(CYGPATH_W) 'test-random.c'; else $(CYGPATH_W) '$(srcdir)/test-random.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-random.Tpo $(DEPDIR)/test_lib-test-random.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-random.c' object='test_lib-test-random.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-random.obj `if test -f 'test-random.c'; then $(CYGPATH_W) 'test-random.c'; else $(CYGPATH_W) '$(srcdir)/test-random.c'; fi`
test_lib-test-seq-range-array.o: test-seq-range-array.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-seq-range-array.o -MD -MP -MF $(DEPDIR)/test_lib-test-seq-range-array.Tpo -c -o test_lib-test-seq-range-array.o `test -f 'test-seq-range-array.c' || echo '$(srcdir)/'`test-seq-range-array.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-seq-range-array.Tpo $(DEPDIR)/test_lib-test-seq-range-array.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-seq-range-array.c' object='test_lib-test-seq-range-array.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-seq-range-array.o `test -f 'test-seq-range-array.c' || echo '$(srcdir)/'`test-seq-range-array.c
test_lib-test-seq-range-array.obj: test-seq-range-array.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-seq-range-array.obj -MD -MP -MF $(DEPDIR)/test_lib-test-seq-range-array.Tpo -c -o test_lib-test-seq-range-array.obj `if test -f 'test-seq-range-array.c'; then $(CYGPATH_W) 'test-seq-range-array.c'; else $(CYGPATH_W) '$(srcdir)/test-seq-range-array.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-seq-range-array.Tpo $(DEPDIR)/test_lib-test-seq-range-array.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-seq-range-array.c' object='test_lib-test-seq-range-array.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-seq-range-array.obj `if test -f 'test-seq-range-array.c'; then $(CYGPATH_W) 'test-seq-range-array.c'; else $(CYGPATH_W) '$(srcdir)/test-seq-range-array.c'; fi`
test_lib-test-seq-set-builder.o: test-seq-set-builder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-seq-set-builder.o -MD -MP -MF $(DEPDIR)/test_lib-test-seq-set-builder.Tpo -c -o test_lib-test-seq-set-builder.o `test -f 'test-seq-set-builder.c' || echo '$(srcdir)/'`test-seq-set-builder.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-seq-set-builder.Tpo $(DEPDIR)/test_lib-test-seq-set-builder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-seq-set-builder.c' object='test_lib-test-seq-set-builder.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-seq-set-builder.o `test -f 'test-seq-set-builder.c' || echo '$(srcdir)/'`test-seq-set-builder.c
test_lib-test-seq-set-builder.obj: test-seq-set-builder.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-seq-set-builder.obj -MD -MP -MF $(DEPDIR)/test_lib-test-seq-set-builder.Tpo -c -o test_lib-test-seq-set-builder.obj `if test -f 'test-seq-set-builder.c'; then $(CYGPATH_W) 'test-seq-set-builder.c'; else $(CYGPATH_W) '$(srcdir)/test-seq-set-builder.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-seq-set-builder.Tpo $(DEPDIR)/test_lib-test-seq-set-builder.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-seq-set-builder.c' object='test_lib-test-seq-set-builder.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-seq-set-builder.obj `if test -f 'test-seq-set-builder.c'; then $(CYGPATH_W) 'test-seq-set-builder.c'; else $(CYGPATH_W) '$(srcdir)/test-seq-set-builder.c'; fi`
test_lib-test-stats-dist.o: test-stats-dist.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-stats-dist.o -MD -MP -MF $(DEPDIR)/test_lib-test-stats-dist.Tpo -c -o test_lib-test-stats-dist.o `test -f 'test-stats-dist.c' || echo '$(srcdir)/'`test-stats-dist.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-stats-dist.Tpo $(DEPDIR)/test_lib-test-stats-dist.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-stats-dist.c' object='test_lib-test-stats-dist.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-stats-dist.o `test -f 'test-stats-dist.c' || echo '$(srcdir)/'`test-stats-dist.c
test_lib-test-stats-dist.obj: test-stats-dist.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-stats-dist.obj -MD -MP -MF $(DEPDIR)/test_lib-test-stats-dist.Tpo -c -o test_lib-test-stats-dist.obj `if test -f 'test-stats-dist.c'; then $(CYGPATH_W) 'test-stats-dist.c'; else $(CYGPATH_W) '$(srcdir)/test-stats-dist.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-stats-dist.Tpo $(DEPDIR)/test_lib-test-stats-dist.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-stats-dist.c' object='test_lib-test-stats-dist.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-stats-dist.obj `if test -f 'test-stats-dist.c'; then $(CYGPATH_W) 'test-stats-dist.c'; else $(CYGPATH_W) '$(srcdir)/test-stats-dist.c'; fi`
test_lib-test-str.o: test-str.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str.o -MD -MP -MF $(DEPDIR)/test_lib-test-str.Tpo -c -o test_lib-test-str.o `test -f 'test-str.c' || echo '$(srcdir)/'`test-str.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str.Tpo $(DEPDIR)/test_lib-test-str.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str.c' object='test_lib-test-str.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str.o `test -f 'test-str.c' || echo '$(srcdir)/'`test-str.c
test_lib-test-str.obj: test-str.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str.obj -MD -MP -MF $(DEPDIR)/test_lib-test-str.Tpo -c -o test_lib-test-str.obj `if test -f 'test-str.c'; then $(CYGPATH_W) 'test-str.c'; else $(CYGPATH_W) '$(srcdir)/test-str.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str.Tpo $(DEPDIR)/test_lib-test-str.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str.c' object='test_lib-test-str.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str.obj `if test -f 'test-str.c'; then $(CYGPATH_W) 'test-str.c'; else $(CYGPATH_W) '$(srcdir)/test-str.c'; fi`
test_lib-test-strescape.o: test-strescape.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-strescape.o -MD -MP -MF $(DEPDIR)/test_lib-test-strescape.Tpo -c -o test_lib-test-strescape.o `test -f 'test-strescape.c' || echo '$(srcdir)/'`test-strescape.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-strescape.Tpo $(DEPDIR)/test_lib-test-strescape.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-strescape.c' object='test_lib-test-strescape.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-strescape.o `test -f 'test-strescape.c' || echo '$(srcdir)/'`test-strescape.c
test_lib-test-strescape.obj: test-strescape.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-strescape.obj -MD -MP -MF $(DEPDIR)/test_lib-test-strescape.Tpo -c -o test_lib-test-strescape.obj `if test -f 'test-strescape.c'; then $(CYGPATH_W) 'test-strescape.c'; else $(CYGPATH_W) '$(srcdir)/test-strescape.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-strescape.Tpo $(DEPDIR)/test_lib-test-strescape.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-strescape.c' object='test_lib-test-strescape.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-strescape.obj `if test -f 'test-strescape.c'; then $(CYGPATH_W) 'test-strescape.c'; else $(CYGPATH_W) '$(srcdir)/test-strescape.c'; fi`
test_lib-test-strfuncs.o: test-strfuncs.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-strfuncs.o -MD -MP -MF $(DEPDIR)/test_lib-test-strfuncs.Tpo -c -o test_lib-test-strfuncs.o `test -f 'test-strfuncs.c' || echo '$(srcdir)/'`test-strfuncs.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-strfuncs.Tpo $(DEPDIR)/test_lib-test-strfuncs.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-strfuncs.c' object='test_lib-test-strfuncs.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-strfuncs.o `test -f 'test-strfuncs.c' || echo '$(srcdir)/'`test-strfuncs.c
test_lib-test-strfuncs.obj: test-strfuncs.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-strfuncs.obj -MD -MP -MF $(DEPDIR)/test_lib-test-strfuncs.Tpo -c -o test_lib-test-strfuncs.obj `if test -f 'test-strfuncs.c'; then $(CYGPATH_W) 'test-strfuncs.c'; else $(CYGPATH_W) '$(srcdir)/test-strfuncs.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-strfuncs.Tpo $(DEPDIR)/test_lib-test-strfuncs.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-strfuncs.c' object='test_lib-test-strfuncs.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-strfuncs.obj `if test -f 'test-strfuncs.c'; then $(CYGPATH_W) 'test-strfuncs.c'; else $(CYGPATH_W) '$(srcdir)/test-strfuncs.c'; fi`
test_lib-test-strnum.o: test-strnum.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-strnum.o -MD -MP -MF $(DEPDIR)/test_lib-test-strnum.Tpo -c -o test_lib-test-strnum.o `test -f 'test-strnum.c' || echo '$(srcdir)/'`test-strnum.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-strnum.Tpo $(DEPDIR)/test_lib-test-strnum.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-strnum.c' object='test_lib-test-strnum.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-strnum.o `test -f 'test-strnum.c' || echo '$(srcdir)/'`test-strnum.c
test_lib-test-strnum.obj: test-strnum.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-strnum.obj -MD -MP -MF $(DEPDIR)/test_lib-test-strnum.Tpo -c -o test_lib-test-strnum.obj `if test -f 'test-strnum.c'; then $(CYGPATH_W) 'test-strnum.c'; else $(CYGPATH_W) '$(srcdir)/test-strnum.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-strnum.Tpo $(DEPDIR)/test_lib-test-strnum.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-strnum.c' object='test_lib-test-strnum.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-strnum.obj `if test -f 'test-strnum.c'; then $(CYGPATH_W) 'test-strnum.c'; else $(CYGPATH_W) '$(srcdir)/test-strnum.c'; fi`
test_lib-test-str-find.o: test-str-find.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str-find.o -MD -MP -MF $(DEPDIR)/test_lib-test-str-find.Tpo -c -o test_lib-test-str-find.o `test -f 'test-str-find.c' || echo '$(srcdir)/'`test-str-find.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str-find.Tpo $(DEPDIR)/test_lib-test-str-find.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str-find.c' object='test_lib-test-str-find.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str-find.o `test -f 'test-str-find.c' || echo '$(srcdir)/'`test-str-find.c
test_lib-test-str-find.obj: test-str-find.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str-find.obj -MD -MP -MF $(DEPDIR)/test_lib-test-str-find.Tpo -c -o test_lib-test-str-find.obj `if test -f 'test-str-find.c'; then $(CYGPATH_W) 'test-str-find.c'; else $(CYGPATH_W) '$(srcdir)/test-str-find.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str-find.Tpo $(DEPDIR)/test_lib-test-str-find.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str-find.c' object='test_lib-test-str-find.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str-find.obj `if test -f 'test-str-find.c'; then $(CYGPATH_W) 'test-str-find.c'; else $(CYGPATH_W) '$(srcdir)/test-str-find.c'; fi`
test_lib-test-str-sanitize.o: test-str-sanitize.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str-sanitize.o -MD -MP -MF $(DEPDIR)/test_lib-test-str-sanitize.Tpo -c -o test_lib-test-str-sanitize.o `test -f 'test-str-sanitize.c' || echo '$(srcdir)/'`test-str-sanitize.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str-sanitize.Tpo $(DEPDIR)/test_lib-test-str-sanitize.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str-sanitize.c' object='test_lib-test-str-sanitize.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str-sanitize.o `test -f 'test-str-sanitize.c' || echo '$(srcdir)/'`test-str-sanitize.c
test_lib-test-str-sanitize.obj: test-str-sanitize.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str-sanitize.obj -MD -MP -MF $(DEPDIR)/test_lib-test-str-sanitize.Tpo -c -o test_lib-test-str-sanitize.obj `if test -f 'test-str-sanitize.c'; then $(CYGPATH_W) 'test-str-sanitize.c'; else $(CYGPATH_W) '$(srcdir)/test-str-sanitize.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str-sanitize.Tpo $(DEPDIR)/test_lib-test-str-sanitize.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str-sanitize.c' object='test_lib-test-str-sanitize.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str-sanitize.obj `if test -f 'test-str-sanitize.c'; then $(CYGPATH_W) 'test-str-sanitize.c'; else $(CYGPATH_W) '$(srcdir)/test-str-sanitize.c'; fi`
test_lib-test-str-table.o: test-str-table.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str-table.o -MD -MP -MF $(DEPDIR)/test_lib-test-str-table.Tpo -c -o test_lib-test-str-table.o `test -f 'test-str-table.c' || echo '$(srcdir)/'`test-str-table.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str-table.Tpo $(DEPDIR)/test_lib-test-str-table.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str-table.c' object='test_lib-test-str-table.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str-table.o `test -f 'test-str-table.c' || echo '$(srcdir)/'`test-str-table.c
test_lib-test-str-table.obj: test-str-table.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-str-table.obj -MD -MP -MF $(DEPDIR)/test_lib-test-str-table.Tpo -c -o test_lib-test-str-table.obj `if test -f 'test-str-table.c'; then $(CYGPATH_W) 'test-str-table.c'; else $(CYGPATH_W) '$(srcdir)/test-str-table.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-str-table.Tpo $(DEPDIR)/test_lib-test-str-table.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-str-table.c' object='test_lib-test-str-table.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-str-table.obj `if test -f 'test-str-table.c'; then $(CYGPATH_W) 'test-str-table.c'; else $(CYGPATH_W) '$(srcdir)/test-str-table.c'; fi`
test_lib-test-time-util.o: test-time-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-time-util.o -MD -MP -MF $(DEPDIR)/test_lib-test-time-util.Tpo -c -o test_lib-test-time-util.o `test -f 'test-time-util.c' || echo '$(srcdir)/'`test-time-util.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-time-util.Tpo $(DEPDIR)/test_lib-test-time-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-time-util.c' object='test_lib-test-time-util.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-time-util.o `test -f 'test-time-util.c' || echo '$(srcdir)/'`test-time-util.c
test_lib-test-time-util.obj: test-time-util.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-time-util.obj -MD -MP -MF $(DEPDIR)/test_lib-test-time-util.Tpo -c -o test_lib-test-time-util.obj `if test -f 'test-time-util.c'; then $(CYGPATH_W) 'test-time-util.c'; else $(CYGPATH_W) '$(srcdir)/test-time-util.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-time-util.Tpo $(DEPDIR)/test_lib-test-time-util.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-time-util.c' object='test_lib-test-time-util.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-time-util.obj `if test -f 'test-time-util.c'; then $(CYGPATH_W) 'test-time-util.c'; else $(CYGPATH_W) '$(srcdir)/test-time-util.c'; fi`
test_lib-test-unichar.o: test-unichar.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-unichar.o -MD -MP -MF $(DEPDIR)/test_lib-test-unichar.Tpo -c -o test_lib-test-unichar.o `test -f 'test-unichar.c' || echo '$(srcdir)/'`test-unichar.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-unichar.Tpo $(DEPDIR)/test_lib-test-unichar.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-unichar.c' object='test_lib-test-unichar.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-unichar.o `test -f 'test-unichar.c' || echo '$(srcdir)/'`test-unichar.c
test_lib-test-unichar.obj: test-unichar.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-unichar.obj -MD -MP -MF $(DEPDIR)/test_lib-test-unichar.Tpo -c -o test_lib-test-unichar.obj `if test -f 'test-unichar.c'; then $(CYGPATH_W) 'test-unichar.c'; else $(CYGPATH_W) '$(srcdir)/test-unichar.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-unichar.Tpo $(DEPDIR)/test_lib-test-unichar.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-unichar.c' object='test_lib-test-unichar.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-unichar.obj `if test -f 'test-unichar.c'; then $(CYGPATH_W) 'test-unichar.c'; else $(CYGPATH_W) '$(srcdir)/test-unichar.c'; fi`
test_lib-test-utc-mktime.o: test-utc-mktime.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-utc-mktime.o -MD -MP -MF $(DEPDIR)/test_lib-test-utc-mktime.Tpo -c -o test_lib-test-utc-mktime.o `test -f 'test-utc-mktime.c' || echo '$(srcdir)/'`test-utc-mktime.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-utc-mktime.Tpo $(DEPDIR)/test_lib-test-utc-mktime.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-utc-mktime.c' object='test_lib-test-utc-mktime.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-utc-mktime.o `test -f 'test-utc-mktime.c' || echo '$(srcdir)/'`test-utc-mktime.c
test_lib-test-utc-mktime.obj: test-utc-mktime.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-utc-mktime.obj -MD -MP -MF $(DEPDIR)/test_lib-test-utc-mktime.Tpo -c -o test_lib-test-utc-mktime.obj `if test -f 'test-utc-mktime.c'; then $(CYGPATH_W) 'test-utc-mktime.c'; else $(CYGPATH_W) '$(srcdir)/test-utc-mktime.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-utc-mktime.Tpo $(DEPDIR)/test_lib-test-utc-mktime.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-utc-mktime.c' object='test_lib-test-utc-mktime.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-utc-mktime.obj `if test -f 'test-utc-mktime.c'; then $(CYGPATH_W) 'test-utc-mktime.c'; else $(CYGPATH_W) '$(srcdir)/test-utc-mktime.c'; fi`
test_lib-test-uri.o: test-uri.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-uri.o -MD -MP -MF $(DEPDIR)/test_lib-test-uri.Tpo -c -o test_lib-test-uri.o `test -f 'test-uri.c' || echo '$(srcdir)/'`test-uri.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-uri.Tpo $(DEPDIR)/test_lib-test-uri.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-uri.c' object='test_lib-test-uri.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-uri.o `test -f 'test-uri.c' || echo '$(srcdir)/'`test-uri.c
test_lib-test-uri.obj: test-uri.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-uri.obj -MD -MP -MF $(DEPDIR)/test_lib-test-uri.Tpo -c -o test_lib-test-uri.obj `if test -f 'test-uri.c'; then $(CYGPATH_W) 'test-uri.c'; else $(CYGPATH_W) '$(srcdir)/test-uri.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-uri.Tpo $(DEPDIR)/test_lib-test-uri.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-uri.c' object='test_lib-test-uri.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-uri.obj `if test -f 'test-uri.c'; then $(CYGPATH_W) 'test-uri.c'; else $(CYGPATH_W) '$(srcdir)/test-uri.c'; fi`
test_lib-test-var-expand.o: test-var-expand.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-var-expand.o -MD -MP -MF $(DEPDIR)/test_lib-test-var-expand.Tpo -c -o test_lib-test-var-expand.o `test -f 'test-var-expand.c' || echo '$(srcdir)/'`test-var-expand.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-var-expand.Tpo $(DEPDIR)/test_lib-test-var-expand.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-var-expand.c' object='test_lib-test-var-expand.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-var-expand.o `test -f 'test-var-expand.c' || echo '$(srcdir)/'`test-var-expand.c
test_lib-test-var-expand.obj: test-var-expand.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-var-expand.obj -MD -MP -MF $(DEPDIR)/test_lib-test-var-expand.Tpo -c -o test_lib-test-var-expand.obj `if test -f 'test-var-expand.c'; then $(CYGPATH_W) 'test-var-expand.c'; else $(CYGPATH_W) '$(srcdir)/test-var-expand.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-var-expand.Tpo $(DEPDIR)/test_lib-test-var-expand.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-var-expand.c' object='test_lib-test-var-expand.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-var-expand.obj `if test -f 'test-var-expand.c'; then $(CYGPATH_W) 'test-var-expand.c'; else $(CYGPATH_W) '$(srcdir)/test-var-expand.c'; fi`
test_lib-test-wildcard-match.o: test-wildcard-match.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-wildcard-match.o -MD -MP -MF $(DEPDIR)/test_lib-test-wildcard-match.Tpo -c -o test_lib-test-wildcard-match.o `test -f 'test-wildcard-match.c' || echo '$(srcdir)/'`test-wildcard-match.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-wildcard-match.Tpo $(DEPDIR)/test_lib-test-wildcard-match.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-wildcard-match.c' object='test_lib-test-wildcard-match.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-wildcard-match.o `test -f 'test-wildcard-match.c' || echo '$(srcdir)/'`test-wildcard-match.c
test_lib-test-wildcard-match.obj: test-wildcard-match.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lib-test-wildcard-match.obj -MD -MP -MF $(DEPDIR)/test_lib-test-wildcard-match.Tpo -c -o test_lib-test-wildcard-match.obj `if test -f 'test-wildcard-match.c'; then $(CYGPATH_W) 'test-wildcard-match.c'; else $(CYGPATH_W) '$(srcdir)/test-wildcard-match.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lib-test-wildcard-match.Tpo $(DEPDIR)/test_lib-test-wildcard-match.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-wildcard-match.c' object='test_lib-test-wildcard-match.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lib_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lib-test-wildcard-match.obj `if test -f 'test-wildcard-match.c'; then $(CYGPATH_W) 'test-wildcard-match.c'; else $(CYGPATH_W) '$(srcdir)/test-wildcard-match.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
@$(NORMAL_INSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
done
uninstall-pkginc_libHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-local
check: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) check-am
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkginc_libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-am
install-exec: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-rm -f event-filter-lexer.c
-rm -f event-filter-parser.c
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
clean: clean-am
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/aqueue.Plo
-rm -f ./$(DEPDIR)/array.Plo
-rm -f ./$(DEPDIR)/askpass.Plo
-rm -f ./$(DEPDIR)/backtrace-string.Plo
-rm -f ./$(DEPDIR)/base32.Plo
-rm -f ./$(DEPDIR)/base64.Plo
-rm -f ./$(DEPDIR)/bits.Plo
-rm -f ./$(DEPDIR)/bsearch-insert-pos.Plo
-rm -f ./$(DEPDIR)/buffer-istream.Plo
-rm -f ./$(DEPDIR)/buffer.Plo
-rm -f ./$(DEPDIR)/child-wait.Plo
-rm -f ./$(DEPDIR)/compat.Plo
-rm -f ./$(DEPDIR)/connection.Plo
-rm -f ./$(DEPDIR)/cpu-limit.Plo
-rm -f ./$(DEPDIR)/crc32.Plo
-rm -f ./$(DEPDIR)/data-stack.Plo
-rm -f ./$(DEPDIR)/eacces-error.Plo
-rm -f ./$(DEPDIR)/env-util.Plo
-rm -f ./$(DEPDIR)/event-filter-lexer.Plo
-rm -f ./$(DEPDIR)/event-filter-parser.Plo
-rm -f ./$(DEPDIR)/event-filter.Plo
-rm -f ./$(DEPDIR)/event-log.Plo
-rm -f ./$(DEPDIR)/execv-const.Plo
-rm -f ./$(DEPDIR)/failures.Plo
-rm -f ./$(DEPDIR)/fd-util.Plo
-rm -f ./$(DEPDIR)/fdatasync-path.Plo
-rm -f ./$(DEPDIR)/fdpass.Plo
-rm -f ./$(DEPDIR)/file-cache.Plo
-rm -f ./$(DEPDIR)/file-copy.Plo
-rm -f ./$(DEPDIR)/file-create-locked.Plo
-rm -f ./$(DEPDIR)/file-dotlock.Plo
-rm -f ./$(DEPDIR)/file-lock.Plo
-rm -f ./$(DEPDIR)/file-set-size.Plo
-rm -f ./$(DEPDIR)/guid.Plo
-rm -f ./$(DEPDIR)/hash-format.Plo
-rm -f ./$(DEPDIR)/hash-method.Plo
-rm -f ./$(DEPDIR)/hash.Plo
-rm -f ./$(DEPDIR)/hash2.Plo
-rm -f ./$(DEPDIR)/hex-binary.Plo
-rm -f ./$(DEPDIR)/hex-dec.Plo
-rm -f ./$(DEPDIR)/hmac-cram-md5.Plo
-rm -f ./$(DEPDIR)/hmac.Plo
-rm -f ./$(DEPDIR)/home-expand.Plo
-rm -f ./$(DEPDIR)/hook-build.Plo
-rm -f ./$(DEPDIR)/hostpid.Plo
-rm -f ./$(DEPDIR)/imem.Plo
-rm -f ./$(DEPDIR)/ioloop-epoll.Plo
-rm -f ./$(DEPDIR)/ioloop-iolist.Plo
-rm -f ./$(DEPDIR)/ioloop-kqueue.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-fd.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-inotify.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-kqueue.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-none.Plo
-rm -f ./$(DEPDIR)/ioloop-poll.Plo
-rm -f ./$(DEPDIR)/ioloop-select.Plo
-rm -f ./$(DEPDIR)/ioloop.Plo
-rm -f ./$(DEPDIR)/iostream-proxy.Plo
-rm -f ./$(DEPDIR)/iostream-pump.Plo
-rm -f ./$(DEPDIR)/iostream-rawlog.Plo
-rm -f ./$(DEPDIR)/iostream-temp.Plo
-rm -f ./$(DEPDIR)/iostream.Plo
-rm -f ./$(DEPDIR)/ipwd.Plo
-rm -f ./$(DEPDIR)/iso8601-date.Plo
-rm -f ./$(DEPDIR)/istream-base64-decoder.Plo
-rm -f ./$(DEPDIR)/istream-base64-encoder.Plo
-rm -f ./$(DEPDIR)/istream-callback.Plo
-rm -f ./$(DEPDIR)/istream-chain.Plo
-rm -f ./$(DEPDIR)/istream-concat.Plo
-rm -f ./$(DEPDIR)/istream-crlf.Plo
-rm -f ./$(DEPDIR)/istream-data.Plo
-rm -f ./$(DEPDIR)/istream-failure-at.Plo
-rm -f ./$(DEPDIR)/istream-file.Plo
-rm -f ./$(DEPDIR)/istream-hash.Plo
-rm -f ./$(DEPDIR)/istream-jsonstr.Plo
-rm -f ./$(DEPDIR)/istream-limit.Plo
-rm -f ./$(DEPDIR)/istream-multiplex.Plo
-rm -f ./$(DEPDIR)/istream-rawlog.Plo
-rm -f ./$(DEPDIR)/istream-seekable.Plo
-rm -f ./$(DEPDIR)/istream-sized.Plo
-rm -f ./$(DEPDIR)/istream-tee.Plo
-rm -f ./$(DEPDIR)/istream-timeout.Plo
-rm -f ./$(DEPDIR)/istream-try.Plo
-rm -f ./$(DEPDIR)/istream-unix.Plo
-rm -f ./$(DEPDIR)/istream.Plo
-rm -f ./$(DEPDIR)/json-parser.Plo
-rm -f ./$(DEPDIR)/json-tree.Plo
-rm -f ./$(DEPDIR)/lib-event.Plo
-rm -f ./$(DEPDIR)/lib-signals.Plo
-rm -f ./$(DEPDIR)/lib.Plo
-rm -f ./$(DEPDIR)/log-throttle.Plo
-rm -f ./$(DEPDIR)/md4.Plo
-rm -f ./$(DEPDIR)/md5.Plo
-rm -f ./$(DEPDIR)/memarea.Plo
-rm -f ./$(DEPDIR)/mempool-allocfree.Plo
-rm -f ./$(DEPDIR)/mempool-alloconly.Plo
-rm -f ./$(DEPDIR)/mempool-datastack.Plo
-rm -f ./$(DEPDIR)/mempool-system.Plo
-rm -f ./$(DEPDIR)/mempool-unsafe-datastack.Plo
-rm -f ./$(DEPDIR)/mempool.Plo
-rm -f ./$(DEPDIR)/mkdir-parents.Plo
-rm -f ./$(DEPDIR)/mmap-anon.Plo
-rm -f ./$(DEPDIR)/mmap-util.Plo
-rm -f ./$(DEPDIR)/module-dir.Plo
-rm -f ./$(DEPDIR)/mountpoint.Plo
-rm -f ./$(DEPDIR)/net.Plo
-rm -f ./$(DEPDIR)/nfs-workarounds.Plo
-rm -f ./$(DEPDIR)/numpack.Plo
-rm -f ./$(DEPDIR)/ostream-buffer.Plo
-rm -f ./$(DEPDIR)/ostream-failure-at.Plo
-rm -f ./$(DEPDIR)/ostream-file.Plo
-rm -f ./$(DEPDIR)/ostream-hash.Plo
-rm -f ./$(DEPDIR)/ostream-multiplex.Plo
-rm -f ./$(DEPDIR)/ostream-null.Plo
-rm -f ./$(DEPDIR)/ostream-rawlog.Plo
-rm -f ./$(DEPDIR)/ostream-unix.Plo
-rm -f ./$(DEPDIR)/ostream-wrapper.Plo
-rm -f ./$(DEPDIR)/ostream.Plo
-rm -f ./$(DEPDIR)/path-util.Plo
-rm -f ./$(DEPDIR)/pkcs5.Plo
-rm -f ./$(DEPDIR)/primes.Plo
-rm -f ./$(DEPDIR)/printf-format-fix.Plo
-rm -f ./$(DEPDIR)/priorityq.Plo
-rm -f ./$(DEPDIR)/process-stat.Plo
-rm -f ./$(DEPDIR)/process-title.Plo
-rm -f ./$(DEPDIR)/rand.Plo
-rm -f ./$(DEPDIR)/randgen.Plo
-rm -f ./$(DEPDIR)/read-full.Plo
-rm -f ./$(DEPDIR)/restrict-access.Plo
-rm -f ./$(DEPDIR)/restrict-process-size.Plo
-rm -f ./$(DEPDIR)/safe-memset.Plo
-rm -f ./$(DEPDIR)/safe-mkdir.Plo
-rm -f ./$(DEPDIR)/safe-mkstemp.Plo
-rm -f ./$(DEPDIR)/sendfile-util.Plo
-rm -f ./$(DEPDIR)/seq-range-array.Plo
-rm -f ./$(DEPDIR)/seq-set-builder.Plo
-rm -f ./$(DEPDIR)/sha1.Plo
-rm -f ./$(DEPDIR)/sha2.Plo
-rm -f ./$(DEPDIR)/sha3.Plo
-rm -f ./$(DEPDIR)/sleep.Plo
-rm -f ./$(DEPDIR)/sort.Plo
-rm -f ./$(DEPDIR)/stats-dist.Plo
-rm -f ./$(DEPDIR)/str-find.Plo
-rm -f ./$(DEPDIR)/str-sanitize.Plo
-rm -f ./$(DEPDIR)/str-table.Plo
-rm -f ./$(DEPDIR)/str.Plo
-rm -f ./$(DEPDIR)/strescape.Plo
-rm -f ./$(DEPDIR)/strfuncs.Plo
-rm -f ./$(DEPDIR)/strnum.Plo
-rm -f ./$(DEPDIR)/test_lib-test-aqueue.Po
-rm -f ./$(DEPDIR)/test_lib-test-array.Po
-rm -f ./$(DEPDIR)/test_lib-test-backtrace.Po
-rm -f ./$(DEPDIR)/test_lib-test-base32.Po
-rm -f ./$(DEPDIR)/test_lib-test-base64.Po
-rm -f ./$(DEPDIR)/test_lib-test-bits.Po
-rm -f ./$(DEPDIR)/test_lib-test-bsearch-insert-pos.Po
-rm -f ./$(DEPDIR)/test_lib-test-buffer-istream.Po
-rm -f ./$(DEPDIR)/test_lib-test-buffer.Po
-rm -f ./$(DEPDIR)/test_lib-test-byteorder.Po
-rm -f ./$(DEPDIR)/test_lib-test-connection.Po
-rm -f ./$(DEPDIR)/test_lib-test-cpu-limit.Po
-rm -f ./$(DEPDIR)/test_lib-test-crc32.Po
-rm -f ./$(DEPDIR)/test_lib-test-data-stack.Po
-rm -f ./$(DEPDIR)/test_lib-test-env-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-category-register.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter-expr.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter-merge.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter-parser.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-flatten.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-log.Po
-rm -f ./$(DEPDIR)/test_lib-test-failures.Po
-rm -f ./$(DEPDIR)/test_lib-test-fd-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-file-cache.Po
-rm -f ./$(DEPDIR)/test_lib-test-file-create-locked.Po
-rm -f ./$(DEPDIR)/test_lib-test-guid.Po
-rm -f ./$(DEPDIR)/test_lib-test-hash-format.Po
-rm -f ./$(DEPDIR)/test_lib-test-hash-method.Po
-rm -f ./$(DEPDIR)/test_lib-test-hash.Po
-rm -f ./$(DEPDIR)/test_lib-test-hex-binary.Po
-rm -f ./$(DEPDIR)/test_lib-test-hmac.Po
-rm -f ./$(DEPDIR)/test_lib-test-imem.Po
-rm -f ./$(DEPDIR)/test_lib-test-ioloop.Po
-rm -f ./$(DEPDIR)/test_lib-test-iostream-proxy.Po
-rm -f ./$(DEPDIR)/test_lib-test-iostream-pump.Po
-rm -f ./$(DEPDIR)/test_lib-test-iostream-temp.Po
-rm -f ./$(DEPDIR)/test_lib-test-iso8601-date.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-base64-decoder.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-base64-encoder.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-chain.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-concat.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-crlf.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-failure-at.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-jsonstr.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-multiplex.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-seekable.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-sized.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-tee.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-try.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-unix.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream.Po
-rm -f ./$(DEPDIR)/test_lib-test-json-parser.Po
-rm -f ./$(DEPDIR)/test_lib-test-json-tree.Po
-rm -f ./$(DEPDIR)/test_lib-test-lib-event.Po
-rm -f ./$(DEPDIR)/test_lib-test-lib-signals.Po
-rm -f ./$(DEPDIR)/test_lib-test-lib.Po
-rm -f ./$(DEPDIR)/test_lib-test-llist.Po
-rm -f ./$(DEPDIR)/test_lib-test-log-throttle.Po
-rm -f ./$(DEPDIR)/test_lib-test-macros.Po
-rm -f ./$(DEPDIR)/test_lib-test-malloc-overflow.Po
-rm -f ./$(DEPDIR)/test_lib-test-memarea.Po
-rm -f ./$(DEPDIR)/test_lib-test-mempool-allocfree.Po
-rm -f ./$(DEPDIR)/test_lib-test-mempool-alloconly.Po
-rm -f ./$(DEPDIR)/test_lib-test-mempool.Po
-rm -f ./$(DEPDIR)/test_lib-test-multiplex.Po
-rm -f ./$(DEPDIR)/test_lib-test-net.Po
-rm -f ./$(DEPDIR)/test_lib-test-numpack.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-buffer.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-failure-at.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-file.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-multiplex.Po
-rm -f ./$(DEPDIR)/test_lib-test-path-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-pkcs5.Po
-rm -f ./$(DEPDIR)/test_lib-test-primes.Po
-rm -f ./$(DEPDIR)/test_lib-test-printf-format-fix.Po
-rm -f ./$(DEPDIR)/test_lib-test-priorityq.Po
-rm -f ./$(DEPDIR)/test_lib-test-random.Po
-rm -f ./$(DEPDIR)/test_lib-test-seq-range-array.Po
-rm -f ./$(DEPDIR)/test_lib-test-seq-set-builder.Po
-rm -f ./$(DEPDIR)/test_lib-test-stats-dist.Po
-rm -f ./$(DEPDIR)/test_lib-test-str-find.Po
-rm -f ./$(DEPDIR)/test_lib-test-str-sanitize.Po
-rm -f ./$(DEPDIR)/test_lib-test-str-table.Po
-rm -f ./$(DEPDIR)/test_lib-test-str.Po
-rm -f ./$(DEPDIR)/test_lib-test-strescape.Po
-rm -f ./$(DEPDIR)/test_lib-test-strfuncs.Po
-rm -f ./$(DEPDIR)/test_lib-test-strnum.Po
-rm -f ./$(DEPDIR)/test_lib-test-time-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-unichar.Po
-rm -f ./$(DEPDIR)/test_lib-test-uri.Po
-rm -f ./$(DEPDIR)/test_lib-test-utc-mktime.Po
-rm -f ./$(DEPDIR)/test_lib-test-var-expand.Po
-rm -f ./$(DEPDIR)/test_lib-test-wildcard-match.Po
-rm -f ./$(DEPDIR)/time-util.Plo
-rm -f ./$(DEPDIR)/unichar.Plo
-rm -f ./$(DEPDIR)/unix-socket-create.Plo
-rm -f ./$(DEPDIR)/unlink-directory.Plo
-rm -f ./$(DEPDIR)/unlink-old-files.Plo
-rm -f ./$(DEPDIR)/uri-util.Plo
-rm -f ./$(DEPDIR)/utc-mktime.Plo
-rm -f ./$(DEPDIR)/utc-offset.Plo
-rm -f ./$(DEPDIR)/var-expand-if.Plo
-rm -f ./$(DEPDIR)/var-expand.Plo
-rm -f ./$(DEPDIR)/wildcard-match.Plo
-rm -f ./$(DEPDIR)/write-full.Plo
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-pkginc_libHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/aqueue.Plo
-rm -f ./$(DEPDIR)/array.Plo
-rm -f ./$(DEPDIR)/askpass.Plo
-rm -f ./$(DEPDIR)/backtrace-string.Plo
-rm -f ./$(DEPDIR)/base32.Plo
-rm -f ./$(DEPDIR)/base64.Plo
-rm -f ./$(DEPDIR)/bits.Plo
-rm -f ./$(DEPDIR)/bsearch-insert-pos.Plo
-rm -f ./$(DEPDIR)/buffer-istream.Plo
-rm -f ./$(DEPDIR)/buffer.Plo
-rm -f ./$(DEPDIR)/child-wait.Plo
-rm -f ./$(DEPDIR)/compat.Plo
-rm -f ./$(DEPDIR)/connection.Plo
-rm -f ./$(DEPDIR)/cpu-limit.Plo
-rm -f ./$(DEPDIR)/crc32.Plo
-rm -f ./$(DEPDIR)/data-stack.Plo
-rm -f ./$(DEPDIR)/eacces-error.Plo
-rm -f ./$(DEPDIR)/env-util.Plo
-rm -f ./$(DEPDIR)/event-filter-lexer.Plo
-rm -f ./$(DEPDIR)/event-filter-parser.Plo
-rm -f ./$(DEPDIR)/event-filter.Plo
-rm -f ./$(DEPDIR)/event-log.Plo
-rm -f ./$(DEPDIR)/execv-const.Plo
-rm -f ./$(DEPDIR)/failures.Plo
-rm -f ./$(DEPDIR)/fd-util.Plo
-rm -f ./$(DEPDIR)/fdatasync-path.Plo
-rm -f ./$(DEPDIR)/fdpass.Plo
-rm -f ./$(DEPDIR)/file-cache.Plo
-rm -f ./$(DEPDIR)/file-copy.Plo
-rm -f ./$(DEPDIR)/file-create-locked.Plo
-rm -f ./$(DEPDIR)/file-dotlock.Plo
-rm -f ./$(DEPDIR)/file-lock.Plo
-rm -f ./$(DEPDIR)/file-set-size.Plo
-rm -f ./$(DEPDIR)/guid.Plo
-rm -f ./$(DEPDIR)/hash-format.Plo
-rm -f ./$(DEPDIR)/hash-method.Plo
-rm -f ./$(DEPDIR)/hash.Plo
-rm -f ./$(DEPDIR)/hash2.Plo
-rm -f ./$(DEPDIR)/hex-binary.Plo
-rm -f ./$(DEPDIR)/hex-dec.Plo
-rm -f ./$(DEPDIR)/hmac-cram-md5.Plo
-rm -f ./$(DEPDIR)/hmac.Plo
-rm -f ./$(DEPDIR)/home-expand.Plo
-rm -f ./$(DEPDIR)/hook-build.Plo
-rm -f ./$(DEPDIR)/hostpid.Plo
-rm -f ./$(DEPDIR)/imem.Plo
-rm -f ./$(DEPDIR)/ioloop-epoll.Plo
-rm -f ./$(DEPDIR)/ioloop-iolist.Plo
-rm -f ./$(DEPDIR)/ioloop-kqueue.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-fd.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-inotify.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-kqueue.Plo
-rm -f ./$(DEPDIR)/ioloop-notify-none.Plo
-rm -f ./$(DEPDIR)/ioloop-poll.Plo
-rm -f ./$(DEPDIR)/ioloop-select.Plo
-rm -f ./$(DEPDIR)/ioloop.Plo
-rm -f ./$(DEPDIR)/iostream-proxy.Plo
-rm -f ./$(DEPDIR)/iostream-pump.Plo
-rm -f ./$(DEPDIR)/iostream-rawlog.Plo
-rm -f ./$(DEPDIR)/iostream-temp.Plo
-rm -f ./$(DEPDIR)/iostream.Plo
-rm -f ./$(DEPDIR)/ipwd.Plo
-rm -f ./$(DEPDIR)/iso8601-date.Plo
-rm -f ./$(DEPDIR)/istream-base64-decoder.Plo
-rm -f ./$(DEPDIR)/istream-base64-encoder.Plo
-rm -f ./$(DEPDIR)/istream-callback.Plo
-rm -f ./$(DEPDIR)/istream-chain.Plo
-rm -f ./$(DEPDIR)/istream-concat.Plo
-rm -f ./$(DEPDIR)/istream-crlf.Plo
-rm -f ./$(DEPDIR)/istream-data.Plo
-rm -f ./$(DEPDIR)/istream-failure-at.Plo
-rm -f ./$(DEPDIR)/istream-file.Plo
-rm -f ./$(DEPDIR)/istream-hash.Plo
-rm -f ./$(DEPDIR)/istream-jsonstr.Plo
-rm -f ./$(DEPDIR)/istream-limit.Plo
-rm -f ./$(DEPDIR)/istream-multiplex.Plo
-rm -f ./$(DEPDIR)/istream-rawlog.Plo
-rm -f ./$(DEPDIR)/istream-seekable.Plo
-rm -f ./$(DEPDIR)/istream-sized.Plo
-rm -f ./$(DEPDIR)/istream-tee.Plo
-rm -f ./$(DEPDIR)/istream-timeout.Plo
-rm -f ./$(DEPDIR)/istream-try.Plo
-rm -f ./$(DEPDIR)/istream-unix.Plo
-rm -f ./$(DEPDIR)/istream.Plo
-rm -f ./$(DEPDIR)/json-parser.Plo
-rm -f ./$(DEPDIR)/json-tree.Plo
-rm -f ./$(DEPDIR)/lib-event.Plo
-rm -f ./$(DEPDIR)/lib-signals.Plo
-rm -f ./$(DEPDIR)/lib.Plo
-rm -f ./$(DEPDIR)/log-throttle.Plo
-rm -f ./$(DEPDIR)/md4.Plo
-rm -f ./$(DEPDIR)/md5.Plo
-rm -f ./$(DEPDIR)/memarea.Plo
-rm -f ./$(DEPDIR)/mempool-allocfree.Plo
-rm -f ./$(DEPDIR)/mempool-alloconly.Plo
-rm -f ./$(DEPDIR)/mempool-datastack.Plo
-rm -f ./$(DEPDIR)/mempool-system.Plo
-rm -f ./$(DEPDIR)/mempool-unsafe-datastack.Plo
-rm -f ./$(DEPDIR)/mempool.Plo
-rm -f ./$(DEPDIR)/mkdir-parents.Plo
-rm -f ./$(DEPDIR)/mmap-anon.Plo
-rm -f ./$(DEPDIR)/mmap-util.Plo
-rm -f ./$(DEPDIR)/module-dir.Plo
-rm -f ./$(DEPDIR)/mountpoint.Plo
-rm -f ./$(DEPDIR)/net.Plo
-rm -f ./$(DEPDIR)/nfs-workarounds.Plo
-rm -f ./$(DEPDIR)/numpack.Plo
-rm -f ./$(DEPDIR)/ostream-buffer.Plo
-rm -f ./$(DEPDIR)/ostream-failure-at.Plo
-rm -f ./$(DEPDIR)/ostream-file.Plo
-rm -f ./$(DEPDIR)/ostream-hash.Plo
-rm -f ./$(DEPDIR)/ostream-multiplex.Plo
-rm -f ./$(DEPDIR)/ostream-null.Plo
-rm -f ./$(DEPDIR)/ostream-rawlog.Plo
-rm -f ./$(DEPDIR)/ostream-unix.Plo
-rm -f ./$(DEPDIR)/ostream-wrapper.Plo
-rm -f ./$(DEPDIR)/ostream.Plo
-rm -f ./$(DEPDIR)/path-util.Plo
-rm -f ./$(DEPDIR)/pkcs5.Plo
-rm -f ./$(DEPDIR)/primes.Plo
-rm -f ./$(DEPDIR)/printf-format-fix.Plo
-rm -f ./$(DEPDIR)/priorityq.Plo
-rm -f ./$(DEPDIR)/process-stat.Plo
-rm -f ./$(DEPDIR)/process-title.Plo
-rm -f ./$(DEPDIR)/rand.Plo
-rm -f ./$(DEPDIR)/randgen.Plo
-rm -f ./$(DEPDIR)/read-full.Plo
-rm -f ./$(DEPDIR)/restrict-access.Plo
-rm -f ./$(DEPDIR)/restrict-process-size.Plo
-rm -f ./$(DEPDIR)/safe-memset.Plo
-rm -f ./$(DEPDIR)/safe-mkdir.Plo
-rm -f ./$(DEPDIR)/safe-mkstemp.Plo
-rm -f ./$(DEPDIR)/sendfile-util.Plo
-rm -f ./$(DEPDIR)/seq-range-array.Plo
-rm -f ./$(DEPDIR)/seq-set-builder.Plo
-rm -f ./$(DEPDIR)/sha1.Plo
-rm -f ./$(DEPDIR)/sha2.Plo
-rm -f ./$(DEPDIR)/sha3.Plo
-rm -f ./$(DEPDIR)/sleep.Plo
-rm -f ./$(DEPDIR)/sort.Plo
-rm -f ./$(DEPDIR)/stats-dist.Plo
-rm -f ./$(DEPDIR)/str-find.Plo
-rm -f ./$(DEPDIR)/str-sanitize.Plo
-rm -f ./$(DEPDIR)/str-table.Plo
-rm -f ./$(DEPDIR)/str.Plo
-rm -f ./$(DEPDIR)/strescape.Plo
-rm -f ./$(DEPDIR)/strfuncs.Plo
-rm -f ./$(DEPDIR)/strnum.Plo
-rm -f ./$(DEPDIR)/test_lib-test-aqueue.Po
-rm -f ./$(DEPDIR)/test_lib-test-array.Po
-rm -f ./$(DEPDIR)/test_lib-test-backtrace.Po
-rm -f ./$(DEPDIR)/test_lib-test-base32.Po
-rm -f ./$(DEPDIR)/test_lib-test-base64.Po
-rm -f ./$(DEPDIR)/test_lib-test-bits.Po
-rm -f ./$(DEPDIR)/test_lib-test-bsearch-insert-pos.Po
-rm -f ./$(DEPDIR)/test_lib-test-buffer-istream.Po
-rm -f ./$(DEPDIR)/test_lib-test-buffer.Po
-rm -f ./$(DEPDIR)/test_lib-test-byteorder.Po
-rm -f ./$(DEPDIR)/test_lib-test-connection.Po
-rm -f ./$(DEPDIR)/test_lib-test-cpu-limit.Po
-rm -f ./$(DEPDIR)/test_lib-test-crc32.Po
-rm -f ./$(DEPDIR)/test_lib-test-data-stack.Po
-rm -f ./$(DEPDIR)/test_lib-test-env-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-category-register.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter-expr.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter-merge.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter-parser.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-filter.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-flatten.Po
-rm -f ./$(DEPDIR)/test_lib-test-event-log.Po
-rm -f ./$(DEPDIR)/test_lib-test-failures.Po
-rm -f ./$(DEPDIR)/test_lib-test-fd-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-file-cache.Po
-rm -f ./$(DEPDIR)/test_lib-test-file-create-locked.Po
-rm -f ./$(DEPDIR)/test_lib-test-guid.Po
-rm -f ./$(DEPDIR)/test_lib-test-hash-format.Po
-rm -f ./$(DEPDIR)/test_lib-test-hash-method.Po
-rm -f ./$(DEPDIR)/test_lib-test-hash.Po
-rm -f ./$(DEPDIR)/test_lib-test-hex-binary.Po
-rm -f ./$(DEPDIR)/test_lib-test-hmac.Po
-rm -f ./$(DEPDIR)/test_lib-test-imem.Po
-rm -f ./$(DEPDIR)/test_lib-test-ioloop.Po
-rm -f ./$(DEPDIR)/test_lib-test-iostream-proxy.Po
-rm -f ./$(DEPDIR)/test_lib-test-iostream-pump.Po
-rm -f ./$(DEPDIR)/test_lib-test-iostream-temp.Po
-rm -f ./$(DEPDIR)/test_lib-test-iso8601-date.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-base64-decoder.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-base64-encoder.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-chain.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-concat.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-crlf.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-failure-at.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-jsonstr.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-multiplex.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-seekable.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-sized.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-tee.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-try.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream-unix.Po
-rm -f ./$(DEPDIR)/test_lib-test-istream.Po
-rm -f ./$(DEPDIR)/test_lib-test-json-parser.Po
-rm -f ./$(DEPDIR)/test_lib-test-json-tree.Po
-rm -f ./$(DEPDIR)/test_lib-test-lib-event.Po
-rm -f ./$(DEPDIR)/test_lib-test-lib-signals.Po
-rm -f ./$(DEPDIR)/test_lib-test-lib.Po
-rm -f ./$(DEPDIR)/test_lib-test-llist.Po
-rm -f ./$(DEPDIR)/test_lib-test-log-throttle.Po
-rm -f ./$(DEPDIR)/test_lib-test-macros.Po
-rm -f ./$(DEPDIR)/test_lib-test-malloc-overflow.Po
-rm -f ./$(DEPDIR)/test_lib-test-memarea.Po
-rm -f ./$(DEPDIR)/test_lib-test-mempool-allocfree.Po
-rm -f ./$(DEPDIR)/test_lib-test-mempool-alloconly.Po
-rm -f ./$(DEPDIR)/test_lib-test-mempool.Po
-rm -f ./$(DEPDIR)/test_lib-test-multiplex.Po
-rm -f ./$(DEPDIR)/test_lib-test-net.Po
-rm -f ./$(DEPDIR)/test_lib-test-numpack.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-buffer.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-failure-at.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-file.Po
-rm -f ./$(DEPDIR)/test_lib-test-ostream-multiplex.Po
-rm -f ./$(DEPDIR)/test_lib-test-path-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-pkcs5.Po
-rm -f ./$(DEPDIR)/test_lib-test-primes.Po
-rm -f ./$(DEPDIR)/test_lib-test-printf-format-fix.Po
-rm -f ./$(DEPDIR)/test_lib-test-priorityq.Po
-rm -f ./$(DEPDIR)/test_lib-test-random.Po
-rm -f ./$(DEPDIR)/test_lib-test-seq-range-array.Po
-rm -f ./$(DEPDIR)/test_lib-test-seq-set-builder.Po
-rm -f ./$(DEPDIR)/test_lib-test-stats-dist.Po
-rm -f ./$(DEPDIR)/test_lib-test-str-find.Po
-rm -f ./$(DEPDIR)/test_lib-test-str-sanitize.Po
-rm -f ./$(DEPDIR)/test_lib-test-str-table.Po
-rm -f ./$(DEPDIR)/test_lib-test-str.Po
-rm -f ./$(DEPDIR)/test_lib-test-strescape.Po
-rm -f ./$(DEPDIR)/test_lib-test-strfuncs.Po
-rm -f ./$(DEPDIR)/test_lib-test-strnum.Po
-rm -f ./$(DEPDIR)/test_lib-test-time-util.Po
-rm -f ./$(DEPDIR)/test_lib-test-unichar.Po
-rm -f ./$(DEPDIR)/test_lib-test-uri.Po
-rm -f ./$(DEPDIR)/test_lib-test-utc-mktime.Po
-rm -f ./$(DEPDIR)/test_lib-test-var-expand.Po
-rm -f ./$(DEPDIR)/test_lib-test-wildcard-match.Po
-rm -f ./$(DEPDIR)/time-util.Plo
-rm -f ./$(DEPDIR)/unichar.Plo
-rm -f ./$(DEPDIR)/unix-socket-create.Plo
-rm -f ./$(DEPDIR)/unlink-directory.Plo
-rm -f ./$(DEPDIR)/unlink-old-files.Plo
-rm -f ./$(DEPDIR)/uri-util.Plo
-rm -f ./$(DEPDIR)/utc-mktime.Plo
-rm -f ./$(DEPDIR)/utc-offset.Plo
-rm -f ./$(DEPDIR)/var-expand-if.Plo
-rm -f ./$(DEPDIR)/var-expand.Plo
-rm -f ./$(DEPDIR)/wildcard-match.Plo
-rm -f ./$(DEPDIR)/write-full.Plo
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-pkginc_libHEADERS
.MAKE: all check check-am install install-am install-exec \
install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \
check-local clean clean-generic clean-libtool \
clean-noinstLTLIBRARIES clean-noinstPROGRAMS cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-pkginc_libHEADERS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
uninstall-pkginc_libHEADERS
.PRECIOUS: Makefile
# We use custom rules here because we want to use flex and bison instead
# of lex and yacc (or bison in yacc-compatibility mode). Both flex and
# bison can handle properly naming the generated files, and it is simpler
# and cleaner to make this rule ourselves instead of working around ylwrap
# and yywrap's antiquated notion of what is hapenning.
.l.c:
$(AM_V_GEN)$(FLEX) -o $@ $<
.y.c:
$(AM_V_GEN)$(BISON) -o $@ $<
# Bison generates both a header and a .c file. Without the following
# dependency, anything including the header will race the bison process.
event-filter-parser.h: event-filter-parser.c
$(srcdir)/UnicodeData.txt:
test -f $@ || wget -O $@ https://dovecot.org/res/UnicodeData.txt
$(srcdir)/unicodemap.c: $(srcdir)/unicodemap.pl $(srcdir)/UnicodeData.txt
perl $(srcdir)/unicodemap.pl < $(srcdir)/UnicodeData.txt > $@
check-local:
for bin in $(test_programs); do \
if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
done
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
dovecot-2.3.21.1/src/lib/array.c 0000644 0000000 0000000 00000010613 14656633576 013135 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
void *
array_idx_modifiable_i(const struct array *array, unsigned int idx)
{
i_assert(idx < array->buffer->used / array->element_size);
return PTR_OFFSET(array->buffer->data, idx * array->element_size);
}
void *array_idx_get_space_i(struct array *array, unsigned int idx)
{
return buffer_get_space_unsafe(array->buffer, idx * array->element_size,
array->element_size);
}
void array_idx_set_i(struct array *array, unsigned int idx, const void *data)
{
buffer_write(array->buffer, idx * array->element_size,
data, array->element_size);
}
void array_idx_clear_i(struct array *array, unsigned int idx)
{
buffer_write_zero(array->buffer, idx * array->element_size,
array->element_size);
}
void *array_insert_space_i(struct array *array, unsigned int idx)
{
void *data;
size_t pos;
pos = idx * array->element_size;
buffer_copy(array->buffer, pos + array->element_size,
array->buffer, pos, SIZE_MAX);
data = buffer_get_space_unsafe(array->buffer, pos, array->element_size);
memset(data, 0, array->element_size);
return data;
}
bool array_cmp_i(const struct array *array1, const struct array *array2)
{
if (!array_is_created_i(array1) || array1->buffer->used == 0)
return !array_is_created_i(array2) || array2->buffer->used == 0;
if (!array_is_created_i(array2))
return FALSE;
return buffer_cmp(array1->buffer, array2->buffer);
}
bool array_equal_fn_i(const struct array *array1, const struct array *array2,
int (*cmp)(const void *, const void*))
{
unsigned int count1, count2, i;
size_t size;
if (!array_is_created_i(array1) || array1->buffer->used == 0)
return !array_is_created_i(array2) || array2->buffer->used == 0;
if (!array_is_created_i(array2))
return FALSE;
count1 = array_count_i(array1); count2 = array_count_i(array2);
if (count1 != count2)
return FALSE;
size = array1->element_size;
i_assert(size == array2->element_size);
for (i = 0; i < count1; i++) {
if (cmp(CONST_PTR_OFFSET(array1->buffer->data, i * size),
CONST_PTR_OFFSET(array2->buffer->data, i * size)) != 0)
return FALSE;
}
return TRUE;
}
bool array_equal_fn_ctx_i(const struct array *array1, const struct array *array2,
int (*cmp)(const void *, const void *, const void *),
const void *context)
{
unsigned int count1, count2, i;
size_t size;
if (!array_is_created_i(array1) || array1->buffer->used == 0)
return !array_is_created_i(array2) || array2->buffer->used == 0;
if (!array_is_created_i(array2))
return FALSE;
count1 = array_count_i(array1); count2 = array_count_i(array2);
if (count1 != count2)
return FALSE;
size = array1->element_size;
i_assert(size == array2->element_size);
for (i = 0; i < count1; i++) {
if (cmp(CONST_PTR_OFFSET(array1->buffer->data, i * size),
CONST_PTR_OFFSET(array2->buffer->data, i * size), context) != 0)
return FALSE;
}
return TRUE;
}
void array_reverse_i(struct array *array)
{
const size_t element_size = array->element_size;
unsigned int i, count = array_count_i(array);
size_t size;
void *data, *tmp;
data = buffer_get_modifiable_data(array->buffer, &size);
tmp = t_buffer_get(array->element_size);
for (i = 0; i+1 < count; i++, count--) {
memcpy(tmp, PTR_OFFSET(data, i * element_size), element_size);
memcpy(PTR_OFFSET(data, i * element_size),
PTR_OFFSET(data, (count-1) * element_size),
element_size);
memcpy(PTR_OFFSET(data, (count-1) * element_size), tmp,
element_size);
}
}
void array_sort_i(struct array *array, int (*cmp)(const void *, const void *))
{
unsigned int count;
count = array_count_i(array);
if (count == 0)
return;
qsort(buffer_get_modifiable_data(array->buffer, NULL),
count, array->element_size, cmp);
}
void *array_bsearch_i(struct array *array, const void *key,
int (*cmp)(const void *, const void *))
{
unsigned int count;
count = array_count_i(array);
return bsearch(key, array->buffer->data,
count, array->element_size, cmp);
}
const void *array_lsearch_i(const struct array *array, const void *key,
int (*cmp)(const void *, const void *))
{
const void * const data = array->buffer->data;
const size_t s = array->element_size;
unsigned int idx;
for (idx = 0; idx < array_count_i(array); idx++) {
if (cmp(key, CONST_PTR_OFFSET(data, idx * s)) == 0) {
return PTR_OFFSET(data, idx * s);
}
}
return NULL;
}
dovecot-2.3.21.1/src/lib/file-cache.c 0000644 0000000 0000000 00000020432 14656633576 013777 0000000 0000000 /* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "mmap-util.h"
#include "file-cache.h"
#include
struct file_cache {
int fd;
char *path;
buffer_t *page_bitmask;
void *mmap_base;
size_t mmap_length;
size_t read_highwater;
};
struct file_cache *file_cache_new(int fd)
{
return file_cache_new_path(fd, "");
}
struct file_cache *file_cache_new_path(int fd, const char *path)
{
struct file_cache *cache;
cache = i_new(struct file_cache, 1);
cache->fd = fd;
cache->path = i_strdup(path);
cache->page_bitmask = buffer_create_dynamic(default_pool, 128);
return cache;
}
void file_cache_free(struct file_cache **_cache)
{
struct file_cache *cache = *_cache;
*_cache = NULL;
if (cache->mmap_base != NULL) {
if (munmap_anon(cache->mmap_base, cache->mmap_length) < 0)
i_error("munmap_anon(%s) failed: %m", cache->path);
}
buffer_free(&cache->page_bitmask);
i_free(cache->path);
i_free(cache);
}
void file_cache_set_fd(struct file_cache *cache, int fd)
{
cache->fd = fd;
file_cache_invalidate(cache, 0, cache->mmap_length);
}
int file_cache_set_size(struct file_cache *cache, uoff_t size)
{
size_t page_size = mmap_get_page_size();
uoff_t diff;
void *new_base;
i_assert(page_size > 0);
diff = size % page_size;
if (diff != 0)
size += page_size - diff;
i_assert((size % page_size) == 0);
if (size <= cache->mmap_length)
return 0;
if (size > SIZE_MAX) {
i_error("file_cache_set_size(%s, %"PRIuUOFF_T"): size too large",
cache->path, size);
return -1;
}
/* grow mmaping */
if (cache->mmap_base == NULL) {
cache->mmap_base = mmap_anon(size);
if (cache->mmap_base == MAP_FAILED) {
i_error("mmap_anon(%s, %"PRIuUOFF_T") failed: %m",
cache->path, size);
cache->mmap_base = NULL;
cache->mmap_length = 0;
return -1;
}
} else {
new_base = mremap_anon(cache->mmap_base, cache->mmap_length,
size, MREMAP_MAYMOVE);
if (new_base == MAP_FAILED) {
i_error("mremap_anon(%s, %"PRIuUOFF_T") failed: %m",
cache->path, size);
return -1;
}
cache->mmap_base = new_base;
}
cache->mmap_length = size;
return 0;
}
ssize_t file_cache_read(struct file_cache *cache, uoff_t offset, size_t size)
{
size_t page_size = mmap_get_page_size();
size_t poffset, psize, dest_offset, dest_size;
unsigned char *bits, *dest;
ssize_t ret;
i_assert(page_size > 0);
if (size > SSIZE_T_MAX) {
/* make sure our calculations won't overflow. most likely
we'll be reading less data, but allow it anyway so caller
doesn't have to deal with any extra checks. */
size = SSIZE_T_MAX;
}
if (offset >= UOFF_T_MAX - size)
size = UOFF_T_MAX - offset;
if (offset + size > cache->mmap_length &&
offset + size - cache->mmap_length > 1024*1024) {
/* growing more than a megabyte, make sure that the
file is large enough so we don't allocate memory
more than needed */
struct stat st;
if (fstat(cache->fd, &st) < 0) {
if (errno != ESTALE)
i_error("fstat(%s) failed: %m", cache->path);
return -1;
}
if (offset + size > (uoff_t)st.st_size) {
if (offset >= (uoff_t)st.st_size)
return 0;
size = (uoff_t)st.st_size - offset;
}
}
if (file_cache_set_size(cache, offset + size) < 0)
return -1;
poffset = offset / page_size;
psize = (offset + size + page_size-1) / page_size - poffset;
i_assert(psize > 0);
bits = buffer_get_space_unsafe(cache->page_bitmask, 0,
(poffset + psize + CHAR_BIT - 1) /
CHAR_BIT);
dest_offset = poffset * page_size;
dest = PTR_OFFSET(cache->mmap_base, dest_offset);
dest_size = page_size;
while (psize > 0) {
if ((bits[poffset / CHAR_BIT] & (1 << (poffset % CHAR_BIT))) != 0) {
/* page is already in cache */
dest_offset += page_size;
if (dest_offset <= cache->read_highwater) {
psize--; poffset++;
dest += page_size;
continue;
}
/* this is the last partially cached block.
use the caching only if we don't want to
read past read_highwater */
if (offset + size <= cache->read_highwater) {
i_assert(psize == 1);
break;
}
/* mark the block noncached again and
read it */
bits[poffset / CHAR_BIT] &=
~(1 << (poffset % CHAR_BIT));
dest_offset -= page_size;
}
ret = pread(cache->fd, dest, dest_size, dest_offset);
if (ret <= 0) {
if (ret < 0)
return -1;
/* EOF. mark the last block as cached even if it
isn't completely. read_highwater tells us how far
we've actually made. */
if (dest_offset == cache->read_highwater) {
i_assert(poffset ==
cache->read_highwater / page_size);
bits[poffset / CHAR_BIT] |=
1 << (poffset % CHAR_BIT);
}
return dest_offset <= offset ? 0 :
dest_offset - offset < size ?
dest_offset - offset : size;
}
dest += ret;
dest_offset += ret;
if (cache->read_highwater < dest_offset) {
unsigned int high_poffset =
cache->read_highwater / page_size;
/* read_highwater needs to be updated. if we didn't
just read that block, we can't trust anymore that
we have it cached */
bits[high_poffset / CHAR_BIT] &=
~(1 << (high_poffset % CHAR_BIT));
cache->read_highwater = dest_offset;
}
if ((size_t)ret != dest_size) {
/* partial read - probably EOF but make sure. */
dest_size -= ret;
continue;
}
bits[poffset / CHAR_BIT] |= 1 << (poffset % CHAR_BIT);
dest_size = page_size;
psize--; poffset++;
}
return size;
}
const void *file_cache_get_map(struct file_cache *cache, size_t *size_r)
{
*size_r = cache->read_highwater;
return cache->mmap_base;
}
void file_cache_write(struct file_cache *cache, const void *data, size_t size,
uoff_t offset)
{
size_t page_size = mmap_get_page_size();
unsigned char *bits;
unsigned int first_page, last_page;
i_assert(page_size > 0);
i_assert(UOFF_T_MAX - offset > size);
if (file_cache_set_size(cache, offset + size) < 0) {
/* couldn't grow mapping. just make sure the written memory
area is invalidated then. */
file_cache_invalidate(cache, offset, size);
return;
}
memcpy(PTR_OFFSET(cache->mmap_base, offset), data, size);
if (cache->read_highwater < offset + size) {
unsigned int page = cache->read_highwater / page_size;
bits = buffer_get_space_unsafe(cache->page_bitmask,
page / CHAR_BIT, 1);
*bits &= ~(1 << (page % CHAR_BIT));
cache->read_highwater = offset + size;
}
/* mark fully written pages cached */
if (size >= page_size) {
first_page = offset / page_size;
last_page = (offset + size) / page_size;
if ((offset % page_size) != 0)
first_page++;
bits = buffer_get_space_unsafe(cache->page_bitmask, 0,
last_page / CHAR_BIT + 1);
for (; first_page < last_page; first_page++) {
bits[first_page / CHAR_BIT] |=
1 << (first_page % CHAR_BIT);
}
}
}
void file_cache_invalidate(struct file_cache *cache, uoff_t offset, uoff_t size)
{
size_t page_size = mmap_get_page_size();
unsigned char *bits, mask;
unsigned int i;
if (offset >= cache->read_highwater || size == 0)
return;
i_assert(page_size > 0);
if (size > cache->read_highwater - offset) {
/* ignore anything after read highwater */
size = cache->read_highwater - offset;
}
if (size >= cache->read_highwater) {
/* we're invalidating everything up to read highwater.
drop the highwater position. */
cache->read_highwater = offset & ~(page_size-1);
}
size = (offset + size + page_size-1) / page_size;
offset /= page_size;
i_assert(size > offset);
size -= offset;
if (size != 1) {
/* tell operating system that we don't need the memory anymore
and it may free it. don't bother to do it for single pages,
there's a good chance that they get re-read back
immediately. */
(void)madvise(PTR_OFFSET(cache->mmap_base, offset * page_size),
size * page_size, MADV_DONTNEED);
}
bits = buffer_get_space_unsafe(cache->page_bitmask, offset / CHAR_BIT,
1 + (size + CHAR_BIT - 1) / CHAR_BIT);
/* set the first byte */
for (i = offset % CHAR_BIT, mask = 0; i < CHAR_BIT && size > 0; i++) {
mask |= 1 << i;
size--;
}
*bits++ &= ~mask;
/* set the middle bytes */
memset(bits, 0, size / CHAR_BIT);
bits += size / CHAR_BIT;
size %= CHAR_BIT;
/* set the last byte */
if (size > 0) {
for (i = 0, mask = 0; i < size; i++)
mask |= 1 << i;
*bits &= ~mask;
}
}
dovecot-2.3.21.1/src/lib/test-istream-seekable.c 0000644 0000000 0000000 00000020416 14656633576 016213 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "sha2.h"
#include "istream-private.h"
#include "istream-sized.h"
#include "istream-hash.h"
#include "istream-seekable.h"
#include
#include
static int fd_callback_fd = -1;
static int fd_callback(const char **path_r, void *context ATTR_UNUSED)
{
int fd;
*path_r = "test-lib.tmp";
fd = open(*path_r, O_RDWR | O_CREAT | O_TRUNC, 0600);
if (fd == -1)
i_error("creat(%s) failed: %m", *path_r);
else
i_unlink(*path_r);
fd_callback_fd = fd;
return fd;
}
static void test_istream_seekable_one(unsigned int buffer_size)
{
static const char *input_string = "xyz";
#define STREAM_COUNT 5
#define STREAM_BYTES 3
struct istream *streams[STREAM_COUNT+1];
struct istream *input;
const unsigned char *data;
size_t size;
unsigned int i, j;
for (i = 0; i < STREAM_COUNT; i++) {
streams[i] = test_istream_create(input_string);
streams[i]->seekable = FALSE;
test_istream_set_allow_eof(streams[i], TRUE);
test_istream_set_size(streams[i], 0);
}
streams[i] = NULL;
input = i_stream_create_seekable(streams, buffer_size, fd_callback, NULL);
test_assert(!input->blocking);
for (i = 0; i/STREAM_BYTES < STREAM_COUNT; i++) {
test_istream_set_size(streams[i/STREAM_BYTES], (i%STREAM_BYTES) + 1);
if (i < buffer_size) {
test_assert(i_stream_read(input) == 1);
data = i_stream_get_data(input, &size);
test_assert(size == i+1);
} else {
test_assert(i_stream_read(input) == -2);
i_stream_skip(input, 1);
test_assert(i_stream_read(input) == 1);
data = i_stream_get_data(input, &size);
test_assert(size == buffer_size);
}
for (j = 0; j < size; j++) {
test_assert((char)data[j] == input_string[(input->v_offset + j) % STREAM_BYTES]);
}
}
test_assert(!input->blocking);
test_assert(i_stream_read(input) == -1);
test_assert(input->blocking);
for (i = 0; i < STREAM_COUNT; i++) {
test_assert(streams[i]->eof && streams[i]->stream_errno == 0);
i_stream_unref(&streams[i]);
}
i_stream_unref(&input);
}
static void test_istream_seekable_random(void)
{
struct istream **streams, *input;
const unsigned char *data;
unsigned char *w_data;
size_t size;
unsigned int i, j, offset, stream_count, data_len, buffer_size;
stream_count = i_rand_minmax(2, 10 + 2 - 1);
streams = t_new(struct istream *, stream_count + 1);
for (i = 0, offset = 0; i < stream_count; i++) {
data_len = i_rand_minmax(1, 100);
w_data = t_malloc_no0(data_len);
for (j = 0; j < data_len; j++)
w_data[j] = (offset++) & 0xff;
streams[i] = test_istream_create_data(w_data, data_len);
streams[i]->seekable = FALSE;
test_istream_set_allow_eof(streams[i], TRUE);
}
streams[i] = NULL;
i_assert(offset > 0);
buffer_size = i_rand_minmax(1, 100); size = 0;
input = i_stream_create_seekable(streams, buffer_size, fd_callback, NULL);
test_assert(!input->blocking);
/* first read it through */
while (i_stream_read(input) > 0) {
size = i_stream_get_data_size(input);
i_stream_skip(input, size);
}
test_assert(input->blocking);
i_stream_seek(input, 0);
for (i = 0; i < 100; i++) {
if (i_rand_limit(3) == 0) {
i_stream_seek(input, i_rand_limit(offset));
} else {
ssize_t ret = i_stream_read(input);
if (input->v_offset + size == offset)
test_assert(ret < 0);
else if (ret == -2) {
test_assert(size == buffer_size);
} else {
test_assert(ret > 0);
test_assert(input->v_offset + ret <= offset);
i_stream_skip(input, i_rand_limit(ret + 1));
data = i_stream_get_data(input, &size);
for (j = 0; j < size; j++) {
test_assert(data[j] == (input->v_offset + j) % 256);
}
}
}
size = i_stream_get_data_size(input);
}
for (i = 0; i < stream_count; i++) {
test_assert(streams[i]->eof && streams[i]->stream_errno == 0);
i_stream_unref(&streams[i]);
}
i_stream_unref(&input);
}
static void test_istream_seekable_eof(void)
{
static const char *in_str = "foo";
unsigned int in_str_len = strlen(in_str);
struct istream *streams[2], *input;
const unsigned char *data;
size_t size;
test_begin("istream seekable eof");
streams[0] = i_stream_create_from_data(in_str, in_str_len);
streams[0]->seekable = FALSE;
streams[1] = NULL;
input = i_stream_create_seekable(streams, in_str_len, fd_callback, NULL);
test_assert(i_stream_read(input) == (ssize_t)in_str_len);
data = i_stream_get_data(input, &size);
test_assert(size == in_str_len);
test_assert(memcmp(data, in_str, in_str_len) == 0);
test_assert(i_stream_read(input) == -1);
data = i_stream_get_data(input, &size);
test_assert(size == in_str_len);
test_assert(memcmp(data, in_str, in_str_len) == 0);
i_stream_seek(input, size);
i_stream_unref(&input);
test_assert(streams[0]->v_offset == in_str_len);
test_assert(streams[0]->eof);
i_stream_unref(&streams[0]);
test_end();
}
static void test_istream_seekable_early_end(void)
{
struct istream *input, *streams[2];
test_begin("istream seekable early end");
streams[0] = test_istream_create("stream");
test_istream_set_size(streams[0], 3);
test_istream_set_allow_eof(streams[0], FALSE);
streams[0]->seekable = FALSE;
streams[1] = NULL;
input = i_stream_create_seekable(streams, 1000, fd_callback, NULL);
test_assert(i_stream_read(input) == 3);
test_istream_set_size(streams[0], 5);
test_assert(i_stream_read(input) == 2);
i_stream_skip(input, 5);
i_stream_unref(&input);
test_assert(streams[0]->v_offset == 5);
i_stream_unref(&streams[0]);
test_end();
}
static void test_istream_seekable_invalid_read(void)
{
test_begin("istream seekable + other streams causing invalid read");
struct sha256_ctx hash_ctx;
sha256_init(&hash_ctx);
struct istream *str_input = test_istream_create("123456");
str_input->seekable = FALSE;
struct istream *seek_inputs[] = { str_input, NULL };
struct istream *seek_input = i_stream_create_seekable(seek_inputs, 3, fd_callback, NULL);
struct istream *sized_input = i_stream_create_sized(seek_input, 3);
struct istream *input = i_stream_create_hash(sized_input, &hash_method_sha256, &hash_ctx);
test_assert(i_stream_read(input) == 3);
test_assert(i_stream_read(input) == -2);
i_stream_skip(input, 3);
test_assert(i_stream_read(input) == -1);
i_stream_unref(&input);
i_stream_unref(&sized_input);
i_stream_unref(&seek_input);
i_stream_unref(&str_input);
test_end();
}
static void test_istream_seekable_get_size(void)
{
test_begin("istream seekable get size");
struct istream *str_input = test_istream_create("123456");
str_input->seekable = FALSE;
struct istream *seek_inputs[] = { str_input, NULL };
struct istream *input = i_stream_create_seekable(seek_inputs, 32, fd_callback, NULL);
uoff_t size;
test_assert(i_stream_read(input) == 6);
test_assert(i_stream_read(input) == -1);
test_assert(i_stream_get_size(input, TRUE, &size) == 1 &&
size == 6);
i_stream_unref(&input);
i_stream_unref(&str_input);
test_end();
}
static void test_istream_seekable_failed_writes(void)
{
struct istream *input, *streams[2];
test_begin("istream seekable failed write");
streams[0] = test_istream_create("stream");
test_istream_set_size(streams[0], 3);
test_istream_set_allow_eof(streams[0], FALSE);
streams[0]->seekable = FALSE;
streams[1] = NULL;
input = i_stream_create_seekable(streams, 2, fd_callback, NULL);
i_stream_set_name(input, "test seekable");
test_assert(i_stream_read(input) == 2);
i_stream_skip(input, 2);
test_assert(i_stream_read(input) == 1);
i_close_fd(&fd_callback_fd);
test_istream_set_size(streams[0], 5);
test_expect_error_string("istream-seekable: write_full(test-lib.tmp) failed: Bad file descriptor");
test_assert(i_stream_read(input) == -1);
test_expect_no_more_errors();
test_expect_error_string("file_istream.close((seekable temp-istream for: test seekable)) failed: Bad file descriptor");
i_stream_unref(&input);
test_expect_no_more_errors();
i_stream_unref(&streams[0]);
test_end();
}
void test_istream_seekable(void)
{
unsigned int i;
test_begin("istream seekable");
for (i = 1; i <= STREAM_BYTES*STREAM_COUNT; i++)
test_istream_seekable_one(i);
test_end();
test_begin("istream seekable random");
for (i = 0; i < 100; i++) T_BEGIN {
test_istream_seekable_random();
} T_END;
test_end();
test_istream_seekable_eof();
test_istream_seekable_early_end();
test_istream_seekable_invalid_read();
test_istream_seekable_get_size();
test_istream_seekable_failed_writes();
}
dovecot-2.3.21.1/src/lib/utc-mktime.c 0000644 0000000 0000000 00000003451 14656633576 014100 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "utc-mktime.h"
static int tm_cmp(const struct tm *tm1, const struct tm *tm2)
{
int diff;
if ((diff = tm1->tm_year - tm2->tm_year) != 0)
return diff;
if ((diff = tm1->tm_mon - tm2->tm_mon) != 0)
return diff;
if ((diff = tm1->tm_mday - tm2->tm_mday) != 0)
return diff;
if ((diff = tm1->tm_hour - tm2->tm_hour) != 0)
return diff;
if ((diff = tm1->tm_min - tm2->tm_min) != 0)
return diff;
return tm1->tm_sec - tm2->tm_sec;
}
static inline void adjust_leap_second(struct tm *tm)
{
if (tm->tm_sec == 60)
tm->tm_sec = 59;
}
#ifdef HAVE_TIMEGM
/* Normalization done by timegm is considered a failure here, since it means
* the timestamp is not valid as-is. Leap second 60 is adjusted to 59 before
* this though. */
time_t utc_mktime(const struct tm *tm)
{
struct tm leap_adj_tm = *tm;
adjust_leap_second(&leap_adj_tm);
struct tm tmp = leap_adj_tm;
time_t t;
t = timegm(&tmp);
if (tm_cmp(&leap_adj_tm, &tmp) != 0)
return (time_t)-1;
return t;
}
#else
time_t utc_mktime(const struct tm *tm)
{
struct tm leap_adj_tm = *tm;
adjust_leap_second(&leap_adj_tm);
const struct tm *try_tm;
time_t t;
int bits, dir;
/* we'll do a binary search across the entire valid time_t range.
when gmtime()'s output matches the tm parameter, we've found the
correct time_t value. this also means that if tm contains invalid
values, -1 is returned. */
#ifdef TIME_T_SIGNED
t = 0;
#else
t = (time_t)1 << (TIME_T_MAX_BITS - 1);
#endif
for (bits = TIME_T_MAX_BITS - 2;; bits--) {
try_tm = gmtime(&t);
dir = tm_cmp(&leap_adj_tm, try_tm);
if (dir == 0)
return t;
if (bits < 0)
break;
if (dir < 0)
t -= (time_t)1 << bits;
else
t += (time_t)1 << bits;
}
return (time_t)-1;
}
#endif
dovecot-2.3.21.1/src/lib/base64.c 0000644 0000000 0000000 00000056334 14656633576 013115 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "base64.h"
#include "buffer.h"
/*
* Low-level Base64 encoder
*/
uoff_t base64_get_full_encoded_size(struct base64_encoder *enc, uoff_t src_size)
{
bool crlf = HAS_ALL_BITS(enc->flags, BASE64_ENCODE_FLAG_CRLF);
bool no_padding = HAS_ALL_BITS(enc->flags,
BASE64_ENCODE_FLAG_NO_PADDING);
uoff_t out_size;
uoff_t newlines;
if (src_size == 0)
return 0;
/* calculate size of encoded data */
out_size = MAX_BASE64_ENCODED_SIZE(src_size);
if (no_padding) {
switch (src_size % 3) {
case 0:
break;
case 1:
i_assert(out_size > 2);
out_size -= 2;
break;
case 2:
i_assert(out_size > 1);
out_size -= 1;
break;
}
}
if (out_size > enc->max_line_len) {
/* newline between each full line */
i_assert(enc->max_line_len > 0);
newlines = (out_size / enc->max_line_len) - 1;
/* an extra newline to separate the partial last line from the
previous full line */
if ((out_size % enc->max_line_len) != 0)
newlines++;
/* update size with added newlines */
out_size += newlines * (crlf ? 2 : 1);
}
return out_size;
}
static size_t
base64_encode_get_out_size(struct base64_encoder *enc, size_t src_size)
{
size_t res_size = enc->w_buf_len;
i_assert(enc->w_buf_len <= sizeof(enc->w_buf));
if (src_size == 0)
return res_size;
/* Handle sub-position */
switch (enc->sub_pos) {
case 0:
break;
case 1:
res_size++;
src_size--;
if (src_size == 0)
return res_size;
/* fall through */
case 2:
res_size += 2;
src_size--;
break;
default:
i_unreached();
}
/* We're now at a 3-byte boundary */
if (src_size == 0)
return res_size;
/* Calculate size we can append to the output from remaining input */
res_size += ((src_size) / 3) * 4;
switch (src_size % 3) {
case 0:
break;
case 1:
res_size += 1;
break;
case 2:
res_size += 2;
break;
}
return res_size;
}
size_t base64_encode_get_size(struct base64_encoder *enc, size_t src_size)
{
bool crlf = HAS_ALL_BITS(enc->flags, BASE64_ENCODE_FLAG_CRLF);
size_t out_size = base64_encode_get_out_size(enc, src_size);
if (src_size == 0) {
/* last block */
switch (enc->sub_pos) {
case 0:
break;
case 1:
out_size += 3;
break;
case 2:
out_size += 2;
break;
default:
i_unreached();
}
}
if (enc->max_line_len < SIZE_MAX) {
size_t line_part, lines;
/* Calculate how many line endings must be added */
i_assert(enc->max_line_len > 0);
lines = out_size / enc->max_line_len;
line_part = out_size % enc->max_line_len;
if (enc->cur_line_len > (enc->max_line_len - line_part))
lines++;
out_size += lines * (crlf ? 2 : 1);
}
if (enc->pending_lf)
out_size++;
return out_size;
}
size_t base64_encode_get_full_space(struct base64_encoder *enc,
size_t dst_space)
{
bool crlf = HAS_ALL_BITS(enc->flags, BASE64_ENCODE_FLAG_CRLF);
bool no_padding = HAS_ALL_BITS(enc->flags,
BASE64_ENCODE_FLAG_NO_PADDING);
size_t src_space = 0;
i_assert(enc->w_buf_len <= sizeof(enc->w_buf));
if (enc->max_line_len < SIZE_MAX) {
size_t max_line_space, lines, nl_space;
/* Calculate how many line endings must be added if all space
were used. */
i_assert(enc->max_line_len < SIZE_MAX-2);
max_line_space = enc->max_line_len + (crlf ? 2 : 1);
lines = dst_space / max_line_space;
/* Calculate how much space is used by newline characters and
subtract this from the available space. */
nl_space = lines * (crlf ? 2 : 1);
if (dst_space <= nl_space)
return 0;
dst_space -= nl_space;
}
if (dst_space <= enc->w_buf_len)
return 0;
dst_space -= enc->w_buf_len;
if (enc->pending_lf)
dst_space--;
if (dst_space == 0)
return 0;
/* Handle sub-position */
switch (enc->sub_pos) {
case 0:
break;
case 1:
dst_space--;
src_space++;
/* fall through */
case 2:
if (dst_space < 2)
return src_space;
dst_space -= 2;
src_space++;
break;
default:
i_unreached();
}
if (dst_space == 0)
return src_space;
src_space += dst_space / 4 * 3;
if (no_padding) {
switch (dst_space % 4) {
case 0:
case 1:
break;
case 2:
src_space += 1;
break;
case 3:
src_space += 2;
break;
}
}
return src_space;
}
static void
base64_encode_more_data(struct base64_encoder *enc,
const unsigned char *src_c, size_t src_size,
size_t *src_pos_r, size_t dst_avail, buffer_t *dest)
{
const struct base64_scheme *b64 = enc->b64;
const char *b64enc = b64->encmap;
size_t res_size;
unsigned char *start, *ptr, *end;
size_t src_pos;
i_assert(!enc->pending_lf);
/* determine how much we can write in destination buffer */
if (dst_avail == 0) {
*src_pos_r = 0;
return;
}
/* pre-allocate space in the destination buffer */
res_size = base64_encode_get_out_size(enc, src_size);
if (res_size > dst_avail)
res_size = dst_avail;
start = buffer_append_space_unsafe(dest, res_size);
end = start + res_size;
ptr = start;
/* write bytes not written in previous call */
i_assert(enc->w_buf_len <= sizeof(enc->w_buf));
if (enc->w_buf_len > res_size) {
memcpy(ptr, enc->w_buf, res_size);
ptr += res_size;
enc->w_buf_len -= res_size;
memmove(enc->w_buf, enc->w_buf + res_size, enc->w_buf_len);
} else if (enc->w_buf_len > 0) {
memcpy(ptr, enc->w_buf, enc->w_buf_len);
ptr += enc->w_buf_len;
enc->w_buf_len = 0;
}
if (ptr == end) {
*src_pos_r = 0;
return;
}
i_assert(enc->w_buf_len == 0);
i_assert(src_size != 0);
/* Handle sub-position */
src_pos = 0;
switch (enc->sub_pos) {
case 0:
break;
case 1:
i_assert(ptr < end);
ptr[0] = b64enc[enc->buf | (src_c[src_pos] >> 4)];
ptr++;
enc->buf = (src_c[src_pos] & 0x0f) << 2;
src_pos++;
if (src_pos == src_size || ptr == end) {
enc->sub_pos = 2;
*src_pos_r = src_pos;
return;
}
/* fall through */
case 2:
ptr[0] = b64enc[enc->buf | ((src_c[src_pos] & 0xc0) >> 6)];
enc->w_buf[0] = b64enc[src_c[src_pos] & 0x3f];
ptr++;
src_pos++;
if (ptr < end) {
ptr[0] = enc->w_buf[0];
ptr++;
enc->w_buf_len = 0;
} else {
enc->sub_pos = 0;
enc->w_buf_len = 1;
*src_pos_r = src_pos;
return;
}
break;
default:
i_unreached();
}
enc->sub_pos = 0;
/* We're now at a 3-byte boundary */
if (src_pos == src_size) {
i_assert(ptr == end);
*src_pos_r = src_pos;
return;
}
/* Convert the bulk */
for (; src_size - src_pos > 2 && &ptr[3] < end;
src_pos += 3, ptr += 4) {
ptr[0] = b64enc[src_c[src_pos] >> 2];
ptr[1] = b64enc[((src_c[src_pos] & 0x03) << 4) |
(src_c[src_pos+1] >> 4)];
ptr[2] = b64enc[((src_c[src_pos+1] & 0x0f) << 2) |
((src_c[src_pos+2] & 0xc0) >> 6)];
ptr[3] = b64enc[src_c[src_pos+2] & 0x3f];
}
/* Convert the bytes beyond the last 3-byte boundary and update state
for next call */
switch (src_size - src_pos) {
case 0:
enc->sub_pos = 0;
enc->buf = 0;
break;
case 1:
enc->sub_pos = 1;
enc->w_buf[0] = b64enc[src_c[src_pos] >> 2];
enc->w_buf_len = 1;
enc->buf = (src_c[src_pos] & 0x03) << 4;
src_pos++;
break;
case 2:
enc->sub_pos = 2;
enc->w_buf[0] = b64enc[src_c[src_pos] >> 2];
enc->w_buf[1] = b64enc[((src_c[src_pos] & 0x03) << 4) |
(src_c[src_pos+1] >> 4)];
enc->w_buf_len = 2;
enc->buf = (src_c[src_pos+1] & 0x0f) << 2;
src_pos += 2;
break;
default:
/* hit the end of the destination buffer */
enc->sub_pos = 0;
enc->w_buf[0] = b64enc[src_c[src_pos] >> 2];
enc->w_buf[1] = b64enc[((src_c[src_pos] & 0x03) << 4) |
(src_c[src_pos+1] >> 4)];
enc->w_buf[2] = b64enc[((src_c[src_pos+1] & 0x0f) << 2) |
((src_c[src_pos+2] & 0xc0) >> 6)];
enc->w_buf[3] = b64enc[src_c[src_pos+2] & 0x3f];
enc->w_buf_len = 4;
enc->buf = 0;
src_pos += 3;
}
/* fill the remaining allocated space */
i_assert(ptr <= end);
res_size = end - ptr;
i_assert(enc->w_buf_len <= sizeof(enc->w_buf));
if (enc->w_buf_len > res_size) {
memcpy(ptr, enc->w_buf, res_size);
ptr += res_size;
enc->w_buf_len -= res_size;
memmove(enc->w_buf, enc->w_buf + res_size, enc->w_buf_len);
} else if (enc->w_buf_len > 0) {
memcpy(ptr, enc->w_buf, enc->w_buf_len);
ptr += enc->w_buf_len;
enc->w_buf_len = 0;
}
i_assert(ptr == end);
*src_pos_r = src_pos;
}
bool base64_encode_more(struct base64_encoder *enc,
const void *src, size_t src_size, size_t *src_pos_r,
buffer_t *dest)
{
bool crlf = HAS_ALL_BITS(enc->flags, BASE64_ENCODE_FLAG_CRLF);
const unsigned char *src_c, *src_p;
size_t src_pos, src_left;
i_assert(!enc->finishing);
i_assert(!enc->finished);
src_p = src_c = src;
src_left = src_size;
while (src_left > 0) {
size_t dst_avail, dst_pos, line_avail, written;
/* determine how much we can write in destination buffer */
dst_avail = buffer_get_avail_size(dest);
if (dst_avail == 0)
break;
/* Emit pending newline immediately */
if (enc->pending_lf) {
i_assert(crlf);
buffer_append_c(dest, '\n');
enc->pending_lf = FALSE;
dst_avail--;
if (dst_avail == 0)
break;
}
i_assert(enc->max_line_len > 0);
i_assert(enc->cur_line_len <= enc->max_line_len);
line_avail = I_MIN(enc->max_line_len - enc->cur_line_len,
dst_avail);
if (line_avail > 0) {
dst_pos = dest->used;
base64_encode_more_data(enc, src_p, src_left, &src_pos,
line_avail, dest);
i_assert(src_pos <= src_left);
src_p += src_pos;
src_left -= src_pos;
i_assert(dest->used >= dst_pos);
written = dest->used - dst_pos;
i_assert(written <= line_avail);
i_assert(written <= enc->max_line_len);
i_assert(enc->cur_line_len <=
(enc->max_line_len - written));
enc->cur_line_len += written;
dst_avail -= written;
}
if (dst_avail == 0)
break;
if (src_left > 0 && enc->cur_line_len == enc->max_line_len) {
if (crlf) {
if (dst_avail >= 2) {
/* emit the full CRLF sequence */
buffer_append(dest, "\r\n", 2);
} else {
/* emit CR */
buffer_append_c(dest, '\r');
/* remember the LF */
enc->pending_lf = TRUE;
}
} else {
buffer_append_c(dest, '\n');
}
enc->cur_line_len = 0;
}
}
i_assert(src_p >= src_c);
src_pos = (src_p - src_c);
if (src_pos_r != NULL)
*src_pos_r = src_pos;
return (src_pos == src_size);
}
bool base64_encode_finish(struct base64_encoder *enc, buffer_t *dest)
{
const struct base64_scheme *b64 = enc->b64;
const char *b64enc = b64->encmap;
bool crlf = HAS_ALL_BITS(enc->flags, BASE64_ENCODE_FLAG_CRLF);
bool padding = HAS_NO_BITS(enc->flags, BASE64_ENCODE_FLAG_NO_PADDING);
unsigned char *ptr, *end;
size_t dst_avail, line_avail, write_full, write;
unsigned int w_buf_pos = 0;
i_assert(!enc->finished);
enc->finishing = TRUE;
dst_avail = 0;
if (dest != NULL)
dst_avail = buffer_get_avail_size(dest);
if (enc->w_buf_len > 0 || enc->pending_lf) {
if (dst_avail == 0)
return FALSE;
i_assert(enc->w_buf_len <= sizeof(enc->w_buf));
}
i_assert(enc->max_line_len > 0);
i_assert(enc->cur_line_len <= enc->max_line_len);
line_avail = enc->max_line_len - enc->cur_line_len;
switch (enc->sub_pos) {
case 0:
break;
case 1:
i_assert(enc->w_buf_len <= (sizeof(enc->w_buf) - 3));
enc->w_buf[enc->w_buf_len] = b64enc[enc->buf];
enc->w_buf_len++;
if (padding) {
enc->w_buf[enc->w_buf_len + 0] = '=';
enc->w_buf[enc->w_buf_len + 1] = '=';
enc->w_buf_len += 2;
}
break;
case 2:
i_assert(enc->w_buf_len <= (sizeof(enc->w_buf) - 2));
enc->w_buf[enc->w_buf_len] = b64enc[enc->buf];
enc->w_buf_len++;
if (padding) {
enc->w_buf[enc->w_buf_len + 0] = '=';
enc->w_buf_len++;
}
break;
default:
i_unreached();
}
enc->sub_pos = 0;
write_full = write = enc->w_buf_len;
if (enc->pending_lf)
write_full++;
if (enc->max_line_len < SIZE_MAX && line_avail < write) {
unsigned int lines;
lines = I_MAX((write - line_avail) / enc->max_line_len, 1);
write_full += lines * (crlf ? 2 : 1);
} else {
line_avail = write;
}
if (write_full == 0) {
enc->finished = TRUE;
return TRUE;
}
i_assert(dest != NULL);
if (write_full > dst_avail)
write_full = dst_avail;
ptr = buffer_append_space_unsafe(dest, write_full);
end = ptr + write_full;
if (enc->pending_lf) {
ptr[0] = '\n';
dst_avail--;
ptr++;
enc->pending_lf = FALSE;
}
if (line_avail > dst_avail)
line_avail = dst_avail;
if (line_avail > 0) {
memcpy(ptr, enc->w_buf, line_avail);
ptr += line_avail;
w_buf_pos += line_avail;
}
while (ptr < end && w_buf_pos < enc->w_buf_len) {
enc->cur_line_len = 0;
if (crlf) {
ptr[0] = '\r';
ptr++;
if (ptr == end) {
enc->pending_lf = TRUE;
break;
}
}
ptr[0] = '\n';
ptr++;
if (ptr == end)
break;
write = I_MIN(enc->w_buf_len - w_buf_pos, enc->max_line_len);
write = I_MIN(write, (size_t)(end - ptr));
memcpy(ptr, &enc->w_buf[w_buf_pos], write);
ptr += write;
w_buf_pos += write;
enc->cur_line_len += write;
i_assert(ptr <= end);
}
i_assert(ptr == end);
if (w_buf_pos < enc->w_buf_len) {
enc->w_buf_len -= w_buf_pos;
memmove(enc->w_buf, enc->w_buf + w_buf_pos, enc->w_buf_len);
return FALSE;
}
if (enc->pending_lf)
return FALSE;
enc->finished = TRUE;
return TRUE;
}
/*
* Low-level Base64 decoder
*/
#define IS_EMPTY(c) \
((c) == '\n' || (c) == '\r' || (c) == ' ' || (c) == '\t')
static inline void
base64_skip_whitespace(struct base64_decoder *dec, const unsigned char *src_c,
size_t src_size, size_t *src_pos)
{
if (HAS_ALL_BITS(dec->flags, BASE64_DECODE_FLAG_NO_WHITESPACE))
return;
/* skip any whitespace in the padding */
while ((*src_pos) < src_size && IS_EMPTY(src_c[(*src_pos)]))
(*src_pos)++;
}
int base64_decode_more(struct base64_decoder *dec,
const void *src, size_t src_size, size_t *src_pos_r,
buffer_t *dest)
{
const struct base64_scheme *b64 = dec->b64;
const unsigned char *src_c = src;
bool expect_boundary = HAS_ALL_BITS(
dec->flags, BASE64_DECODE_FLAG_EXPECT_BOUNDARY);
bool no_whitespace = HAS_ALL_BITS(
dec->flags, BASE64_DECODE_FLAG_NO_WHITESPACE);
bool no_padding = HAS_ALL_BITS(
dec->flags, BASE64_DECODE_FLAG_NO_PADDING);
size_t src_pos, dst_avail;
int ret = 1;
i_assert(!dec->finished);
i_assert(!dec->failed);
if (dec->seen_boundary) {
/* already seen the boundary/end of base64 data */
if (src_pos_r != NULL)
*src_pos_r = 0;
dec->failed = TRUE;
return -1;
}
src_pos = 0;
if (dec->seen_end) {
/* skip any whitespace at the end */
base64_skip_whitespace(dec, src_c, src_size, &src_pos);
if (src_pos_r != NULL)
*src_pos_r = src_pos;
if (src_pos < src_size) {
if (!expect_boundary) {
dec->failed = TRUE;
return -1;
}
dec->seen_boundary = TRUE;
return 0;
}
if (no_whitespace) {
dec->seen_boundary = TRUE;
return 0;
}
/* more whitespace may follow */
return 1;
}
if (src_size == 0) {
if (src_pos_r != NULL)
*src_pos_r = 0;
return 1;
}
dst_avail = buffer_get_avail_size(dest);
if (dst_avail == 0) {
i_assert(src_pos_r != NULL);
*src_pos_r = 0;
return 1;
}
for (; !dec->seen_padding && src_pos < src_size; src_pos++) {
unsigned char in = src_c[src_pos];
unsigned char dm = b64->decmap[in];
if (dm == 0xff) {
if (no_whitespace) {
ret = -1;
break;
}
if (unlikely(!IS_EMPTY(in))) {
ret = -1;
break;
}
continue;
}
if (dst_avail == 0) {
i_assert(src_pos_r != NULL);
*src_pos_r = src_pos;
return 1;
}
switch (dec->sub_pos) {
case 0:
dec->buf = dm;
dec->sub_pos++;
break;
case 1:
dec->buf = (dec->buf << 2) | (dm >> 4);
buffer_append_c(dest, dec->buf);
dst_avail--;
dec->buf = dm;
dec->sub_pos++;
break;
case 2:
dec->buf = ((dec->buf << 4) & 0xff) | (dm >> 2);
buffer_append_c(dest, dec->buf);
dst_avail--;
dec->buf = dm;
dec->sub_pos++;
break;
case 3:
dec->buf = ((dec->buf << 6) & 0xc0) | dm;
buffer_append_c(dest, dec->buf);
dst_avail--;
dec->buf = 0;
dec->sub_pos = 0;
break;
default:
i_unreached();
}
}
if (dec->seen_padding) {
/* skip any whitespace in or after the padding */
base64_skip_whitespace(dec, src_c, src_size, &src_pos);
if (src_pos == src_size) {
if (src_pos_r != NULL)
*src_pos_r = src_pos;
return 1;
}
}
if (dec->seen_padding || ret < 0) {
/* try to parse the end (padding) of the base64 input */
i_assert(src_pos < src_size);
if (no_padding) {
/* no padding allowed */
i_assert(!dec->seen_padding);
ret = -1;
} else {
switch (dec->sub_pos) {
case 0:
case 1:
/* no padding expected */
ret = -1;
break;
case 2:
if (unlikely(src_c[src_pos] != '=')) {
/* invalid character */
ret = -1;
break;
}
dec->seen_padding = TRUE;
dec->sub_pos++;
src_pos++;
if (src_pos == src_size) {
ret = 1;
break;
}
/* skip any whitespace in the padding */
base64_skip_whitespace(dec, src_c, src_size,
&src_pos);
if (src_pos == src_size) {
ret = 1;
break;
}
/* fall through */
case 3:
if (unlikely(src_c[src_pos] != '=')) {
/* invalid character */
ret = -1;
break;
}
dec->seen_padding = TRUE;
dec->seen_end = TRUE;
dec->sub_pos = 0;
src_pos++;
/* skip any trailing whitespace */
base64_skip_whitespace(dec, src_c, src_size,
&src_pos);
if (src_pos < src_size) {
ret = -1;
break;
}
if (no_whitespace) {
dec->seen_boundary = TRUE;
ret = 0;
} else {
/* more whitespace may follow */
ret = 1;
}
break;
}
}
}
if (ret < 0) {
if (!expect_boundary) {
dec->failed = TRUE;
} else {
dec->seen_boundary = TRUE;
ret = 0;
}
}
if (src_pos_r != NULL)
*src_pos_r = src_pos;
return ret;
}
int base64_decode_finish(struct base64_decoder *dec)
{
i_assert(!dec->finished);
dec->finished = TRUE;
if (dec->failed)
return -1;
if (HAS_ALL_BITS(dec->flags,
BASE64_DECODE_FLAG_NO_PADDING)) {
i_assert(!dec->seen_padding);
return 0;
}
if (HAS_ALL_BITS(dec->flags,
BASE64_DECODE_FLAG_IGNORE_PADDING))
return 0;
return (dec->sub_pos == 0 ? 0 : -1);
}
/*
* Generic Base64 API
*/
buffer_t *t_base64_scheme_encode(const struct base64_scheme *b64,
enum base64_encode_flags flags,
size_t max_line_len,
const void *src, size_t src_size)
{
buffer_t *buf;
buf = t_buffer_create(MAX_BASE64_ENCODED_SIZE(src_size));
base64_scheme_encode(b64, flags, max_line_len, src, src_size, buf);
return buf;
}
int base64_scheme_decode(const struct base64_scheme *b64,
enum base64_decode_flags flags,
const void *src, size_t src_size, buffer_t *dest)
{
struct base64_decoder dec;
int ret;
base64_decode_init(&dec, b64, flags);
ret = base64_decode_more(&dec, src, src_size, NULL, dest);
if (ret >= 0)
ret = base64_decode_finish(&dec);
return ret;
}
buffer_t *t_base64_scheme_decode(const struct base64_scheme *b64,
enum base64_decode_flags flags,
const void *src, size_t src_size)
{
buffer_t *buf;
buf = t_buffer_create(MAX_BASE64_DECODED_SIZE(src_size));
(void)base64_scheme_decode(b64, flags, src, src_size, buf);
return buf;
}
/*
* "base64" encoding scheme (RFC 4648, Section 4)
*/
struct base64_scheme base64_scheme = {
.encmap = {
'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', '+', '/',
},
.decmap = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0-7 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8-15 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16-23 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24-31 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32-39 */
0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40-47 */
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48-55 */
0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56-63 */
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 64-71 */
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* 72-79 */
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 80-87 */
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88-95 */
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96-103 */
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104-111 */
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112-119 */
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120-127 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128-255 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
};
/*
* "base64url" encoding scheme (RFC 4648, Section 5)
*/
struct base64_scheme base64url_scheme = {
.encmap = {
'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', '-', '_',
},
.decmap = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0-7 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8-15 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16-23 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24-31 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32-39 */
0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, /* 40-47 */
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48-55 */
0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56-63 */
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 64-71 */
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* 72-79 */
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 80-87 */
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0x3f, /* 88-95 */
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96-103 */
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104-111 */
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112-119 */
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120-127 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128-255 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
},
};
dovecot-2.3.21.1/src/lib/ostream-wrapper.h 0000644 0000000 0000000 00000017000 14656633576 015151 0000000 0000000 #ifndef OSTREAM_WRAPPER_H
#define OSTREAM_WRAPPER_H
#include "ostream-private.h"
/* The wrapper output stream allows turning any form* of activity involving data
output into a standard Dovecot output stream. The wrapper output stream can
operate both in blocking and non-blocking mode. When the wrapped activity is
non-blocking, a blocking wrapper output stream will implicitly run its own
ioloop.
It is possible to have the wrapper output stream object available even before
the data can be written anywhere, even before any form of output object (a
connection) exists. In that case, any data written to the wrapper stream is
buffered until the buffer is full. Once that happens, the stream will block
or refuse writes until the underlying output becomes available.
The wrapper output stream is not meant to be used directly. Instead, it is
to be used as part of the implementation of an application-specific output
stream. The wrapper output stream serves as the means to prevent code
duplication between similar output stream implementations. It defines several
methods that need to be implemented by the application-specific output
stream.
* Currently, the wrapper stream still expects an output stream object when
data is to be written somewhere, but that should be easily circumvented
once such behavior is needed (FIXME).
*/
struct wrapper_ostream {
struct ostream_private ostream;
struct event *event;
/* Called when the implementation should start making the parent output
stream available, e.g. connect to the server. This happens when data
was written to the wrapper ostream (when it is corked this only
happens when the wrapper ostream buffer is full or the wrapper
ostream is finished). */
void (*output_start)(struct wrapper_ostream *wostream);
/* Returns TRUE when the output is ready for data. */
bool (*output_ready)(struct wrapper_ostream *wostream);
/* Called when an error occurred while writing to the output stream. */
void (*output_error)(struct wrapper_ostream *wostream);
/* Called when the wrapper ostream was finished using o_stream_finish()
and the wrapper ostream buffer is empty. Also, the parent output
was flushed successfully. */
int (*output_finish)(struct wrapper_ostream *wostream);
/* Called when the wrapper ostream does not need write to parent output
stream. This is will e.g. drop the parent output's flush callback or
equivalent notification mechanism. */
void (*output_halt)(struct wrapper_ostream *wostream);
/* Called when the wrapper ostream has data available for the parent
output and wants wrapper_ostream_continue() to be called when the
parent stream is writeable. */
void (*output_resume)(struct wrapper_ostream *wostream);
/* Update the timeouts. The sender_blocking parameter indicates which
side of the data transfer is blocking, so whether a timeout needs to
be set for limiting the time other side is not doing anything. */
void (*output_update_timeouts)(struct wrapper_ostream *wostream,
bool sender_blocking);
/* Called before and after running ioloop for performing blocking I/O
wait. Use these vfuncs to switch to and from the temporary ioloop. */
struct ioloop *(*wait_begin)(struct wrapper_ostream *wostream,
struct ioloop *ioloop);
void (*wait_end)(struct wrapper_ostream *wostream,
struct ioloop *prev_ioloop);
/* Called before and after running the flush callback for the ostream.
*/
void (*callback_pre)(struct wrapper_ostream *wostream);
void (*callback_post)(struct wrapper_ostream *wostream);
/* Called when the ostream is switched to a different ioloop. */
void (*switch_ioloop_to)(struct wrapper_ostream *wostream,
struct ioloop *ioloop);
/* Called when the wrapper ostream is forcibly closed using
o_stream_close() (or indirectly through e.g. o_stream_destroy()). */
void (*close)(struct wrapper_ostream *wostream);
/* Called when the ostream is destroyed. */
void (*destroy)(struct wrapper_ostream *wostream);
buffer_t *buffer; // FIXME: use a ringbuffer instead (file_ostream)
/* The (parent) output stream. */
struct ostream *output;
/* The ioloop used while flushing/sending output for when the wrapper
ostream is blocking. */
struct ioloop *flush_ioloop;
/* Error set using wrapper_ostream_return_error(). This is returned to
the application once it continues using the wrapper ostream. */
char *pending_error;
int pending_errno;
/* Timeout for delayed execution of wrapper_ostream_continue(). */
struct timeout *to_event;
/* Output was started (output_start() vfunc was called). */
bool output_started:1;
/* Output was finished (output_finish() vfunc was called). */
bool output_finished:1;
/* Output was was closed somehow. This means that the output is no
longer available. This is not the same as the ostream close flag. */
bool output_closed:1;
/* Output was closed directly or indirectly by the application action.
*/
bool output_closed_api:1;
bool flush_pending:1;
bool flush_waiting:1;
bool flushing:1;
bool continuing:1;
bool returned_error:1;
};
/* Create the wrapper output stream. This function calls o_stream_create()
internally. The initial maximum buffer size is set to max_buffer_size. When
blocking is TRUE, a blocking output stream will be created. The provided
event is used internally for debug logging. */
struct ostream *
wrapper_ostream_create(struct wrapper_ostream *wostream,
size_t max_buffer_size, bool blocking,
struct event *event) ATTR_NULL(4);
/* Continue sending output. Returns 1 if all buffered data is sent so far,
0 if not, and -1 if an error occurred. */
int wrapper_ostream_continue(struct wrapper_ostream *wostream);
/* Trigger an (asynchronous) flush on the output stream. */
void wrapper_ostream_trigger_flush(struct wrapper_ostream *wostream);
/* This function returns the size of the data buffered in the wrapper stream,
but only when the output stream is finished using o_stream_finish(). When the
output stream is finished, the data is complete and this function returns
TRUE and size_r is set to the size. If it is not complete, this function
returns FALSE and size_r is not assigned. This function is meant to be called
just before sending the first block of data internally for deciding between
sending the data using a chunked transfer encoding or, when it is already
complete, as a single blob with known size. E.g., for HTTP this is the choice
between sending the message using the Transfer-Encoding: chunked header or
the Content-Length header. */
bool wrapper_ostream_get_buffered_size(struct wrapper_ostream *wostream,
uoff_t *size_r);
/* Call this when the underlying output stream first becomes available. */
void wrapper_ostream_output_available(struct wrapper_ostream *wostream,
struct ostream *output);
/* Call this to notify the wrapper that the underlying output is destroyed and
no more data can be written ever. */
void wrapper_ostream_output_destroyed(struct wrapper_ostream *wostream);
/* Call this to notify the wrapper that an error has occurred. It will be
returned as such for the next stream write/flush and subsequent
o_stream_get_error(). */
void wrapper_ostream_set_error(struct wrapper_ostream *wostream,
int stream_errno, const char *stream_error);
/* Notify the application immediately about any error condition set earlier
using wrapper_ostream_set_error() by calling the ostream flush callback
right now.
*/
void wrapper_ostream_notify_error(struct wrapper_ostream *wostream);
#endif
dovecot-2.3.21.1/src/lib/askpass.c 0000644 0000000 0000000 00000002627 14656633576 013472 0000000 0000000 /* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "str.h"
#include "askpass.h"
#include
#include
#include
#include
static void askpass_str(const char *prompt, buffer_t *pass)
{
struct termios old_tio, tio;
bool tty, restore_tio = FALSE;
char ch;
int fd;
tty = isatty(STDIN_FILENO) != 0;
if (tty) {
fputs(prompt, stderr);
fflush(stderr);
fd = open("/dev/tty", O_RDONLY);
if (fd < 0)
i_fatal("open(/dev/tty) failed: %m");
/* turn off echo */
if (tcgetattr(fd, &old_tio) == 0) {
restore_tio = TRUE;
tio = old_tio;
tio.c_lflag &= ENUM_NEGATE(ECHO | ECHONL);
(void)tcsetattr(fd, TCSAFLUSH, &tio);
}
} else {
/* read it from stdin without showing a prompt */
fd = STDIN_FILENO;
}
/* read the password */
while (read(fd, &ch, 1) > 0) {
if (ch == '\n' || ch == '\r')
break;
buffer_append_c(pass, ch);
}
if (tty) {
if (restore_tio)
(void)tcsetattr(fd, TCSAFLUSH, &old_tio);
fputs("\n", stderr); fflush(stderr);
i_close_fd(&fd);
}
}
void askpass(const char *prompt, char *buf, size_t buf_size)
{
buffer_t str;
buffer_create_from_data(&str, buf, buf_size);
askpass_str(prompt, &str);
buffer_append_c(&str, '\0');
}
const char *t_askpass(const char *prompt)
{
string_t *str = t_str_new(32);
askpass_str(prompt, str);
return str_c(str);
}
dovecot-2.3.21.1/src/lib/iostream.c 0000644 0000000 0000000 00000007123 14656633576 013644 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-private.h"
static void
io_stream_default_close(struct iostream_private *stream ATTR_UNUSED,
bool close_parent ATTR_UNUSED)
{
}
static void
io_stream_default_destroy(struct iostream_private *stream ATTR_UNUSED)
{
}
void io_stream_init(struct iostream_private *stream)
{
if (stream->close == NULL)
stream->close = io_stream_default_close;
if (stream->destroy == NULL)
stream->destroy = io_stream_default_destroy;
stream->ioloop = current_ioloop;
stream->refcount = 1;
}
void io_stream_ref(struct iostream_private *stream)
{
i_assert(stream->refcount > 0);
stream->refcount++;
}
bool io_stream_unref(struct iostream_private *stream)
{
i_assert(stream->refcount > 0);
if (--stream->refcount != 0)
return TRUE;
stream->close(stream, FALSE);
stream->destroy(stream);
return FALSE;
}
void io_stream_free(struct iostream_private *stream)
{
const struct iostream_destroy_callback *dc;
if (array_is_created(&stream->destroy_callbacks)) {
array_foreach(&stream->destroy_callbacks, dc)
dc->callback(dc->context);
array_free(&stream->destroy_callbacks);
}
i_free(stream->error);
i_free(stream->name);
i_free(stream);
}
void io_stream_close(struct iostream_private *stream, bool close_parent)
{
stream->close(stream, close_parent);
}
void io_stream_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
stream->set_max_buffer_size(stream, max_size);
}
void io_stream_add_destroy_callback(struct iostream_private *stream,
void (*callback)(void *), void *context)
{
struct iostream_destroy_callback *dc;
if (!array_is_created(&stream->destroy_callbacks))
i_array_init(&stream->destroy_callbacks, 2);
dc = array_append_space(&stream->destroy_callbacks);
dc->callback = callback;
dc->context = context;
}
void io_stream_remove_destroy_callback(struct iostream_private *stream,
void (*callback)(void *))
{
const struct iostream_destroy_callback *dcs;
unsigned int i, count;
dcs = array_get(&stream->destroy_callbacks, &count);
for (i = 0; i < count; i++) {
if (dcs[i].callback == callback) {
array_delete(&stream->destroy_callbacks, i, 1);
return;
}
}
i_unreached();
}
void io_stream_set_error(struct iostream_private *stream,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
io_stream_set_verror(stream, fmt, args);
va_end(args);
}
void io_stream_set_verror(struct iostream_private *stream,
const char *fmt, va_list args)
{
/* one of the parameters may be the old stream->error, so don't free
it before the new error is created. */
char *error = i_strdup_vprintf(fmt, args);
i_free(stream->error);
stream->error = error;
}
const char *io_stream_get_disconnect_reason(struct istream *input,
struct ostream *output)
{
const char *errstr;
if (input != NULL && input->stream_errno != 0) {
errno = input->stream_errno;
errstr = i_stream_get_error(input);
} else if (output != NULL && output->stream_errno != 0) {
errno = output->stream_errno;
errstr = o_stream_get_error(output);
} else {
errno = 0;
errstr = "";
}
if (errno == 0 || errno == EPIPE)
return "Connection closed";
else
return t_strdup_printf("Connection closed: %s", errstr);
}
void io_stream_switch_ioloop_to(struct iostream_private *stream,
struct ioloop *ioloop)
{
stream->ioloop = ioloop;
}
struct ioloop *io_stream_get_ioloop(struct iostream_private *stream)
{
return (stream->ioloop == NULL ? current_ioloop : stream->ioloop);
}
dovecot-2.3.21.1/src/lib/test-crc32.c 0000644 0000000 0000000 00000000474 14656633576 013714 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "crc32.h"
void test_crc32(void)
{
const char str[] = "foo\0bar";
test_begin("crc32");
test_assert(crc32_str(str) == 0x8c736521);
test_assert(crc32_data(str, sizeof(str)) == 0x32c9723d);
test_end();
}
dovecot-2.3.21.1/src/lib/test-event-log.c 0000644 0000000 0000000 00000225516 14656633576 014706 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "ioloop.h"
#include "str.h"
#include "failures-private.h"
#include
enum test_log_event_type {
TYPE_END,
TYPE_PREFIX_APPEND,
TYPE_PREFIX_REPLACE,
TYPE_PREFIX_APPEND_CB,
TYPE_PREFIX_REPLACE_CB,
TYPE_MESSAGE_AMEND,
TYPE_SKIP,
};
enum test_log_event_flag {
FLAG_BASE_EVENT = BIT(0),
FLAG_DROP_PREFIXES_1 = BIT(1),
FLAG_DROP_PREFIXES_2 = BIT(2),
FLAG_DROP_PREFIXES_4 = BIT(3),
};
enum test_log_flag {
FLAG_NO_SEND = BIT(0),
};
struct test_log_event {
enum test_log_event_type type;
const char *str;
enum test_log_event_flag flags;
};
struct test_log {
const struct test_log_event *prefixes;
const char *global_log_prefix;
const char *base_send_prefix;
const char *base_str_prefix;
const char *result;
const char *result_str_out;
enum test_log_flag flags;
};
static char *test_output = NULL;
static void ATTR_FORMAT(2, 0)
info_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
size_t prefix_len;
i_assert(ctx->type == LOG_TYPE_INFO);
i_free(test_output);
T_BEGIN {
string_t *str = failure_handler.v->format(ctx, &prefix_len,
format, args);
test_output = i_strdup(str_c(str));
} T_END;
}
static void ATTR_FORMAT(2, 0)
error_handler(const struct failure_context *ctx,
const char *format, va_list args)
{
size_t prefix_len;
i_assert(ctx->type == LOG_TYPE_WARNING ||
ctx->type == LOG_TYPE_ERROR);
i_free(test_output);
T_BEGIN {
string_t *str = failure_handler.v->format(ctx, &prefix_len,
format, args);
test_output = i_strdup(str_c(str));
} T_END;
}
static const char *
test_event_log_prefix_cb(char *prefix)
{
return t_strdup_printf("callback(%s)", prefix);
}
static const char *
test_event_log_message_cb(char *prefix,
enum log_type log_type ATTR_UNUSED,
const char *message)
{
return t_strdup_printf("[%s%s]", prefix, message);
}
static void test_event_log_message(void)
{
struct test_log tests[] = {
{
.prefixes = (const struct test_log_event []) {
{ .type = TYPE_END }
},
.global_log_prefix = "global1.",
.result = "global1.Info: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ .type = TYPE_END }
},
.result = "replaced2.Info: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global2.",
.result = "global2.Info: appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended1,appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ .type = TYPE_END }
},
.result = "replaced2.Info: appended3#TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND_CB, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: callback(appended1-)TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-", 0 },
{ .type = TYPE_END }
},
.result = "callback(replaced2-)Info: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.result = "callback(replaced1.)Info: appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2-Info: TEXT",
},
/* Tests involving event_set_log_message_callback() */
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-" , 0},
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-[amended2-TEXT]]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: appended1-[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: "
"appended1-[amended1-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: [amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2,Info: [amended2-TEXT]",
},
/* Tests with params->base_str_out != NULL */
{
.prefixes = (const struct test_log_event []) {
{ .type = TYPE_END }
},
.global_log_prefix = "global1.",
.result = "global1.Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ .type = TYPE_END }
},
.result = "replaced2.Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ .type = TYPE_END }
},
.result = "replaced2.Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced2.Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: appended2.TEXT",
.result_str_out = "appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: appended2.TEXT",
.result_str_out = "appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced1,Info: appended2.TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global2.",
.result = "global2.Info: appended1,TEXT",
.result_str_out = "appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global2.",
.result = "global2.Info: appended1,TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended1,appended2.TEXT",
.result_str_out = "appended1,appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended1,appended2.TEXT",
.result_str_out = "appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended1,appended2.TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3.TEXT",
.result_str_out = "appended1,appended2.appended3.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3.TEXT",
.result_str_out = "appended2.appended3.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3.TEXT",
.result_str_out = "appended3.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3.TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ .type = TYPE_END }
},
.result = "replaced2.Info: appended3#TEXT",
.result_str_out = "appended3#TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ .type = TYPE_END }
},
.result = "replaced2.Info: appended3#TEXT",
.result_str_out = "appended3#TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ .type = TYPE_END }
},
.result = "replaced2.Info: appended3#TEXT",
.result_str_out = "appended3#TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced2.Info: appended3#TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND_CB, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: callback(appended1-)TEXT",
.result_str_out = "callback(appended1-)TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND_CB, "appended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: callback(appended1-)TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-", 0 },
{ .type = TYPE_END }
},
.result = "callback(replaced2-)Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-", 0 },
{ .type = TYPE_END }
},
.result = "callback(replaced2-)Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-", 0 },
{ .type = TYPE_END }
},
.result = "callback(replaced2-)Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "callback(replaced2-)Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.result = "callback(replaced1.)Info: appended1,TEXT",
.result_str_out = "appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.result = "callback(replaced1.)Info: appended1,TEXT",
.result_str_out = "appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "callback(replaced1.)Info: appended1,TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2-Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2-Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced2-Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-" , 0},
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-TEXT]",
.result_str_out = "[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-" ,
FLAG_BASE_EVENT},
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-TEXT]",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-[amended2-TEXT]]",
.result_str_out = "[amended1-[amended2-TEXT]]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-[amended2-TEXT]]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-[amended2-TEXT]]",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-TEXT]",
.result_str_out = "[amended1-appended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-TEXT]",
.result_str_out = "appended1-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-TEXT]",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: appended1-[amended1-TEXT]",
.result_str_out = "appended1-[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: appended1-[amended1-TEXT]",
.result_str_out = "[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: appended1-[amended1-TEXT]",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: "
"appended1-[amended1-appended2-TEXT]",
.result_str_out = "appended1-[amended1-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: "
"appended1-[amended1-appended2-TEXT]",
.result_str_out = "[amended1-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: "
"appended1-[amended1-appended2-TEXT]",
.result_str_out = "appended2-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: "
"appended1-[amended1-appended2-TEXT]",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
.result_str_out = "[amended1-appended1-"
"[amended2-appended2-TEXT]]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
.result_str_out = "appended1-[amended2-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
.result_str_out = "[amended2-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
.result_str_out = "appended2-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = "global4.Info: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: [amended1-TEXT]",
.result_str_out = "[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.result = "replaced1,Info: [amended1-TEXT]",
.result_str_out = "[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced1,Info: [amended1-TEXT]",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "TEXT",
},
/* Tests involving params->no_send */
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = NULL,
.result_str_out = "appended3.TEXT",
.flags = FLAG_NO_SEND,
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.result = NULL,
.result_str_out = "[amended2-appended2-TEXT]",
.flags = FLAG_NO_SEND,
},
/* Tests with params->base_*_prefix assigned */
{
.prefixes = (const struct test_log_event []) {
{ .type = TYPE_END }
},
.global_log_prefix = "global1.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global1.Info: PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2.Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2.Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2.Info: PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: appended2.TEXT",
.result_str_out = "appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: PREFIX: appended2.TEXT",
.result_str_out = "STR_PREFIX: appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: appended2.PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global2.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global2.Info: PREFIX: appended1,TEXT",
.result_str_out = "STR_PREFIX: appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global2.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global2.Info: appended1,PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: PREFIX: "
"appended1,appended2.TEXT",
.result_str_out = "STR_PREFIX: "
"appended1,appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: appended1,PREFIX: "
"appended2.TEXT",
.result_str_out = "STR_PREFIX: appended2.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: appended1,appended2."
"PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: PREFIX: "
"appended1,appended2.appended3.TEXT",
.result_str_out = "STR_PREFIX: "
"appended1,appended2.appended3.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: appended1,PREFIX: "
"appended2.appended3.TEXT",
.result_str_out = "STR_PREFIX: "
"appended2.appended3.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: appended1,appended2.PREFIX: "
"appended3.TEXT",
.result_str_out = "STR_PREFIX: appended3.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: "
"appended1,appended2.appended3.PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2.Info: appended3#TEXT",
.result_str_out = "appended3#TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2.Info: appended3#TEXT",
.result_str_out = "appended3#TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2.Info: PREFIX: appended3#TEXT",
.result_str_out = "STR_PREFIX: appended3#TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2.Info: appended3#PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: appended5-TEXT",
.result_str_out = "appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended5-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: PREFIX: appended5-TEXT",
.result_str_out = "STR_PREFIX: appended5-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3#", 0 },
{ TYPE_PREFIX_REPLACE, "replaced4;", 0 },
{ TYPE_PREFIX_APPEND, "appended5-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced4;Info: appended5-PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND_CB, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: PREFIX: "
"callback(appended1-)TEXT",
.result_str_out = "STR_PREFIX: "
"callback(appended1-)TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND_CB, "appended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global3.Info: callback(appended1-)PREFIX: "
"TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "callback(replaced2-)Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "callback(replaced2-)Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "callback(replaced2-)Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_REPLACE, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE_CB, "replaced2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "callback(replaced2-)Info: PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "callback(replaced1.)Info: appended1,TEXT",
.result_str_out = "appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "callback(replaced1.)Info: PREFIX: "
"appended1,TEXT",
.result_str_out = "STR_PREFIX: appended1,TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "callback(replaced1.)Info: appended1,PREFIX: "
"TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2-Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2-Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE_CB, "replaced1.", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2-Info: PREFIX: TEXT",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-" , 0},
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: PREFIX: [amended1-TEXT]",
.result_str_out = "STR_PREFIX: [amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-" ,
FLAG_BASE_EVENT},
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-PREFIX: TEXT]",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: PREFIX: "
"[amended1-[amended2-TEXT]]",
.result_str_out = "STR_PREFIX: "
"[amended1-[amended2-TEXT]]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-PREFIX: "
"[amended2-TEXT]]",
.result_str_out = "STR_PREFIX: [amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-[amended2-PREFIX: "
"TEXT]]",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: PREFIX: "
"[amended1-appended1-TEXT]",
.result_str_out = "STR_PREFIX: "
"[amended1-appended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-PREFIX: "
"appended1-TEXT]",
.result_str_out = "STR_PREFIX: appended1-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-appended1-PREFIX: "
"TEXT]",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: PREFIX: "
"appended1-[amended1-TEXT]",
.result_str_out = "STR_PREFIX: "
"appended1-[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: appended1-PREFIX: "
"[amended1-TEXT]",
.result_str_out = "STR_PREFIX: [amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: appended1-[amended1-PREFIX: "
"TEXT]",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: PREFIX: "
"appended1-[amended1-appended2-TEXT]",
.result_str_out = "STR_PREFIX: "
"appended1-[amended1-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: appended1-PREFIX: "
"[amended1-appended2-TEXT]",
.result_str_out = "STR_PREFIX: "
"[amended1-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: appended1-[amended1-PREFIX: "
"appended2-TEXT]",
.result_str_out = "STR_PREFIX: appended2-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: "
"appended1-[amended1-appended2-PREFIX: TEXT]",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: PREFIX: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
.result_str_out = "STR_PREFIX: [amended1-appended1-"
"[amended2-appended2-TEXT]]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-PREFIX: appended1-"
"[amended2-appended2-TEXT]]",
.result_str_out = "STR_PREFIX: "
"appended1-[amended2-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-appended1-PREFIX: "
"[amended2-appended2-TEXT]]",
.result_str_out = "STR_PREFIX: "
"[amended2-appended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_APPEND, "appended2-", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-appended1-"
"[amended2-PREFIX: appended2-TEXT]]",
.result_str_out = "STR_PREFIX: appended2-TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_APPEND, "appended1-", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ TYPE_PREFIX_APPEND, "appended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.global_log_prefix = "global4.",
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "global4.Info: [amended1-appended1-"
"[amended2-appended2-PREFIX: TEXT]]",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: [amended1-TEXT]",
.result_str_out = "[amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: PREFIX: [amended1-TEXT]",
.result_str_out = "STR_PREFIX: [amended1-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced1,Info: [amended1-PREFIX: TEXT]",
.result_str_out = "STR_PREFIX: TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-",
FLAG_BASE_EVENT },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2,Info: [amended2-TEXT]",
.result_str_out = "[amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,",
FLAG_BASE_EVENT },
{ TYPE_MESSAGE_AMEND, "amended2-", 0 },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2,Info: PREFIX: [amended2-TEXT]",
.result_str_out = "STR_PREFIX: [amended2-TEXT]",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_REPLACE, "replaced1,", 0 },
{ TYPE_MESSAGE_AMEND, "amended1-", 0 },
{ TYPE_PREFIX_REPLACE, "replaced2,", 0 },
{ TYPE_MESSAGE_AMEND, "amended2-",
FLAG_BASE_EVENT },
{ .type = TYPE_END }
},
.base_send_prefix = "PREFIX: ",
.base_str_prefix = "STR_PREFIX: ",
.result = "replaced2,Info: [amended2-PREFIX: TEXT]",
.result_str_out = "STR_PREFIX: TEXT",
},
/* Tests in which parent log prefixes are dropped by an event
lower in the hierarchy. */
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.", 0 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3."
"appended4.appended5.TEXT",
.result_str_out = "appended1,appended2.appended3."
"appended4.appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.",
FLAG_DROP_PREFIXES_1 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3."
"appended5.TEXT",
.result_str_out = "appended1,appended2.appended3."
"appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.", 0 },
{ TYPE_SKIP, NULL, FLAG_DROP_PREFIXES_1 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended3."
"appended4.TEXT",
.result_str_out = "appended1,appended2.appended3."
"appended4.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.",
FLAG_DROP_PREFIXES_2 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended1,appended2.appended5.TEXT",
.result_str_out = "appended1,appended2.appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.",
(FLAG_DROP_PREFIXES_1 |
FLAG_DROP_PREFIXES_2) },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended1,appended5.TEXT",
.result_str_out = "appended1,appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.",
FLAG_DROP_PREFIXES_4 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended5.TEXT",
.result_str_out = "appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.",
(FLAG_DROP_PREFIXES_1 |
FLAG_DROP_PREFIXES_2 |
FLAG_DROP_PREFIXES_4) },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended5.TEXT",
.result_str_out = "appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.", 0 },
{ TYPE_SKIP, NULL, (FLAG_DROP_PREFIXES_1 |
FLAG_DROP_PREFIXES_2 |
FLAG_DROP_PREFIXES_4) },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: TEXT",
.result_str_out = "TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_DROP_PREFIXES_1 },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.",
FLAG_DROP_PREFIXES_1 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended2.appended3.appended5.TEXT",
.result_str_out = "appended2.appended3.appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,",
FLAG_DROP_PREFIXES_1 },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_DROP_PREFIXES_1 },
{ TYPE_PREFIX_APPEND, "appended3.",
FLAG_DROP_PREFIXES_1 },
{ TYPE_PREFIX_APPEND, "appended4.",
FLAG_DROP_PREFIXES_1 },
{ TYPE_PREFIX_APPEND, "appended5.",
FLAG_DROP_PREFIXES_1 },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended5.TEXT",
.result_str_out = "appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ .type = TYPE_SKIP },
{ TYPE_PREFIX_APPEND, "appended2.",
FLAG_DROP_PREFIXES_1 },
{ .type = TYPE_SKIP },
{ TYPE_PREFIX_APPEND, "appended3.", 0 },
{ .type = TYPE_SKIP },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ .type = TYPE_SKIP },
{ TYPE_PREFIX_APPEND, "appended5.",
FLAG_DROP_PREFIXES_1 },
{ .type = TYPE_SKIP },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: "
"appended2.appended3.appended5.TEXT",
.result_str_out = "appended2.appended3.appended5.TEXT",
},
{
.prefixes = (const struct test_log_event []) {
{ TYPE_PREFIX_APPEND, "appended1,", 0 },
{ TYPE_PREFIX_APPEND, "appended2.", 0 },
{ TYPE_PREFIX_APPEND, "appended3.",
FLAG_DROP_PREFIXES_1 },
{ TYPE_PREFIX_APPEND, "appended4.", 0 },
{ TYPE_PREFIX_APPEND, "appended5.",
(FLAG_DROP_PREFIXES_1 |
FLAG_DROP_PREFIXES_2) },
{ .type = TYPE_END }
},
.global_log_prefix = "global3.",
.result = "global3.Info: appended5.TEXT",
.result_str_out = "appended5.TEXT",
},
};
test_begin("event log message");
failure_callback_t *orig_fatal, *orig_error, *orig_info, *orig_debug;
i_get_failure_handlers(&orig_fatal, &orig_error, &orig_info, &orig_debug);
i_set_info_handler(info_handler);
for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) T_BEGIN {
const struct test_log *test = &tests[i];
struct event_log_params params = {
.log_type = LOG_TYPE_INFO,
.base_send_prefix = test->base_send_prefix,
.base_str_prefix = test->base_str_prefix,
.no_send = ((test->flags & FLAG_NO_SEND) != 0),
};
i_free(test_output);
if (test->global_log_prefix != NULL)
i_set_failure_prefix("%s", test->global_log_prefix);
else
i_set_failure_prefix("UNEXPECTED GLOBAL PREFIX");
struct event *event, *parent;
event = parent = event_create(NULL);
for (unsigned int j = 0; test->prefixes[j].type != TYPE_END; j++) {
unsigned int drop_prefixes = 0;
if (event == NULL) {
struct event *child = event_create(parent);
event_unref(&parent);
event = parent = child;
}
if ((test->prefixes[j].flags & FLAG_BASE_EVENT) != 0) {
i_assert(params.base_event == NULL);
params.base_event = event;
}
if ((test->prefixes[j].flags &
FLAG_DROP_PREFIXES_1) != 0)
drop_prefixes += 1;
if ((test->prefixes[j].flags &
FLAG_DROP_PREFIXES_2) != 0)
drop_prefixes += 2;
if ((test->prefixes[j].flags &
FLAG_DROP_PREFIXES_4) != 0)
drop_prefixes += 4;
event_drop_parent_log_prefixes(event, drop_prefixes);
switch (test->prefixes[j].type) {
case TYPE_END:
i_unreached();
case TYPE_PREFIX_APPEND:
event_set_append_log_prefix(event, test->prefixes[j].str);
break;
case TYPE_PREFIX_REPLACE:
event_replace_log_prefix(event, test->prefixes[j].str);
break;
case TYPE_PREFIX_APPEND_CB:
event_set_log_prefix_callback(event, FALSE,
test_event_log_prefix_cb,
(char*)test->prefixes[j].str);
break;
case TYPE_PREFIX_REPLACE_CB:
event_set_log_prefix_callback(event, TRUE,
test_event_log_prefix_cb,
(char*)test->prefixes[j].str);
break;
case TYPE_MESSAGE_AMEND:
event_set_log_message_callback(event,
test_event_log_message_cb,
(char*)test->prefixes[j].str);
break;
case TYPE_SKIP:
break;
}
event = NULL;
}
event = parent;
if (test->result_str_out != NULL) {
/* Use small value so buffer size grows. This way the
unit test fails if anyone attempts to add data-stack
frame to event_log(). */
params.base_str_out = t_str_new(1);
}
event_log(event, ¶ms, "TEXT");
test_assert_strcmp(test->result, test_output);
if (test->result_str_out != NULL) {
test_assert_strcmp(test->result_str_out,
str_c(params.base_str_out));
}
event_unref(&event);
} T_END;
i_set_info_handler(orig_info);
i_unset_failure_prefix();
i_free(test_output);
test_end();
}
static void test_event_duration()
{
uintmax_t duration;
test_begin("event duration");
struct event *e = event_create(NULL);
usleep(10);
e_info(e, "Submit event");
event_get_last_duration(e, &duration);
test_assert(duration > 0);
event_unref(&e);
test_end();
}
static void test_event_log_level(void)
{
test_begin("event log level");
failure_callback_t *orig_fatal, *orig_error, *orig_info, *orig_debug;
i_get_failure_handlers(&orig_fatal, &orig_error, &orig_info, &orig_debug);
i_set_info_handler(info_handler);
i_set_error_handler(error_handler);
struct event *event = event_create(NULL);
event_set_min_log_level(event, LOG_TYPE_WARNING);
errno = EACCES;
e_info(event, "Info event");
test_assert(test_output == NULL);
e_warning(event, "Warning event");
test_assert_strcmp(test_output, "Warning: Warning event");
event_unref(&event);
i_set_info_handler(orig_info);
i_set_error_handler(orig_error);
i_free(test_output);
test_assert(errno == EACCES);
test_end();
}
void test_event_log(void)
{
test_event_log_message();
test_event_duration();
test_event_log_level();
}
dovecot-2.3.21.1/src/lib/test-aqueue.c 0000644 0000000 0000000 00000003510 14656633576 014257 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "array.h"
#include "aqueue.h"
static bool aqueue_is_ok(struct aqueue *aqueue, unsigned int deleted_n)
{
const unsigned int *p;
unsigned int n, i, count;
count = aqueue_count(aqueue);
for (i = 0, n = 1; i < count; i++, n++) {
p = array_idx_i(aqueue->arr, aqueue_idx(aqueue, i));
if (i == deleted_n)
n++;
if (*p != n)
return FALSE;
}
return TRUE;
}
static const unsigned int aqueue_input[] = { 1, 2, 3, 4, 5, 6 };
static const char *test_aqueue2(unsigned int initial_size)
{
ARRAY(unsigned int) aqueue_array;
unsigned int i, j, k;
for (i = 0; i < N_ELEMENTS(aqueue_input); i++) {
for (k = 0; k < N_ELEMENTS(aqueue_input); k++) {
struct aqueue *aqueue;
t_array_init(&aqueue_array, initial_size);
aqueue = aqueue_init(&aqueue_array.arr);
aqueue->head = aqueue->tail = initial_size - 1;
for (j = 0; j < k; j++) {
aqueue_append(aqueue, &aqueue_input[j]);
if (aqueue_count(aqueue) != j + 1) {
return t_strdup_printf("Wrong count after append %u vs %u)",
aqueue_count(aqueue), j + 1);
}
if (!aqueue_is_ok(aqueue, UINT_MAX))
return "Invalid data after append";
}
if (k != 0 && i < k) {
aqueue_delete(aqueue, i);
if (aqueue_count(aqueue) != k - 1)
return "Wrong count after delete";
if (!aqueue_is_ok(aqueue, i))
return "Invalid data after delete";
}
aqueue_clear(aqueue);
if (aqueue_count(aqueue) != 0)
return "aqueue_clear() broken";
aqueue_deinit(&aqueue);
}
}
return NULL;
}
void test_aqueue(void)
{
unsigned int i;
const char *reason = NULL;
for (i = 1; i <= N_ELEMENTS(aqueue_input) + 1 && reason == NULL; i++) {
T_BEGIN {
reason = test_aqueue2(i);
} T_END;
}
test_out_reason("aqueue", reason == NULL, reason);
}
dovecot-2.3.21.1/src/lib/mountpoint.h 0000644 0000000 0000000 00000001336 14656633576 014242 0000000 0000000 #ifndef MOUNTPOINT_H
#define MOUNTPOINT_H
struct mountpoint {
char *device_path;
char *mount_path;
char *type;
dev_t dev;
unsigned int block_size; /* may not be set for iteration */
};
/* Returns 1 = found, 0 = not found (from mount tabs, or the path itself),
-1 = error */
int mountpoint_get(const char *path, pool_t pool, struct mountpoint *point_r);
/* Iterate through mountpoints */
struct mountpoint_iter *mountpoint_iter_init(void);
/* Returns the next mountpoint or NULL if there are no more. */
const struct mountpoint *mountpoint_iter_next(struct mountpoint_iter *iter);
/* Returns 0 if mountpoints were iterated successfully, -1 if it failed. */
int mountpoint_iter_deinit(struct mountpoint_iter **iter);
#endif
dovecot-2.3.21.1/src/lib/hash-decl.h 0000644 0000000 0000000 00000001017 14656633576 013652 0000000 0000000 #ifndef HASH_DECL_H
#define HASH_DECL_H
#define HASH_TABLE_UNION(key_type, value_type) { \
struct hash_table *_table; \
key_type _key; \
key_type *_keyp; \
const key_type _const_key; \
value_type _value; \
value_type *_valuep; \
}
#define HASH_TABLE_DEFINE_TYPE(name, key_type, value_type) \
union hash ## __ ## name HASH_TABLE_UNION(key_type, value_type)
#define HASH_TABLE(key_type, value_type) \
union HASH_TABLE_UNION(key_type, value_type)
#define HASH_TABLE_TYPE(name) \
union hash ## __ ## name
#endif
dovecot-2.3.21.1/src/lib/hex-dec.c 0000644 0000000 0000000 00000001477 14656633576 013344 0000000 0000000 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "hex-dec.h"
void dec2hex(unsigned char *hexstr, uintmax_t dec, unsigned int hexstr_size)
{
unsigned int i;
for (i = 0; i < hexstr_size; i++) {
unsigned int value = dec & 0x0f;
if (value < 10)
hexstr[hexstr_size-i-1] = value + '0';
else
hexstr[hexstr_size-i-1] = value - 10 + 'A';
dec >>= 4;
}
}
uintmax_t hex2dec(const unsigned char *data, unsigned int len)
{
unsigned int i;
uintmax_t value = 0;
for (i = 0; i < len; i++) {
value = value*0x10;
if (data[i] >= '0' && data[i] <= '9')
value += data[i]-'0';
else if (data[i] >= 'A' && data[i] <= 'F')
value += data[i]-'A' + 10;
else if (data[i] >= 'a' && data[i] <= 'f')
value += data[i]-'a' + 10;
else
return 0;
}
return value;
}
dovecot-2.3.21.1/src/lib/iostream-temp.c 0000644 0000000 0000000 00000027413 14656633576 014613 0000000 0000000 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "write-full.h"
#include "istream-private.h"
#include "ostream-private.h"
#include "iostream-temp.h"
#include
#define IOSTREAM_TEMP_MAX_BUF_SIZE_DEFAULT (1024*128)
struct temp_ostream {
struct ostream_private ostream;
char *temp_path_prefix;
enum iostream_temp_flags flags;
size_t max_mem_size;
struct istream *dupstream;
uoff_t dupstream_offset, dupstream_start_offset;
char *name;
buffer_t *buf;
int fd;
bool fd_tried;
uoff_t fd_size;
};
static bool o_stream_temp_dup_cancel(struct temp_ostream *tstream,
enum ostream_send_istream_result *res_r);
static void
o_stream_temp_close(struct iostream_private *stream,
bool close_parent ATTR_UNUSED)
{
struct temp_ostream *tstream =
container_of(stream, struct temp_ostream, ostream.iostream);
i_close_fd(&tstream->fd);
buffer_free(&tstream->buf);
i_free(tstream->temp_path_prefix);
i_free(tstream->name);
}
static int o_stream_temp_move_to_fd(struct temp_ostream *tstream)
{
string_t *path;
if (tstream->fd_tried)
return -1;
tstream->fd_tried = TRUE;
path = t_str_new(128);
str_append(path, tstream->temp_path_prefix);
tstream->fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
if (tstream->fd == -1) {
i_error("safe_mkstemp(%s) failed: %m", str_c(path));
return -1;
}
if (i_unlink(str_c(path)) < 0) {
i_close_fd(&tstream->fd);
return -1;
}
if (write_full(tstream->fd, tstream->buf->data, tstream->buf->used) < 0) {
i_error("write(%s) failed: %m", str_c(path));
i_close_fd(&tstream->fd);
return -1;
}
/* make the fd available also to o_stream_get_fd(),
e.g. for unit tests */
tstream->ostream.fd = tstream->fd;
tstream->fd_size = tstream->buf->used;
buffer_free(&tstream->buf);
return 0;
}
int o_stream_temp_move_to_memory(struct ostream *output)
{
struct temp_ostream *tstream =
container_of(output->real_stream, struct temp_ostream, ostream);
unsigned char buf[IO_BLOCK_SIZE];
uoff_t offset = 0;
ssize_t ret = 0;
i_assert(tstream->buf == NULL);
tstream->buf = buffer_create_dynamic(default_pool, 8192);
while (offset < tstream->ostream.ostream.offset &&
(ret = pread(tstream->fd, buf, sizeof(buf), offset)) > 0) {
if ((size_t)ret > tstream->ostream.ostream.offset - offset)
ret = tstream->ostream.ostream.offset - offset;
buffer_append(tstream->buf, buf, ret);
offset += ret;
}
if (ret < 0) {
/* not really expecting this to happen */
i_error("iostream-temp %s: read(%s*) failed: %m",
o_stream_get_name(&tstream->ostream.ostream),
tstream->temp_path_prefix);
tstream->ostream.ostream.stream_errno = EIO;
return -1;
}
i_close_fd(&tstream->fd);
tstream->ostream.fd = -1;
return 0;
}
static ssize_t
o_stream_temp_fd_sendv(struct temp_ostream *tstream,
const struct const_iovec *iov, unsigned int iov_count)
{
size_t bytes = 0;
unsigned int i;
for (i = 0; i < iov_count; i++) {
if (write_full(tstream->fd, iov[i].iov_base, iov[i].iov_len) < 0) {
i_error("iostream-temp %s: write(%s*) failed: %m - moving to memory",
o_stream_get_name(&tstream->ostream.ostream),
tstream->temp_path_prefix);
if (o_stream_temp_move_to_memory(&tstream->ostream.ostream) < 0)
return -1;
for (; i < iov_count; i++) {
buffer_append(tstream->buf, iov[i].iov_base, iov[i].iov_len);
bytes += iov[i].iov_len;
tstream->ostream.ostream.offset += iov[i].iov_len;
}
i_assert(tstream->fd_tried);
return bytes;
}
bytes += iov[i].iov_len;
tstream->ostream.ostream.offset += iov[i].iov_len;
}
tstream->fd_size += bytes;
return bytes;
}
static ssize_t
o_stream_temp_sendv(struct ostream_private *stream,
const struct const_iovec *iov, unsigned int iov_count)
{
struct temp_ostream *tstream =
container_of(stream, struct temp_ostream, ostream);
ssize_t ret = 0;
unsigned int i;
enum ostream_send_istream_result res;
tstream->flags &= ENUM_NEGATE(IOSTREAM_TEMP_FLAG_TRY_FD_DUP);
if (tstream->dupstream != NULL) {
if (o_stream_temp_dup_cancel(tstream, &res))
return -1;
}
if (tstream->fd != -1)
return o_stream_temp_fd_sendv(tstream, iov, iov_count);
for (i = 0; i < iov_count; i++) {
if (tstream->buf->used + iov[i].iov_len > tstream->max_mem_size) {
if (o_stream_temp_move_to_fd(tstream) == 0) {
i_assert(tstream->fd != -1);
return o_stream_temp_fd_sendv(tstream, iov+i,
iov_count-i);
}
/* failed to move to temp fd, just keep it in memory */
}
buffer_append(tstream->buf, iov[i].iov_base, iov[i].iov_len);
ret += iov[i].iov_len;
stream->ostream.offset += iov[i].iov_len;
}
return ret;
}
static bool o_stream_temp_dup_cancel(struct temp_ostream *tstream,
enum ostream_send_istream_result *res_r)
{
struct istream *input;
uoff_t size = tstream->dupstream_offset -
tstream->dupstream_start_offset;
bool ret = TRUE; /* use res_r to return error */
i_stream_seek(tstream->dupstream, tstream->dupstream_start_offset);
tstream->ostream.ostream.offset = 0;
input = i_stream_create_limit(tstream->dupstream, size);
i_stream_unref(&tstream->dupstream);
*res_r = io_stream_copy(&tstream->ostream.ostream, input);
switch (*res_r) {
case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
/* everything copied */
ret = FALSE;
break;
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
i_unreached();
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
tstream->ostream.ostream.stream_errno = input->stream_errno;
io_stream_set_error(&tstream->ostream.iostream,
"iostream-temp: read(%s) failed: %s",
i_stream_get_name(input),
i_stream_get_error(input));
break;
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
break;
}
i_stream_destroy(&input);
return ret;
}
static bool
o_stream_temp_dup_istream(struct temp_ostream *outstream,
struct istream *instream,
enum ostream_send_istream_result *res_r)
{
uoff_t in_size;
if (!instream->readable_fd || i_stream_get_fd(instream) == -1)
return FALSE;
if (i_stream_get_size(instream, TRUE, &in_size) <= 0) {
if (outstream->dupstream != NULL)
return o_stream_temp_dup_cancel(outstream, res_r);
return FALSE;
}
i_assert(instream->v_offset <= in_size);
if (outstream->dupstream == NULL) {
outstream->dupstream = instream;
outstream->dupstream_start_offset = instream->v_offset;
i_stream_ref(outstream->dupstream);
} else {
if (outstream->dupstream != instream ||
outstream->dupstream_offset != instream->v_offset ||
outstream->dupstream_offset > in_size)
return o_stream_temp_dup_cancel(outstream, res_r);
}
i_stream_seek(instream, in_size);
/* we should be at EOF now. o_stream_send_istream() asserts if
eof isn't set. */
instream->eof = TRUE;
outstream->dupstream_offset = instream->v_offset;
outstream->ostream.ostream.offset =
outstream->dupstream_offset - outstream->dupstream_start_offset;
*res_r = OSTREAM_SEND_ISTREAM_RESULT_FINISHED;
return TRUE;
}
static enum ostream_send_istream_result
o_stream_temp_send_istream(struct ostream_private *_outstream,
struct istream *instream)
{
struct temp_ostream *outstream =
container_of(_outstream, struct temp_ostream, ostream);
enum ostream_send_istream_result res;
if ((outstream->flags & IOSTREAM_TEMP_FLAG_TRY_FD_DUP) != 0) {
if (o_stream_temp_dup_istream(outstream, instream, &res))
return res;
outstream->flags &= ENUM_NEGATE(IOSTREAM_TEMP_FLAG_TRY_FD_DUP);
}
return io_stream_copy(&outstream->ostream.ostream, instream);
}
static int
o_stream_temp_write_at(struct ostream_private *stream,
const void *data, size_t size, uoff_t offset)
{
struct temp_ostream *tstream =
container_of(stream, struct temp_ostream, ostream);
if (tstream->fd == -1) {
i_assert(stream->ostream.offset == tstream->buf->used);
buffer_write(tstream->buf, offset, data, size);
stream->ostream.offset = tstream->buf->used;
} else {
if (pwrite_full(tstream->fd, data, size, offset) < 0) {
stream->ostream.stream_errno = errno;
i_close_fd(&tstream->fd);
return -1;
}
if (tstream->fd_size < offset + size)
tstream->fd_size = offset + size;
}
return 0;
}
static int o_stream_temp_seek(struct ostream_private *_stream, uoff_t offset)
{
_stream->ostream.offset = offset;
return 0;
}
struct ostream *iostream_temp_create(const char *temp_path_prefix,
enum iostream_temp_flags flags)
{
return iostream_temp_create_named(temp_path_prefix, flags, "");
}
struct ostream *iostream_temp_create_named(const char *temp_path_prefix,
enum iostream_temp_flags flags,
const char *name)
{
return iostream_temp_create_sized(temp_path_prefix, flags, name,
IOSTREAM_TEMP_MAX_BUF_SIZE_DEFAULT);
}
struct ostream *iostream_temp_create_sized(const char *temp_path_prefix,
enum iostream_temp_flags flags,
const char *name,
size_t max_mem_size)
{
struct temp_ostream *tstream;
struct ostream *output;
tstream = i_new(struct temp_ostream, 1);
tstream->ostream.ostream.blocking = TRUE;
tstream->ostream.sendv = o_stream_temp_sendv;
tstream->ostream.send_istream = o_stream_temp_send_istream;
tstream->ostream.write_at = o_stream_temp_write_at;
tstream->ostream.seek = o_stream_temp_seek;
tstream->ostream.iostream.close = o_stream_temp_close;
tstream->temp_path_prefix = i_strdup(temp_path_prefix);
tstream->flags = flags;
tstream->max_mem_size = max_mem_size;
tstream->buf = buffer_create_dynamic(default_pool, 8192);
tstream->fd = -1;
output = o_stream_create(&tstream->ostream, NULL, -1);
tstream->name = i_strdup(name);
if (name[0] == '\0') {
o_stream_set_name(output, t_strdup_printf(
"(temp iostream in %s)", temp_path_prefix));
} else {
o_stream_set_name(output, t_strdup_printf(
"(temp iostream in %s for %s)", temp_path_prefix, name));
}
return output;
}
static void iostream_temp_buf_destroyed(buffer_t *buf)
{
buffer_free(&buf);
}
struct istream *iostream_temp_finish(struct ostream **output,
size_t max_buffer_size)
{
struct temp_ostream *tstream =
container_of((*output)->real_stream, struct temp_ostream,
ostream);
struct istream *input, *input2;
uoff_t abs_offset, size;
const char *for_path;
int fd;
if (tstream->name[0] == '\0')
for_path = "";
else
for_path = t_strdup_printf(" for %s", tstream->name);
if (tstream->dupstream != NULL && !tstream->dupstream->closed) {
abs_offset = i_stream_get_absolute_offset(tstream->dupstream) -
tstream->dupstream->v_offset +
tstream->dupstream_start_offset;
size = tstream->dupstream_offset -
tstream->dupstream_start_offset;
fd = dup(i_stream_get_fd(tstream->dupstream));
if (fd == -1)
input = i_stream_create_error_str(errno, "dup() failed: %m");
else {
input2 = i_stream_create_fd_autoclose(&fd, max_buffer_size);
i_stream_seek(input2, abs_offset);
input = i_stream_create_limit(input2, size);
i_stream_unref(&input2);
}
i_stream_set_name(input, t_strdup_printf(
"(Temp file in %s%s, from %s)", tstream->temp_path_prefix,
for_path, i_stream_get_name(tstream->dupstream)));
i_stream_unref(&tstream->dupstream);
} else if (tstream->dupstream != NULL) {
/* return the original failed stream. */
input = tstream->dupstream;
} else if (tstream->fd != -1) {
int fd = tstream->fd;
input = i_stream_create_fd_autoclose(&tstream->fd, max_buffer_size);
i_stream_set_name(input, t_strdup_printf(
"(Temp file fd %d in %s%s, %"PRIuUOFF_T" bytes)",
fd, tstream->temp_path_prefix, for_path, tstream->fd_size));
} else {
input = i_stream_create_from_data(tstream->buf->data,
tstream->buf->used);
i_stream_set_name(input, t_strdup_printf(
"(Temp buffer in %s%s, %zu bytes)",
tstream->temp_path_prefix, for_path, tstream->buf->used));
i_stream_add_destroy_callback(input, iostream_temp_buf_destroyed,
tstream->buf);
tstream->buf = NULL;
}
o_stream_destroy(output);
return input;
}
dovecot-2.3.21.1/src/lib/path-util.h 0000644 0000000 0000000 00000006046 14656633576 013740 0000000 0000000 #ifndef PATH_UTIL_H
#define PATH_UTIL_H
/* Returns path as the normalized absolute path, which means that './'
* and '../' components are resolved, and that duplicate and trailing
* slashes are removed. If it's not already the absolute path, it's
* assumed to be relative to the current working directory.
*
* NOTE: Be careful with this function. The resolution of '../' components
* with the parent component as if it were a normal directory is not valid
* if the path contains symbolic links.
*
* Returns 0 on success, and -1 on failure. errno and error_r are set on
* failure, and error_r cannot be NULL.
*/
int t_normpath(const char *path, const char **npath_r, const char **error_r);
/* Like t_normpath(), but path is relative to given root. */
int t_normpath_to(const char *path, const char *root, const char **npath_r,
const char **error_r);
/* Returns path as the real normalized absolute path, which means that all
* symbolic links in the path are resolved, that './' and '../' components
* are resolved, and that duplicate and trailing slashes are removed. If it's
* not already the absolute path, it's assumed to be relative to the current
* working directory.
*
* NOTE: This function calls stat() for each path component and more when
* there are symbolic links (just like POSIX realpath()).
*
* Returns 0 on success, and -1 on failure. errno and error_r are set on
* failure, and error_r cannot be NULL.
*/
int t_realpath(const char *path, const char **npath_r, const char **error_r);
/* Like t_realpath(), but path is relative to given root. */
int t_realpath_to(const char *path, const char *root, const char **npath_r,
const char **error_r);
/* Returns path as absolute path. If it's not already absolute path,
* it's assumed to be relative to current working directory.
*
* In the t_abspath functions, the returned paths are not normalized. This
* means that './' and '../' are not resolved, but they left in the returned
* path as given in the parameters. Symbolic links are not resolved either.
*
* Returns 0 on success, and -1 on failure. error_r is set on failure, and
* cannot be NULL.
*/
int t_abspath(const char *path, const char **abspath_r, const char **error_r);
/* Like t_abspath(), but path is relative to given root. */
const char *t_abspath_to(const char *path, const char *root);
/* Get current working directory allocated from data stack. Returns 0 on
* success and 1 on failure. error_r is set on failure and cannot be NULL. */
int t_get_working_dir(const char **dir_r, const char **error_r);
/* Get symlink destination allocated from data stack. Returns 0 on success and
* -1 on failure. error_r is set on failure and cannot be NULL. */
int t_readlink(const char *path, const char **dest_r, const char **error_r);
/* Update binpath to be absolute:
* a) begins with '/' -> no change
* b) contains '/' -> assume relative to working directory
* c) set to first executable that's found from $PATH
*
* error_r is set on failure, and cannot be NULL.
*/
bool t_binary_abspath(const char **binpath, const char **error_r);
#endif
dovecot-2.3.21.1/src/lib/iostream-rawlog-private.h 0000644 0000000 0000000 00000001150 14656633576 016604 0000000 0000000 #ifndef IOSTREAM_RAWLOG_PRIVATE_H
#define IOSTREAM_RAWLOG_PRIVATE_H
#include "iostream-rawlog.h"
#define IOSTREAM_RAWLOG_MAX_PREFIX_LEN 3
struct rawlog_iostream {
struct iostream_private *iostream;
enum iostream_rawlog_flags flags;
struct ostream *rawlog_output;
buffer_t *buffer;
bool input;
bool line_continued;
};
void iostream_rawlog_init(struct rawlog_iostream *rstream,
enum iostream_rawlog_flags flags, bool input);
void iostream_rawlog_write(struct rawlog_iostream *rstream,
const unsigned char *data, size_t size);
void iostream_rawlog_close(struct rawlog_iostream *rstream);
#endif
dovecot-2.3.21.1/src/lib/iostream.h 0000644 0000000 0000000 00000000537 14656633576 013653 0000000 0000000 #ifndef IOSTREAM_H
#define IOSTREAM_H
/* Returns human-readable reason for why iostream was disconnected.
The output is either "Connection closed" for clean disconnections or
"Connection closed: " for unclean disconnections. */
const char *io_stream_get_disconnect_reason(struct istream *input,
struct ostream *output);
#endif
dovecot-2.3.21.1/src/lib/test-llist.c 0000644 0000000 0000000 00000012712 14656633576 014125 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "llist.h"
struct dllist {
struct dllist *prev, *next;
};
static void test_dllist(void)
{
struct dllist *head = NULL, *l4, *l3, *l2, *l1;
struct dllist empty = { NULL, NULL };
l4 = t_new(struct dllist, 1);
l3 = t_new(struct dllist, 1);
l2 = t_new(struct dllist, 1);
l1 = t_new(struct dllist, 1);
test_begin("dllist");
DLLIST_PREPEND(&head, l4);
test_assert(head == l4);
test_assert(l4->prev == NULL && l4->next == NULL);
DLLIST_PREPEND(&head, l3);
test_assert(head == l3);
test_assert(l3->prev == NULL && l3->next == l4);
test_assert(l4->prev == l3 && l4->next == NULL);
DLLIST_PREPEND(&head, l2);
DLLIST_PREPEND(&head, l1);
/* remove from middle */
DLLIST_REMOVE(&head, l2);
test_assert(l2->prev == NULL && l2->next == NULL);
test_assert(head == l1);
test_assert(l1->prev == NULL && l1->next == l3);
test_assert(l3->prev == l1 && l3->next == l4);
test_assert(l4->prev == l3 && l4->next == NULL);
/* remove from head */
DLLIST_REMOVE(&head, l1);
test_assert(l1->prev == NULL && l1->next == NULL);
test_assert(head == l3);
test_assert(l3->prev == NULL && l3->next == l4);
test_assert(l4->prev == l3 && l4->next == NULL);
/* remove from tail */
DLLIST_PREPEND(&head, l1);
DLLIST_REMOVE(&head, l4);
test_assert(l4->prev == NULL && l4->next == NULL);
test_assert(head == l1);
test_assert(l1->prev == NULL && l1->next == l3);
test_assert(l3->prev == l1 && l3->next == NULL);
/* removal of an entry not in the list shouldn't cause the list to break */
DLLIST_REMOVE(&head, &empty);
test_assert(head == l1);
test_assert(l1->prev == NULL && l1->next == l3);
test_assert(l3->prev == l1 && l3->next == NULL);
/* remove last two */
DLLIST_REMOVE(&head, l1);
DLLIST_REMOVE(&head, l3);
test_assert(l3->prev == NULL && l3->next == NULL);
test_assert(head == NULL);
test_end();
}
static void test_dllist2(void)
{
struct dllist *head = NULL, *tail = NULL, *l4, *l3, *l2, *l1;
struct dllist empty = { NULL, NULL };
l4 = t_new(struct dllist, 1);
l3 = t_new(struct dllist, 1);
l2 = t_new(struct dllist, 1);
l1 = t_new(struct dllist, 1);
test_begin("dllist2");
/* prepend to empty */
DLLIST2_PREPEND(&head, &tail, l3);
test_assert(head == l3 && tail == l3);
test_assert(l3->next == NULL && l3->prev == NULL);
/* remove last */
DLLIST2_REMOVE(&head, &tail, l3);
test_assert(head == NULL && tail == NULL);
test_assert(l3->next == NULL && l3->prev == NULL);
/* append to empty */
DLLIST2_APPEND(&head, &tail, l3);
test_assert(head == l3 && tail == l3);
test_assert(l3->next == NULL && l3->prev == NULL);
/* prepend */
DLLIST2_PREPEND(&head, &tail, l2);
test_assert(head == l2 && tail == l3);
test_assert(l2->prev == NULL && l2->next == l3);
test_assert(l3->prev == l2 && l3->next == NULL);
/* append */
DLLIST2_APPEND(&head, &tail, l4);
test_assert(head == l2 && tail == l4);
test_assert(l2->prev == NULL && l2->next == l3);
test_assert(l3->prev == l2 && l3->next == l4);
test_assert(l4->prev == l3 && l4->next == NULL);
DLLIST2_PREPEND(&head, &tail, l1);
/* remove from middle */
DLLIST2_REMOVE(&head, &tail, l2);
test_assert(l2->prev == NULL && l2->next == NULL);
test_assert(head == l1 && tail == l4);
test_assert(l1->prev == NULL && l1->next == l3);
test_assert(l3->prev == l1 && l3->next == l4);
test_assert(l4->prev == l3 && l4->next == NULL);
/* remove from head */
DLLIST2_REMOVE(&head, &tail, l1);
test_assert(l1->prev == NULL && l1->next == NULL);
test_assert(head == l3 && tail == l4);
test_assert(l3->prev == NULL && l3->next == l4);
test_assert(l4->prev == l3 && l4->next == NULL);
/* remove from tail */
DLLIST2_PREPEND(&head, &tail, l1);
DLLIST2_REMOVE(&head, &tail, l4);
test_assert(l4->prev == NULL && l4->next == NULL);
test_assert(head == l1 && tail == l3);
test_assert(l1->prev == NULL && l1->next == l3);
test_assert(l3->prev == l1 && l3->next == NULL);
/* removal of an entry not in the list shouldn't cause the list to break */
DLLIST2_REMOVE(&head, &tail, &empty);
test_assert(head == l1);
test_assert(head == l1 && tail == l3);
test_assert(l1->prev == NULL && l1->next == l3);
test_assert(l3->prev == l1 && l3->next == NULL);
/* remove last two */
DLLIST2_REMOVE(&head, &tail, l1);
DLLIST2_REMOVE(&head, &tail, l3);
test_assert(l3->prev == NULL && l3->next == NULL);
test_assert(head == NULL && tail == NULL);
test_end();
}
static void test_dllist2_join(void)
{
struct dllist *head, *tail, *elem[4];
struct dllist *head2, *tail2, *elem2[N_ELEMENTS(elem)];
test_begin("dllist2 join");
for (unsigned int i = 0; i < N_ELEMENTS(elem); i++) {
elem[i] = t_new(struct dllist, 1);
elem2[i] = t_new(struct dllist, 1);
}
for (unsigned int i = 0; i < N_ELEMENTS(elem); i++) {
for (unsigned int j = 0; j < N_ELEMENTS(elem2); j++) {
head = tail = head2 = tail2 = NULL;
for (unsigned int n = 0; n < i; n++)
DLLIST2_APPEND(&head, &tail, elem[n]);
for (unsigned int n = 0; n < j; n++)
DLLIST2_APPEND(&head2, &tail2, elem2[n]);
DLLIST2_JOIN(&head, &tail, &head2, &tail2);
/* verify */
struct dllist *tmp = head, *last = NULL;
for (unsigned int n = 0; n < i; n++) {
test_assert(tmp == elem[n]);
last = tmp;
tmp = tmp->next;
}
for (unsigned int n = 0; n < j; n++) {
test_assert(tmp == elem2[n]);
last = tmp;
tmp = tmp->next;
}
test_assert(tmp == NULL);
test_assert(tail == last);
}
}
test_end();
}
void test_llist(void)
{
test_dllist();
test_dllist2();
test_dllist2_join();
}
dovecot-2.3.21.1/src/lib/restrict-process-size.c 0000644 0000000 0000000 00000004160 14656633576 016302 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "restrict-process-size.h"
#include
void restrict_process_size(rlim_t bytes)
{
struct rlimit rlim;
rlim.rlim_max = rlim.rlim_cur = bytes;
if (setrlimit(RLIMIT_DATA, &rlim) < 0) {
i_fatal("setrlimit(RLIMIT_DATA, %llu): %m",
(unsigned long long)bytes);
}
#ifdef HAVE_RLIMIT_AS
if (setrlimit(RLIMIT_AS, &rlim) < 0) {
i_fatal("setrlimit(RLIMIT_AS, %llu): %m",
(unsigned long long)bytes);
}
#endif
}
void restrict_process_count(rlim_t count ATTR_UNUSED)
{
#ifdef HAVE_RLIMIT_NPROC
struct rlimit rlim;
rlim.rlim_max = rlim.rlim_cur = count;
if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
i_error("setrlimit(RLIMIT_NPROC, %llu): %m",
(unsigned long long)count);
}
#endif
}
void restrict_fd_limit(rlim_t count)
{
#ifdef HAVE_SETRLIMIT
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = count;
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
i_error("setrlimit(RLIMIT_NOFILE, %llu): %m",
(unsigned long long)count);
}
#endif
}
int restrict_get_process_size(rlim_t *limit_r)
{
struct rlimit rlim;
#ifdef HAVE_RLIMIT_AS
if (getrlimit(RLIMIT_AS, &rlim) < 0) {
i_error("getrlimit(RLIMIT_AS): %m");
return -1;
}
#else
if (getrlimit(RLIMIT_DATA, &rlim) < 0) {
i_error("getrlimit(RLIMIT_DATA): %m");
return -1;
}
#endif
*limit_r = rlim.rlim_cur;
return 0;
}
int restrict_get_core_limit(rlim_t *limit_r)
{
#ifdef HAVE_RLIMIT_CORE
struct rlimit rlim;
if (getrlimit(RLIMIT_CORE, &rlim) < 0) {
i_error("getrlimit(RLIMIT_CORE) failed: %m");
return -1;
}
*limit_r = rlim.rlim_cur;
return 0;
#else
return -1;
#endif
}
int restrict_get_process_limit(rlim_t *limit_r)
{
#ifdef HAVE_RLIMIT_NPROC
struct rlimit rlim;
if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
i_error("getrlimit(RLIMIT_NPROC) failed: %m");
return -1;
}
*limit_r = rlim.rlim_cur;
return 0;
#else
return -1;
#endif
}
int restrict_get_fd_limit(rlim_t *limit_r)
{
struct rlimit rlim;
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
i_error("getrlimit(RLIMIT_NOFILE) failed: %m");
return -1;
}
*limit_r = rlim.rlim_cur;
return 0;
}
dovecot-2.3.21.1/src/lib/env-util.h 0000644 0000000 0000000 00000002133 14656633576 013565 0000000 0000000 #ifndef ENV_UTIL_H
#define ENV_UTIL_H
/* Add a new environment variable or replace an existing one.
Wrapper to setenv(). Note that setenv() often doesn't free memory used by
replaced environment, so don't keep repeatedly changing values in
environment. */
void env_put(const char *name, const char *value);
/* env_put() NULL-terminated array of name=value strings */
void env_put_array(const char *const *envs);
/* Remove a single environment. */
void env_remove(const char *name);
/* Clear all environment variables. */
void env_clean(void);
/* Clear all environment variables except what's listed in preserve_envs[] */
void env_clean_except(const char *const preserve_envs[]);
/* Save a copy of the current environment. */
struct env_backup *env_backup_save(void);
/* Clear the current environment and restore the backup. */
void env_backup_restore(struct env_backup *env);
/* Free the memory used by environment backup. */
void env_backup_free(struct env_backup **env);
/* Returns the value of "&environ". This is more portable than using it
directly. */
char ***env_get_environ_p(void);
#endif
dovecot-2.3.21.1/src/lib/test-file-create-locked.c 0000644 0000000 0000000 00000006415 14656633576 016420 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "unlink-directory.h"
#include "file-create-locked.h"
#include "sleep.h"
#include
#include
#include
static void create_file(const char *path)
{
int fd;
fd = creat(path, 0600);
if (fd == -1)
i_fatal("creat(%s) failed: %m", path);
i_close_fd(&fd);
}
static bool wait_for_file(pid_t pid, const char *path)
{
struct stat st;
for (unsigned int i = 0; i < 1000; i++) {
if (stat(path, &st) == 0)
return TRUE;
if (errno != ENOENT)
i_fatal("stat(%s) failed: %m", path);
if (kill(pid, 0) < 0) {
if (errno == ESRCH)
return FALSE;
i_fatal("kill(SIGSRCH) failed: %m");
}
i_sleep_msecs(10);
}
i_error("%s isn't being created", path);
return FALSE;
}
static void test_file_create_locked_basic(void)
{
struct file_create_settings set = {
.lock_timeout_secs = 0,
.lock_settings = {
.lock_method = FILE_LOCK_METHOD_FCNTL,
},
};
const char *path = ".test-file-create-locked";
struct file_lock *lock;
const char *error;
bool created;
pid_t pid;
int fd;
test_begin("file_create_locked()");
i_unlink_if_exists(path);
i_unlink_if_exists(".test-temp-file-create-locked-child");
pid = fork();
switch (pid) {
case (pid_t)-1:
i_error("fork() failed: %m");
break;
case 0:
/* child */
fd = file_create_locked(path, &set, &lock, &created, &error);
test_assert(fd > 0);
test_assert(created);
if (test_has_failed())
lib_exit(1);
create_file(".test-temp-file-create-locked-child");
sleep(60);
i_close_fd(&fd);
lib_exit(0);
default:
/* parent */
test_assert(wait_for_file(pid, ".test-temp-file-create-locked-child"));
if (test_has_failed())
break;
test_assert(file_create_locked(path, &set, &lock, &created, &error) == -1);
test_assert(errno == EAGAIN);
if (kill(pid, SIGKILL) < 0)
i_error("kill(SIGKILL) failed: %m");
break;
}
i_unlink_if_exists(".test-temp-file-create-locked-child");
i_unlink_if_exists(path);
test_end();
}
static void test_file_create_locked_mkdir(void)
{
struct file_create_settings set = {
.lock_timeout_secs = 0,
.lock_settings = {
.lock_method = FILE_LOCK_METHOD_FCNTL,
},
};
const char *path;
struct file_lock *lock;
const char *error, *dir;
bool created;
int fd;
test_begin("file_create_locked() with mkdir");
dir = ".test-temp-file-create-locked-dir";
if (unlink_directory(dir, UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
i_fatal("unlink_directory(%s) failed: %s", dir, error);
path = t_strconcat(dir, "/lockfile", NULL);
/* try without mkdir enabled */
test_assert(file_create_locked(path, &set, &lock, &created, &error) == -1);
test_assert(errno == ENOENT);
/* try with mkdir enabled */
set.mkdir_mode = 0700;
fd = file_create_locked(path, &set, &lock, &created, &error);
test_assert(fd > 0);
test_assert(created);
i_close_fd(&fd);
struct stat st;
if (stat(dir, &st) < 0)
i_error("stat(%s) failed: %m", dir);
test_assert((st.st_mode & 0777) == 0700);
i_unlink(path);
file_lock_free(&lock);
if (unlink_directory(dir, UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
i_fatal("unlink_directory(%s) failed: %s", dir, error);
test_end();
}
void test_file_create_locked(void)
{
test_file_create_locked_basic();
test_file_create_locked_mkdir();
}
dovecot-2.3.21.1/src/lib/ostream-hash.h 0000644 0000000 0000000 00000000544 14656633576 014421 0000000 0000000 #ifndef OSTREAM_HASH_H
#define OSTREAM_HASH_H
struct hash_method;
/* hash_context must be allocated and initialized by caller. This ostream will
simply call method->loop() for all the data going through the ostream. */
struct ostream *
o_stream_create_hash(struct ostream *output, const struct hash_method *method,
void *hash_context);
#endif
dovecot-2.3.21.1/src/lib/test-event-category-register.c 0000644 0000000 0000000 00000023524 14656633576 017557 0000000 0000000 /* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "ioloop.h"
#include "time-util.h"
#include "lib-event-private.h"
#include "failures-private.h"
/* we call a generic "unregister category function; to tell it what exact
* behavior it should expect from lib-lib, we pass in one of the following
* values
*/
enum unreg_expectation {
UNREG_NOT_LAST,
UNREG_LAST,
UNREG_NOP,
};
#define CAT_NAME_PREFIX "test-category"
/* pointer to a category we expect to be registered/unregistered */
static struct event_category *expected_callback_cat;
static bool callback_called;
static struct event *dummy_event;
static void check_category(struct event_category *cat)
{
callback_called = TRUE;
/* lib-lib called a callback with a NULL? (useless and a bug) */
test_assert(cat != NULL);
/* callback called, but didn't expect to be called? */
test_assert(expected_callback_cat != NULL);
/* test_assert() doesn't terminate, so avoid NULL ptr derefs later on */
if ((cat == NULL) || (expected_callback_cat == NULL))
return;
/* check that the categories have the same values */
test_assert(strcmp(cat->name, expected_callback_cat->name) == 0);
test_assert(cat->internal == expected_callback_cat->internal);
}
static void check_cat_registered(const char *name, bool should_exist)
{
struct event_category *cat;
callback_called = FALSE;
cat = event_category_find_registered(name);
test_assert(callback_called == FALSE);
test_assert((cat != NULL) == should_exist);
}
static void register_cat(struct event_category *newcat,
struct event_category *expcat)
{
/* start with a known state - no regs expected */
expected_callback_cat = NULL;
callback_called = FALSE;
dummy_event = event_create(NULL);
test_assert(callback_called == FALSE);
/* we expect a registration only when adding a cat */
expected_callback_cat = (expcat);
event_add_category(dummy_event, (newcat));
expected_callback_cat = NULL;
/* check that all went well */
test_assert(callback_called == (expcat != NULL));
test_assert((newcat)->internal != NULL);
test_assert(event_category_find_registered((newcat)->name) != NULL);
/* clean up */
event_unref(&dummy_event);
}
static void unregister_cat(struct event_category *cat,
enum unreg_expectation expectation)
{
/* sanity check that cat is set up as expected */
switch (expectation) {
case UNREG_NOT_LAST:
/* must be registered to unregister */
test_assert(event_category_find_registered((cat)->name) != NULL);
expected_callback_cat = NULL;
break;
case UNREG_LAST:
/* must be registered to unregister */
test_assert(event_category_find_registered((cat)->name) != NULL);
expected_callback_cat = cat;
break;
case UNREG_NOP:
/* must not be registered for no-op */
/* event_category_find_registered(cat->name) should return
NULL, but since we don't actually unregister this lookup
would fail. Therefore, we skip it. */
expected_callback_cat = NULL;
break;
}
/* Note: We don't actually have a way to unregister categories. We
keep the above checks and the calls to this function as a form of
documentation of how unregistering should work. */
}
static void test_event_category_1ptr_null(void)
{
#define CAT_NAME_0 CAT_NAME_PREFIX "-1ptr-null"
static struct event_category cat = { .name = CAT_NAME_0 };
test_begin("event category rereg: same ptr, NULL parent");
check_cat_registered(CAT_NAME_0, FALSE);
register_cat(&cat, &cat);
register_cat(&cat, NULL);
check_cat_registered(CAT_NAME_0, TRUE);
unregister_cat(&cat, UNREG_LAST);
unregister_cat(&cat, UNREG_NOP);
test_end();
#undef CAT_NAME_0
}
static void test_event_category_1ptr_nonnull(void)
{
#define CAT_NAME_0 CAT_NAME_PREFIX "-1ptr-nonnull-0"
#define CAT_NAME_1 CAT_NAME_PREFIX "-1ptr-nonnull-1"
static struct event_category cat = { .name = CAT_NAME_0 };
static struct event_category cat_with_parent = { .name = CAT_NAME_1, .parent = &cat };
test_begin("event category rereg: same ptr, non-NULL parent");
check_cat_registered(CAT_NAME_0, FALSE);
check_cat_registered(CAT_NAME_1, FALSE);
register_cat(&cat, &cat);
register_cat(&cat_with_parent, &cat_with_parent);
register_cat(&cat_with_parent, NULL);
check_cat_registered(CAT_NAME_0, TRUE);
check_cat_registered(CAT_NAME_1, TRUE);
unregister_cat(&cat_with_parent, UNREG_LAST);
unregister_cat(&cat_with_parent, UNREG_NOP);
/* NOTE: we must unreg children before parent cats */
unregister_cat(&cat, UNREG_LAST);
unregister_cat(&cat, UNREG_NOP);
test_end();
#undef CAT_NAME_0
#undef CAT_NAME_1
}
static void test_event_category_2ptr_null(void)
{
#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-null"
static struct event_category cat0 = { .name = CAT_NAME_0 };
static struct event_category cat1 = { .name = CAT_NAME_0 };
test_begin("event category rereg: different ptr, NULL parent");
check_cat_registered(CAT_NAME_0, FALSE);
register_cat(&cat0, &cat0);
register_cat(&cat1, NULL);
check_cat_registered(CAT_NAME_0, TRUE);
unregister_cat(&cat0, UNREG_NOT_LAST);
unregister_cat(&cat1, UNREG_LAST);
unregister_cat(&cat0, UNREG_NOP);
unregister_cat(&cat1, UNREG_NOP);
test_end();
#undef CAT_NAME_0
}
static void test_event_category_2ptr_nonnull_same(void)
{
#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-nonnull-same-0"
#define CAT_NAME_1 CAT_NAME_PREFIX "-2ptr-nonnull-same-1"
static struct event_category cat = { .name = CAT_NAME_0 };
static struct event_category cat_with_parent0 = { .name = CAT_NAME_1, .parent = &cat };
static struct event_category cat_with_parent1 = { .name = CAT_NAME_1, .parent = &cat };
test_begin("event category rereg: different ptr, same non-NULL parent");
check_cat_registered(CAT_NAME_0, FALSE);
check_cat_registered(CAT_NAME_1, FALSE);
register_cat(&cat, &cat);
register_cat(&cat_with_parent0, &cat_with_parent0);
register_cat(&cat_with_parent1, NULL);
check_cat_registered(CAT_NAME_0, TRUE);
check_cat_registered(CAT_NAME_1, TRUE);
unregister_cat(&cat_with_parent0, UNREG_NOT_LAST);
unregister_cat(&cat_with_parent1, UNREG_LAST);
unregister_cat(&cat_with_parent0, UNREG_NOP);
unregister_cat(&cat_with_parent1, UNREG_NOP);
/* NOTE: we must unreg children before parent cats */
unregister_cat(&cat, UNREG_LAST);
unregister_cat(&cat, UNREG_NOP);
test_end();
#undef CAT_NAME_0
#undef CAT_NAME_1
}
static void test_event_category_2ptr_nonnull_similar(void)
{
#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-nonnull-similar-0"
#define CAT_NAME_1 CAT_NAME_PREFIX "-2ptr-nonnull-similar-1"
static struct event_category cat0 = { .name = CAT_NAME_0 };
static struct event_category cat1 = { .name = CAT_NAME_0 };
static struct event_category cat_with_parent0 = { .name = CAT_NAME_1, .parent = &cat0 };
static struct event_category cat_with_parent1 = { .name = CAT_NAME_1, .parent = &cat1 };
test_begin("event category rereg: different ptr, similar non-NULL parent");
check_cat_registered(CAT_NAME_0, FALSE);
check_cat_registered(CAT_NAME_1, FALSE);
register_cat(&cat0, &cat0);
register_cat(&cat1, NULL);
register_cat(&cat_with_parent0, &cat_with_parent0);
register_cat(&cat_with_parent1, NULL);
check_cat_registered(CAT_NAME_0, TRUE);
check_cat_registered(CAT_NAME_1, TRUE);
unregister_cat(&cat_with_parent0, UNREG_NOT_LAST);
unregister_cat(&cat_with_parent1, UNREG_LAST);
unregister_cat(&cat_with_parent0, UNREG_NOP);
unregister_cat(&cat_with_parent1, UNREG_NOP);
/* NOTE: we must unreg children before parent cats */
unregister_cat(&cat0, UNREG_NOT_LAST);
unregister_cat(&cat1, UNREG_LAST);
unregister_cat(&cat0, UNREG_NOP);
unregister_cat(&cat1, UNREG_NOP);
test_end();
#undef CAT_NAME_0
#undef CAT_NAME_1
}
void test_event_category_register(void)
{
event_category_register_callback(check_category);
/*
* registering/unregistering the same exact category struct (i.e.,
* the pointer is the same) is a no-op after the first call
*/
test_event_category_1ptr_null();
test_event_category_1ptr_nonnull();
/*
* registering/unregistering two different category structs (i.e.,
* the pointers are different) is a almost a no-op
*/
test_event_category_2ptr_null();
test_event_category_2ptr_nonnull_same();
test_event_category_2ptr_nonnull_similar();
event_category_unregister_callback(check_category);
}
enum fatal_test_state fatal_event_category_register(unsigned int stage)
{
#define CAT_NAME_0 CAT_NAME_PREFIX "-2ptr-nonnull-different-0"
#define CAT_NAME_1 CAT_NAME_PREFIX "-2ptr-nonnull-different-1"
#define CAT_NAME_2 CAT_NAME_PREFIX "-2ptr-nonnull-different-2"
static struct event_category cat_no_parent0 = { .name = CAT_NAME_0 };
static struct event_category cat_parent0 = { .name = CAT_NAME_1, .parent = &cat_no_parent0 };
static struct event_category cat_other = { .name = CAT_NAME_2 };
static struct event_category cat_other_parent = { .name = CAT_NAME_1, .parent = &cat_other };
/* we have only one fatal stage at this point */
switch (stage) {
case 0:
event_category_register_callback(check_category);
test_begin("event category rereg: different ptr, different non-NULL parent");
check_cat_registered(CAT_NAME_0, FALSE);
check_cat_registered(CAT_NAME_1, FALSE);
check_cat_registered(CAT_NAME_2, FALSE);
register_cat(&cat_no_parent0, &cat_no_parent0);
register_cat(&cat_other, &cat_other);
register_cat(&cat_parent0, &cat_parent0);
test_expect_fatal_string("event category parent mismatch detected");
register_cat(&cat_other_parent, NULL); /* expected panic */
return FATAL_TEST_FAILURE;
case 1:
event_unref(&dummy_event);
unregister_cat(&cat_parent0, UNREG_LAST);
unregister_cat(&cat_parent0, UNREG_NOP);
unregister_cat(&cat_other, UNREG_LAST);
unregister_cat(&cat_other, UNREG_NOP);
/* NOTE: we must unreg children before parent cats */
unregister_cat(&cat_no_parent0, UNREG_LAST);
unregister_cat(&cat_no_parent0, UNREG_NOP);
test_end();
event_category_unregister_callback(check_category);
return FATAL_TEST_FINISHED;
default:
return FATAL_TEST_ABORT;
}
#undef CAT_NAME_0
#undef CAT_NAME_1
#undef CAT_NAME_2
}
dovecot-2.3.21.1/src/lib/test-istream-failure-at.c 0000644 0000000 0000000 00000003217 14656633576 016471 0000000 0000000 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "istream.h"
#include "istream-failure-at.h"
#define TEST_DATA_LENGTH 128
#define TEST_ERRMSG "test-istream-failure-at error triggered"
void test_istream_failure_at(void)
{
struct istream *input, *data_input;
unsigned char test_data[TEST_DATA_LENGTH];
unsigned int i;
ssize_t ret;
test_begin("istream failure at");
for (i = 0; i < sizeof(test_data); i++)
test_data[i] = i;
data_input = i_stream_create_from_data(test_data, sizeof(test_data));
for (i = 0; i < TEST_DATA_LENGTH; i++) {
i_stream_seek(data_input, 0);
input = i_stream_create_failure_at(data_input, i, EIO, TEST_ERRMSG);
while ((ret = i_stream_read(input)) > 0)
i_stream_skip(input, ret);
test_assert_idx(ret == -1 && input->v_offset == i &&
input->stream_errno == EIO &&
strcmp(i_stream_get_error(input), TEST_ERRMSG) == 0, i);
i_stream_destroy(&input);
}
/* shouldn't fail */
i_stream_seek(data_input, 0);
input = i_stream_create_failure_at(data_input, TEST_DATA_LENGTH, EIO, TEST_ERRMSG);
while ((ret = i_stream_read(input)) > 0)
i_stream_skip(input, ret);
test_assert(ret == -1 && input->stream_errno == 0);
i_stream_destroy(&input);
/* fail at EOF */
i_stream_seek(data_input, 0);
input = i_stream_create_failure_at_eof(data_input, EIO, TEST_ERRMSG);
while ((ret = i_stream_read(input)) > 0)
i_stream_skip(input, ret);
test_assert_idx(ret == -1 && input->v_offset == TEST_DATA_LENGTH &&
input->stream_errno == EIO &&
strcmp(i_stream_get_error(input), TEST_ERRMSG) == 0, i);
i_stream_destroy(&input);
i_stream_destroy(&data_input);
test_end();
}
dovecot-2.3.21.1/src/lib/buffer.c 0000644 0000000 0000000 00000031364 14656633576 013276 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
/* @UNSAFE: whole file */
#include "lib.h"
#include "buffer.h"
struct real_buffer {
union {
struct buffer buf;
struct {
/* public: */
const void *r_buffer;
size_t used;
/* private: */
unsigned char *w_buffer;
size_t dirty, alloc, writable_size, max_size;
pool_t pool;
bool alloced:1;
bool dynamic:1;
};
};
};
typedef int buffer_check_sizes[COMPILE_ERROR_IF_TRUE(sizeof(struct real_buffer) > sizeof(buffer_t)) ?1:1];
static void buffer_alloc(struct real_buffer *buf, size_t size)
{
i_assert(buf->w_buffer == NULL || buf->alloced);
if (size == buf->alloc)
return;
i_assert(size > buf->alloc);
if (buf->w_buffer == NULL)
buf->w_buffer = p_malloc(buf->pool, size);
else
buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, size);
buf->alloc = size;
buf->writable_size = size-1; /* -1 for str_c() NUL */
buf->r_buffer = buf->w_buffer;
buf->alloced = TRUE;
}
static inline void
buffer_check_limits(struct real_buffer *buf, size_t pos, size_t data_size)
{
size_t new_size;
if (unlikely(buf->max_size - pos < data_size))
i_panic("Buffer write out of range (%zu + %zu)", pos, data_size);
new_size = pos + data_size;
if (new_size > buf->used && buf->used < buf->dirty) {
/* clear used..dirty area */
size_t max = I_MIN(I_MIN(buf->alloc, buf->dirty), new_size);
memset(buf->w_buffer + buf->used, 0, max - buf->used);
}
/* Use buf->writable_size instead of buf->alloc to always keep +1 byte
available in case str_c() is called for this buffer. This is mainly
for cases where the buffer is allocated from data stack, and str_c()
is called in a separate stack frame. */
if (new_size > buf->writable_size) {
if (unlikely(!buf->dynamic)) {
i_panic("Buffer full (%zu > %zu, pool %s)",
pos + data_size, buf->alloc,
buf->pool == NULL ? "" :
pool_get_name(buf->pool));
}
size_t new_alloc_size =
pool_get_exp_grown_size(buf->pool, buf->alloc,
new_size + 1);
if (new_alloc_size > buf->max_size) {
/* limit to max_size, but do include +1 for
str_c() NUL */
new_alloc_size = buf->max_size + 1;
}
buffer_alloc(buf, new_alloc_size);
}
#if 0
else if (new_size > buf->used && buf->alloced &&
!buf->pool->alloconly_pool && !buf->pool->datastack_pool) {
void *new_buf;
/* buffer's size increased: move the buffer's memory elsewhere.
this should help catch bugs where old pointers are tried to
be used to access the buffer's memory */
new_buf = p_malloc(buf->pool, buf->alloc);
memcpy(new_buf, buf->w_buffer, buf->alloc);
p_free(buf->pool, buf->w_buffer);
buf->w_buffer = new_buf;
buf->r_buffer = new_buf;
}
#endif
if (new_size > buf->used)
buf->used = new_size;
i_assert(buf->used <= buf->alloc);
i_assert(buf->w_buffer != NULL);
}
static inline void
buffer_check_append_limits(struct real_buffer *buf, size_t data_size)
{
/* Fast path: See if data to be appended fits into allocated buffer.
If it does, we don't even need to memset() the dirty buffer since
it's going to be filled with the newly appended data. */
if (buf->writable_size - buf->used < data_size)
buffer_check_limits(buf, buf->used, data_size);
else
buf->used += data_size;
}
#undef buffer_create_from_data
void buffer_create_from_data(buffer_t *buffer, void *data, size_t size)
{
struct real_buffer *buf;
i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
buf = container_of(buffer, struct real_buffer, buf);
i_zero(buf);
buf->alloc = buf->writable_size = buf->max_size = size;
buf->r_buffer = buf->w_buffer = data;
/* clear the whole memory area. unnecessary usually, but if the
buffer is used by e.g. str_c() it tries to access uninitialized
memory */
memset(data, 0, size);
}
#undef buffer_create_from_const_data
void buffer_create_from_const_data(buffer_t *buffer,
const void *data, size_t size)
{
struct real_buffer *buf;
i_assert(sizeof(*buffer) >= sizeof(struct real_buffer));
buf = container_of(buffer, struct real_buffer, buf);
i_zero(buf);
buf->used = buf->alloc = buf->writable_size = buf->max_size = size;
buf->r_buffer = data;
i_assert(buf->w_buffer == NULL);
}
buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size)
{
return buffer_create_dynamic_max(pool, init_size, SIZE_MAX);
}
buffer_t *buffer_create_dynamic_max(pool_t pool, size_t init_size,
size_t max_size)
{
struct real_buffer *buf;
#ifdef DEBUG
/* we increment this by 1 later on, so if it's SIZE_MAX
it turns into 0 and hides a potential bug.
Too scary to use in production for now, though. This
can change in future. */
i_assert(init_size < SIZE_MAX);
#endif
buf = p_new(pool, struct real_buffer, 1);
buf->pool = pool;
buf->dynamic = TRUE;
buf->max_size = max_size;
/* buffer_alloc() reserves +1 for str_c() NIL, so add +1 here to
init_size so we can actually write that much to the buffer without
realloc */
buffer_alloc(buf, init_size+1);
return &buf->buf;
}
void buffer_free(buffer_t **_buf)
{
if (*_buf == NULL)
return;
struct real_buffer *buf = container_of(*_buf, struct real_buffer, buf);
*_buf = NULL;
if (buf->alloced)
p_free(buf->pool, buf->w_buffer);
if (buf->pool != NULL)
p_free(buf->pool, buf);
}
void *buffer_free_without_data(buffer_t **_buf)
{
struct real_buffer *buf = container_of(*_buf, struct real_buffer, buf);
void *data;
*_buf = NULL;
data = buf->w_buffer;
p_free(buf->pool, buf);
return data;
}
pool_t buffer_get_pool(const buffer_t *_buf)
{
const struct real_buffer *buf =
container_of(_buf, const struct real_buffer, buf);
return buf->pool;
}
void buffer_write(buffer_t *_buf, size_t pos,
const void *data, size_t data_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
buffer_check_limits(buf, pos, data_size);
if (data_size > 0)
memcpy(buf->w_buffer + pos, data, data_size);
}
void buffer_append(buffer_t *_buf, const void *data, size_t data_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
if (data_size > 0) {
size_t pos = buf->used;
buffer_check_append_limits(buf, data_size);
memcpy(buf->w_buffer + pos, data, data_size);
}
}
void buffer_append_c(buffer_t *_buf, unsigned char chr)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
size_t pos = buf->used;
buffer_check_append_limits(buf, 1);
buf->w_buffer[pos] = chr;
}
void buffer_insert(buffer_t *_buf, size_t pos,
const void *data, size_t data_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
if (pos >= buf->used)
buffer_write(_buf, pos, data, data_size);
else {
buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX);
memcpy(buf->w_buffer + pos, data, data_size);
}
}
void buffer_delete(buffer_t *_buf, size_t pos, size_t size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
size_t end_size;
if (pos >= buf->used)
return;
end_size = buf->used - pos;
if (size < end_size) {
/* delete from between */
end_size -= size;
memmove(buf->w_buffer + pos,
buf->w_buffer + pos + size, end_size);
} else {
/* delete the rest of the buffer */
end_size = 0;
}
buffer_set_used_size(_buf, pos + end_size);
}
void buffer_replace(buffer_t *_buf, size_t pos, size_t size,
const void *data, size_t data_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
size_t end_size;
if (pos >= buf->used) {
buffer_write(_buf, pos, data, data_size);
return;
}
end_size = buf->used - pos;
if (size < end_size) {
end_size -= size;
if (data_size == 0) {
/* delete from between */
memmove(buf->w_buffer + pos,
buf->w_buffer + pos + size, end_size);
} else {
/* insert */
buffer_copy(_buf, pos + data_size, _buf, pos + size,
SIZE_MAX);
memcpy(buf->w_buffer + pos, data, data_size);
}
} else {
/* overwrite the end */
end_size = 0;
buffer_write(_buf, pos, data, data_size);
}
buffer_set_used_size(_buf, pos + data_size + end_size);
}
void buffer_write_zero(buffer_t *_buf, size_t pos, size_t data_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
buffer_check_limits(buf, pos, data_size);
memset(buf->w_buffer + pos, 0, data_size);
}
void buffer_append_zero(buffer_t *_buf, size_t data_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
/* NOTE: When appending it's enough to check that the limits are
valid, because the data is already guaranteed to be zero-filled. */
buffer_check_limits(buf, buf->used, data_size);
}
void buffer_insert_zero(buffer_t *_buf, size_t pos, size_t data_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
if (pos >= buf->used)
buffer_write_zero(_buf, pos, data_size);
else {
buffer_copy(_buf, pos + data_size, _buf, pos, SIZE_MAX);
memset(buf->w_buffer + pos, 0, data_size);
}
}
void buffer_copy(buffer_t *_dest, size_t dest_pos,
const buffer_t *_src, size_t src_pos, size_t copy_size)
{
struct real_buffer *dest = container_of(_dest, struct real_buffer, buf);
const struct real_buffer *src =
container_of(_src, const struct real_buffer, buf);
size_t max_size;
i_assert(src_pos <= src->used);
max_size = src->used - src_pos;
if (copy_size > max_size)
copy_size = max_size;
buffer_check_limits(dest, dest_pos, copy_size);
i_assert(src->r_buffer != NULL);
if (src == dest) {
memmove(dest->w_buffer + dest_pos,
CONST_PTR_OFFSET(src->r_buffer, src_pos), copy_size);
} else {
memcpy(dest->w_buffer + dest_pos,
CONST_PTR_OFFSET(src->r_buffer, src_pos), copy_size);
}
}
void buffer_append_buf(buffer_t *dest, const buffer_t *src,
size_t src_pos, size_t copy_size)
{
buffer_copy(dest, dest->used, src, src_pos, copy_size);
}
void *buffer_get_space_unsafe(buffer_t *_buf, size_t pos, size_t size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
buffer_check_limits(buf, pos, size);
return buf->w_buffer + pos;
}
void *buffer_append_space_unsafe(buffer_t *buf, size_t size)
{
/* NOTE: can't use buffer_check_append_limits() here because it doesn't
guarantee that the buffer is zero-filled. */
return buffer_get_space_unsafe(buf, buf->used, size);
}
void *buffer_get_modifiable_data(const buffer_t *_buf, size_t *used_size_r)
{
const struct real_buffer *buf =
container_of(_buf, const struct real_buffer, buf);
if (used_size_r != NULL)
*used_size_r = buf->used;
i_assert(buf->used == 0 || buf->w_buffer != NULL);
return buf->w_buffer;
}
void buffer_set_used_size(buffer_t *_buf, size_t used_size)
{
struct real_buffer *buf = container_of(_buf, struct real_buffer, buf);
i_assert(used_size <= buf->alloc);
if (buf->used > buf->dirty)
buf->dirty = buf->used;
buf->used = used_size;
}
size_t buffer_get_size(const buffer_t *_buf)
{
const struct real_buffer *buf =
container_of(_buf, const struct real_buffer, buf);
return buf->alloc;
}
size_t buffer_get_writable_size(const buffer_t *_buf)
{
const struct real_buffer *buf =
container_of(_buf, const struct real_buffer, buf);
/* Use buf->writable_size instead of buf->alloc to reserve +1 for
str_c() NUL in buffer_check_limits(). Otherwise the caller might
increase the buffer's alloc size unnecessarily when it just wants
to access the entire buffer. */
return buf->writable_size;
}
size_t buffer_get_avail_size(const buffer_t *_buf)
{
const struct real_buffer *buf =
container_of(_buf, const struct real_buffer, buf);
i_assert(buf->alloc >= buf->used);
return ((buf->dynamic ? SIZE_MAX : buf->alloc) - buf->used);
}
bool buffer_cmp(const buffer_t *buf1, const buffer_t *buf2)
{
if (buf1->used != buf2->used)
return FALSE;
if (buf1->used == 0)
return TRUE;
return memcmp(buf1->data, buf2->data, buf1->used) == 0;
}
void buffer_verify_pool(buffer_t *_buf)
{
const struct real_buffer *buf =
container_of(_buf, struct real_buffer, buf);
void *ret;
if (buf->pool != NULL && buf->pool->datastack_pool && buf->alloc > 0) {
/* this doesn't really do anything except verify the
stack frame */
ret = p_realloc(buf->pool, buf->w_buffer,
buf->alloc, buf->alloc);
i_assert(ret == buf->w_buffer);
}
}
void ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
ATTR_NO_SANITIZE_INTEGER
buffer_truncate_rshift_bits(buffer_t *buf, size_t bits)
{
/* no-op if it's shorten than bits in any case.. */
if (buf->used * 8 < bits) return;
if (bits > 0) {
/* truncate it to closest byte boundary */
size_t bytes = ((bits + 7) & ~(size_t)7) / 8;
/* remaining bits */
bits = bits % 8;
buffer_set_used_size(buf, I_MIN(bytes, buf->used));
unsigned char *ptr = buffer_get_modifiable_data(buf, &bytes);
/* right shift over byte array */
if (bits > 0) {
for(size_t i=bytes-1;i>0;i--)
ptr[i] = (ptr[i]>>(8-bits)) +
((ptr[i-1]&(0xff>>(bits)))<>(8-bits);
}
} else {
buffer_set_used_size(buf, 0);
}
}
dovecot-2.3.21.1/src/lib/ostream.c 0000644 0000000 0000000 00000051636 14656633576 013503 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "ostream-private.h"
void o_stream_set_name(struct ostream *stream, const char *name)
{
i_free(stream->real_stream->iostream.name);
stream->real_stream->iostream.name = i_strdup(name);
}
const char *o_stream_get_name(struct ostream *stream)
{
while (stream->real_stream->iostream.name == NULL) {
stream = stream->real_stream->parent;
if (stream == NULL)
return "";
}
return stream->real_stream->iostream.name;
}
int o_stream_get_fd(struct ostream *stream)
{
return stream->real_stream->fd;
}
const char *o_stream_get_error(struct ostream *stream)
{
struct ostream *s;
/* we'll only return errors for streams that have stream_errno set.
we might be returning unintended error otherwise. */
if (stream->stream_errno == 0)
return "";
for (s = stream; s != NULL; s = s->real_stream->parent) {
if (s->stream_errno == 0)
break;
if (s->real_stream->iostream.error != NULL)
return s->real_stream->iostream.error;
}
return strerror(stream->stream_errno);
}
const char *o_stream_get_disconnect_reason(struct ostream *stream)
{
return io_stream_get_disconnect_reason(NULL, stream);
}
static void o_stream_close_full(struct ostream *stream, bool close_parents)
{
/* Ideally o_stream_finish() would be called for all non-failed
ostreams, but strictly requiring it would cause unnecessary
complexity for many callers. Just require that at this point
after flushing there isn't anything in the output buffer or that
we're ignoring all errors. */
if (o_stream_flush(stream) == 0)
i_assert(stream->real_stream->error_handling_disabled);
if (!stream->closed && !stream->real_stream->closing) {
/* first mark the stream as being closed so the
o_stream_copy_error_from_parent() won't recurse us back
here. but don't immediately mark the stream closed, because
we may still want to write something to it. */
stream->real_stream->closing = TRUE;
io_stream_close(&stream->real_stream->iostream, close_parents);
stream->closed = TRUE;
}
if (stream->stream_errno == 0)
stream->stream_errno = EPIPE;
}
void o_stream_destroy(struct ostream **_stream)
{
struct ostream *stream = *_stream;
if (stream == NULL)
return;
*_stream = NULL;
o_stream_close_full(stream, FALSE);
o_stream_unref(&stream);
}
void o_stream_ref(struct ostream *stream)
{
io_stream_ref(&stream->real_stream->iostream);
}
void o_stream_unref(struct ostream **_stream)
{
struct ostream *stream;
if (*_stream == NULL)
return;
stream = *_stream;
if (stream->real_stream->last_errors_not_checked &&
!stream->real_stream->error_handling_disabled &&
stream->real_stream->iostream.refcount == 1) {
i_panic("output stream %s is missing error handling",
o_stream_get_name(stream));
}
if (!io_stream_unref(&stream->real_stream->iostream))
io_stream_free(&stream->real_stream->iostream);
*_stream = NULL;
}
#undef o_stream_add_destroy_callback
void o_stream_add_destroy_callback(struct ostream *stream,
ostream_callback_t *callback, void *context)
{
io_stream_add_destroy_callback(&stream->real_stream->iostream,
callback, context);
}
void o_stream_remove_destroy_callback(struct ostream *stream,
void (*callback)())
{
io_stream_remove_destroy_callback(&stream->real_stream->iostream,
callback);
}
void o_stream_close(struct ostream *stream)
{
if (stream != NULL)
o_stream_close_full(stream, TRUE);
}
#undef o_stream_set_flush_callback
void o_stream_set_flush_callback(struct ostream *stream,
stream_flush_callback_t *callback,
void *context)
{
struct ostream_private *_stream = stream->real_stream;
_stream->set_flush_callback(_stream, callback, context);
}
void o_stream_unset_flush_callback(struct ostream *stream)
{
struct ostream_private *_stream = stream->real_stream;
_stream->set_flush_callback(_stream, NULL, NULL);
}
void o_stream_set_max_buffer_size(struct ostream *stream, size_t max_size)
{
io_stream_set_max_buffer_size(&stream->real_stream->iostream, max_size);
}
size_t o_stream_get_max_buffer_size(struct ostream *stream)
{
return stream->real_stream->max_buffer_size;
}
void o_stream_cork(struct ostream *stream)
{
struct ostream_private *_stream = stream->real_stream;
if (unlikely(stream->closed || stream->stream_errno != 0))
return;
_stream->cork(_stream, TRUE);
}
void o_stream_uncork(struct ostream *stream)
{
struct ostream_private *_stream = stream->real_stream;
if (unlikely(stream->closed || stream->stream_errno != 0))
return;
_stream->cork(_stream, FALSE);
}
bool o_stream_is_corked(struct ostream *stream)
{
struct ostream_private *_stream = stream->real_stream;
return _stream->corked;
}
int o_stream_flush(struct ostream *stream)
{
struct ostream_private *_stream = stream->real_stream;
int ret = 1;
o_stream_ignore_last_errors(stream);
if (unlikely(stream->closed || stream->stream_errno != 0)) {
errno = stream->stream_errno;
return -1;
}
if (unlikely(_stream->noverflow)) {
io_stream_set_error(&_stream->iostream,
"Output stream buffer was full (%zu bytes)",
o_stream_get_max_buffer_size(stream));
errno = stream->stream_errno = ENOBUFS;
return -1;
}
if (unlikely((ret = _stream->flush(_stream)) < 0)) {
i_assert(stream->stream_errno != 0);
errno = stream->stream_errno;
}
return ret;
}
void o_stream_set_flush_pending(struct ostream *stream, bool set)
{
struct ostream_private *_stream = stream->real_stream;
if (unlikely(stream->closed || stream->stream_errno != 0))
return;
_stream->flush_pending(_stream, set);
}
size_t o_stream_get_buffer_used_size(const struct ostream *stream)
{
const struct ostream_private *_stream = stream->real_stream;
return _stream->get_buffer_used_size(_stream);
}
size_t o_stream_get_buffer_avail_size(const struct ostream *stream)
{
const struct ostream_private *_stream = stream->real_stream;
return _stream->get_buffer_avail_size(_stream);
}
int o_stream_seek(struct ostream *stream, uoff_t offset)
{
struct ostream_private *_stream = stream->real_stream;
if (unlikely(stream->closed || stream->stream_errno != 0)) {
errno = stream->stream_errno;
return -1;
}
if (unlikely(_stream->seek(_stream, offset) < 0)) {
i_assert(stream->stream_errno != 0);
errno = stream->stream_errno;
return -1;
}
return 1;
}
ssize_t o_stream_send(struct ostream *stream, const void *data, size_t size)
{
struct const_iovec iov;
i_zero(&iov);
iov.iov_base = data;
iov.iov_len = size;
return o_stream_sendv(stream, &iov, 1);
}
static ssize_t
o_stream_sendv_int(struct ostream *stream, const struct const_iovec *iov,
unsigned int iov_count, bool *overflow_r)
{
struct ostream_private *_stream = stream->real_stream;
unsigned int i;
size_t total_size;
ssize_t ret;
*overflow_r = FALSE;
for (i = 0, total_size = 0; i < iov_count; i++)
total_size += iov[i].iov_len;
if (total_size == 0)
return 0;
i_assert(!_stream->finished);
ret = _stream->sendv(_stream, iov, iov_count);
if (ret > 0)
stream->real_stream->last_write_timeval = ioloop_timeval;
if (unlikely(ret != (ssize_t)total_size)) {
if (ret < 0) {
i_assert(stream->stream_errno != 0);
errno = stream->stream_errno;
} else {
i_assert(!stream->blocking);
stream->overflow = TRUE;
*overflow_r = TRUE;
}
}
return ret;
}
ssize_t o_stream_sendv(struct ostream *stream, const struct const_iovec *iov,
unsigned int iov_count)
{
bool overflow;
if (unlikely(stream->closed || stream->stream_errno != 0)) {
errno = stream->stream_errno;
return -1;
}
return o_stream_sendv_int(stream, iov, iov_count, &overflow);
}
ssize_t o_stream_send_str(struct ostream *stream, const char *str)
{
return o_stream_send(stream, str, strlen(str));
}
void o_stream_nsend(struct ostream *stream, const void *data, size_t size)
{
struct const_iovec iov;
i_zero(&iov);
iov.iov_base = data;
iov.iov_len = size;
o_stream_nsendv(stream, &iov, 1);
}
void o_stream_nsendv(struct ostream *stream, const struct const_iovec *iov,
unsigned int iov_count)
{
bool overflow;
if (unlikely(stream->closed || stream->stream_errno != 0 ||
stream->real_stream->noverflow))
return;
(void)o_stream_sendv_int(stream, iov, iov_count, &overflow);
if (overflow)
stream->real_stream->noverflow = TRUE;
stream->real_stream->last_errors_not_checked = TRUE;
}
void o_stream_nsend_str(struct ostream *stream, const char *str)
{
o_stream_nsend(stream, str, strlen(str));
}
int o_stream_finish(struct ostream *stream)
{
stream->real_stream->finished = TRUE;
return o_stream_flush(stream);
}
void o_stream_set_finish_also_parent(struct ostream *stream, bool set)
{
stream->real_stream->finish_also_parent = set;
}
void o_stream_set_finish_via_child(struct ostream *stream, bool set)
{
stream->real_stream->finish_via_child = set;
}
void o_stream_ignore_last_errors(struct ostream *stream)
{
while (stream != NULL) {
stream->real_stream->last_errors_not_checked = FALSE;
stream = stream->real_stream->parent;
}
}
void o_stream_abort(struct ostream *stream)
{
o_stream_ignore_last_errors(stream);
if (stream->stream_errno != 0)
return;
io_stream_set_error(&stream->real_stream->iostream, "aborted writing");
stream->stream_errno = EPIPE;
}
void o_stream_set_no_error_handling(struct ostream *stream, bool set)
{
stream->real_stream->error_handling_disabled = set;
}
enum ostream_send_istream_result
o_stream_send_istream(struct ostream *outstream, struct istream *instream)
{
struct ostream_private *_outstream = outstream->real_stream;
uoff_t old_outstream_offset = outstream->offset;
uoff_t old_instream_offset = instream->v_offset;
enum ostream_send_istream_result res;
if (unlikely(instream->closed || instream->stream_errno != 0)) {
errno = instream->stream_errno;
return OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT;
}
if (unlikely(outstream->closed || outstream->stream_errno != 0)) {
errno = outstream->stream_errno;
return OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT;
}
i_assert(!_outstream->finished);
res = _outstream->send_istream(_outstream, instream);
switch (res) {
case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
i_assert(instream->stream_errno == 0);
i_assert(outstream->stream_errno == 0);
i_assert(!i_stream_have_bytes_left(instream));
break;
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
i_assert(!instream->blocking);
break;
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
i_assert(!outstream->blocking);
o_stream_set_flush_pending(outstream, TRUE);
break;
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
i_assert(instream->stream_errno != 0);
return res;
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
i_assert(outstream->stream_errno != 0);
return res;
}
/* non-failure - make sure stream offsets match */
i_assert((outstream->offset - old_outstream_offset) ==
(instream->v_offset - old_instream_offset));
if (outstream->offset != old_outstream_offset)
outstream->real_stream->last_write_timeval = ioloop_timeval;
return res;
}
void o_stream_nsend_istream(struct ostream *outstream, struct istream *instream)
{
i_assert(instream->blocking);
switch (o_stream_send_istream(outstream, instream)) {
case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
break;
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
i_unreached();
case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
outstream->real_stream->noverflow = TRUE;
break;
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
outstream->stream_errno = instream->stream_errno;
io_stream_set_error(&outstream->real_stream->iostream,
"nsend-istream: read(%s) failed: %s",
i_stream_get_name(instream),
i_stream_get_error(instream));
break;
case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
break;
}
outstream->real_stream->last_errors_not_checked = TRUE;
}
int o_stream_pwrite(struct ostream *stream, const void *data, size_t size,
uoff_t offset)
{
int ret;
if (unlikely(stream->closed || stream->stream_errno != 0)) {
errno = stream->stream_errno;
return -1;
}
i_assert(!stream->real_stream->finished);
ret = stream->real_stream->write_at(stream->real_stream,
data, size, offset);
if (ret > 0)
stream->real_stream->last_write_timeval = ioloop_timeval;
else if (unlikely(ret < 0)) {
i_assert(stream->stream_errno != 0);
errno = stream->stream_errno;
}
return ret;
}
void o_stream_get_last_write_time(struct ostream *stream, struct timeval *tv_r)
{
*tv_r = stream->real_stream->last_write_timeval;
}
enum ostream_send_istream_result
io_stream_copy(struct ostream *outstream, struct istream *instream)
{
struct const_iovec iov;
const unsigned char *data;
ssize_t ret;
while (i_stream_read_more(instream, &data, &iov.iov_len) > 0) {
iov.iov_base = data;
if ((ret = o_stream_sendv(outstream, &iov, 1)) < 0)
return OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT;
else if (ret == 0)
return OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT;
i_stream_skip(instream, ret);
}
if (instream->stream_errno != 0)
return OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT;
if (i_stream_have_bytes_left(instream))
return OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT;
return OSTREAM_SEND_ISTREAM_RESULT_FINISHED;
}
void o_stream_switch_ioloop_to(struct ostream *stream, struct ioloop *ioloop)
{
struct ostream_private *_stream = stream->real_stream;
io_stream_switch_ioloop_to(&_stream->iostream, ioloop);
_stream->switch_ioloop_to(_stream, ioloop);
}
void o_stream_switch_ioloop(struct ostream *stream)
{
o_stream_switch_ioloop_to(stream, current_ioloop);
}
static void o_stream_default_close(struct iostream_private *stream,
bool close_parent)
{
struct ostream_private *_stream =
container_of(stream, struct ostream_private, iostream);
(void)o_stream_flush(&_stream->ostream);
if (close_parent)
o_stream_close(_stream->parent);
}
static void o_stream_default_destroy(struct iostream_private *stream)
{
struct ostream_private *_stream =
container_of(stream, struct ostream_private, iostream);
o_stream_unref(&_stream->parent);
}
static void
o_stream_default_set_max_buffer_size(struct iostream_private *stream,
size_t max_size)
{
struct ostream_private *_stream =
container_of(stream, struct ostream_private, iostream);
if (_stream->parent != NULL)
o_stream_set_max_buffer_size(_stream->parent, max_size);
_stream->max_buffer_size = max_size;
}
static void o_stream_default_cork(struct ostream_private *_stream, bool set)
{
_stream->corked = set;
if (set) {
if (_stream->parent != NULL)
o_stream_cork(_stream->parent);
} else {
(void)o_stream_flush(&_stream->ostream);
_stream->last_errors_not_checked = TRUE;
if (_stream->parent != NULL)
o_stream_uncork(_stream->parent);
}
}
void o_stream_copy_error_from_parent(struct ostream_private *_stream)
{
struct ostream *src = _stream->parent;
struct ostream *dest = &_stream->ostream;
i_assert(src->stream_errno != 0);
dest->stream_errno = src->stream_errno;
dest->overflow = src->overflow;
if (src->closed)
o_stream_close(dest);
}
int o_stream_flush_parent_if_needed(struct ostream_private *_stream)
{
if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE) {
/* we already have quite a lot of data in parent stream.
unless we can flush it, don't add any more to it or we
could keep wasting memory by just increasing the buffer
size all the time. */
if (o_stream_flush(_stream->parent) < 0) {
o_stream_copy_error_from_parent(_stream);
return -1;
}
if (o_stream_get_buffer_used_size(_stream->parent) >= IO_BLOCK_SIZE)
return 0;
}
return 1;
}
int o_stream_flush_parent(struct ostream_private *_stream)
{
int ret;
i_assert(_stream->parent != NULL);
if (!_stream->finished || !_stream->finish_also_parent ||
!_stream->parent->real_stream->finish_via_child)
ret = o_stream_flush(_stream->parent);
else
ret = o_stream_finish(_stream->parent);
if (ret < 0)
o_stream_copy_error_from_parent(_stream);
return ret;
}
static int o_stream_default_flush(struct ostream_private *_stream)
{
if (_stream->parent == NULL)
return 1;
return o_stream_flush_parent(_stream);
}
static void
o_stream_default_set_flush_callback(struct ostream_private *_stream,
stream_flush_callback_t *callback,
void *context)
{
if (_stream->parent != NULL)
o_stream_set_flush_callback(_stream->parent, callback, context);
_stream->callback = callback;
_stream->context = context;
}
static void
o_stream_default_set_flush_pending(struct ostream_private *_stream, bool set)
{
if (_stream->parent != NULL)
o_stream_set_flush_pending(_stream->parent, set);
}
static size_t
o_stream_default_get_buffer_used_size(const struct ostream_private *_stream)
{
if (_stream->parent == NULL)
return 0;
else
return o_stream_get_buffer_used_size(_stream->parent);
}
static size_t
o_stream_default_get_buffer_avail_size(const struct ostream_private *_stream)
{
/* This default implementation assumes that the returned buffer size is
between 0..max_buffer_size. There's no assert though, in case the
max_buffer_size changes. */
size_t used = o_stream_get_buffer_used_size(&_stream->ostream);
return _stream->max_buffer_size <= used ? 0 :
_stream->max_buffer_size - used;
}
static int
o_stream_default_seek(struct ostream_private *_stream,
uoff_t offset ATTR_UNUSED)
{
_stream->ostream.stream_errno = ESPIPE;
return -1;
}
static ssize_t
o_stream_default_sendv(struct ostream_private *stream,
const struct const_iovec *iov, unsigned int iov_count)
{
ssize_t ret;
if ((ret = o_stream_sendv(stream->parent, iov, iov_count)) < 0) {
o_stream_copy_error_from_parent(stream);
return -1;
}
stream->ostream.offset += ret;
return ret;
}
static int
o_stream_default_write_at(struct ostream_private *_stream,
const void *data ATTR_UNUSED,
size_t size ATTR_UNUSED, uoff_t offset ATTR_UNUSED)
{
_stream->ostream.stream_errno = ESPIPE;
return -1;
}
static enum ostream_send_istream_result
o_stream_default_send_istream(struct ostream_private *outstream,
struct istream *instream)
{
return io_stream_copy(&outstream->ostream, instream);
}
static void
o_stream_default_switch_ioloop_to(struct ostream_private *_stream,
struct ioloop *ioloop)
{
if (_stream->parent != NULL)
o_stream_switch_ioloop_to(_stream->parent, ioloop);
}
struct ostream *
o_stream_create(struct ostream_private *_stream, struct ostream *parent, int fd)
{
_stream->finish_also_parent = TRUE;
_stream->finish_via_child = TRUE;
_stream->fd = fd;
_stream->ostream.real_stream = _stream;
if (parent != NULL) {
_stream->ostream.blocking = parent->blocking;
_stream->parent = parent;
o_stream_ref(parent);
_stream->callback = parent->real_stream->callback;
_stream->context = parent->real_stream->context;
_stream->max_buffer_size = parent->real_stream->max_buffer_size;
_stream->error_handling_disabled =
parent->real_stream->error_handling_disabled;
}
if (_stream->iostream.close == NULL)
_stream->iostream.close = o_stream_default_close;
if (_stream->iostream.destroy == NULL)
_stream->iostream.destroy = o_stream_default_destroy;
if (_stream->iostream.set_max_buffer_size == NULL) {
_stream->iostream.set_max_buffer_size =
o_stream_default_set_max_buffer_size;
}
if (_stream->cork == NULL)
_stream->cork = o_stream_default_cork;
if (_stream->flush == NULL)
_stream->flush = o_stream_default_flush;
if (_stream->set_flush_callback == NULL) {
_stream->set_flush_callback =
o_stream_default_set_flush_callback;
}
if (_stream->flush_pending == NULL)
_stream->flush_pending = o_stream_default_set_flush_pending;
if (_stream->get_buffer_used_size == NULL)
_stream->get_buffer_used_size =
o_stream_default_get_buffer_used_size;
if (_stream->get_buffer_avail_size == NULL) {
_stream->get_buffer_avail_size =
o_stream_default_get_buffer_avail_size;
}
if (_stream->seek == NULL)
_stream->seek = o_stream_default_seek;
if (_stream->sendv == NULL)
_stream->sendv = o_stream_default_sendv;
if (_stream->write_at == NULL)
_stream->write_at = o_stream_default_write_at;
if (_stream->send_istream == NULL)
_stream->send_istream = o_stream_default_send_istream;
if (_stream->switch_ioloop_to == NULL)
_stream->switch_ioloop_to = o_stream_default_switch_ioloop_to;
io_stream_init(&_stream->iostream);
return &_stream->ostream;
}
struct ostream *o_stream_create_error(int stream_errno)
{
struct ostream_private *stream;
struct ostream *output;
stream = i_new(struct ostream_private, 1);
stream->ostream.blocking = TRUE;
stream->ostream.closed = TRUE;
stream->ostream.stream_errno = stream_errno;
output = o_stream_create(stream, NULL, -1);
o_stream_set_no_error_handling(output, TRUE);
o_stream_set_name(output, "(error)");
return output;
}
struct ostream *
o_stream_create_error_str(int stream_errno, const char *fmt, ...)
{
struct ostream *output;
va_list args;
va_start(args, fmt);
output = o_stream_create_error(stream_errno);
io_stream_set_verror(&output->real_stream->iostream, fmt, args);
va_end(args);
return output;
}
struct ostream *o_stream_create_passthrough(struct ostream *output)
{
struct ostream_private *stream;
stream = i_new(struct ostream_private, 1);
return o_stream_create(stream, output, o_stream_get_fd(output));
}
dovecot-2.3.21.1/src/lib/test-hex-binary.c 0000644 0000000 0000000 00000003105 14656633576 015040 0000000 0000000 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "buffer.h"
#include "str.h"
#include "hex-binary.h"
static void test_binary_to_hex(void)
{
static unsigned char input[] = { 0xff, 0x00, 0x01, 0xb3 };
static char *output_lcase = "ff0001b3";
static char *output_ucase = "FF0001B3";
string_t *str;
test_begin("binary to hex");
test_assert(strcmp(binary_to_hex(input, sizeof(input)), output_lcase) == 0);
test_end();
test_begin("binary to hex ucase");
test_assert(strcmp(binary_to_hex_ucase(input, sizeof(input)), output_ucase) == 0);
test_end();
test_begin("binary to hex ucase");
str = t_str_new(32);
str_append_c(str, '<');
binary_to_hex_append(str, input, sizeof(input));
str_append_c(str, '>');
test_assert(strcmp(str_c(str), t_strconcat("<", output_lcase, ">", NULL)) == 0);
test_end();
}
static void test_hex_to_binary(void)
{
static const char *ok_input = "0001fEFf";
static unsigned char ok_output[] = { 0x00, 0x01, 0xfe, 0xff };
static const char *error_input[] = {
"00 01",
"0x01",
"0g"
};
buffer_t *buf = t_buffer_create(10);
unsigned int i;
test_begin("hex to binary");
test_assert(hex_to_binary("", buf) == 0);
test_assert(buf->used == 0);
test_assert(hex_to_binary(ok_input, buf) == 0);
test_assert(buf->used == N_ELEMENTS(ok_output));
test_assert(memcmp(buf->data, ok_output, buf->used) == 0);
for (i = 0; i < N_ELEMENTS(error_input); i++)
test_assert(hex_to_binary(error_input[i], buf) == -1);
test_end();
}
void test_hex_binary(void)
{
test_binary_to_hex();
test_hex_to_binary();
}
dovecot-2.3.21.1/src/lib/execv-const.c 0000644 0000000 0000000 00000001476 14656633576 014264 0000000 0000000 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "execv-const.h"
#include
static char **argv_drop_const(const char *const argv[])
{
char **ret;
unsigned int i, count;
for (count = 0; argv[count] != NULL; count++) ;
ret = t_new(char *, count + 1);
for (i = 0; i < count; i++)
ret[i] = t_strdup_noconst(argv[i]);
return ret;
}
void execv_const(const char *path, const char *const argv[])
{
(void)execv(path, argv_drop_const(argv));
i_fatal_status(errno == ENOMEM ? FATAL_OUTOFMEM : FATAL_EXEC,
"execv(%s) failed: %m", path);
}
void execvp_const(const char *file, const char *const argv[])
{
(void)execvp(file, argv_drop_const(argv));
i_fatal_status(errno == ENOMEM ? FATAL_OUTOFMEM : FATAL_EXEC,
"execvp(%s) failed: %m", file);
}
dovecot-2.3.21.1/src/lib/lib-signals.h 0000644 0000000 0000000 00000005361 14656633576 014234 0000000 0000000 #ifndef LIB_SIGNALS_H
#define LIB_SIGNALS_H
#include
enum libsig_flags {
/* Signal handler will be called later from IO loop when it's safe to
do any kind of work */
LIBSIG_FLAG_DELAYED = 0x01,
/* Restart syscalls instead of having them fail with EINTR */
LIBSIG_FLAG_RESTART = 0x02,
/* Automatically shift delayed signal handling for this signal
to a newly started ioloop. */
LIBSIG_FLAG_IOLOOP_AUTOMOVE = 0x04,
};
#define LIBSIG_FLAGS_SAFE (LIBSIG_FLAG_DELAYED | LIBSIG_FLAG_RESTART)
typedef void signal_handler_t(const siginfo_t *si, void *context);
/* Number of times a "termination signal" has been received.
These signals are SIGINT, SIGQUIT and SIGTERM. Callers can compare this to
their saved previous value to see if a syscall returning EINTR should be
treated as someone wanting to end the process or just some internal signal
that should be ignored, such as SIGCHLD.
This is marked as volatile so that compiler won't optimize away its
comparisons. It may not work perfectly everywhere, such as when accessing it
isn't atomic, so you shouldn't heavily rely on its actual value. */
extern volatile unsigned int signal_term_counter;
/* Convert si_code to string */
const char *lib_signal_code_to_str(int signo, int sicode);
/* Detach IOs from all ioloops. This isn't normally necessary, except when
forking a process. */
void lib_signals_ioloop_detach(void);
void lib_signals_ioloop_attach(void);
/* Set signal handler for specific signal. */
void lib_signals_set_handler(int signo, enum libsig_flags flags,
signal_handler_t *handler, void *context)
ATTR_NULL(4);
/* Ignore given signal. */
void lib_signals_ignore(int signo, bool restart_syscalls);
/* Clear all signal handlers for a specific signal and set the signal to be
ignored. */
void lib_signals_clear_handlers_and_ignore(int signo);
/* Unset specific signal handler for specific signal. */
void lib_signals_unset_handler(int signo,
signal_handler_t *handler, void *context)
ATTR_NULL(3);
/* Indicate whether signals are expected for the indicated delayed handler. When
signals are expected, the io for delayed handlers will be allowed to wait
alone on the ioloop. */
void lib_signals_set_expected(int signo, bool expected,
signal_handler_t *handler, void *context);
ATTR_NULL(4);
/* Switch ioloop for a specific signal handler created with
LIBSIG_FLAG_NO_IOLOOP_AUTOMOVE. */
void lib_signals_switch_ioloop(int signo,
signal_handler_t *handler, void *context);
/* Log a syscall error inside a (non-delayed) signal handler where i_error() is
unsafe. errno number will be appended to the prefix. */
void lib_signals_syscall_error(const char *prefix);
void lib_signals_init(void);
void lib_signals_deinit(void);
#endif
dovecot-2.3.21.1/src/lib/test-istream-sized.c 0000644 0000000 0000000 00000005754 14656633576 015566 0000000 0000000 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "istream.h"
#include "istream-sized.h"
static const struct {
const char *input;
uoff_t size;
int stream_errno;
} tests[] = {
{ "", 0, 0 },
{ "", 1, EPIPE },
{ "a", 1, 0 },
{ "ab", 1, EINVAL },
{ "ab", 0, EINVAL },
{ "ab", UOFF_T_MAX, EPIPE },
};
static void
run_test(const char *sized_input, uoff_t sized_size, int stream_errno)
{
unsigned int sized_input_len = strlen(sized_input);
struct istream *input_data, *input;
const unsigned char *data;
size_t i, size;
int ret = 0;
input_data = test_istream_create_data(sized_input, sized_input_len);
test_istream_set_allow_eof(input_data, FALSE);
input = i_stream_create_sized(input_data, sized_size);
for (i = 1; i < sized_input_len; i++) {
test_istream_set_size(input_data, i);
while ((ret = i_stream_read(input)) > 0) ;
if (ret == -1 && stream_errno != 0)
break;
test_assert(ret == 0);
}
if (ret == 0) {
test_istream_set_allow_eof(input_data, TRUE);
test_istream_set_size(input_data, i);
while ((ret = i_stream_read(input)) > 0) ;
}
test_assert(ret == -1);
test_assert(input->stream_errno == stream_errno);
data = i_stream_get_data(input, &size);
test_assert(size == I_MIN(sized_input_len, sized_size));
if (size > 0)
test_assert(memcmp(data, sized_input, size) == 0);
i_stream_unref(&input);
i_stream_unref(&input_data);
}
static void test_istream_sized_full(bool exact)
{
const unsigned char test_data[10] = "1234567890";
struct istream *test_input, *input;
unsigned int i, j;
int expected_errno;
for (i = 1; i < sizeof(test_data)*2; i++) {
test_input = test_istream_create_data(test_data, sizeof(test_data));
test_istream_set_allow_eof(test_input, FALSE);
test_istream_set_size(test_input, 0);
if (exact)
input = i_stream_create_sized(test_input, i);
else
input = i_stream_create_min_sized(test_input, i);
for (j = 1; j <= I_MIN(i, sizeof(test_data)); j++) {
test_assert_idx(i_stream_read(input) == 0, j);
test_istream_set_size(test_input, j);
test_assert_idx(i_stream_read(input) == 1, j);
}
test_assert_idx(i_stream_read(input) == 0, i);
if (j <= sizeof(test_data))
test_istream_set_size(test_input, j);
else
test_istream_set_allow_eof(test_input, TRUE);
test_assert_idx(i_stream_read(input) == -1 && input->eof, i);
if (i > sizeof(test_data))
expected_errno = EPIPE;
else if (i < sizeof(test_data) && exact)
expected_errno = EINVAL;
else
expected_errno = 0;
test_assert_idx(input->stream_errno == expected_errno, i);
i_stream_unref(&input);
i_stream_unref(&test_input);
}
}
void test_istream_sized(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(tests); i++) {
test_begin(t_strdup_printf("istream sized %u", i+1));
run_test(tests[i].input, tests[i].size, tests[i].stream_errno);
test_end();
}
test_begin("istream sized");
test_istream_sized_full(TRUE);
test_end();
test_begin("istream sized min");
test_istream_sized_full(FALSE);
test_end();
}
dovecot-2.3.21.1/src/lib/ioloop-select.c 0000644 0000000 0000000 00000007366 14656633576 014610 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop-private.h"
#ifdef IOLOOP_SELECT
#ifdef HAVE_SYS_SELECT_H
# include /* According to POSIX 1003.1-2001 */
#endif
#include
#include
struct ioloop_handler_context {
int highest_fd;
fd_set read_fds, write_fds, except_fds;
fd_set tmp_read_fds, tmp_write_fds, tmp_except_fds;
};
static void update_highest_fd(struct ioloop *ioloop)
{
struct ioloop_handler_context *ctx = ioloop->handler_context;
struct io_file *io;
int max_highest_fd;
max_highest_fd = ctx->highest_fd-1;
ctx->highest_fd = -1;
for (io = ioloop->io_files; io != NULL; io = io->next) {
if (io->fd <= ctx->highest_fd)
continue;
ctx->highest_fd = io->fd;
if (ctx->highest_fd == max_highest_fd)
break;
}
}
void io_loop_handler_init(struct ioloop *ioloop,
unsigned int initial_fd_count ATTR_UNUSED)
{
struct ioloop_handler_context *ctx;
ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
ctx->highest_fd = -1;
FD_ZERO(&ctx->read_fds);
FD_ZERO(&ctx->write_fds);
FD_ZERO(&ctx->except_fds);
}
void io_loop_handler_deinit(struct ioloop *ioloop)
{
i_free(ioloop->handler_context);
}
void io_loop_handle_add(struct io_file *io)
{
struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
enum io_condition condition = io->io.condition;
int fd = io->fd;
i_assert(fd >= 0);
if (fd >= FD_SETSIZE)
i_fatal("fd %d too large for select()", fd);
if ((condition & (IO_READ | IO_ERROR)) != 0)
FD_SET(fd, &ctx->read_fds);
if ((condition & IO_WRITE) != 0)
FD_SET(fd, &ctx->write_fds);
FD_SET(fd, &ctx->except_fds);
if (io->fd > ctx->highest_fd)
ctx->highest_fd = io->fd;
}
void io_loop_handle_remove(struct io_file *io, bool closed ATTR_UNUSED)
{
struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
enum io_condition condition = io->io.condition;
int fd = io->fd;
i_assert(fd >= 0 && fd < FD_SETSIZE);
if ((condition & (IO_READ | IO_ERROR)) != 0)
FD_CLR(fd, &ctx->read_fds);
if ((condition & IO_WRITE) != 0)
FD_CLR(fd, &ctx->write_fds);
if (!FD_ISSET(fd, &ctx->read_fds) && !FD_ISSET(fd, &ctx->write_fds)) {
FD_CLR(fd, &ctx->except_fds);
/* check if we removed the highest fd */
if (io->fd == ctx->highest_fd)
update_highest_fd(io->io.ioloop);
}
i_free(io);
}
#define io_check_condition(ctx, fd, cond) \
((FD_ISSET((fd), &(ctx)->tmp_read_fds) && ((cond) & (IO_READ|IO_ERROR)) != 0) || \
(FD_ISSET((fd), &(ctx)->tmp_write_fds) && ((cond) & IO_WRITE) != 0) || \
(FD_ISSET((fd), &(ctx)->tmp_except_fds)))
void io_loop_handler_run_internal(struct ioloop *ioloop)
{
struct ioloop_handler_context *ctx = ioloop->handler_context;
struct timeval tv;
struct io_file *io;
int ret;
/* get the time left for next timeout task */
io_loop_run_get_wait_time(ioloop, &tv);
memcpy(&ctx->tmp_read_fds, &ctx->read_fds, sizeof(fd_set));
memcpy(&ctx->tmp_write_fds, &ctx->write_fds, sizeof(fd_set));
memcpy(&ctx->tmp_except_fds, &ctx->except_fds, sizeof(fd_set));
ret = select(ctx->highest_fd + 1, &ctx->tmp_read_fds,
&ctx->tmp_write_fds, &ctx->tmp_except_fds, &tv);
if (ret < 0 && errno != EINTR)
i_warning("select() : %m");
/* execute timeout handlers */
io_loop_handle_timeouts(ioloop);
if (ret <= 0 || !ioloop->running) {
/* no I/O events */
return;
}
io = ioloop->io_files;
for (; io != NULL && ret > 0; io = ioloop->next_io_file) {
ioloop->next_io_file = io->next;
if (io->fd == -1) {
/* io_add_istream() without fd */
} else if (io_check_condition(ctx, io->fd, io->io.condition)) {
ret--;
io_loop_call_io(&io->io);
if (!ioloop->running)
break;
}
}
}
#endif
dovecot-2.3.21.1/src/lib/var-expand.c 0000644 0000000 0000000 00000044344 14656633576 014074 0000000 0000000 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "md5.h"
#include "hash.h"
#include "hex-binary.h"
#include "base64.h"
#include "hostpid.h"
#include "hmac.h"
#include "pkcs5.h"
#include "hash-method.h"
#include "str.h"
#include "strescape.h"
#include "var-expand.h"
#include "var-expand-private.h"
#include
#include
#define TABLE_LAST(t) \
((t)->key == '\0' && (t)->long_key == NULL)
struct var_expand_modifier {
char key;
const char *(*func)(const char *, struct var_expand_context *);
};
static ARRAY(struct var_expand_extension_func_table) var_expand_extensions;
static const char *
m_str_lcase(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
return t_str_lcase(str);
}
static const char *
m_str_ucase(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
return t_str_ucase(str);
}
static const char *
m_str_escape(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
return str_escape(str);
}
static const char *
m_str_hex(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
unsigned long long l;
if (str_to_ullong(str, &l) < 0)
l = 0;
return t_strdup_printf("%llx", l);
}
static const char *
m_str_reverse(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
size_t len = strlen(str);
char *p, *rev;
rev = t_malloc_no0(len + 1);
rev[len] = '\0';
for (p = rev + len - 1; *str != '\0'; str++)
*p-- = *str;
return rev;
}
static const char *m_str_hash(const char *str, struct var_expand_context *ctx)
{
unsigned int value = str_hash(str);
string_t *hash = t_str_new(20);
if (ctx->width != 0) {
value %= ctx->width;
ctx->width = 0;
}
str_printfa(hash, "%x", value);
while ((int)str_len(hash) < ctx->offset)
str_insert(hash, 0, "0");
ctx->offset = 0;
return str_c(hash);
}
static const char *
m_str_newhash(const char *str, struct var_expand_context *ctx)
{
string_t *hash = t_str_new(20);
unsigned char result[MD5_RESULTLEN];
unsigned int i;
uint64_t value = 0;
md5_get_digest(str, strlen(str), result);
for (i = 0; i < sizeof(value); i++) {
value <<= 8;
value |= result[i];
}
if (ctx->width != 0) {
value %= ctx->width;
ctx->width = 0;
}
str_printfa(hash, "%x", (unsigned int)value);
while ((int)str_len(hash) < ctx->offset)
str_insert(hash, 0, "0");
ctx->offset = 0;
return str_c(hash);
}
static const char *
m_str_md5(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
unsigned char digest[16];
md5_get_digest(str, strlen(str), digest);
return binary_to_hex(digest, sizeof(digest));
}
static const char *
m_str_ldap_dn(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
string_t *ret = t_str_new(256);
while (*str != '\0') {
if (*str == '.')
str_append(ret, ",dc=");
else
str_append_c(ret, *str);
str++;
}
return str_free_without_data(&ret);
}
static const char *
m_str_trim(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
{
size_t len;
len = strlen(str);
while (len > 0 && i_isspace(str[len-1]))
len--;
return t_strndup(str, len);
}
#define MAX_MODIFIER_COUNT 10
static const struct var_expand_modifier modifiers[] = {
{ 'L', m_str_lcase },
{ 'U', m_str_ucase },
{ 'E', m_str_escape },
{ 'X', m_str_hex },
{ 'R', m_str_reverse },
{ 'H', m_str_hash },
{ 'N', m_str_newhash },
{ 'M', m_str_md5 },
{ 'D', m_str_ldap_dn },
{ 'T', m_str_trim },
{ '\0', NULL }
};
static int
var_expand_short(const struct var_expand_table *table, char key,
const char **var_r, const char **error_r)
{
const struct var_expand_table *t;
if (table != NULL) {
for (t = table; !TABLE_LAST(t); t++) {
if (t->key == key) {
*var_r = t->value != NULL ? t->value : "";
return 1;
}
}
}
/* not found */
if (key == '%') {
*var_r = "%";
return 1;
}
if (*error_r == NULL)
*error_r = t_strdup_printf("Unknown variable '%%%c'", key);
*var_r = t_strdup_printf("UNSUPPORTED_VARIABLE_%c", key);
return 0;
}
static int
var_expand_hash(struct var_expand_context *ctx,
const char *key, const char *field,
const char **result_r, const char **error_r)
{
enum {
FORMAT_HEX,
FORMAT_HEX_UC,
FORMAT_BASE64
} format = FORMAT_HEX;
const char *p = strchr(key, ';');
const char *const *args = NULL;
const char *algo = key;
const char *value;
int ret;
if (p != NULL) {
algo = t_strcut(key, ';');
args = t_strsplit(p+1, ",");
}
const struct hash_method *method;
if (strcmp(algo, "pkcs5") == 0) {
method = hash_method_lookup("sha256");
} else if ((method = hash_method_lookup(algo)) == NULL) {
return 0;
}
string_t *field_value = t_str_new(64);
string_t *salt = t_str_new(64);
string_t *tmp = t_str_new(method->digest_size);
if ((ret = var_expand_long(ctx, field, strlen(field),
&value, error_r)) < 1) {
return ret;
}
str_append(field_value, value);
/* default values */
unsigned int rounds = 1;
unsigned int truncbits = 0;
if (strcmp(algo, "pkcs5") == 0) {
rounds = 2048;
str_append(salt, field);
}
while(args != NULL && *args != NULL) {
const char *k = t_strcut(*args, '=');
const char *value = strchr(*args, '=');
if (value == NULL) {
args++;
continue;
} else {
value++;
}
if (strcmp(k, "rounds") == 0) {
if (str_to_uint(value, &rounds)<0) {
*error_r = t_strdup_printf(
"Cannot parse hash arguments:"
"'%s' is not number for rounds",
value);
return -1;
}
if (rounds < 1) {
*error_r = t_strdup_printf(
"Cannot parse hash arguments:"
"rounds must be at least 1");
return -1;
}
} else if (strcmp(k, "truncate") == 0) {
if (str_to_uint(value, &truncbits)<0) {
*error_r = t_strdup_printf(
"Cannot parse hash arguments:"
"'%s' is not number for truncbits",
value);
return -1;
}
truncbits = I_MIN(truncbits, method->digest_size*8);
} else if (strcmp(k, "salt") == 0) {
str_truncate(salt, 0);
if (var_expand_with_funcs(salt, value, ctx->table,
ctx->func_table, ctx->context,
error_r) < 0) {
return -1;
}
break;
} else if (strcmp(k, "format") == 0) {
if (strcmp(value, "hex") == 0) {
format = FORMAT_HEX;
} else if (strcmp(value, "hexuc") == 0){
format = FORMAT_HEX_UC;
} else if (strcmp(value, "base64") == 0) {
format = FORMAT_BASE64;
} else {
*error_r = t_strdup_printf(
"Cannot parse hash arguments:"
"'%s' is not supported format",
value);
return -1;
}
}
args++;
}
str_truncate(tmp, 0);
if (strcmp(algo, "pkcs5") == 0) {
if (pkcs5_pbkdf(PKCS5_PBKDF2, method,
field_value->data, field_value->used,
salt->data, salt->used,
rounds, HMAC_MAX_CONTEXT_SIZE, tmp) != 0) {
*error_r = "Cannot hash: PKCS5_PBKDF2 failed";
return -1;
}
} else {
void *context = t_malloc_no0(method->context_size);
str_append_str(tmp, field_value);
for(;rounds>0;rounds--) {
method->init(context);
if (salt->used > 0)
method->loop(context, salt->data, salt->used);
method->loop(context, tmp->data, tmp->used);
unsigned char *digest =
buffer_get_modifiable_data(tmp, NULL);
method->result(context, digest);
if (tmp->used != method->digest_size)
buffer_set_used_size(tmp, method->digest_size);
}
}
if (truncbits > 0)
buffer_truncate_rshift_bits(tmp, truncbits);
switch(format) {
case FORMAT_HEX:
*result_r = binary_to_hex(tmp->data, tmp->used);
return 1;
case FORMAT_HEX_UC:
*result_r = binary_to_hex(tmp->data, tmp->used);
return 1;
case FORMAT_BASE64: {
string_t *dest = t_str_new(64);
base64_encode(tmp->data, tmp->used, dest);
*result_r = str_c(dest);
return 1;
}
}
i_unreached();
}
static int
var_expand_func(const struct var_expand_func_table *func_table,
const char *key, const char *data, void *context,
const char **var_r, const char **error_r)
{
const char *value = NULL;
int ret;
if (strcmp(key, "env") == 0) {
value = getenv(data);
*var_r = value != NULL ? value : "";
return 1;
}
if (func_table != NULL) {
for (; func_table->key != NULL; func_table++) {
if (strcmp(func_table->key, key) == 0) {
ret = func_table->func(data, context, &value, error_r);
*var_r = value != NULL ? value : "";
return ret;
}
}
}
if (*error_r == NULL)
*error_r = t_strdup_printf("Unknown variable '%%%s'", key);
*var_r = t_strdup_printf("UNSUPPORTED_VARIABLE_%s", key);
return 0;
}
static int
var_expand_try_extension(struct var_expand_context *ctx,
const char *key, const char *data,
const char **var_r, const char **error_r)
{
int ret;
const char *sep = strchr(key, ';');
if (sep == NULL) sep = key + strlen(key);
/* try with extensions */
const struct var_expand_extension_func_table *f;
array_foreach(&var_expand_extensions, f) {
/* ensure we won't match abbreviations */
size_t len = sep-key;
if (strncasecmp(key, f->key, len) == 0 && f->key[len] == '\0')
return f->func(ctx, key, data, var_r, error_r);
}
if ((ret = var_expand_func(ctx->func_table, key, data,
ctx->context, var_r, error_r)) == 0) {
*error_r = t_strdup_printf("Unknown variable '%%%s'", key);
}
return ret;
}
int
var_expand_long(struct var_expand_context *ctx,
const void *key_start, size_t key_len,
const char **var_r, const char **error_r)
{
const struct var_expand_table *t;
const char *key, *value = NULL;
int ret = 1;
if (ctx->table != NULL) {
for (t = ctx->table; !TABLE_LAST(t); t++) {
if (t->long_key != NULL &&
strncmp(t->long_key, key_start, key_len) == 0 &&
t->long_key[key_len] == '\0') {
*var_r = t->value != NULL ? t->value : "";
return 1;
}
}
}
key = t_strndup(key_start, key_len);
/* built-in variables: */
switch (key_len) {
case 3:
if (strcmp(key, "pid") == 0)
value = my_pid;
else if (strcmp(key, "uid") == 0)
value = dec2str(geteuid());
else if (strcmp(key, "gid") == 0)
value = dec2str(getegid());
break;
case 8:
if (strcmp(key, "hostname") == 0)
value = my_hostname;
break;
}
if (value == NULL) {
const char *data = strchr(key, ':');
if (data != NULL)
key = t_strdup_until(key, data++);
else
data = "";
ret = var_expand_try_extension(ctx, key, data, &value, error_r);
if (ret <= 0 && value == NULL) {
value = "";
}
}
*var_r = value;
return ret;
}
int var_expand_with_funcs(string_t *dest, const char *str,
const struct var_expand_table *table,
const struct var_expand_func_table *func_table,
void *context, const char **error_r)
{
const struct var_expand_modifier *m;
const char *var;
struct var_expand_context ctx;
const char *(*modifier[MAX_MODIFIER_COUNT])
(const char *, struct var_expand_context *);
const char *end;
unsigned int i, modifier_count;
size_t len;
int ret, final_ret = 1;
*error_r = NULL;
i_zero(&ctx);
ctx.table = table;
ctx.func_table = func_table;
ctx.context = context;
for (; *str != '\0'; str++) {
if (*str != '%')
str_append_c(dest, *str);
else {
int sign = 1;
str++;
/* reset per-field modifiers */
ctx.offset = 0;
ctx.width = 0;
ctx.zero_padding = FALSE;
/* [.][] */
if (*str == '-') {
sign = -1;
str++;
}
if (*str == '0') {
ctx.zero_padding = TRUE;
str++;
}
while (*str >= '0' && *str <= '9') {
ctx.width = ctx.width*10 + (*str - '0');
str++;
}
if (*str == '.') {
ctx.offset = sign * ctx.width;
sign = 1;
ctx.width = 0;
str++;
/* if offset was prefixed with zero (or it was
plain zero), just ignore that. zero padding
is done with the width. */
ctx.zero_padding = FALSE;
if (*str == '0') {
ctx.zero_padding = TRUE;
str++;
}
if (*str == '-') {
sign = -1;
str++;
}
while (*str >= '0' && *str <= '9') {
ctx.width = ctx.width*10 + (*str - '0');
str++;
}
ctx.width = sign * ctx.width;
}
modifier_count = 0;
while (modifier_count < MAX_MODIFIER_COUNT) {
modifier[modifier_count] = NULL;
for (m = modifiers; m->key != '\0'; m++) {
if (m->key == *str) {
/* @UNSAFE */
modifier[modifier_count] =
m->func;
str++;
break;
}
}
if (modifier[modifier_count] == NULL)
break;
modifier_count++;
}
if (*str == '\0')
break;
var = NULL;
if (*str == '{' && strchr(str, '}') != NULL) {
/* %{long_key} */
unsigned int ctr = 1;
bool escape = FALSE;
end = str;
while(*++end != '\0' && ctr > 0) {
if (!escape && *end == '\\') {
escape = TRUE;
continue;
}
if (escape) {
escape = FALSE;
continue;
}
if (*end == '{') ctr++;
if (*end == '}') ctr--;
}
if (ctr == 0)
/* it needs to come back a bit */
end--;
/* if there is no } it will consume rest of the
string */
len = end - (str + 1);
ret = var_expand_long(&ctx, str+1, len,
&var, error_r);
str = end;
} else {
ret = var_expand_short(ctx.table, *str,
&var, error_r);
}
i_assert(var != NULL);
if (final_ret > ret)
final_ret = ret;
if (ret <= 0)
str_append(dest, var);
else {
for (i = 0; i < modifier_count; i++)
var = modifier[i](var, &ctx);
if (ctx.offset < 0) {
/* if offset is < 0 then we want to
start at the end */
size_t len = strlen(var);
size_t offset_from_end = -ctx.offset;
if (len > offset_from_end)
var += len - offset_from_end;
} else {
while (*var != '\0' && ctx.offset > 0) {
ctx.offset--;
var++;
}
}
if (ctx.width == 0)
str_append(dest, var);
else if (!ctx.zero_padding) {
if (ctx.width < 0)
ctx.width = strlen(var) - (-ctx.width);
str_append_max(dest, var, ctx.width);
} else {
/* %05d -like padding. no truncation. */
ssize_t len = strlen(var);
while (len < ctx.width) {
str_append_c(dest, '0');
ctx.width--;
}
str_append(dest, var);
}
}
}
}
return final_ret;
}
int var_expand(string_t *dest, const char *str,
const struct var_expand_table *table, const char **error_r)
{
return var_expand_with_funcs(dest, str, table, NULL, NULL, error_r);
}
static bool
var_get_key_range_full(const char *str, unsigned int *idx_r,
unsigned int *size_r)
{
const struct var_expand_modifier *m;
unsigned int i = 0;
/* [.][] */
while ((str[i] >= '0' && str[i] <= '9') || str[i] == '-')
i++;
if (str[i] == '.') {
i++;
while ((str[i] >= '0' && str[i] <= '9') || str[i] == '-')
i++;
}
do {
for (m = modifiers; m->key != '\0'; m++) {
if (m->key == str[i]) {
i++;
break;
}
}
} while (m->key != '\0');
if (str[i] != '{') {
/* short key */
*idx_r = i;
*size_r = str[i] == '\0' ? 0 : 1;
return FALSE;
} else {
unsigned int depth = 1;
bool escape = FALSE;
/* long key */
*idx_r = ++i;
for (; str[i] != '\0'; i++) {
if (!escape && str[i] == '\\') {
escape = TRUE;
continue;
}
if (escape) {
escape = FALSE;
continue;
}
if (str[i] == '{')
depth++;
if (str[i] == '}') {
if (--depth==0)
break;
}
}
*size_r = i - *idx_r;
return TRUE;
}
}
char var_get_key(const char *str)
{
unsigned int idx, size;
if (var_get_key_range_full(str, &idx, &size))
return '{';
return str[idx];
}
void var_get_key_range(const char *str, unsigned int *idx_r,
unsigned int *size_r)
{
(void)var_get_key_range_full(str, idx_r, size_r);
}
static bool var_has_long_key(const char **str, const char *long_key)
{
const char *start, *end;
start = strchr(*str, '{');
i_assert(start != NULL);
end = strchr(++start, '}');
if (end == NULL)
return FALSE;
if (strncmp(start, long_key, end-start) == 0 &&
long_key[end-start] == '\0')
return TRUE;
*str = end;
return FALSE;
}
bool var_has_key(const char *str, char key, const char *long_key)
{
char c;
for (; *str != '\0'; str++) {
if (*str == '%' && str[1] != '\0') {
str++;
c = var_get_key(str);
if (c == key && key != '\0')
return TRUE;
if (c == '{' && long_key != NULL) {
if (var_has_long_key(&str, long_key))
return TRUE;
}
}
}
return FALSE;
}
void var_expand_extensions_deinit(void)
{
array_free(&var_expand_extensions);
}
void var_expand_extensions_init(void)
{
i_array_init(&var_expand_extensions, 32);
/* put all hash methods there */
for(const struct hash_method **meth = hash_methods;
*meth != NULL;
meth++) {
struct var_expand_extension_func_table *func =
array_append_space(&var_expand_extensions);
func->key = (*meth)->name;
func->func = var_expand_hash;
}
/* pkcs5 */
struct var_expand_extension_func_table *func =
array_append_space(&var_expand_extensions);
func->key = "pkcs5";
func->func = var_expand_hash;
/* if */
func = array_append_space(&var_expand_extensions);
func->key = "if";
func->func = var_expand_if;
}
void
var_expand_register_func_array(const struct var_expand_extension_func_table *funcs)
{
for(const struct var_expand_extension_func_table *ptr = funcs;
ptr->key != NULL;
ptr++) {
i_assert(*ptr->key != '\0');
array_push_front(&var_expand_extensions, ptr);
}
}
void
var_expand_unregister_func_array(const struct var_expand_extension_func_table *funcs)
{
for(const struct var_expand_extension_func_table *ptr = funcs;
ptr->key != NULL;
ptr++) {
i_assert(ptr->func != NULL);
for(unsigned int i = 0; i < array_count(&var_expand_extensions); i++) {
const struct var_expand_extension_func_table *func =
array_idx(&var_expand_extensions, i);
if (strcasecmp(func->key, ptr->key) == 0) {
array_delete(&var_expand_extensions, i, 1);
}
}
}
}
struct var_expand_table *
var_expand_merge_tables(pool_t pool, const struct var_expand_table *a,
const struct var_expand_table *b)
{
ARRAY(struct var_expand_table) table;
size_t a_size = var_expand_table_size(a);
size_t b_size = var_expand_table_size(b);
p_array_init(&table, pool, a_size + b_size + 1);
for(size_t i=0; ikey = a[i].key;
entry->value = p_strdup(pool, a[i].value);
entry->long_key = p_strdup(pool, a[i].long_key);
}
for(size_t i=0; ikey = b[i].key;
entry->value = p_strdup(pool, b[i].value);
entry->long_key = p_strdup(pool, b[i].long_key);
}
array_append_zero(&table);
return array_front_modifiable(&table);
}
dovecot-2.3.21.1/src/lib/ostream-failure-at.h 0000644 0000000 0000000 00000000444 14656633576 015526 0000000 0000000 #ifndef OSTREAM_FAILURE_AT_H
#define OSTREAM_FAILURE_AT_H
struct ostream *
o_stream_create_failure_at(struct ostream *output, uoff_t failure_offset,
const char *error_string);
struct ostream *
o_stream_create_failure_at_flush(struct ostream *output, const char *error_string);
#endif
dovecot-2.3.21.1/src/lib/istream-jsonstr.h 0000644 0000000 0000000 00000000275 14656633576 015173 0000000 0000000 #ifndef ISTREAM_JSONSTR_H
#define ISTREAM_JSONSTR_H
/* Parse input until '"' is reached. Unescape JSON \x codes. */
struct istream *i_stream_create_jsonstr(struct istream *input);
#endif
dovecot-2.3.21.1/src/lib/crc32.c 0000644 0000000 0000000 00000007524 14656633576 012742 0000000 0000000 /* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "crc32.h"
static uint32_t crc32tab[256] = {
0x00000000,
0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E,
0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0,
0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63,
0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA,
0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180,
0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87,
0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,
0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541,
0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F,
0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E,
0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C,
0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B,
0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2,
0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671,
0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,
0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,
0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795,
0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82,
0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8,
0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF,
0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE,
0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,
0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02,
0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
uint32_t crc32_data(const void *data, size_t size)
{
return crc32_data_more(0, data, size);
}
uint32_t crc32_data_more(uint32_t crc, const void *data, size_t size)
{
const uint8_t *p = data, *end = p + size;
crc ^= 0xffffffff;
for (; p != end; p++)
crc = (crc >> 8) ^ crc32tab[((crc ^ *p) & 0xff)];
crc ^= 0xffffffff;
return crc;
}
uint32_t crc32_str(const char *str)
{
return crc32_str_more(0, str);
}
uint32_t crc32_str_more(uint32_t crc, const char *str)
{
const uint8_t *p = (const uint8_t *)str;
crc ^= 0xffffffff;
for (; *p != '\0'; p++)
crc = (crc >> 8) ^ crc32tab[((crc ^ *p) & 0xff)];
crc ^= 0xffffffff;
return crc;
}
dovecot-2.3.21.1/src/lib/base32.h 0000644 0000000 0000000 00000003340 14656633576 013102 0000000 0000000 #ifndef BASE32_H
#define BASE32_H
/* Translates binary data into base32 (RFC 4648, Section 6). The src must not
point to dest buffer. The pad argument determines whether output is padded
with '='.
*/
void base32_encode(bool pad, const void *src, size_t src_size,
buffer_t *dest);
/* Translates binary data into base32hex (RFC 4648, Section 7). The src must
not point to dest buffer. The pad argument determines whether output is
padded with '='.
*/
void base32hex_encode(bool pad, const void *src, size_t src_size,
buffer_t *dest);
/* Translates base32/base32hex data into binary and appends it to dest buffer.
dest may point to same buffer as src. Returns 1 if all ok, 0 if end of
base32 data found, -1 if data is invalid.
Any whitespace characters are ignored.
This function may be called multiple times for parsing the same stream.
If src_pos is non-NULL, it's updated to first non-translated character in
src. */
int base32_decode(const void *src, size_t src_size,
size_t *src_pos_r, buffer_t *dest) ATTR_NULL(4);
int base32hex_decode(const void *src, size_t src_size,
size_t *src_pos_r, buffer_t *dest) ATTR_NULL(4);
/* Decode given string to a buffer allocated from data stack. */
buffer_t *t_base32_decode_str(const char *str);
buffer_t *t_base32hex_decode_str(const char *str);
/* Returns TRUE if c is a valid base32 encoding character (excluding '=') */
bool base32_is_valid_char(char c);
bool base32hex_is_valid_char(char c);
/* max. buffer size required for base32_encode()/base32hex_encode() */
#define MAX_BASE32_ENCODED_SIZE(size) \
((size) / 5 * 8 + 8)
/* max. buffer size required for base32_decode()/base32hex_decode() */
#define MAX_BASE32_DECODED_SIZE(size) \
((size) / 8 * 5 + 5)
#endif
dovecot-2.3.21.1/src/lib/array.h 0000644 0000000 0000000 00000034577 14656633576 013161 0000000 0000000 #ifndef ARRAY_H
#define ARRAY_H
/* Array is a buffer accessible using fixed size elements. As long as the
compiler provides a typeof() operator, the array provides type safety. If
a wrong type is tried to be added to the array, or if the array's contents
are tried to be used using a wrong type, the compiler will give a warning.
Example usage:
struct foo {
ARRAY(struct bar) bars;
...
};
i_array_init(&foo->bars, 10);
struct bar *bar = array_idx(&foo->bars, 5);
struct baz *baz = array_idx(&foo->bars, 5); // compiler warning
If you want to pass an array as a parameter to a function, you'll need to
create a type for the array using ARRAY_DEFINE_TYPE() and use the type in
the parameter using ARRAY_TYPE(). Any arrays that you want to be passing
around, such as structure members as in the above example, must also be
defined using ARRAY_TYPE() too, rather than ARRAY().
Example:
ARRAY_DEFINE_TYPE(foo, struct foo);
void do_foo(ARRAY_TYPE(foo) *foos) {
struct foo *foo = array_idx(foos, 0);
}
struct foo_manager {
ARRAY_TYPE(foo) foos; // pedantically, ARRAY(struct foo) is a different type
};
// ...
do_foo(&my_foo_manager->foos); // No compiler warning about mismatched types
*/
#include "array-decl.h"
#include "buffer.h"
#define p_array_init(array, pool, init_count) \
array_create(array, pool, sizeof(**(array)->v), init_count)
#define i_array_init(array, init_count) \
p_array_init(array, default_pool, init_count)
#define t_array_init(array, init_count) \
p_array_init(array, pool_datastack_create(), init_count)
#ifdef HAVE_TYPEOF
# define ARRAY_TYPE_CAST_CONST(array) \
(typeof(*(array)->v))
# define ARRAY_TYPE_CAST_MODIFIABLE(array) \
(typeof(*(array)->v_modifiable))
# define ARRAY_TYPE_CHECK(array, data) \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
**(array)->v_modifiable, *(data))
# define ARRAY_TYPES_CHECK(array1, array2) \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
**(array1)->v_modifiable, **(array2)->v_modifiable)
#else
# define ARRAY_TYPE_CAST_CONST(array)
# define ARRAY_TYPE_CAST_MODIFIABLE(array)
# define ARRAY_TYPE_CHECK(array, data) 0
# define ARRAY_TYPES_CHECK(array1, array2) 0
#endif
/* Usage:
ARRAY(struct foo) foo_arr;
struct foo *foo;
array_foreach(&foo_arr, foo) {
..
}
Note that deleting an element while iterating will cause the iteration to
skip over the next element. So deleting a single element and breaking out
of the loop is fine, but continuing the loop is likely a bug. Use
array_foreach_reverse() instead when deleting multiple elements.
*/
#define array_foreach(array, elem) \
for (const void *elem ## __foreach_end = \
(const char *)(elem = *(array)->v) + (array)->arr.buffer->used; \
elem != elem ## __foreach_end; (elem)++)
#define array_foreach_modifiable(array, elem) \
for (const void *elem ## _end = \
(const char *)(elem = ARRAY_TYPE_CAST_MODIFIABLE(array) \
buffer_get_modifiable_data((array)->arr.buffer, NULL)) + \
(array)->arr.buffer->used; \
elem != elem ## _end; (elem)++)
/* Iterate the array in reverse order. */
#define array_foreach_reverse(array, elem) \
for (elem = CONST_PTR_OFFSET(*(array)->v, (array)->arr.buffer->used); \
(const char *)(elem--) > (const char *)*(array)->v; )
#define array_foreach_reverse_modifiable(array, elem) \
for (elem = ARRAY_TYPE_CAST_MODIFIABLE(array) \
((char *)buffer_get_modifiable_data((array)->arr.buffer, NULL) + \
(array)->arr.buffer->used); \
(const char *)(elem--) > (const char *)*(array)->v; )
/* Usage:
ARRAY(struct foo *) foo_ptrs_arr;
struct foo *foo;
array_foreach_elem(&foo_ptrs_arr, foo) {
..
} */
#define array_foreach_elem(array, elem) \
for (const void *_foreach_end = \
CONST_PTR_OFFSET(*(array)->v, (array)->arr.buffer->used), \
*_foreach_ptr = CONST_PTR_OFFSET(*(array)->v, ARRAY_TYPE_CHECK(array, &elem) + \
COMPILE_ERROR_IF_TRUE(sizeof(elem) > sizeof(void *))) \
; \
(_foreach_ptr != _foreach_end && \
(memcpy(&elem, _foreach_ptr, sizeof(elem)), TRUE)) \
; \
_foreach_ptr = CONST_PTR_OFFSET(_foreach_ptr, sizeof(elem)))
#define array_ptr_to_idx(array, elem) \
((elem) - (array)->v[0])
/* Return index of iterated element inside array_foreach() or
array_foreach_modifiable() loop. Note that this doesn't work inside
array_foreach_elem() loop. */
#define array_foreach_idx(array, elem) \
array_ptr_to_idx(array, elem)
static inline void
array_create_from_buffer_i(struct array *array, buffer_t *buffer,
size_t element_size)
{
array->buffer = buffer;
array->element_size = element_size;
}
#define array_create_from_buffer(array, buffer, element_size) \
array_create_from_buffer_i(&(array)->arr, buffer, element_size)
static inline void
array_create_i(struct array *array, pool_t pool,
size_t element_size, unsigned int init_count)
{
buffer_t *buffer;
buffer = buffer_create_dynamic_max(pool, init_count * element_size,
SIZE_MAX / element_size < UINT_MAX ? SIZE_MAX :
UINT_MAX * element_size);
array_create_from_buffer_i(array, buffer, element_size);
}
#define array_create(array, pool, element_size, init_count) \
array_create_i(&(array)->arr, pool, element_size, init_count)
static inline void
array_free_i(struct array *array)
{
buffer_free(&array->buffer);
}
#define array_free(array) \
array_free_i(&(array)->arr)
static inline void * ATTR_WARN_UNUSED_RESULT
array_free_without_data_i(struct array *array)
{
return buffer_free_without_data(&array->buffer);
}
#define array_free_without_data(array) \
ARRAY_TYPE_CAST_MODIFIABLE(array)array_free_without_data_i(&(array)->arr)
static inline bool
array_is_created_i(const struct array *array)
{
return array->buffer != NULL;
}
#define array_is_created(array) \
array_is_created_i(&(array)->arr)
static inline pool_t ATTR_PURE
array_get_pool_i(struct array *array)
{
return buffer_get_pool(array->buffer);
}
#define array_get_pool(array) \
array_get_pool_i(&(array)->arr)
static inline void
array_clear_i(struct array *array)
{
buffer_set_used_size(array->buffer, 0);
}
#define array_clear(array) \
array_clear_i(&(array)->arr)
static inline unsigned int ATTR_PURE
array_count_i(const struct array *array)
{
return array->buffer->used / array->element_size;
}
#define array_count(array) \
array_count_i(&(array)->arr)
/* No need for the real count if all we're doing is comparing against 0 */
#define array_is_empty(array) \
((array)->arr.buffer->used == 0)
#define array_not_empty(array) \
((array)->arr.buffer->used > 0)
static inline void
array_append_i(struct array *array, const void *data, unsigned int count)
{
buffer_append(array->buffer, data, count * array->element_size);
}
#define array_append(array, data, count) \
TYPE_CHECKS(void, ARRAY_TYPE_CHECK(array, data), \
array_append_i(&(array)->arr, data, count))
static inline void
array_append_array_i(struct array *dest_array, const struct array *src_array)
{
i_assert(dest_array->element_size == src_array->element_size);
buffer_append_buf(dest_array->buffer, src_array->buffer, 0, SIZE_MAX);
}
#define array_append_array(dest_array, src_array) \
TYPE_CHECKS(void, ARRAY_TYPES_CHECK(dest_array, src_array), \
array_append_array_i(&(dest_array)->arr, &(src_array)->arr))
static inline void
array_insert_i(struct array *array, unsigned int idx,
const void *data, unsigned int count)
{
buffer_insert(array->buffer, idx * array->element_size,
data, count * array->element_size);
}
#define array_insert(array, idx, data, count) \
TYPE_CHECKS(void, ARRAY_TYPE_CHECK(array, data), \
array_insert_i(&(array)->arr, idx, data, count))
static inline void
array_delete_i(struct array *array, unsigned int idx, unsigned int count)
{
buffer_delete(array->buffer, idx * array->element_size,
count * array->element_size);
}
#define array_delete(array, idx, count) \
array_delete_i(&(array)->arr, idx, count)
static inline const void *
array_get_i(const struct array *array, unsigned int *count_r)
{
*count_r = array_count_i(array);
return array->buffer->data;
}
#define array_get(array, count) \
ARRAY_TYPE_CAST_CONST(array)array_get_i(&(array)->arr, count)
/* Re: i_assert() vs. pure: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51971#c1 */
static inline const void * ATTR_PURE
array_idx_i(const struct array *array, unsigned int idx)
{
i_assert(idx < array->buffer->used / array->element_size);
return CONST_PTR_OFFSET(array->buffer->data, idx * array->element_size);
}
#define array_front(array) array_idx(array, 0)
#define array_front_modifiable(array) array_idx_modifiable(array, 0)
#define array_back(array) array_idx(array, array_count(array)-1)
#define array_back_modifiable(array) array_idx_modifiable(array, array_count(array)-1)
#define array_pop_back(array) array_delete(array, array_count(array)-1, 1);
#define array_push_back(array, item) array_append(array, (item), 1)
#define array_pop_front(array) array_delete(array, 0, 1)
#define array_push_front(array, item) array_insert(array, 0, (item), 1)
#define array_idx(array, idx) \
ARRAY_TYPE_CAST_CONST(array)array_idx_i(&(array)->arr, idx)
/* Using *array_idx() will fail if the compiler doesn't support typeof().
The same can be done with array_idx_elem() for arrays that have pointers. */
#ifdef HAVE_TYPEOF
# define array_idx_elem(array, idx) \
(TRUE ? *array_idx(array, idx) : \
COMPILE_ERROR_IF_TRUE(sizeof(**(array)->v) != sizeof(void *)))
#else
# define array_idx_elem(array, idx) \
(*(void **)array_idx_i(&(array)->arr, idx))
#endif
static inline void *
array_get_modifiable_i(struct array *array, unsigned int *count_r)
{
*count_r = array_count_i(array);
return buffer_get_modifiable_data(array->buffer, NULL);
}
#define array_get_modifiable(array, count) \
ARRAY_TYPE_CAST_MODIFIABLE(array) \
array_get_modifiable_i(&(array)->arr, count)
void *
array_idx_modifiable_i(const struct array *array, unsigned int idx) ATTR_PURE;
#define array_idx_modifiable(array, idx) \
ARRAY_TYPE_CAST_MODIFIABLE(array) \
array_idx_modifiable_i(&(array)->arr, idx)
void *array_idx_get_space_i(struct array *array, unsigned int idx);
#define array_idx_get_space(array, idx) \
ARRAY_TYPE_CAST_MODIFIABLE(array) \
array_idx_get_space_i(&(array)->arr, idx)
void array_idx_set_i(struct array *array, unsigned int idx, const void *data);
#define array_idx_set(array, idx, data) \
TYPE_CHECKS(void, ARRAY_TYPE_CHECK(array, data), \
array_idx_set_i(&(array)->arr, idx, data))
void array_idx_clear_i(struct array *array, unsigned int idx);
#define array_idx_clear(array, idx) \
array_idx_clear_i(&(array)->arr, idx)
static inline void *
array_append_space_i(struct array *array)
{
void *data;
data = buffer_append_space_unsafe(array->buffer, array->element_size);
memset(data, 0, array->element_size);
return data;
}
#define array_append_space(array) \
ARRAY_TYPE_CAST_MODIFIABLE(array)array_append_space_i(&(array)->arr)
#define array_append_zero(array) \
(void)array_append_space_i(&(array)->arr)
void *array_insert_space_i(struct array *array, unsigned int idx);
#define array_insert_space(array, idx) \
ARRAY_TYPE_CAST_MODIFIABLE(array) \
array_insert_space_i(&(array)->arr, idx)
static inline void
array_copy(struct array *dest, unsigned int dest_idx,
const struct array *src, unsigned int src_idx, unsigned int count)
{
i_assert(dest->element_size == src->element_size);
buffer_copy(dest->buffer, dest_idx * dest->element_size,
src->buffer, src_idx * src->element_size,
count * dest->element_size);
}
bool array_cmp_i(const struct array *array1,
const struct array *array2) ATTR_PURE;
#define array_cmp(array1, array2) \
array_cmp_i(&(array1)->arr, &(array2)->arr)
/* Test equality via a comparator */
bool array_equal_fn_i(const struct array *array1,
const struct array *array2,
int (*cmp)(const void*, const void *)) ATTR_PURE;
#define array_equal_fn(array1, array2, cmp) \
TYPE_CHECKS(bool, \
ARRAY_TYPES_CHECK(array1, array2) || \
CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array1)->v), \
typeof(*(array2)->v))), \
array_equal_fn_i(&(array1)->arr, &(array2)->arr, \
(int (*)(const void *, const void *))cmp))
bool array_equal_fn_ctx_i(const struct array *array1,
const struct array *array2,
int (*cmp)(const void*, const void *, const void *),
const void *context) ATTR_PURE;
/* Same, but with a context pointer.
context can't be void* as ``const typeof(context)'' won't compile,
so ``const typeof(*context)*'' is required instead, and that requires a
complete type. */
#define array_equal_fn_ctx(array1, array2, cmp, ctx) \
TYPE_CHECKS(bool, \
ARRAY_TYPES_CHECK(array1, array2) || \
CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array1)->v), \
typeof(*(array2)->v), \
const typeof(*ctx)*)), \
array_equal_fn_ctx_i(&(array1)->arr, &(array2)->arr, \
(int (*)(const void *, const void *, const void *))cmp, ctx))
void array_reverse_i(struct array *array);
#define array_reverse(array) \
array_reverse_i(&(array)->arr)
void array_sort_i(struct array *array, int (*cmp)(const void *, const void *));
#define array_sort(array, cmp) \
TYPE_CHECKS(void, \
CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array)->v), \
typeof(*(array)->v))), \
array_sort_i(&(array)->arr, (int (*)(const void *, const void *))cmp))
void *array_bsearch_i(struct array *array, const void *key,
int (*cmp)(const void *, const void *));
#define array_bsearch(array, key, cmp) \
TYPE_CHECKS(void *, \
CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*key) *), \
typeof(*(array)->v))), \
ARRAY_TYPE_CAST_MODIFIABLE(array)array_bsearch_i(&(array)->arr, \
(const void *)key, (int (*)(const void *, const void *))cmp))
/* Returns pointer to first element for which cmp(key,elem)==0, or NULL */
const void *array_lsearch_i(const struct array *array, const void *key,
int (*cmp)(const void *, const void *));
static inline void *array_lsearch_modifiable_i(struct array *array, const void *key,
int (*cmp)(const void *, const void *))
{
return (void *)array_lsearch_i(array, key, cmp);
}
#define ARRAY_LSEARCH_CALL(modifiable, array, key, cmp) \
TYPE_CHECKS(void *, \
CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*key) *), \
typeof(*(array)->v))), \
array_lsearch##modifiable##i( \
&(array)->arr, (const void *)key, \
(int (*)(const void *, const void *))cmp))
#define array_lsearch(array, key, cmp) \
ARRAY_TYPE_CAST_CONST(array)ARRAY_LSEARCH_CALL(_, array, key, cmp)
#define array_lsearch_modifiable(array, key, cmp) \
ARRAY_TYPE_CAST_MODIFIABLE(array)ARRAY_LSEARCH_CALL(_modifiable_, array, key, cmp)
#endif
dovecot-2.3.21.1/src/lib/utc-offset.h 0000644 0000000 0000000 00000000244 14656633576 014102 0000000 0000000 #ifndef UTC_OFFSET_H
#define UTC_OFFSET_H
#include
/* Returns given time's offset to UTC in minutes. */
int utc_offset(struct tm *tm, time_t t);
#endif
dovecot-2.3.21.1/src/lib/hash.h 0000644 0000000 0000000 00000017260 14656633576 012754 0000000 0000000 #ifndef HASH_H
#define HASH_H
struct hash_table;
#ifdef HAVE_TYPEOF
# define HASH_VALUE_CAST(table) (typeof((table)._value))
#else
# define HASH_VALUE_CAST(table)
#endif
/* Returns hash code. */
typedef unsigned int hash_callback_t(const void *p);
/* Returns 0 if the pointers are equal. */
typedef int hash_cmp_callback_t(const void *p1, const void *p2);
/* Create a new hash table. If initial_size is 0, the default value is used.
table_pool is used to allocate/free large hash tables, node_pool is used
for smaller allocations and can also be alloconly pool. The pools must not
be free'd before hash_table_destroy() is called. */
void hash_table_create(struct hash_table **table_r, pool_t node_pool,
unsigned int initial_size,
hash_callback_t *hash_cb,
hash_cmp_callback_t *key_compare_cb);
#define hash_table_create(table, pool, size, hash_cb, key_cmp_cb) \
TYPE_CHECKS(void, \
COMPILE_ERROR_IF_TRUE( \
sizeof((*table)._key) != sizeof(void *) || \
sizeof((*table)._value) != sizeof(void *)) || \
COMPILE_ERROR_IF_TRUE( \
!__builtin_types_compatible_p(typeof(&key_cmp_cb), \
int (*)(typeof((*table)._key), typeof((*table)._key))) && \
!__builtin_types_compatible_p(typeof(&key_cmp_cb), \
int (*)(typeof((*table)._const_key), typeof((*table)._const_key)))) || \
COMPILE_ERROR_IF_TRUE( \
!__builtin_types_compatible_p(typeof(&hash_cb), \
unsigned int (*)(typeof((*table)._key))) && \
!__builtin_types_compatible_p(typeof(&hash_cb), \
unsigned int (*)(typeof((*table)._const_key)))), \
hash_table_create(&(*table)._table, pool, size, \
(hash_callback_t *)hash_cb, \
(hash_cmp_callback_t *)key_cmp_cb))
/* Create hash table where comparisons are done directly with the pointers. */
void hash_table_create_direct(struct hash_table **table_r, pool_t node_pool,
unsigned int initial_size);
#define hash_table_create_direct(table, pool, size) \
TYPE_CHECKS(void, \
COMPILE_ERROR_IF_TRUE( \
sizeof((*table)._key) != sizeof(void *) || \
sizeof((*table)._value) != sizeof(void *)), \
hash_table_create_direct(&(*table)._table, pool, size))
#define hash_table_is_created(table) \
((table)._table != NULL)
void hash_table_destroy(struct hash_table **table);
#define hash_table_destroy(table) \
hash_table_destroy(&(*table)._table)
/* Remove all nodes from hash table. If free_collisions is TRUE, the
memory allocated from node_pool is freed, or discarded with alloconly pools.
WARNING: If you p_clear() the node_pool, the free_collisions must be TRUE. */
void hash_table_clear(struct hash_table *table, bool free_collisions);
#define hash_table_clear(table, free_collisions) \
hash_table_clear((table)._table, free_collisions)
void *hash_table_lookup(const struct hash_table *table, const void *key) ATTR_PURE;
#define hash_table_lookup(table, key) \
TYPE_CHECKS(void *, \
COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._key, (table)._const_key, key), \
HASH_VALUE_CAST(table)hash_table_lookup((table)._table, (key)))
bool hash_table_lookup_full(const struct hash_table *table,
const void *lookup_key,
void **orig_key_r, void **value_r);
#ifndef __cplusplus
# define hash_table_lookup_full(table, lookup_key, orig_key_r, value_r) \
TYPE_CHECKS(bool, \
COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, lookup_key) || \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, orig_key_r) || \
COMPILE_ERROR_IF_TRUE(sizeof(*(orig_key_r)) != sizeof(void *)) || \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r) || \
COMPILE_ERROR_IF_TRUE(sizeof(*(value_r)) != sizeof(void *)), \
hash_table_lookup_full((table)._table, \
(lookup_key), (void *)(orig_key_r), (void *)(value_r)))
#else
/* C++ requires (void **) casting, but that's not possible with strict
aliasing, so .. we'll just disable the type checks */
# define hash_table_lookup_full(table, lookup_key, orig_key_r, value_r) \
hash_table_lookup_full((table)._table, lookup_key, orig_key_r, value_r)
#endif
/* Suppose to insert a new key-value node to the hash table.
If the key already exists, assert-crash. */
void hash_table_insert(struct hash_table *table, void *key, void *value);
/* If the key doesn't exists, do the exact same as hash_table_insert()
If the key already exists, preserve the original key and update only the value.*/
void hash_table_update(struct hash_table *table, void *key, void *value);
#define hash_table_insert(table, key, value) \
TYPE_CHECKS(void, \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key) || \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value), \
hash_table_insert((table)._table, (void *)(key), (void *)(value)))
#define hash_table_update(table, key, value) \
TYPE_CHECKS(void, \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key) || \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value), \
hash_table_update((table)._table, (void *)(key), (void *)(value)))
bool hash_table_try_remove(struct hash_table *table, const void *key);
#define hash_table_try_remove(table, key) \
TYPE_CHECKS(bool, \
COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, key), \
hash_table_try_remove((table)._table, (const void *)(key)))
#define hash_table_remove(table, key) \
STMT_START { \
if (unlikely(!hash_table_try_remove(table, key))) \
i_panic("key not found from hash"); \
} STMT_END
unsigned int hash_table_count(const struct hash_table *table) ATTR_PURE;
#define hash_table_count(table) \
hash_table_count((table)._table)
/* Iterates through all nodes in hash table. You may safely call hash_table_*()
functions while iterating, but if you add any new nodes, they may or may
not be called for in this iteration. */
struct hash_iterate_context *hash_table_iterate_init(struct hash_table *table);
#define hash_table_iterate_init(table) \
hash_table_iterate_init((table)._table)
bool hash_table_iterate(struct hash_iterate_context *ctx,
void **key_r, void **value_r);
#ifndef __cplusplus
# define hash_table_iterate(ctx, table, key_r, value_r) \
TYPE_CHECKS(bool, \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, key_r) || \
COMPILE_ERROR_IF_TRUE(sizeof(*(key_r)) != sizeof(void *)) || \
COMPILE_ERROR_IF_TRUE(sizeof(*(value_r)) != sizeof(void *)) || \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r), \
hash_table_iterate(ctx, (void *)(key_r), (void *)(value_r)))
#else
/* C++ requires (void **) casting, but that's not possible with strict
aliasing, so .. we'll just disable the type checks */
# define hash_table_iterate(ctx, table, key_r, value_r) \
hash_table_iterate(ctx, key_r, value_r)
#endif
void hash_table_iterate_deinit(struct hash_iterate_context **ctx);
/* Hash table isn't resized, and removed nodes aren't removed from
the list while hash table is freezed. Supports nesting. */
void hash_table_freeze(struct hash_table *table);
void hash_table_thaw(struct hash_table *table);
#define hash_table_freeze(table) \
hash_table_freeze((table)._table)
#define hash_table_thaw(table) \
hash_table_thaw((table)._table)
/* Copy all nodes from one hash table to another */
void hash_table_copy(struct hash_table *dest, struct hash_table *src);
#define hash_table_copy(table1, table2) \
hash_table_copy((table1)._table, (table2)._table)
/* hash function for strings */
unsigned int str_hash(const char *p) ATTR_PURE;
unsigned int strcase_hash(const char *p) ATTR_PURE;
/* fast hash function which uppercases a-z. Does not work well
with input that consists from non number/letter input, as
it works by dropping 0x20. */
unsigned int strfastcase_hash(const char *p) ATTR_PURE;
/* a generic hash for a given memory block */
unsigned int mem_hash(const void *p, unsigned int size) ATTR_PURE;
#endif
dovecot-2.3.21.1/src/lib/mkdir-parents.h 0000644 0000000 0000000 00000002616 14656633576 014610 0000000 0000000 #ifndef MKDIR_PARENTS_H
#define MKDIR_PARENTS_H
#include
/* Create path and all the directories under it if needed. Permissions for
existing directories isn't changed. Returns 0 if ok. If directory already
exists, returns -1 with errno=EEXIST. */
int mkdir_parents(const char *path, mode_t mode);
/* Like mkdir_parents(), but use the given uid/gid for newly created
directories. (uid_t)-1 or (gid_t)-1 can be used to indicate that it
doesn't need to be changed. If gid isn't (gid_t)-1 and the parent directory
had setgid-bit enabled, it's removed unless explicitly included in the
mode. */
int mkdir_parents_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
/* Like mkdir_parents_chown(), but change only group. If chown() fails with
EACCES, use gid_origin in the error message. */
int mkdir_parents_chgrp(const char *path, mode_t mode,
gid_t gid, const char *gid_origin);
/* Like mkdir_parents_chown(), but don't actually create any parents. */
int mkdir_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int mkdir_chgrp(const char *path, mode_t mode,
gid_t gid, const char *gid_origin);
/* stat() the path or its first parent that exists. Returns 0 if ok, -1 if
failed. root_dir is set to the last stat()ed directory (on success and
on failure). */
int stat_first_parent(const char *path, const char **root_dir_r,
struct stat *st_r);
#endif
dovecot-2.3.21.1/src/lib/istream-timeout.c 0000644 0000000 0000000 00000011371 14656633576 015151 0000000 0000000 /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "time-util.h"
#include "istream-private.h"
#include "istream-timeout.h"
struct timeout_istream {
struct istream_private istream;
struct timeout *to;
struct timeval last_read_timestamp;
time_t created;
unsigned int timeout_msecs;
bool update_timestamp;
};
static void i_stream_timeout_close(struct iostream_private *stream,
bool close_parent)
{
struct timeout_istream *tstream =
container_of(stream, struct timeout_istream, istream.iostream);
timeout_remove(&tstream->to);
if (close_parent)
i_stream_close(tstream->istream.parent);
}
static void i_stream_timeout_switch_ioloop_to(struct istream_private *stream,
struct ioloop *ioloop)
{
struct timeout_istream *tstream =
container_of(stream, struct timeout_istream, istream);
if (tstream->to != NULL)
tstream->to = io_loop_move_timeout_to(ioloop, &tstream->to);
}
static void i_stream_timeout(struct timeout_istream *tstream)
{
struct iostream_private *iostream = &tstream->istream.iostream;
unsigned int over_msecs;
int diff;
if (tstream->update_timestamp) {
/* we came here after a long-running code. timeouts are handled
before IOs, so wait for i_stream_read() to be called again
before assuming that we've timed out. */
return;
}
timeout_remove(&tstream->to);
diff = timeval_diff_msecs(&ioloop_timeval, &tstream->last_read_timestamp);
if (diff < (int)tstream->timeout_msecs) {
/* we haven't reached the read timeout yet, update it */
if (diff < 0)
diff = 0;
tstream->to = timeout_add_to(io_stream_get_ioloop(iostream),
tstream->timeout_msecs - diff,
i_stream_timeout, tstream);
return;
}
over_msecs = diff - tstream->timeout_msecs;
io_stream_set_error(&tstream->istream.iostream,
"Read timeout in %u.%03u s after %"PRIuUOFF_T" bytes%s",
diff/1000, diff%1000,
tstream->istream.istream.v_offset,
over_msecs < 1000 ? "" : t_strdup_printf(
" (requested timeout in %u ms)", tstream->timeout_msecs));
tstream->istream.istream.stream_errno = ETIMEDOUT;
i_stream_set_input_pending(tstream->istream.parent, TRUE);
}
static void i_stream_timeout_set_pending(struct timeout_istream *tstream)
{
/* make sure we get called again on the next ioloop run. this updates
the timeout to the timestamp where we actually would have wanted to
start waiting for more data (so if there is long-running code
outside the ioloop it's not counted) */
tstream->update_timestamp = TRUE;
tstream->last_read_timestamp = ioloop_timeval;
i_stream_set_input_pending(&tstream->istream.istream, TRUE);
}
static ssize_t
i_stream_timeout_read(struct istream_private *stream)
{
struct timeout_istream *tstream =
container_of(stream, struct timeout_istream, istream);
struct iostream_private *iostream = &tstream->istream.iostream;
ssize_t ret;
i_stream_seek(stream->parent, stream->parent_start_offset +
stream->istream.v_offset);
ret = i_stream_read_copy_from_parent(&stream->istream);
if (ret < 0) {
/* failed */
if (errno == ECONNRESET || errno == EPIPE) {
int diff = ioloop_time - tstream->created;
io_stream_set_error(&tstream->istream.iostream,
"%s (opened %d secs ago)",
i_stream_get_error(stream->parent), diff);
}
} else if (tstream->to == NULL && tstream->timeout_msecs > 0) {
/* first read. add the timeout here instead of in init
in case the stream is created long before it's actually
read from. */
tstream->to = timeout_add_to(io_stream_get_ioloop(iostream),
tstream->timeout_msecs,
i_stream_timeout, tstream);
i_stream_timeout_set_pending(tstream);
} else if (ret > 0 && tstream->to != NULL) {
/* we read something, reset the timeout */
timeout_reset(tstream->to);
i_stream_timeout_set_pending(tstream);
} else if (tstream->update_timestamp) {
tstream->update_timestamp = FALSE;
tstream->last_read_timestamp = ioloop_timeval;
}
return ret;
}
struct istream *
i_stream_create_timeout(struct istream *input, unsigned int timeout_msecs)
{
struct timeout_istream *tstream;
tstream = i_new(struct timeout_istream, 1);
tstream->timeout_msecs = timeout_msecs;
tstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
tstream->istream.stream_size_passthrough = TRUE;
tstream->created = ioloop_time;
tstream->istream.read = i_stream_timeout_read;
tstream->istream.switch_ioloop_to = i_stream_timeout_switch_ioloop_to;
tstream->istream.iostream.close = i_stream_timeout_close;
tstream->istream.istream.readable_fd = input->readable_fd;
tstream->istream.istream.blocking = input->blocking;
tstream->istream.istream.seekable = input->seekable;
return i_stream_create(&tstream->istream, input,
i_stream_get_fd(input), 0);
}
dovecot-2.3.21.1/src/lib/fdpass.c 0000644 0000000 0000000 00000013455 14656633576 013306 0000000 0000000 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
/*
fdpass.c - File descriptor passing between processes via UNIX sockets
This isn't fully portable, but pretty much all UNIXes nowadays should
support this. If you're having runtime problems with fd_read(), check the
end of fd_read() and play with the if condition. If you're having problems
with fd_send(), try defining BUGGY_CMSG_MACROS.
If this file doesn't compile at all, you should check if this is supported
in your system at all. It may require some extra #define to enable it.
If not, you're pretty much out of luck. Cygwin didn't last I checked.
*/
#define _XPG4_2
#if defined(irix) || defined (__irix__) || defined(sgi) || defined (__sgi__)
# define _XOPEN_SOURCE 4 /* for IRIX */
#endif
#if !defined(_AIX) && !defined(_XOPEN_SOURCE_EXTENDED)
# define _XOPEN_SOURCE_EXTENDED /* for Tru64, breaks AIX */
#endif
#ifdef HAVE_CONFIG_H
# include "lib.h"
#else
# define i_assert(x)
#endif
#include
#include
#include
#include
#include
#include
#include "fdpass.h"
#ifndef HAVE_CONFIG_H
struct const_iovec {
const void *iov_base;
size_t iov_len;
};
#endif
/* RFC 2292 defines CMSG_*() macros, but some operating systems don't have them
so we'll define our own if they don't exist.
CMSG_LEN(data) is used to calculate size of sizeof(struct cmsghdr) +
sizeof(data) and padding between them.
CMSG_SPACE(data) also calculates the padding needed after the data, in case
multiple objects are sent.
cmsghdr contains cmsg_len field and two integers. cmsg_len is sometimes
defined as sockaddr_t and sometimes size_t, so it can be either 32bit or
64bit. This padding is added by compiler in sizeof(struct cmsghdr).
Padding required by CMSG_DATA() can vary. Usually it wants size_t or 32bit.
With Solaris it's in _CMSG_DATA_ALIGNMENT (32bit), we assume others want
size_t.
We don't really need CMSG_SPACE() to be exactly correct, because currently
we send only one object at a time. But anyway I'm trying to keep that
correct in case it's sometimes needed..
*/
#ifdef BUGGY_CMSG_MACROS
/* Some OSes have broken CMSG macros in 64bit systems. The macros use 64bit
alignment while kernel uses 32bit alignment. */
# undef CMSG_SPACE
# undef CMSG_LEN
# undef CMSG_DATA
# define CMSG_DATA(cmsg) ((char *)((cmsg) + 1))
# define _CMSG_DATA_ALIGNMENT 4
# define _CMSG_HDR_ALIGNMENT 4
#endif
#ifndef CMSG_SPACE
# define MY_ALIGN(len, align) \
(((len) + align - 1) & ~(align - 1))
/* Alignment between cmsghdr and data */
# ifndef _CMSG_DATA_ALIGNMENT
# define _CMSG_DATA_ALIGNMENT sizeof(size_t)
# endif
/* Alignment between data and next cmsghdr */
# ifndef _CMSG_HDR_ALIGNMENT
# define _CMSG_HDR_ALIGNMENT sizeof(size_t)
# endif
# define CMSG_SPACE(len) \
(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + \
MY_ALIGN(len, _CMSG_HDR_ALIGNMENT))
# define CMSG_LEN(len) \
(MY_ALIGN(sizeof(struct cmsghdr), _CMSG_DATA_ALIGNMENT) + (len))
#endif
#ifdef SCM_RIGHTS
ssize_t fd_send(int handle, int send_fd, const void *data, size_t size)
{
struct msghdr msg;
struct const_iovec iov;
struct cmsghdr *cmsg;
char buf[CMSG_SPACE(sizeof(int))];
/* at least one byte is required to be sent with fd passing */
i_assert(size > 0 && size < INT_MAX);
memset(&msg, 0, sizeof(struct msghdr));
iov.iov_base = data;
iov.iov_len = size;
msg.msg_iov = (void *)&iov;
msg.msg_iovlen = 1;
if (send_fd != -1) {
/* set the control and controllen before CMSG_FIRSTHDR(). */
memset(buf, 0, sizeof(buf));
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(send_fd));
/* set the real length we want to use. Do it after all is
set just in case CMSG macros required the extra padding
in the end. */
msg.msg_controllen = cmsg->cmsg_len;
}
return sendmsg(handle, &msg, 0);
}
#ifdef LINUX20
/* Linux 2.0.x doesn't set any cmsg fields. Note that this might make some
attacks possible so don't do it unless you really have to. */
# define CHECK_CMSG(cmsg) ((cmsg) != NULL)
#else
# define CHECK_CMSG(cmsg) \
((cmsg) != NULL && \
(size_t)(cmsg)->cmsg_len >= (size_t)CMSG_LEN(sizeof(int)) && \
(cmsg)->cmsg_level == SOL_SOCKET && (cmsg)->cmsg_type == SCM_RIGHTS)
#endif
ssize_t fd_read(int handle, void *data, size_t size, int *fd)
{
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
ssize_t ret;
char buf[CMSG_SPACE(sizeof(int))];
i_assert(size > 0 && size < INT_MAX);
memset(&msg, 0, sizeof (struct msghdr));
iov.iov_base = data;
iov.iov_len = size;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
memset(buf, 0, sizeof(buf));
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
ret = recvmsg(handle, &msg, 0);
if (ret <= 0) {
*fd = -1;
return ret;
}
/* at least one byte transferred - we should have the fd now.
do extra checks to make sure it really is an fd that is being
transferred to avoid potential DoS conditions. some systems don't
set all these values correctly however so CHECK_CMSG() is somewhat
system dependent */
cmsg = CMSG_FIRSTHDR(&msg);
if (!CHECK_CMSG(cmsg))
*fd = -1;
else
memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
return ret;
}
#else
# ifdef __GNUC__
# warning SCM_RIGHTS not supported, privilege separation not possible
# endif
ssize_t fd_send(int handle ATTR_UNUSED, int send_fd ATTR_UNUSED,
const void *data ATTR_UNUSED, size_t size ATTR_UNUSED)
{
errno = ENOSYS;
return -1;
}
ssize_t fd_read(int handle ATTR_UNUSED, void *data ATTR_UNUSED,
size_t size ATTR_UNUSED, int *fd ATTR_UNUSED)
{
errno = ENOSYS;
return -1;
}
#endif
dovecot-2.3.21.1/src/lib/child-wait.c 0000644 0000000 0000000 00000006141 14656633576 014045 0000000 0000000 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "lib-signals.h"
#include "hash.h"
#include "child-wait.h"
#include
struct child_wait {
unsigned int pid_count;
child_wait_callback_t *callback;
void *context;
};
static int child_wait_refcount = 0;
/* pid_t => wait */
static HASH_TABLE(void *, struct child_wait *) child_pids;
static void
sigchld_handler(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED);
#undef child_wait_new_with_pid
struct child_wait *
child_wait_new_with_pid(pid_t pid, child_wait_callback_t *callback,
void *context)
{
struct child_wait *wait;
wait = i_new(struct child_wait, 1);
wait->callback = callback;
wait->context = context;
if (pid != (pid_t)-1)
child_wait_add_pid(wait, pid);
return wait;
}
void child_wait_free(struct child_wait **_wait)
{
struct child_wait *wait = *_wait;
struct hash_iterate_context *iter;
void *key;
struct child_wait *value;
*_wait = NULL;
if (wait->pid_count > 0) {
/* this should be rare, so iterating hash is fast enough */
iter = hash_table_iterate_init(child_pids);
while (hash_table_iterate(iter, child_pids, &key, &value)) {
if (value == wait) {
hash_table_remove(child_pids, key);
if (--wait->pid_count == 0)
break;
}
}
hash_table_iterate_deinit(&iter);
}
i_free(wait);
}
void child_wait_add_pid(struct child_wait *wait, pid_t pid)
{
wait->pid_count++;
hash_table_insert(child_pids, POINTER_CAST(pid), wait);
lib_signals_set_expected(SIGCHLD, TRUE, sigchld_handler, NULL);
}
void child_wait_remove_pid(struct child_wait *wait, pid_t pid)
{
wait->pid_count--;
hash_table_remove(child_pids, POINTER_CAST(pid));
if (hash_table_count(child_pids) == 0)
lib_signals_set_expected(SIGCHLD, FALSE, sigchld_handler, NULL);
}
static void
sigchld_handler(const siginfo_t *si ATTR_UNUSED, void *context ATTR_UNUSED)
{
struct child_wait_status status;
while ((status.pid = waitpid(-1, &status.status, WNOHANG)) > 0) {
status.wait = hash_table_lookup(child_pids,
POINTER_CAST(status.pid));
if (status.wait != NULL) {
child_wait_remove_pid(status.wait, status.pid);
status.wait->callback(&status, status.wait->context);
}
}
if (status.pid == -1 && errno != EINTR && errno != ECHILD)
i_error("waitpid() failed: %m");
}
void child_wait_switch_ioloop(void)
{
lib_signals_switch_ioloop(SIGCHLD, sigchld_handler, NULL);
}
void child_wait_init(void)
{
if (child_wait_refcount++ > 0) {
child_wait_switch_ioloop();
return;
}
hash_table_create_direct(&child_pids, default_pool, 0);
lib_signals_set_handler(SIGCHLD, LIBSIG_FLAGS_SAFE,
sigchld_handler, NULL);
}
void child_wait_deinit(void)
{
struct hash_iterate_context *iter;
void *key;
struct child_wait *value;
i_assert(child_wait_refcount > 0);
if (--child_wait_refcount > 0) {
child_wait_switch_ioloop();
return;
}
lib_signals_unset_handler(SIGCHLD, sigchld_handler, NULL);
iter = hash_table_iterate_init(child_pids);
while (hash_table_iterate(iter, child_pids, &key, &value))
i_free(value);
hash_table_iterate_deinit(&iter);
hash_table_destroy(&child_pids);
}
dovecot-2.3.21.1/src/lib/istream-sized.h 0000644 0000000 0000000 00000003143 14656633576 014604 0000000 0000000 #ifndef ISTREAM_SIZED_H
#define ISTREAM_SIZED_H
struct istream_sized_error_data {
/* Stream's current v_offset */
uoff_t v_offset;
/* How many more bytes are being added within this read() */
size_t new_bytes;
/* What's the original wanted size. */
uoff_t wanted_size;
/* TRUE if we're at EOF now */
bool eof;
};
typedef const char *
istream_sized_callback_t(const struct istream_sized_error_data *data,
void *context);
/* Assume that input stream is exactly the given size. If the stream is too
small, fail with stream_errno=EPIPE. If stream is too large, fail with
stream_errno=EINVAL. */
struct istream *i_stream_create_sized(struct istream *input, uoff_t size);
struct istream *i_stream_create_sized_range(struct istream *input,
uoff_t offset, uoff_t size);
/* Like i_stream_create_sized*(), but allow input stream's size to be larger. */
struct istream *i_stream_create_min_sized(struct istream *input, uoff_t min_size);
struct istream *i_stream_create_min_sized_range(struct istream *input,
uoff_t offset, uoff_t min_size);
/* Same as i_stream_create_sized(), but set the error message via the
callback. */
struct istream *
i_stream_create_sized_with_callback(struct istream *input, uoff_t size,
istream_sized_callback_t *error_callback,
void *context);
#define i_stream_create_sized_with_callback(input, size, error_callback, context) \
i_stream_create_sized_with_callback(input, size - \
CALLBACK_TYPECHECK(error_callback, \
const char *(*)(const struct istream_sized_error_data *, typeof(context))), \
(istream_sized_callback_t *)error_callback, context)
#endif
dovecot-2.3.21.1/src/lib/test-event-filter.c 0000644 0000000 0000000 00000050135 14656633576 015403 0000000 0000000 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "ioloop.h"
#include "event-filter-private.h"
static void test_event_filter_override_parent_fields(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: override parent fields");
struct event *parent = event_create(NULL);
event_add_str(parent, "str", "parent_str");
event_add_str(parent, "parent_str", "parent_str");
event_add_int(parent, "int1", 0);
event_add_int(parent, "int2", 5);
event_add_int(parent, "parent_int", 6);
struct event *child = event_create(parent);
event_add_str(child, "str", "child_str");
event_add_str(child, "child_str", "child_str");
event_add_int(child, "int1", 6);
event_add_int(child, "int2", 0);
event_add_int(child, "child_int", 8);
/* parent matches: test a mix of parent/child fields */
filter = event_filter_create();
test_assert(event_filter_parse("str=parent_str AND int1=0 AND int2=5", filter, &error) == 0);
test_assert(event_filter_match(filter, parent, &failure_ctx));
test_assert(!event_filter_match(filter, child, &failure_ctx));
event_filter_unref(&filter);
/* parent matches: test fields that exist only in parent */
filter = event_filter_create();
test_assert(event_filter_parse("parent_str=parent_str AND parent_int=6", filter, &error) == 0);
test_assert(event_filter_match(filter, parent, &failure_ctx));
test_assert(event_filter_match(filter, child, &failure_ctx));
event_filter_unref(&filter);
/* child matches: test a mix of parent/child fields */
filter = event_filter_create();
test_assert(event_filter_parse("str=child_str AND int1=6 AND int2=0", filter, &error) == 0);
test_assert(event_filter_match(filter, child, &failure_ctx));
test_assert(!event_filter_match(filter, parent, &failure_ctx));
event_filter_unref(&filter);
/* child matches: test fields that exist only in child */
filter = event_filter_create();
test_assert(event_filter_parse("child_str=child_str AND child_int=8", filter, &error) == 0);
test_assert(event_filter_match(filter, child, &failure_ctx));
test_assert(!event_filter_match(filter, parent, &failure_ctx));
event_filter_unref(&filter);
event_unref(&parent);
event_unref(&child);
test_end();
}
static void test_event_filter_override_global_fields(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: override global fields");
struct event *global = event_create(NULL);
event_add_str(global, "str", "global_str");
event_add_str(global, "global_str", "global_str");
event_add_int(global, "int1", 0);
event_add_int(global, "int2", 5);
event_add_int(global, "global_int", 6);
event_push_global(global);
struct event *local = event_create(NULL);
event_add_str(local, "str", "local_str");
event_add_str(local, "local_str", "local_str");
event_add_int(local, "int1", 6);
event_add_int(local, "int2", 0);
event_add_int(local, "local_int", 8);
/* global matches: test a mix of global/local fields */
filter = event_filter_create();
test_assert(event_filter_parse("str=global_str AND int1=0 AND int2=5", filter, &error) == 0);
test_assert(event_filter_match(filter, global, &failure_ctx));
test_assert(!event_filter_match(filter, local, &failure_ctx));
event_filter_unref(&filter);
/* global matches: test fields that exist only in global */
filter = event_filter_create();
test_assert(event_filter_parse("global_str=global_str AND global_int=6", filter, &error) == 0);
test_assert(event_filter_match(filter, global, &failure_ctx));
test_assert(event_filter_match(filter, local, &failure_ctx));
event_filter_unref(&filter);
/* local matches: test a mix of global/local fields */
filter = event_filter_create();
test_assert(event_filter_parse("str=local_str AND int1=6 AND int2=0", filter, &error) == 0);
test_assert(event_filter_match(filter, local, &failure_ctx));
test_assert(!event_filter_match(filter, global, &failure_ctx));
event_filter_unref(&filter);
/* local matches: test fields that exist only in local */
filter = event_filter_create();
test_assert(event_filter_parse("local_str=local_str AND local_int=8", filter, &error) == 0);
test_assert(event_filter_match(filter, local, &failure_ctx));
test_assert(!event_filter_match(filter, global, &failure_ctx));
event_filter_unref(&filter);
event_pop_global(global);
event_unref(&global);
event_unref(&local);
test_end();
}
static void test_event_filter_clear_parent_fields(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
const char *keys[] = { "str", "int" };
test_begin("event filter: clear parent fields");
struct event *parent = event_create(NULL);
event_add_str(parent, "str", "parent_str");
event_add_int(parent, "int", 0);
struct event *child = event_create(parent);
event_field_clear(child, "str");
event_field_clear(child, "int");
for (unsigned int i = 0; i < N_ELEMENTS(keys); i++) {
/* match any value */
const char *query = t_strdup_printf("%s=*", keys[i]);
filter = event_filter_create();
test_assert(event_filter_parse(query, filter, &error) == 0);
test_assert_idx(event_filter_match(filter, parent, &failure_ctx), i);
test_assert_idx(!event_filter_match(filter, child, &failure_ctx), i);
event_filter_unref(&filter);
}
/* match empty field */
filter = event_filter_create();
test_assert(event_filter_parse("str=\"\"", filter, &error) == 0);
test_assert(!event_filter_match(filter, parent, &failure_ctx));
test_assert(event_filter_match(filter, child, &failure_ctx));
event_filter_unref(&filter);
/* match nonexistent field */
filter = event_filter_create();
test_assert(event_filter_parse("nonexistent=\"\"", filter, &error) == 0);
test_assert(event_filter_match(filter, parent, &failure_ctx));
test_assert(event_filter_match(filter, child, &failure_ctx));
event_filter_unref(&filter);
event_unref(&parent);
event_unref(&child);
test_end();
}
static void test_event_filter_clear_global_fields(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
const char *keys[] = { "str", "int" };
test_begin("event filter: clear global fields");
struct event *global = event_create(NULL);
event_add_str(global, "str", "global_str");
event_add_int(global, "int", 0);
event_push_global(global);
struct event *local = event_create(NULL);
event_field_clear(local, "str");
event_field_clear(local, "int");
for (unsigned int i = 0; i < N_ELEMENTS(keys); i++) {
/* match any value */
const char *query = t_strdup_printf("%s=*", keys[i]);
filter = event_filter_create();
test_assert(event_filter_parse(query, filter, &error) == 0);
test_assert_idx(event_filter_match(filter, global, &failure_ctx), i);
test_assert_idx(!event_filter_match(filter, local, &failure_ctx), i);
event_filter_unref(&filter);
}
/* match empty field */
filter = event_filter_create();
test_assert(event_filter_parse("str=\"\"", filter, &error) == 0);
test_assert(!event_filter_match(filter, global, &failure_ctx));
test_assert(event_filter_match(filter, local, &failure_ctx));
event_filter_unref(&filter);
/* match nonexistent field */
filter = event_filter_create();
test_assert(event_filter_parse("nonexistent=\"\"", filter, &error) == 0);
test_assert(event_filter_match(filter, global, &failure_ctx));
test_assert(event_filter_match(filter, local, &failure_ctx));
event_filter_unref(&filter);
event_pop_global(global);
event_unref(&global);
event_unref(&local);
test_end();
}
static void test_event_filter_inc_int(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: create and update keys with event_inc_int");
struct event *root = event_create(NULL);
filter = event_filter_create();
test_assert(event_filter_parse("int=14", filter, &error) == 0);
const struct event_field *f = event_find_field_recursive(root, "int");
i_assert(f == NULL);
test_assert(!event_filter_match(filter, root, &failure_ctx));
event_inc_int(root, "int", 7);
test_assert(!event_filter_match(filter, root, &failure_ctx));
f = event_find_field_recursive(root, "int");
i_assert(f != NULL);
test_assert_strcmp(f->key, "int");
test_assert(f->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX);
test_assert(f->value.intmax == 7);
event_inc_int(root, "int", 7);
test_assert(event_filter_match(filter, root, &failure_ctx));
f = event_find_field_recursive(root, "int");
i_assert(f != NULL);
test_assert_strcmp(f->key, "int");
test_assert(f->value_type == EVENT_FIELD_VALUE_TYPE_INTMAX);
test_assert(f->value.intmax == 14);
event_filter_unref(&filter);
event_unref(&root);
test_end();
}
static void test_event_filter_parent_category_match(void)
{
static struct event_category parent_category = {
.name = "parent",
};
static struct event_category child_category = {
.parent = &parent_category,
.name = "child",
};
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: parent category match");
struct event *e = event_create(NULL);
event_add_category(e, &child_category);
filter = event_filter_create();
test_assert(event_filter_parse("category=parent", filter, &error) == 0);
test_assert(event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
event_unref(&e);
test_end();
}
static void test_event_filter_strlist(void)
{
struct event_filter *filter;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: match string list");
struct event *e = event_create(NULL);
filter = event_filter_create();
/* should match empty list */
event_filter_parse("abc=\"\"", filter, NULL);
test_assert(event_filter_match(filter, e, &failure_ctx));
/* should still be empty */
event_strlist_append(e, "abc", NULL);
test_assert(event_filter_match(filter, e, &failure_ctx));
/* should not match non-empty list */
event_strlist_append(e, "abc", "one");
test_assert(!event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
/* should match non-empty list that has value 'one' */
filter = event_filter_create();
event_strlist_append(e, "abc", "two");
event_filter_parse("abc=one", filter, NULL);
test_assert(event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
/* should match non-empty list that has no value 'three' */
filter = event_filter_create();
event_filter_parse("abc=one AND NOT abc=three", filter, NULL);
test_assert(event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
event_unref(&e);
test_end();
}
static void test_event_filter_strlist_recursive(void)
{
struct event_filter *filter;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: match string list - recursive");
struct event *parent = event_create(NULL);
struct event *e = event_create(parent);
/* empty filter: parent is non-empty */
filter = event_filter_create();
event_filter_parse("list1=\"\"", filter, NULL);
test_assert(event_filter_match(filter, e, &failure_ctx));
event_strlist_append(parent, "list1", "foo");
test_assert(!event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
/* matching filter: matches parent */
filter = event_filter_create();
event_filter_parse("list2=parent", filter, NULL);
/* empty: */
test_assert(!event_filter_match(filter, e, &failure_ctx));
/* set parent but no child: */
event_strlist_append(parent, "list2", "parent");
test_assert(event_filter_match(filter, e, &failure_ctx));
/* set child to non-matching: */
event_strlist_append(e, "list2", "child");
test_assert(event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
/* matching filter: matches child */
filter = event_filter_create();
event_filter_parse("list3=child", filter, NULL);
/* empty: */
test_assert(!event_filter_match(filter, e, &failure_ctx));
/* set child but no parent: */
event_strlist_append(e, "list3", "child");
test_assert(event_filter_match(filter, e, &failure_ctx));
/* set parent to non-matching: */
event_strlist_append(e, "list3", "parent");
test_assert(event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
event_unref(&e);
event_unref(&parent);
test_end();
}
static void test_event_filter_strlist_global_events(void)
{
struct event_filter *filter;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: match string list - global events");
struct event *global = event_create(NULL);
event_push_global(global);
struct event *e = event_create(NULL);
/* empty filter: global is non-empty */
filter = event_filter_create();
event_filter_parse("list1=\"\"", filter, NULL);
test_assert(event_filter_match(filter, e, &failure_ctx));
event_strlist_append(global, "list1", "foo");
test_assert(!event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
/* matching filter: matches global */
filter = event_filter_create();
event_filter_parse("list2=global", filter, NULL);
/* empty: */
test_assert(!event_filter_match(filter, e, &failure_ctx));
/* set global but no local: */
event_strlist_append(global, "list2", "global");
test_assert(event_filter_match(filter, e, &failure_ctx));
/* set local to non-matching: */
event_strlist_append(e, "list2", "local");
test_assert(event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
/* matching filter: matches local */
filter = event_filter_create();
event_filter_parse("list3=local", filter, NULL);
/* empty: */
test_assert(!event_filter_match(filter, e, &failure_ctx));
/* set local but no global: */
event_strlist_append(e, "list3", "local");
test_assert(event_filter_match(filter, e, &failure_ctx));
/* set global to non-matching: */
event_strlist_append(e, "list3", "global");
test_assert(event_filter_match(filter, e, &failure_ctx));
event_filter_unref(&filter);
event_unref(&e);
event_pop_global(global);
event_unref(&global);
test_end();
}
static void test_event_filter_named_and_str(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: event name and str");
filter = event_filter_create();
struct event *e_noname_nostr = event_create(NULL);
struct event *e_noname_str = event_create(NULL);
event_add_str(e_noname_str, "str", "str");
struct event *e_noname_wrongstr = event_create(NULL);
event_add_str(e_noname_wrongstr, "str", "wrong");
struct event *e_named_nostr = event_create(NULL);
event_set_name(e_named_nostr, "named");
struct event *e_named_str = event_create(NULL);
event_set_name(e_named_str, "named");
event_add_str(e_named_str, "str", "str");
struct event *e_named_wrongstr = event_create(NULL);
event_set_name(e_named_wrongstr, "named");
event_add_str(e_named_wrongstr, "str", "wrong");
struct event *e_wrongname_nostr = event_create(NULL);
event_set_name(e_wrongname_nostr, "wrong");
struct event *e_wrongname_str = event_create(NULL);
event_set_name(e_wrongname_str, "wrong");
event_add_str(e_wrongname_str, "str", "str");
struct event *e_wrongname_wrongstr = event_create(NULL);
event_set_name(e_wrongname_wrongstr, "wrong");
event_add_str(e_wrongname_wrongstr, "str", "wrong");
test_assert(event_filter_parse("event=named AND str=str", filter, &error) == 0);
test_assert(filter->named_queries_only);
test_assert(!event_filter_match(filter, e_noname_nostr, &failure_ctx));
test_assert(!event_filter_match(filter, e_noname_str, &failure_ctx));
test_assert(!event_filter_match(filter, e_noname_wrongstr, &failure_ctx));
test_assert(!event_filter_match(filter, e_named_nostr, &failure_ctx));
test_assert(event_filter_match(filter, e_named_str, &failure_ctx));
test_assert(!event_filter_match(filter, e_named_wrongstr, &failure_ctx));
test_assert(!event_filter_match(filter, e_wrongname_nostr, &failure_ctx));
test_assert(!event_filter_match(filter, e_wrongname_str, &failure_ctx));
test_assert(!event_filter_match(filter, e_wrongname_wrongstr, &failure_ctx));
event_filter_unref(&filter);
event_unref(&e_noname_nostr);
event_unref(&e_noname_str);
event_unref(&e_noname_wrongstr);
event_unref(&e_named_nostr);
event_unref(&e_named_str);
event_unref(&e_named_wrongstr);
event_unref(&e_wrongname_nostr);
event_unref(&e_wrongname_str);
event_unref(&e_wrongname_wrongstr);
test_end();
}
static void test_event_filter_named_or_str(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: event name or str");
filter = event_filter_create();
struct event *e_noname_nostr = event_create(NULL);
struct event *e_noname_str = event_create(NULL);
event_add_str(e_noname_str, "str", "str");
struct event *e_noname_wrongstr = event_create(NULL);
event_add_str(e_noname_wrongstr, "str", "wrong");
struct event *e_named_nostr = event_create(NULL);
event_set_name(e_named_nostr, "named");
struct event *e_named_str = event_create(NULL);
event_set_name(e_named_str, "named");
event_add_str(e_named_str, "str", "str");
struct event *e_named_wrongstr = event_create(NULL);
event_set_name(e_named_wrongstr, "named");
event_add_str(e_named_wrongstr, "str", "wrong");
struct event *e_wrongname_nostr = event_create(NULL);
event_set_name(e_wrongname_nostr, "wrong");
struct event *e_wrongname_str = event_create(NULL);
event_set_name(e_wrongname_str, "wrong");
event_add_str(e_wrongname_str, "str", "str");
struct event *e_wrongname_wrongstr = event_create(NULL);
event_set_name(e_wrongname_wrongstr, "wrong");
event_add_str(e_wrongname_wrongstr, "str", "wrong");
test_assert(event_filter_parse("event=named OR str=str", filter, &error) == 0);
test_assert(!filter->named_queries_only);
test_assert(!event_filter_match(filter, e_noname_nostr, &failure_ctx));
test_assert(event_filter_match(filter, e_noname_str, &failure_ctx));
test_assert(!event_filter_match(filter, e_noname_wrongstr, &failure_ctx));
test_assert(event_filter_match(filter, e_named_nostr, &failure_ctx));
test_assert(event_filter_match(filter, e_named_str, &failure_ctx));
test_assert(event_filter_match(filter, e_named_wrongstr, &failure_ctx));
test_assert(!event_filter_match(filter, e_wrongname_nostr, &failure_ctx));
test_assert(event_filter_match(filter, e_wrongname_str, &failure_ctx));
test_assert(!event_filter_match(filter, e_wrongname_wrongstr, &failure_ctx));
event_filter_unref(&filter);
event_unref(&e_noname_nostr);
event_unref(&e_noname_str);
event_unref(&e_noname_wrongstr);
event_unref(&e_named_nostr);
event_unref(&e_named_str);
event_unref(&e_named_wrongstr);
event_unref(&e_wrongname_nostr);
event_unref(&e_wrongname_str);
event_unref(&e_wrongname_wrongstr);
test_end();
}
static void test_event_filter_named_separate_from_str(void)
{
struct event_filter *filter;
const char *error;
const struct failure_context failure_ctx = {
.type = LOG_TYPE_DEBUG
};
test_begin("event filter: event name separate from str");
filter = event_filter_create();
struct event *e_named = event_create(NULL);
event_set_name(e_named, "named");
struct event *e_noname = event_create(NULL);
event_add_str(e_noname, "str", "str");
test_assert(event_filter_parse("event=named", filter, &error) == 0);
test_assert(event_filter_parse("str=str", filter, &error) == 0);
test_assert(!filter->named_queries_only);
test_assert(event_filter_match(filter, e_named, &failure_ctx));
test_assert(event_filter_match(filter, e_noname, &failure_ctx));
event_filter_unref(&filter);
event_unref(&e_named);
event_unref(&e_noname);
test_end();
}
void test_event_filter(void)
{
test_event_filter_override_parent_fields();
test_event_filter_override_global_fields();
test_event_filter_clear_parent_fields();
test_event_filter_clear_global_fields();
test_event_filter_inc_int();
test_event_filter_parent_category_match();
test_event_filter_strlist();
test_event_filter_strlist_recursive();
test_event_filter_strlist_global_events();
test_event_filter_named_and_str();
test_event_filter_named_or_str();
test_event_filter_named_separate_from_str();
}
dovecot-2.3.21.1/src/lib/test-memarea.c 0000644 0000000 0000000 00000001776 14656633576 014415 0000000 0000000 /* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
#include "test-lib.h"
#include "buffer.h"
#include "memarea.h"
static bool test_callback_called = FALSE;
static void test_callback(buffer_t *buf)
{
test_assert(!test_callback_called);
test_callback_called = TRUE;
buffer_free(&buf);
}
void test_memarea(void)
{
struct memarea *area, *area2;
buffer_t *buf;
size_t size;
test_begin("memarea");
buf = buffer_create_dynamic(default_pool, 128);
buffer_append(buf, "123", 3);
area = memarea_init(buf->data, buf->used, test_callback, buf);
test_assert(memarea_get_refcount(area) == 1);
test_assert(memarea_get(area, &size) == buf->data && size == buf->used);
area2 = area;
memarea_ref(area2);
test_assert(memarea_get_refcount(area2) == 2);
test_assert(memarea_get(area2, &size) == buf->data && size == buf->used);
memarea_unref(&area2);
test_assert(area2 == NULL);
test_assert(!test_callback_called);
memarea_unref(&area);
test_assert(test_callback_called);
test_end();
}
dovecot-2.3.21.1/src/lib/nfs-workarounds.c 0000644 0000000 0000000 00000023642 14656633576 015167 0000000 0000000 /* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
/*
These tests were done with various Linux 2.6 kernels, FreeBSD 6.2 and
Solaris 8 and 10.
Attribute cache is usually flushed with chown()ing or fchown()ing the file.
The safest way would be to use uid=-1 gid=-1, but this doesn't work with
Linux (it does with FreeBSD 6.2 and Solaris). So we'll first get the
file's owner and use it. As long as we're not root the file's owner can't
change accidentally. If would be possible to also use chmod()/fchmod(), but
that's riskier since it could actually cause an unwanted change.
Write cache can be flushed with fdatasync(). It's all we need, but other
tested alternatives are: fcntl locking (Linux 2.6, Solaris),
fchown() (Solaris) and dup()+close() (Linux 2.6, Solaris).
Read cache flushing is more problematic. There's no universal way to do it.
The working methods are:
Linux 2.6: fcntl(), O_DIRECT
Solaris: fchown(), fcntl(), dup()+close()
FreeBSD 6.2: fchown()
fchown() can be easily used for Solaris and FreeBSD, but Linux requires
playing with locks. O_DIRECT requires CONFIG_NFS_DIRECTIO to be enabled, so
we can't always use it.
*/
#include "lib.h"
#include "path-util.h"
#include "nfs-workarounds.h"
#include
#include