Compare commits

..

1 Commits

Author SHA1 Message Date
Badlop 23bf45e881 Create tag for ejabberd 2.1.0 final release.
SVN Revision: 2737
2009-11-13 16:01:44 +00:00
253 changed files with 13351 additions and 17324 deletions
+4 -3
View File
@@ -9,7 +9,8 @@ To compile ejabberd you need:
- GNU Make
- GCC
- Libexpat 1.95 or higher
- Erlang/OTP R10B-9 or higher. Recommended versions: R12B-5 and R13B04
- Erlang/OTP R10B-9 or higher. The recommended version is R12B-5.
Support for R13 is experimental.
- OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL
encryption. Optional, highly recommended.
- Zlib 1.2.3 or higher, for Stream Compression support
@@ -19,8 +20,8 @@ To compile ejabberd you need:
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
- GNU Iconv 1.8 or higher, for the IRC Transport
(mod_irc). Optional. Not needed on systems with GNU Libc.
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
- exmpp 0.9.2 or higher. Optional. For import/export XEP-0227 files.
- ImageMagicks Convert program. Optional. For CAPTCHA challenges.
- exmpp 0.9.1 or higher. Optional. For import/export XEP-0227 files.
1. Compile and install on *nix systems
@@ -97,7 +97,7 @@ extract_lang_all ()
done
cd $MSGS_DIR
REVISION=`git describe --always`
REVISION=`svn info | grep "^Rev" | head -1 | awk '{print $2}'`
zip $HOME/ejabberd-langs-$REVISION.zip *.translate;
rm *.translate
+1 -1
View File
@@ -16,7 +16,7 @@ release:
@echo "* Do not forget to update the version number in src/ejabberd.app!"
@echo "* Do not forget to update the features in introduction.tex (including \new{} and \improved{} tags)."
@echo "Press any key to continue"
##@read foo
@read foo
@echo "% ejabberd version (automatically generated)." > version.tex
@echo "\newcommand{\version}{"`sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../src/ejabberd.app`"}" >> version.tex
@echo -n "% Contributed modules (automatically generated)." > contributed_modules.tex
+2 -5
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.4 Developers Guide
<TITLE>Ejabberd 2.1.0 Developers Guide
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -49,7 +49,7 @@ TD P{margin:0px;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.4 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.0 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
@@ -194,9 +194,6 @@ operation are as follows:
auth:User:Server:Password (check if a username/password pair is correct)
</LI><LI CLASS="li-itemize">isuser:User:Server (check if it&#X2019;s a valid user)
</LI><LI CLASS="li-itemize">setpass:User:Server:Password (set user&#X2019;s password)
</LI><LI CLASS="li-itemize">tryregister:User:Server:Password (try to register an account)
</LI><LI CLASS="li-itemize">removeuser:User:Server (remove this account)
</LI><LI CLASS="li-itemize">removeuser3:User:Server:Password (remove this account if the password is correct)
</LI></UL>
</LI></UL>
</LI><LI CLASS="li-itemize">write to stdout: AABB
-3
View File
@@ -176,9 +176,6 @@ That script is supposed to do theses actions, in an infinite loop:
\item auth:User:Server:Password (check if a username/password pair is correct)
\item isuser:User:Server (check if it's a valid user)
\item setpass:User:Server:Password (set user's password)
\item tryregister:User:Server:Password (try to register an account)
\item removeuser:User:Server (remove this account)
\item removeuser3:User:Server:Password (remove this account if the password is correct)
\end{itemize}
\end{itemize}
\item write to stdout: AABB
+2 -2
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.4 Feature Sheet
<TITLE>Ejabberd 2.1.0 Feature Sheet
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.4 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.0 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
+258 -384
View File
File diff suppressed because it is too large Load Diff
+92 -237
View File
@@ -92,13 +92,11 @@
\newcommand{\modrosterodbc}{\module{mod\_roster\_odbc}}
\newcommand{\modservicelog}{\module{mod\_service\_log}}
\newcommand{\modsharedroster}{\module{mod\_shared\_roster}}
\newcommand{\modsic}{\module{mod\_sic}}
\newcommand{\modstats}{\module{mod\_stats}}
\newcommand{\modtime}{\module{mod\_time}}
\newcommand{\modvcard}{\module{mod\_vcard}}
\newcommand{\modvcardldap}{\module{mod\_vcard\_ldap}}
\newcommand{\modvcardodbc}{\module{mod\_vcard\_odbc}}
\newcommand{\modvcardxupdate}{\module{mod\_vcard\_xupdate}}
\newcommand{\modversion}{\module{mod\_version}}
%% Contributed modules
@@ -310,7 +308,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need:
\item GNU Make
\item GCC
\item Libexpat 1.95 or higher
\item Erlang/OTP R10B-9 or higher. The recommended versions are R12B-5 and R13B04.
\item Erlang/OTP R10B-9 or higher. The recommended version is R12B-5. Support for R13 is experimental.
\item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
\item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional.
\item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}.
@@ -318,7 +316,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need:
\item PAM library. Optional. For Pluggable Authentication Modules (PAM). See section \ref{pam}.
\item GNU Iconv 1.8 or higher, for the IRC Transport (mod\_irc). Optional. Not needed on systems with GNU Libc. See section \ref{modirc}.
\item ImageMagick's Convert program. Optional. For CAPTCHA challenges. See section \ref{captcha}.
\item exmpp 0.9.2 or higher. Optional. For import/export user data with \xepref{0227} XML files.
\item exmpp 0.9.1 or higher. Optional. For import/export user data with \xepref{0227} XML files.
\end{itemize}
\makesubsection{download}{Download Source Code}
@@ -327,12 +325,10 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need:
Released versions of \ejabberd{} are available in the ProcessOne \ejabberd{} downloads page:
\ahrefurl{http://www.process-one.net/en/ejabberd/downloads}
\ind{Git repository}
Alternatively, the latest development source code can be retrieved from the Git repository using the commands:
\ind{Subversion repository}
Alternatively, the latest development version can be retrieved from the Subversion repository using this command:
\begin{verbatim}
git clone git://git.process-one.net/ejabberd/mainline.git ejabberd
cd ejabberd
git checkout -b 2.1.x origin/2.1.x
svn co http://svn.process-one.net/ejabberd/trunk ejabberd
\end{verbatim}
@@ -384,6 +380,21 @@ Some options that you may be interested in modifying:
Disable the use of Erlang/OTP supervision for transient processes.
\end{description}
\makesubsection{snowleopard}{Compiling ejabberd under Snow Leopard with Erlang R13B}
\ind{install!snowleopard}
Erl Interface, the library to link Erlang with C code, is compiled as
32-bits code in Erlang R13B-2. Mac OS X Snow Leopard is a 64-bits
system and will try compiling ejabberd C code in 64-bits as a default.
To compile ejabberd on Mac OS X Snow Leopard with Erlang R13B-2, you
need to force C code to be compiled with 32-bits. This is done with
the following configure command:
\begin{verbatim}
CC='gcc -m32' CFLAGS=-m32 LDFLAGS=-m32 ./configure
\end{verbatim}
\makesubsection{install}{Install}
\ind{install!install}
@@ -798,18 +809,18 @@ The available modules, their purpose and the options allowed by each one are:
\begin{description}
\titem{\texttt{ejabberd\_c2s}}
Handles c2s connections.\\
Options: \texttt{access}, \texttt{certfile}, \texttt{max\_fsm\_queue},
Options: \texttt{access}, \texttt{certfile},
\texttt{max\_stanza\_size}, \texttt{shaper},
\texttt{starttls}, \texttt{starttls\_required}, \texttt{tls},
\texttt{zlib}
\titem{\texttt{ejabberd\_s2s\_in}}
Handles incoming s2s connections.\\
Options: \texttt{max\_stanza\_size}, \texttt{shaper}
Options: \texttt{max\_stanza\_size}
\titem{\texttt{ejabberd\_service}}
Interacts with an \footahref{http://www.ejabberd.im/tutorials-transports}{external component}
(as defined in the Jabber Component Protocol (\xepref{0114}).\\
Options: \texttt{access}, \texttt{hosts}, \texttt{max\_fsm\_queue},
\texttt{service\_check\_from}, \texttt{shaper}
\texttt{shaper}, \texttt{service\_check\_from}
\titem{\texttt{ejabberd\_stun}}
Handles STUN Binding requests as defined in
\footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389}.\\
@@ -833,10 +844,13 @@ This is a detailed description of each option allowed by the listening modules:
lots of new incoming connections as they may be dropped if there is
no space in the queue (and ejabberd was not able to accept them
immediately). Default value is 5.
\titem{captcha} \ind{options!http-captcha}
Simple web page that allows a user to fill a CAPTCHA challenge (see section \ref{captcha}).
\titem{\{certfile, Path\}} Full path to a file containing the default SSL certificate.
To define a certificate file specific for a given domain, use the global option \term{domain\_certfile}.
\titem{\{service\_check\_from, true|false\}} \ind{options!service\_check\_from}
This option can be used with \term{ejabberd\_service} only. It is
used to disable control on the from field on packets send by an
external components. The option can be either \term{true} or
\term{false}. The default value is \term{true} which conforms to \xepref{0114}.
\titem{\{hosts, [Hostname, ...], [HostOption, ...]\}} \ind{options!hosts}
The external Jabber component that connects to this \term{ejabberd\_service}
can serve one or more hostnames.
@@ -846,6 +860,8 @@ This is a detailed description of each option allowed by the listening modules:
Note that you cannot define in a single \term{ejabberd\_service} components of
different services: add an \term{ejabberd\_service} for each service,
as seen in an example below.
\titem{captcha} \ind{options!http-captcha}
Simple web page that allows a user to fill a CAPTCHA challenge (see section \ref{captcha}).
\titem{http\_bind} \ind{options!http\_bind}\ind{protocols!XEP-0206: HTTP Binding}\ind{JWChat}\ind{web-based XMPP client}
This option enables HTTP Binding (\xepref{0124} and \xepref{0206}) support. HTTP Bind
enables access via HTTP requests to \ejabberd{} from behind firewalls which
@@ -878,27 +894,17 @@ This is a detailed description of each option allowed by the listening modules:
The option can be defined in \term{ejabberd.cfg}, expressing the time
in seconds: \verb|{http_poll_timeout, 300}.|
\titem{\{max\_fsm\_queue, Size\}}
This option specifies the maximum number of elements in the queue of the FSM
(Finite State Machine).
Roughly speaking, each message in such queues represents one XML
stanza queued to be sent into its relevant outgoing stream. If queue size
reaches the limit (because, for example, the receiver of stanzas is too slow),
the FSM and the corresponding connection (if any) will be terminated
and error message will be logged.
The reasonable value for this option depends on your hardware configuration.
However, there is no much sense to set the size above 1000 elements.
This option can be specified for \term{ejabberd\_service} and
\term{ejabberd\_c2s} listeners,
This option specifies the maximum number of elements in the queue of the FSM.
This option can be specified for an \term{ejabberd\_service} listener,
or also globally for \term{ejabberd\_s2s\_out}.
If the option is not specified for \term{ejabberd\_service} or
\term{ejabberd\_c2s} listeners,
If the option is not specified for an \term{ejabberd\_service} listener,
the globally configured value is used.
The allowed values are integers and 'undefined'.
Default value: 'undefined'.
\titem{\{max\_stanza\_size, Size\}}
\ind{options!max\_stanza\_size}This option specifies an
approximate maximum size in bytes of XML stanzas. Approximate,
because it is calculated with the precision of one block of read
because it is calculated with the precision of one block of readed
data. For example \verb|{max_stanza_size, 65536}|. The default
value is \term{infinity}. Recommended values are 65536 for c2s
connections and 131072 for s2s connections. s2s max stanza size
@@ -910,13 +916,10 @@ This is a detailed description of each option allowed by the listening modules:
and you also want \term{mod\_http\_bind} to serve the URIs \term{/http-bind/},
use this option: \term{\{request\_handlers, [\{["a", "b"], mod\_foo\}, \{["http-bind"], mod\_http\_bind\}]\}}
\titem{\{service\_check\_from, true|false\}}
\ind{options!service\_check\_from}
This option can be used with \term{ejabberd\_service} only.
\xepref{0114} requires that the domain must match the hostname of the component.
If this option is set to \term{false}, \ejabberd{} will allow the component
to send stanzas with any arbitrary domain in the 'from' attribute.
Only use this option if you are completely sure about it.
The default value is \term{true}, to be compliant with \xepref{0114}.
By enabling this option, \ejabberd{} allows the component to send packets with any arbitrary domain in the 'from' attribute.
Note that \xepref{0114} requires that the domain must match the hostname of the component.
Only enable this option if you are completely sure you need to enable it.
Default value: false.
\titem{\{shaper, none|ShaperName\}} \ind{options!shaper}This option defines a
shaper for the port (see section~\ref{shapers}). The default value
is \term{none}.
@@ -935,10 +938,9 @@ This is a detailed description of each option allowed by the listening modules:
commonly on port 5223 for client-to-server communications.
But this method is nowadays deprecated and not recommended.
The preferable encryption method is STARTTLS on port 5222, as defined
\footahref{http://xmpp.org/rfcs/rfc3920.html\#tls}{RFC 3920: XMPP Core},
\footahref{http://xmpp.org/specs/rfc3920.html\#tls}{RFC 3920: XMPP Core},
which can be enabled in \ejabberd{} with the option \term{starttls}.
If this option is set, you should also set the \option{certfile} option.
The option \term{tls} can also be used in \term{ejabberd\_http} to support HTTPS.
\titem{web\_admin} \ind{options!web\_admin}\ind{web admin}This option
enables the Web Admin for \ejabberd{} administration which is available
at \verb|http://server:port/admin/|. Login and password are the username and
@@ -977,28 +979,13 @@ There are some additional global options that can be specified in the ejabberd c
The maximum allowed delay for retry to connect after a failed connection attempt.
Specified in seconds. The default value is 300 seconds (5 minutes).
\titem{\{max\_fsm\_queue, Size\}}
This option specifies the maximum number of elements in the queue of the FSM
(Finite State Machine).
Roughly speaking, each message in such queues represents one XML
stanza queued to be sent into its relevant outgoing stream. If queue size
reaches the limit (because, for example, the receiver of stanzas is too slow),
the FSM and the corresponding connection (if any) will be terminated
and error message will be logged.
The reasonable value for this option depends on your hardware configuration.
However, there is no much sense to set the size above 1000 elements.
This option can be specified for \term{ejabberd\_service} and
\term{ejabberd\_c2s} listeners,
This option specifies the maximum number of elements in the queue of the FSM.
This option can be specified for an \term{ejabberd\_service} listener,
or also globally for \term{ejabberd\_s2s\_out}.
If the option is not specified for \term{ejabberd\_service} or
\term{ejabberd\_c2s} listeners,
If the option is not specified for an \term{ejabberd\_service} listener,
the globally configured value is used.
The allowed values are integers and 'undefined'.
Default value: 'undefined'.
\titem{\{route\_subdomains, local|s2s\}}
Defines if ejabberd must route stanzas directed to subdomains locally (compliant with
\footahref{http://xmpp.org/rfcs/rfc3920.html\#rules.subdomain}{RFC 3920: XMPP Core}),
or to foreign server using S2S (compliant with
\footahref{http://tools.ietf.org/html/draft-saintandre-rfc3920bis-09\#section-11.3}{RFC 3920 bis}).
\end{description}
\makesubsubsection{listened-examples}{Examples}
@@ -1187,7 +1174,8 @@ for user authentication. The syntax is:
The following authentication methods are supported by \ejabberd{}:
\begin{itemize}
\item internal (default) --- See section~\ref{internalauth}.
\item external --- See section~\ref{extauth}.
\item external --- There are \footahref{http://www.ejabberd.im/extauth}{some
example authentication scripts}.
\item ldap --- See section~\ref{ldap}.
\item odbc --- See section~\ref{mysql}, \ref{pgsql},
\ref{mssql} and \ref{odbc}.
@@ -1195,7 +1183,7 @@ The following authentication methods are supported by \ejabberd{}:
\item pam --- See section~\ref{pam}.
\end{itemize}
Account creation is only supported by internal, external and odbc methods.
Account creation is only supported by internal and odbc methods.
\makesubsubsection{internalauth}{Internal}
\ind{internal authentication}\ind{Mnesia}
@@ -1217,42 +1205,6 @@ Examples:
\end{verbatim}
\end{itemize}
\makesubsubsection{extauth}{External Script}
\ind{external authentication}
In this authentication method, when \ejabberd{} starts,
it start a script, and calls it to perform authentication tasks.
The server administrator can write the external authentication script
in any language.
The details on the interface between ejabberd and the script are described
in the \term{ejabberd Developers Guide}.
There are also \footahref{http://www.ejabberd.im/extauth}{several example authentication scripts}.
These are the specific options:
\begin{description}
\titem{\{extauth\_program, PathToScript\}}
Indicate in this option the full path to the external authentication script.
The script must be executable by ejabberd.
\titem{\{extauth\_cache, false|CacheTimeInteger\}}
The value \term{false} disables the caching feature, this is the default.
The integer \term{0} (zero) enables caching for statistics, but doesn't use that cached information to authenticate users.
If another integer value is set, caching is enabled both for statistics and for authentication:
the CacheTimeInteger indicates the number of seconds that ejabberd can reuse
the authentication information since the user last disconnected,
to verify again the user authentication without querying again the extauth script.
Note: caching should not be enabled in a host if internal auth is also enabled.
If caching is enabled, \term{mod\_last} or \term{mod\_last\_odbc} must be enabled also in that vhost.
\end{description}
This example sets external authentication, the extauth script, and enables caching for 10 minutes:
\begin{verbatim}
{auth_method, [external]}.
{extauth_program, "/etc/ejabberd/JabberAuth.class.php"}.
{extauth_cache, 600}.
\end{verbatim}
\makesubsubsection{saslanonymous}{SASL Anonymous and Anonymous Login}
\ind{sasl anonymous}\ind{anonymous login}
@@ -1333,10 +1285,6 @@ Options:
\titem{\{pam\_service, Name\}}\ind{options!pam\_service}This option defines the PAM service name.
Default is \term{"ejabberd"}. Refer to the PAM documentation of your operation system
for more information.
\titem{\{pam\_userinfotype, username|jid\}}\ind{options!pam\_userinfotype}
This option defines what type of information about the user ejabberd
provides to the PAM service: only the username, or the user JID.
Default is \term{username}.
\end{description}
Example:
@@ -1490,11 +1438,6 @@ second elements of the tuples in the list. If it matches, the first element of
the first matched tuple is returned, otherwise the value `\term{deny}' is
returned.
If you define specific Access rights in a virtual host,
remember that the globally defined Access rights have precedence over those.
This means that, in case of conflict, the Access granted or denied in the global server is used
and the Access of a virtual host doesn't have effect.
Example:
\begin{verbatim}
{access, configure, [{allow, admin}]}.
@@ -1531,7 +1474,7 @@ This example limits the number of sessions per user to 5 for all users, and to 1
\ind{options!max\_s2s\_connections}
The special access \term{max\_s2s\_connections} specifies how many
simultaneous S2S connections can be established to a specific remote XMPP server.
simultaneus S2S connections can be established to a specific remote XMPP server.
The default value is \term{1}.
There's also available the access \term{max\_s2s\_connections\_per\_node}.
@@ -1990,9 +1933,19 @@ enabled. This can be done, by using next commands:
\makesubsubsection{configuremssql}{Database Connection}
\ind{Microsoft SQL Server!Database Connection}
The configuration of Database Connection for a Microsoft SQL Server
is the same as the configuration for
ODBC compatible servers (see section~\ref{configureodbc}).
By default \ejabberd{} opens 10 connections to the database for each virtual host.
Use this option to modify the value:
\begin{verbatim}
{odbc_pool_size, 10}.
\end{verbatim}
You can configure an interval to make a dummy SQL request
to keep alive the connections to the database.
The default value is 'undefined', so no keepalive requests are made.
Specify in seconds: for example 28800 means 8 hours.
\begin{verbatim}
{odbc_keepalive_interval, undefined}.
\end{verbatim}
\makesubsubsection{mssqlauth}{Authentication}
@@ -2000,8 +1953,7 @@ ODBC compatible servers (see section~\ref{configureodbc}).
%TODO: not sure if this section is right!!!!!!
The configuration of Authentication for a Microsoft SQL Server
is the same as the configuration for
The configuration of Microsoft SQL Server is the same as the configuration of
ODBC compatible servers (see section~\ref{odbcauth}).
\makesubsubsection{mssqlstorage}{Storage}
@@ -2198,12 +2150,9 @@ module loaded!
server and use LDAP directory as vCard storage. Shared rosters are not supported
yet.
Usually \ejabberd{} treats LDAP as a read-only storage:
Note that \ejabberd{} treats LDAP as a read-only storage:
it is possible to consult data, but not possible to
create accounts or edit vCard that is stored in LDAP.
However, it is possible to change passwords if \module{mod\_register} module is enabled
and LDAP server supports
\footahref{http://tools.ietf.org/html/rfc3062}{RFC 3062}.
create accounts, change password or edit vCard that is stored in LDAP.
\makesubsubsection{ldapconnection}{Connection}
@@ -2217,11 +2166,6 @@ Allowed values are: \term{none}, \term{tls}.
The value \term{tls} enables encryption by using LDAP over SSL.
Note that STARTTLS encryption is not supported.
The default value is: \term{none}.
\titem{\{ldap\_tls\_verify, false|soft|hard\}} \ind{options!ldap\_tls\_verify}
This option specifies whether to verify LDAP server certificate or not when TLS is enabled.
When \term{hard} is enabled \ejabberd{} doesn't proceed if a certificate is invalid.
When \term{soft} is enabled \ejabberd{} proceeds even if check fails.
The default is \term{false} which means no checks are performed.
\titem{\{ldap\_port, Number\}} \ind{options!ldap\_port}Port to connect to your LDAP server.
The default port is~389 if encryption is disabled; and 636 if encryption is enabled.
If you configure a value, it is stored in \ejabberd{}'s database.
@@ -2242,7 +2186,8 @@ Example:
{ldap_password, "secret"}.
\end{verbatim}
Note that current LDAP implementation does not support SASL authentication.
Note that current LDAP implementation does not support SSL secured communication
and SASL authentication.
\makesubsubsection{ldapauth}{Authentication}
@@ -2271,27 +2216,12 @@ You can authenticate users against an LDAP directory. Available options are:
\titem{\{ldap\_filter, Filter\}}\ind{options!ldap\_filter}\ind{protocols!RFC 4515:
LDAP String Representation of Search Filters}
\footahref{http://tools.ietf.org/html/rfc4515}{RFC 4515} LDAP filter. The
default Filter value is: \term{undefined}. Example:
default is \term{none}. Example:
\term{"(\&(objectClass=shadowAccount)(memberOf=Jabber Users))"}. Please, do
not forget to close brackets and do not use superfluous whitespaces. Also you
\emph{must not} use \option{ldap\_uidattr} attribute in filter because this
attribute will be substituted in LDAP filter automatically.
\titem{\{ldap\_dn\_filter, \{ Filter, FilterAttrs \}\}}\ind{options!ldap\_dn\_filter}
This filter is applied on the results returned by the main filter. This filter
performs additional LDAP lookup to make the complete result. This is useful
when you are unable to define all filter rules in \term{ldap\_filter}. You
can define \term{"\%u"}, \term{"\%d"}, \term{"\%s"} and \term{"\%D"} pattern
variables in Filter: \term{"\%u"} is replaced by a user's part of a JID,
\term{"\%d"} is replaced by the corresponding domain (virtual host),
all \term{"\%s"} variables are consecutively replaced by values of FilterAttrs
attributes and \term{"\%D"} is replaced by Distinguished Name. By default
\term{ldap\_dn\_filter} is undefined.
Example:
\begin{verbatim}
{ldap_dn_filter, {"(&(name=%s)(owner=%D)(user=%u@%d))", ["sn"]}}.
\end{verbatim}
Since this filter makes additional LDAP lookups, use it only in the
last resort: try to define all filter rules in \term{ldap\_filter} if possible.
\titem{\{ldap\_local\_filter, Filter\}}\ind{options!ldap\_local\_filter}
If you can't use \term{ldap\_filter} due to performance reasons
(the LDAP server has many users registered),
@@ -2518,13 +2448,11 @@ The following table lists all modules included in \ejabberd{}.
\hline \ahrefloc{modservicelog}{\modservicelog{}} & Copy user messages to logger service & \\
\hline \ahrefloc{modsharedroster}{\modsharedroster{}} & Shared roster management & \modroster{} or \\
& & \modrosterodbc\\
\hline \ahrefloc{modsic}{\modsic{}} & Server IP Check (\xepref{0279}) & \\
\hline \ahrefloc{modstats}{\modstats{}} & Statistics Gathering (\xepref{0039}) & \\
\hline \ahrefloc{modtime}{\modtime{}} & Entity Time (\xepref{0202}) & \\
\hline \ahrefloc{modvcard}{\modvcard{}} & vcard-temp (\xepref{0054}) & \\
\hline \ahrefloc{modvcardldap}{\modvcardldap{}} & vcard-temp (\xepref{0054}) & LDAP server \\
\hline \ahrefloc{modvcard}{\modvcardodbc{}} & vcard-temp (\xepref{0054}) & supported DB (*) \\
\hline \ahrefloc{modvcardxupdate}{\modvcardxupdate{}} & vCard-Based Avatars (\xepref{0153}) & \modvcard{} or \modvcardodbc{} \\
\hline \ahrefloc{modversion}{\modversion{}} & Software Version (\xepref{0092}) & \\
\hline
\end{tabular}
@@ -2926,11 +2854,12 @@ Options:
DirectoryIndex variable. When a web request hits a directory
instead of a regular file, those directory indices are looked in
order, and the first one found is returned.
\titem{\{custom\_headers, [ \{Name, Value\}, ...]\}} \ind{options!customheaders}
Indicate custom HTTP headers to be included in all responses.
Default value is: \term{[]}
\titem{\{content\_types, [ \{Name, Type\}, ...]\}} \ind{options!contenttypes}
Specify mappings of extension to content type.
%B \titem{content\_types} \ind{options!contenttypes}
%M \titem{\{content\_types, \{Extension, Type\} \}} \ind{options!contenttypes}
%B \titem{\{content\_types, [ Extension, Type, ... ]\}} \ind{options!contenttypes}
%B \titem{\{content\_types, [ {Extension, Type}, ... ]\}} \ind{options!contenttypes}
%M \titem{\{content\_types, [ \{Extension, Type\}, ... ]\}} \ind{options!contenttypes}
Specify a mapping of extensions to content types.
There are several content types already defined,
with this option you can add new definitions, modify or delete existing ones.
To delete an existing definition, simply define it with a value: `undefined'.
@@ -2953,9 +2882,6 @@ To use this module you must enable it:
{docroot, "/var/www"},
{accesslog, "/var/log/ejabberd/access.log"},
{directory_indices, ["index.html", "main.htm"]},
{custom_headers, [{"X-Powered-By", "Erlang/OTP"},
{"X-Fry", "It's a widely-believed fact!"}
]},
{content_types, [{".ogg", "audio/ogg"},
{".png", "image/png"},
{".jpg", undefined}
@@ -3454,7 +3380,7 @@ online again. Thus it is very similar to how email works. Note that
(see section~\ref{ejabberdctl}).
\begin{description}
\titem{\{access\_max\_user\_messages, AccessName\}}\ind{options!access\_max\_user\_messages}
\titem{\{access\_max\_user\_messages, Number\}}\ind{options!access\_max\_user\_messages}
This option defines which access rule will be enforced to limit
the maximum number of offline messages that a user can have (quota).
When a user has too many offline messages, any new messages that he receive are discarded,
@@ -3545,7 +3471,7 @@ their \XMPP{} client, they will be able to:
\item Allowing or blocking all communications based on JID, group, or
subscription type (or globally).
\end{itemize}
(from \ahrefurl{http://xmpp.org/rfcs/rfc3921.html\#privacy})
(from \ahrefurl{http://xmpp.org/specs/rfc3921.html\#privacy})
\end{quote}
Options:
@@ -3586,12 +3512,6 @@ to listen for. Default is an IP address of the service's DNS name, or,
if fails, \verb|{127,0,0,1}|.
\titem{\{port, Number\}}\ind{options!port}This option defines port to listen for
incoming connections. Default is~7777.
\titem{\{hostname, HostName\}}\ind{options!hostname}Defines a hostname advertised
by the service when establishing a session with clients. This is useful when
you run the service behind a NAT. The default is the value of \term{ip} option.
Examples: \term{"proxy.mydomain.org"}, \term{"200.150.100.50"}. Note that
not all clients understand domain names in stream negotiation,
so you should think twice before setting domain name in this option.
\titem{\{auth\_type, anonymous|plain\}}\ind{options!auth\_type}SOCKS5 authentication type.
Possible values are \term{anonymous} and \term{plain}. Default is
\term{anonymous}.
@@ -3651,8 +3571,6 @@ and it requires \modcaps{}.
Options:
\begin{description}
\hostitem{pubsub}
If you use \modpubsubodbc, please ensure the prefix contains only one dot,
for example `\jid{pubsub.}', or `\jid{publish.}',.
\titem{\{access\_createnode, AccessName\}} \ind{options!access\_createnode}
This option restricts which users are allowed to create pubsub nodes using
ACL and ACCESS.
@@ -3749,10 +3667,6 @@ Options:
rules to restrict registration. If a rule returns `deny' on the requested
user name, registration for that user name is denied. (there are no
restrictions by default).
\titem{\{access\_from, AccessName\}} \ind{options!access\_from}By default, \ejabberd{}
doesn't allow to register new accounts from s2s or existing c2s sessions. You can
change it by defining access rule in this option. Use with care: allowing registration
from s2s leads to uncontrolled massive accounts creation by rogue users.
\titem{\{welcome\_message, Message\}} \ind{options!welcomem}Set a welcome message that
is sent to each newly registered account. The first string is the subject, and
the second string is the message body.
@@ -3836,7 +3750,7 @@ Also define a registration timeout of one hour:
\ind{modules!\modroster{}}\ind{roster management}\ind{protocols!RFC 3921: XMPP IM}
This module implements roster management as defined in
\footahref{http://xmpp.org/rfcs/rfc3921.html\#roster}{RFC 3921: XMPP IM}.
\footahref{http://xmpp.org/specs/rfc3921.html\#roster}{RFC 3921: XMPP IM}.
It also supports Roster Versioning (\xepref{0237}).
Options:
@@ -4014,17 +3928,6 @@ Examples:
\end{table}
\end{itemize}
\makesubsection{modsic}{\modsic{}}
\ind{modules!\modstats{}}\ind{protocols!XEP-0279: Server IP Check}
This module adds support for Server IP Check (\xepref{0279}). This protocol
enables a client to discover its external IP address.
Options:
\begin{description}
\iqdiscitem{\ns{urn:xmpp:sic:0}}
\end{description}
\makesubsection{modstats}{\modstats{}}
\ind{modules!\modstats{}}\ind{protocols!XEP-0039: Statistics Gathering}\ind{statistics}
@@ -4147,12 +4050,9 @@ Examples:
implemented in the \modvcardldap{} module. This module does not depend on the
authentication method (see~\ref{ldapauth}).
Usually \ejabberd{} treats LDAP as a read-only storage:
Note that \ejabberd{} treats LDAP as a read-only storage:
it is possible to consult data, but not possible to
create accounts or edit vCard that is stored in LDAP.
However, it is possible to change passwords if \module{mod\_register} module is enabled
and LDAP server supports
\footahref{http://tools.ietf.org/html/rfc3062}{RFC 3062}.
create accounts, change password or edit vCard that is stored in LDAP.
The \modvcardldap{} module has
its own optional parameters. The first group of parameters has the same
@@ -4356,27 +4256,6 @@ searching his info in LDAP.
\end{verbatim}
\end{itemize}
\makesubsection{modvcardxupdate}{\modvcardxupdate{}}
\ind{modules!\modvcardxupdate{}}\ind{protocols!XEP-0153: vCard-Based Avatars}
The user's client can store an avatar in the user vCard.
The vCard-Based Avatars protocol (\xepref{0153})
provides a method for clients to inform the contacts what is the avatar hash value.
However, simple or small clients may not implement that protocol.
If this module is enabled, all the outgoing client presence stanzas get automatically
the avatar hash on behalf of the client.
So, the contacts receive the presence stanzas with the Update Data described
in \xepref{0153} as if the client would had inserted it itself.
If the client had already included such element in the presence stanza,
it is replaced with the element generated by ejabberd.
By enabling this module, each vCard modification produces a hash recalculation,
and each presence sent by a client produces hash retrieval and a
presence stanza rewrite.
For this reason, enabling this module will introduce a computational overhead
in servers with clients that change frequently their presence.
\makesubsection{modversion}{\modversion{}}
\ind{modules!\modversion{}}\ind{protocols!XEP-0092: Software Version}
@@ -4511,7 +4390,7 @@ The command line parameters:
\titem{-name ejabberd}
The Erlang node will be fully identified.
This is only useful if you plan to setup an \ejabberd{} cluster with nodes in different networks.
\titem{-kernel inetrc '"/etc/ejabberd/inetrc"'}
\titem{-kernel inetrc "/etc/ejabberd/inetrc"}
Indicates which IP name resolution to use.
If using \term{-sname}, specify either this option or \term{ERL\_INETRC}.
\titem{-kernel inet\_dist\_listen\_min 4200 inet\_dist\_listen\_min 4210}
@@ -4526,7 +4405,7 @@ The command line parameters:
Specify the directory where Erlang binary files (*.beam) are located.
\titem{-s ejabberd}
Tell Erlang runtime system to start the \ejabberd{} application.
\titem{-mnesia dir '"/var/lib/ejabberd/"'}
\titem{-mnesia dir "/var/lib/ejabberd/"}
Specify the Mnesia database directory.
\titem{-sasl sasl\_error\_logger \{file, "/var/log/ejabberd/erlang.log"\}}
Path to the Erlang/OTP system log file.
@@ -4588,13 +4467,11 @@ The most interesting ones are:
Store internal Mnesia database to a binary backup file.
\titem {restore ejabberd.backup}
Restore immediately from a binary backup file the internal Mnesia database.
This will consume a lot of memory if you have a large database,
so better use \term{install\_fallback}.
This will consume quite some memory for big servers.
\titem {install\_fallback ejabberd.backup}
The binary backup file is installed as fallback:
it will be used to restore the database at the next ejabberd start.
This means that, after running this command, you have to restart ejabberd.
This command requires less memory than \term{restore}.
Similar to \term{restore}, but requires less memory.
\titem {dump ejabberd.dump}
Dump internal Mnesia database to a text file dump.
\titem {load ejabberd.dump}
@@ -4608,7 +4485,8 @@ The most interesting ones are:
using \xepref{0227} formatted XML files
from/to other Jabber/XMPP servers
or move users of a vhost to another ejabberd installation.
See also \footahref{https://support.process-one.net/doc/display/MESSENGER/ejabberd+migration+kit}{ejabberd migration kit}.
See also
\footahref{https://support.process-one.net/doc/display/P1/ejabberd+migration+kit}{ejabberd migration kit}.
\titem{import\_file, import\_dir} \ind{migration from other software}
These options can be used to migrate accounts
using jabberd1.4 formatted XML files.
@@ -4640,8 +4518,9 @@ ArgumentValue = any()
\end{verbatim}
The default value is to not define any restriction: \term{[]}.
The authentication information is provided when executing a command,
and is Username, Hostname and Password of a local XMPP account
If at least one restriction is defined, then the frontend expects
that authentication information is provided when executing a command.
The authentication information is Username, Hostname and Password of a local XMPP account
that has permission to execute the corresponding command.
This means that the account must be registered in the local ejabberd,
because the information will be verified.
@@ -4708,10 +4587,7 @@ Here you can edit access restrictions, manage users, create backups,
manage the database, enable/disable ports listened for, view server
statistics,\ldots
The access rule \term{configure} determines what accounts can access the Web Admin and modify it.
The access rule \term{webadmin\_view} is to grant only view access: those accounts can browse the Web Admin with read-only access.
Example configurations:
Examples:
\begin{itemize}
\item You can serve the Web Admin on the same port as the
\ind{protocols!XEP-0025: HTTP Polling}HTTP Polling interface. In this example
@@ -4725,14 +4601,10 @@ Example configurations:
URL). If you log in with `\jid{admin@example.com}' on \\
\verb|http://example.org:5280/admin/server/example.com/| you can only
administer the virtual host \jid{example.com}.
The account `\jid{reviewer@example.com}' can browse that vhost in read-only mode.
\begin{verbatim}
{acl, admins, {user, "admin", "example.net"}}.
{host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}.
{host_config, "example.com", [{acl, viewers, {user, "reviewer", "example.com"}}]}.
{access, configure, [{allow, admins}]}.
{access, webadmin_view, [{allow, viewers}]}.
{hosts, ["example.org"]}.
@@ -4848,26 +4720,9 @@ ejabberdctl start
ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE
\end{verbatim}
\item Install the backup file as a fallback:
\item Import the new backup:
\begin{verbatim}
ejabberdctl install_fallback $NEWFILE
\end{verbatim}
\item Stop ejabberd:
\begin{verbatim}
ejabberdctl stop
\end{verbatim}
You may see an error message in the log files, it's normal, so don't worry:
\begin{verbatim}
Mnesia(ejabberd@newmachine):
** ERROR ** (ignoring core)
** FATAL ** A fallback is installed and Mnesia must be restarted.
Forcing shutdown after mnesia_down from ejabberd@newmachine...
\end{verbatim}
\item Now you can finally start ejabberd:
\begin{verbatim}
ejabberdctl start
ejabberdctl restore $NEWFILE
\end{verbatim}
\item Check that the information of the old database is available: accounts, rosters...
@@ -5060,7 +4915,7 @@ following steps:
\item Copy \verb|~ejabberd/.erlang.cookie| file from \term{first} to
\term{second}.
(alt) You can also add `\verb|-setcookie content_of_.erlang.cookie|'
(alt) You can also add `\verb|-cookie content_of_.erlang.cookie|'
option to all `\shell{erl}' commands below.
\item On \term{second} run the following command as the \ejabberd{} daemon user,
@@ -5068,7 +4923,7 @@ following steps:
\begin{verbatim}
erl -sname ejabberd \
-mnesia dir '"/var/lib/ejabberd/"' \
-mnesia dir "/var/lib/ejabberd/" \
-mnesia extra_db_nodes "['ejabberd@first']" \
-s mnesia
\end{verbatim}
@@ -5337,7 +5192,7 @@ Thanks to all people who contributed to this guide:
\makechapter{copyright}{Copyright Information}
Ejabberd Installation and Operation Guide.\\
Copyright \copyright{} 2003 --- 2010 ProcessOne
Copyright \copyright{} 2003 --- 2009 ProcessOne
This document is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
-47
View File
@@ -1,47 +0,0 @@
Release Notes
ejabberd 2.1.1
ejabberd 2.1.1 is the first bugfix release in ejabberd 2.1.x branch.
ejabberd 2.1.1 includes several important bugfixes.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.1.1
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The changes are:
* Core
- Call ejabberd_router:route/3 instead of sending a message
- Can't connect if starttls_required and zlib are set
- Routes vCard request to the occupant full JID, but should to bare JID
- S2S: fix allow_host/2 on subdomains. added hook s2s_allow_host
* MUC
- Support converting one-to-one chat to MUC
- Add support for serving a Unique Room Name
* Publish Subscribe
- Receive same last published PEP items at reconnect if several resources online
- Typo in mod_pubsub_odbc breaks Service Discovery and more
* Web
- Fix memory and port leak when TLS is enabled in HTTP
- WebAdmin doesn't report correct last activity with postgresql backend
- Option to define custom HTTP headers in mod_http_fileserver
- Show informative webpage when browsing the HTTP-Poll page
* Other
- Change captcha.sh to not depend on bash
- Generate main XML file also when exporting only a vhost
- Fix last newline in ejabberdctl result
- Guide: fix -setcookie, mod_pubsub_odbc host, content_types
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
-51
View File
@@ -1,51 +0,0 @@
Release Notes
ejabberd 2.1.2
ejabberd 2.1.2 is the second bugfix release in ejabberd 2.1.x branch.
ejabberd 2.1.2 includes several bugfixes.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.1.2
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The major changes are:
* Core
- Close sessions that were half connected
- Fix SASL PLAIN authentication message for RFC4616 compliance
- Fix support for old Erlang/OTP R10 and R11
- Return proper error (not 'conflict') when register is forbidden by ACL
- When ejabberd stops, send stream close to clients
* ejabberdctl
- Check for EGID in ejabberdctl command
- Command to stop ejabberd informing users, with grace period
- If there's a problem in config file, display config lines and stop node
* MUC
- Kick occupants with reason when room is stopped due to MUC shutdown
- Write in room log when a room is created, destroyed, started, stopped
* PubSub and PEP
- Don't call gen_server on internal event (improves performance and scalability)
- Fix duplicate SHIM header in Pubsub message
- Notification messages of Pubsub node config change contained a SHIM header
- SubID SHIM header missing in Pubsub message with multiple
subscriptions on the same node
- PEP: last published item not sent from unavailable users when the
subscription is implicit (XEP-0115)
- pep_mapping not working due to Node type mismatch
* WebAdmin
- If big offline message queue, show only subset on WebAdmin
- Support in user list page of WebAdmin when mod_offline is disabled
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
-91
View File
@@ -1,91 +0,0 @@
Release Notes
ejabberd 2.1.3
ejabberd 2.1.3 is the third release in ejabberd 2.1.x branch.
ejabberd 2.1.3 includes many bugfixes, and some improvements.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.1.3
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
This is the full list of changes:
* Client connections
- Avoid 'invalid' value in iq record
- Avoid resending stream:error stanzas on terminate (EJAB-1180)
- Close also legacy sessions that were half connected (EJAB-1165)
- iq_query_info/1 now returns 'invalid' if XMLNS is invalid
- New ejabberd_c2s option support: max_fsm_queue
- Rewrite mnesia counter functions to use dirty_update_counter (EJAB-1177)
- Run user_receive_packet also when sending offline messages (EJAB-1193)
- Use p1_fsm behaviour in c2s FSM (EJAB-1173)
* Clustering
- Fix cluster race condition in route read
- New command to set master Mnesia node
- Use mnesia:async_dirty when cleaning table from failed node
* Documentation
- Add quotes in documentation of some erl arguments (EJAB-1191)
- Add option access_from (EJAB-1187)
- Add option max_fsm_queue (EJAB-1185)
- Fix documentation installation, no need for executable permission (EJAB-1170)
- Fix typo in EJABBERD_BIN_PATH (EJAB-891)
- Fix typos in example config comments (EJAB-1192)
* ejabberdctl
- Support concurrent connections with bound connection names
- Add support for Jot in ctl and TTY in debug
- Support help command names with old - characters
- Fix to really use the variable ERL_PROCESSES
* Erlang compatibility
- Don't call queue:filter/2 to keep compatibility with older Erlang versions
- Use alternative of file:read_line/1 to not require R13B02
* HTTP
- Add new debugging hook to the http receiving process
- Allow a request_handler to serve a file in root of HTTP
* HTTP-Bind (BOSH)
- Cross-domain HTTP-Bind support (EJAB-1168)
- Hibernate http-bind process after handling a request
- Reduce verbosity of HTTP Binding log messages
* LDAP
- Document ldap_dn_filter, fetch only needed attributes in search (EJAB-1204)
- Use "%u" pattern as default for ldap_uids (EJAB-1203)
* Localization
- Fix German translation (EJAB-1195)
- Fix Russian translation
* ODBC
- Fix MSSQL support, which was broken (EJAB-1201)
- Improved SQL reconnect behaviour
* Pubsub, PEP and Caps
- Add extended stanza addressing 'replyto' on PEP (EJAB-1198)
- Add pubsub#purge_offline (EJAB-1186)
- Fix pubsub#title option (EJAB-1190)
- Fix remove_user for node subscriptions (EJAB-1172)
- Optimizations in mod_caps
* Other
- mod_register: Add new acl access_from, default is to deny
- mod_sic: new module for the experimental XEP-0279 Server IP Check (EJAB-1205)
- PIEFXIS: Catch errors when exporting to PIEFXIS file (EJAB-1178)
- Proxy65: new option "hostname" (EJAB-838)
- Roster: Fix resending authorization problem
- Shared Roster Groups: get contacts nickname from vcard (EJAB-114)
- S2S: Improved s2s connections clean up (EJAB-1202)
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
-80
View File
@@ -1,80 +0,0 @@
Release Notes
ejabberd 2.1.4
ejabberd 2.1.4 is the fourth release in ejabberd 2.1.x branch,
and includes many small bugfixes and improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.4
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
This is the full list of changes:
* Authentication
- Extauth: Optionally cache extauth users in mnesia (EJAB-641)
- LDAP: Allow inband password change (EJAB-199)
- LDAP: Extensible match support (EJAB-722)
- LDAP: New option ldap_tls_verify is added (EJAB-1229)
- PAM: New option pam_userinfotype to provide username or JID (EJAB-652)
* HTTP
- Add xml default content type
- Don't show HTTP request in logs, because reveals password (EJAB-1231)
- Move HTTP session timeout log from warning level to info
- New Access rule webadmin_view for read-only
* HTTP-Bind (BOSH)
- Change max inactivity from 30 to 120 seconds
- Export functions to facilitate prebinding methods
- Use dirty_delete when removing the session
- Remove an unneeded delay of 100 milliseconds
* Pubsub, PEP and Caps
- Enforce pubsub#presence_based_delivery (EJAB-1221)
- Enforce pubsub#show_values subscription option (EJAB-1096)
- Fix error code when unsubscribing from a non-existent node
- Fix to send node notifications (EJAB-1225)
- Full support for XEP-0115 v1.5 (EJAB-1223)(EJAB-1189)
- Make last_item_cache feature to be cluster aware
- Prevent orphaned pubsub node (EJAB-1233)
- Send created node notifications
* Other
- Bounce messages when closing c2s session
- Bugfixes when handling Service Discovery to contacts (EJAB-1207)
- Compilation of ejabberd_debug.erl is now optional
- Don't send error stanza as reply to error stanza (EJAB-930)
- Don't store blocked messages in offline queue
- Reduce verbosity of log when captcha_cmd is checked but not configured
- Use a standard method to get a random seed (EJAB-1229)
- Commands: new update_list and update to update modified modules (EJAB-1237)
- Localization: Updated most translations
- MUC: Refactor code to reduce calls to get_affiliation and get_role
- ODBC: Add created_at column also to PostgreSQL schema
- Vcard: Automatic vcard avatar addition in presence
Upgrading From previous ejabberd releases:
- If you use PostgreSQL, maybe you want to add the column created_at
to several tables. This is only a suggestion; ejabberd doesn't use
that column. Add it to your existing database executing those SQL
statements:
ALTER TABLE users ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
ALTER TABLE rosterusers ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
ALTER TABLE spool ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
ALTER TABLE vcard ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
ALTER TABLE privacy_list ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
ALTER TABLE privacy_storage ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+1 -1
View File
@@ -1,2 +1,2 @@
% ejabberd version (automatically generated).
\newcommand{\version}{2.1.4}
\newcommand{\version}{2.1.0}
View File
+14 -17
View File
@@ -34,13 +34,11 @@ EFLAGS += @ERLANG_SSL39@ -pa .
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
EFLAGS+=+debug_info
endif
DEBUGTOOLS = ejabberd_debug.erl
ifdef ejabberd_debug
EFLAGS+=-Dejabberd_debug
SOURCES+=$(DEBUGTOOLS)
endif
ifeq (@hipe@, true)
@@ -71,8 +69,7 @@ SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ str
ERLSHLIBS = expat_erl.so
ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl
SOURCES_ALL = $(wildcard *.erl)
SOURCES_MISC = $(ERLBEHAVS) $(DEBUGTOOLS)
SOURCES += $(filter-out $(SOURCES_MISC),$(SOURCES_ALL))
SOURCES = $(filter-out $(ERLBEHAVS),$(SOURCES_ALL))
ERLBEHAVBEAMS = $(ERLBEHAVS:.erl=.beam)
BEAMS = $(SOURCES:.erl=.beam)
@@ -113,9 +110,6 @@ MSGSDIR = $(PRIVDIR)/msgs
# /var/lib/ejabberd/
SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
# /var/lock/ejabberdctl
CTLLOCKDIR = $(DESTDIR)@localstatedir@/lock/ejabberdctl
# /var/lib/ejabberd/.erlang.cookie
COOKIEFILE = $(SPOOLDIR)/.erlang.cookie
@@ -238,11 +232,6 @@ install: all
chmod -R 750 $(SPOOLDIR)
[ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; }
#
# ejabberdctl lock directory
install -d -m 750 $(O_USER) $(CTLLOCKDIR)
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(CTLLOCKDIR) >$(CHOWN_OUTPUT)
chmod -R 750 $(CTLLOCKDIR)
#
# Log directory
install -d -m 750 $(O_USER) $(LOGDIR)
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(LOGDIR) >$(CHOWN_OUTPUT)
@@ -250,9 +239,9 @@ install: all
#
# Documentation
install -d $(DOCDIR)
install -m 644 ../doc/guide.html $(DOCDIR)
install -m 644 ../doc/*.png $(DOCDIR)
install -m 644 ../doc/*.txt $(DOCDIR)
install ../doc/guide.html $(DOCDIR)
install ../doc/*.png $(DOCDIR)
install ../doc/*.txt $(DOCDIR)
uninstall: uninstall-binary
@@ -276,7 +265,6 @@ uninstall-all: uninstall-binary
rm -rf $(ETCDIR)
rm -rf $(EJABBERDDIR)
rm -rf $(SPOOLDIR)
rm -rf $(CTLLOCKDIR)
rm -rf $(LOGDIR)
clean: clean-recursive clean-local
@@ -298,3 +286,12 @@ Makefile: Makefile.in
dialyzer: $(BEAMS)
@dialyzer -c .
LASTSVNREVCHANGELOG = 2075
changelog:
svn up -r $(LASTSVNREVCHANGELOG) ../ChangeLog
mv ../ChangeLog ../ChangeLog.old
svn2cl -r BASE:$(LASTSVNREVCHANGELOG) -o ../ChangeLog --group-by-day \
--separate-daylogs --break-before-msg --reparagraph ..
cat ../ChangeLog.old >> ../ChangeLog
rm ../ChangeLog.old
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 18 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+6 -7
View File
@@ -1,11 +1,11 @@
%%%----------------------------------------------------------------------
%%% File : adhoc.erl
%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
%%% Purpose : Provide helper functions for ad-hoc commands (XEP-0050)
%%% Purpose : Provide helper functions for ad-hoc commands (JEP-0050)
%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -44,11 +44,10 @@ parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}
Action = xml:get_tag_attr_s("action", SubEl),
XData = find_xdata_el(SubEl),
{xmlelement, _, _, AllEls} = SubEl,
Others = case XData of
false ->
AllEls;
_ ->
lists:delete(XData, AllEls)
if XData ->
Others = lists:delete(XData, AllEls);
true ->
Others = AllEls
end,
#adhoc_request{lang = Lang,
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+7 -5
View File
@@ -1,11 +1,11 @@
%%%----------------------------------------------------------------------
%%% File : configure.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose :
%%% Purpose :
%%% Created : 27 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -58,7 +58,7 @@ start() ->
end,
EVersion = "ERLANG_VERSION = " ++ erlang:system_info(version) ++ "\n",
EIDirS = "EI_DIR = " ++ code:lib_dir(erl_interface) ++ "\n",
EIDirS = "EI_DIR = " ++ code:lib_dir("erl_interface") ++ "\n",
RootDirS = "ERLANG_DIR = " ++ code:root_dir() ++ "\n",
%% Load the ejabberd application description so that ?VERSION can read the vsn key
application:load(ejabberd),
@@ -67,8 +67,8 @@ start() ->
OpenSSLDir = "OPENSSL_DIR = c:\\sdk\\OpenSSL\n",
DBType = "DBTYPE = generic\n", %% 'generic' or 'mssql'
SSLDir = "SSLDIR = " ++ code:lib_dir(ssl) ++ "\n",
StdLibDir = "STDLIBDIR = " ++ code:lib_dir(stdlib) ++ "\n",
SSLDir = "SSLDIR = " ++ code:lib_dir("ssl") ++ "\n",
StdLibDir = "STDLIBDIR = " ++ code:lib_dir("stdlib") ++ "\n",
file:write_file("Makefile.inc",
list_to_binary(EVersion ++
@@ -87,3 +87,5 @@ start() ->
ZlibDir ++
ZlibLib)),
halt().
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -6,7 +6,7 @@
%%% Created : 23 Aug 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+3 -28
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -44,7 +44,7 @@ mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
{ok, #state{check_password = CheckPassword}}.
mech_step(State, ClientIn) ->
case prepare(ClientIn) of
case parse(ClientIn) of
[AuthzId, User, Password] ->
case (State#state.check_password)(User, Password) of
{true, AuthModule} ->
@@ -57,24 +57,6 @@ mech_step(State, ClientIn) ->
{error, "bad-protocol"}
end.
prepare(ClientIn) ->
case parse(ClientIn) of
[[], UserMaybeDomain, Password] ->
case parse_domain(UserMaybeDomain) of
%% <NUL>login@domain<NUL>pwd
[User, _Domain] ->
[UserMaybeDomain, User, Password];
%% <NUL>login<NUL>pwd
[User] ->
["", User, Password]
end;
%% login@domain<NUL>login<NUL>pwd
[AuthzId, User, Password] ->
[AuthzId, User, Password];
_ ->
error
end.
parse(S) ->
parse1(S, "", []).
@@ -89,12 +71,5 @@ parse1([], S, T) ->
lists:reverse([lists:reverse(S) | T]).
parse_domain(S) ->
parse_domain1(S, "", []).
parse_domain1([$@ | Cs], S, T) ->
parse_domain1(Cs, "", [lists:reverse(S) | T]);
parse_domain1([C | Cs], S, T) ->
parse_domain1(Cs, [C | S], T);
parse_domain1([], S, T) ->
lists:reverse([lists:reverse(S) | T]).
+1 -1
View File
@@ -2,7 +2,7 @@
{application, ejabberd,
[{description, "ejabberd"},
{vsn, "2.1.4"},
{vsn, "2.1.0"},
{modules, [acl,
adhoc,
configure,
+34 -41
View File
@@ -5,7 +5,7 @@
%%% The parameters used in this configuration file are explained in more detail
%%% in the ejabberd Installation and Operation Guide.
%%% Please consult the Guide in case of doubts, it is included with
%%% Please consult the Guide in case of doubts, it is included in
%%% your copy of ejabberd, and is also available online at
%%% http://www.process-one.net/en/ejabberd/docs/
@@ -26,11 +26,11 @@
%%% [http_poll, web_admin, tls]
%%%
%%% - A keyword of ejabberd is a word in lowercase.
%%% Strings are enclosed in "" and can contain spaces, dots, ...
%%% The strings are enclosed in "" and can have spaces, dots...
%%% {language, "en"}.
%%% {ldap_rootdn, "dc=example,dc=com"}.
%%%
%%% - This term includes a tuple, a keyword, a list, and two strings:
%%% - This term includes a tuple, a keyword, a list and two strings:
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
%%%
@@ -74,7 +74,7 @@
%%
%% watchdog_admins: Only useful for developers: if an ejabberd process
%% consumes a lot of memory, send live notifications to these XMPP
%% consumes a lot of memory, send live notifications to these XMPP
%% accounts.
%%
%%{watchdog_admins, ["bob@example.com"]}.
@@ -91,9 +91,9 @@
{hosts, ["localhost"]}.
%%
%% route_subdomains: Delegate subdomains to other XMPP servers.
%% route_subdomains: Delegate subdomains to other XMPP server.
%% For example, if this ejabberd serves example.org and you want
%% to allow communication with an XMPP server called im.example.org.
%% to allow communication with a XMPP server called im.example.org.
%%
%%{route_subdomains, s2s}.
@@ -102,8 +102,8 @@
%%%' LISTENING PORTS
%%
%% listen: The ports ejabberd will listen on, which service each is handled
%% by and what options to start it with.
%% listen: Which ports will ejabberd listen, which service handles it
%% and what options to start it with.
%%
{listen,
[
@@ -111,8 +111,8 @@
{5222, ejabberd_c2s, [
%%
%% If TLS is compiled in and you installed a SSL
%% certificate, specify the full path to the
%% If TLS is compiled and you installed a SSL
%% certificate, put the correct path to the
%% file and uncomment this line:
%%
%%{certfile, "/path/to/ssl.pem"}, starttls,
@@ -123,7 +123,7 @@
]},
%%
%% To enable the old SSL connection method on port 5223:
%% To enable the old SSL connection method in port 5223:
%%
%%{5223, ejabberd_c2s, [
%% {access, c2s},
@@ -138,7 +138,7 @@
]},
%%
%% ejabberd_service: Interact with external components (transports, ...)
%% ejabberd_service: Interact with external components (transports...)
%%
%%{8888, ejabberd_service, [
%% {access, all},
@@ -249,14 +249,14 @@
%%{ldap_encrypt, none}.
%%{ldap_encrypt, tls}.
%%
%% Port to connect to on LDAP servers:
%% Port connect to LDAP servers:
%%{ldap_port, 389}.
%%{ldap_port, 636}.
%%
%% LDAP manager:
%%{ldap_rootdn, "dc=example,dc=com"}.
%%
%% Password of LDAP manager:
%% Password to LDAP manager:
%%{ldap_password, "******"}.
%%
%% Search base of LDAP directory:
@@ -286,11 +286,11 @@
%%%. ==============
%%%' DATABASE SETUP
%% ejabberd by default uses the internal Mnesia database,
%% so you do not necessarily need this section.
%% ejabberd uses by default the internal Mnesia database,
%% so you can avoid this section.
%% This section provides configuration examples in case
%% you want to use other database backends.
%% Please consult the ejabberd Guide for details on database creation.
%% Please consult the ejabberd Guide for details about database creation.
%%
%% MySQL server:
@@ -324,8 +324,8 @@
%%{odbc_pool_size, 10}.
%%
%% Interval to make a dummy SQL request to keep the connections to the
%% database alive. Specify in seconds: for example 28800 means 8 hours
%% Interval to make a dummy SQL request to keep alive the connections
%% to the database. Specify in seconds: for example 28800 means 8 hours
%%
%%{odbc_keepalive_interval, undefined}.
@@ -334,28 +334,22 @@
%%%' TRAFFIC SHAPERS
%%
%% The "normal" shaper limits traffic speed to 1000 B/s
%% The "normal" shaper limits traffic speed to 1.000 B/s
%%
{shaper, normal, {maxrate, 1000}}.
%%
%% The "fast" shaper limits traffic speed to 50000 B/s
%% The "fast" shaper limits traffic speed to 50.000 B/s
%%
{shaper, fast, {maxrate, 50000}}.
%%
%% This option specifies the maximum number of elements in the queue
%% of the FSM. Refer to the documentation for details.
%%
{max_fsm_queue, 1000}.
%%%. ====================
%%%' ACCESS CONTROL LISTS
%%
%% The 'admin' ACL grants administrative privileges to XMPP accounts.
%% You can put here as many accounts as you want.
%% You can put as many accounts as you want.
%%
%%{acl, admin, {user, "aleksey", "localhost"}}.
%%{acl, admin, {user, "ermine", "example.org"}}.
@@ -396,7 +390,7 @@
{access, max_user_sessions, [{10, all}]}.
%% Maximum number of offline messages that users can have:
{access, max_user_offline_messages, [{5000, admin}, {100, all}]}.
{access, max_user_offline_messages, [{5000, admin}, {100, all}]}.
%% This rule allows access only for local users:
{access, local, [{allow, local}]}.
@@ -405,41 +399,41 @@
{access, c2s, [{deny, blocked},
{allow, all}]}.
%% For C2S connections, all users except admins use the "normal" shaper
%% For C2S connections, all users except admins use "normal" shaper
{access, c2s_shaper, [{none, admin},
{normal, all}]}.
%% All S2S connections use the "fast" shaper
%% All S2S connections use "fast" shaper
{access, s2s_shaper, [{fast, all}]}.
%% Only admins can send announcement messages:
{access, announce, [{allow, admin}]}.
%% Only admins can use the configuration interface:
%% Only admins can use configuration interface:
{access, configure, [{allow, admin}]}.
%% Admins of this server are also admins of the MUC service:
%% Admins of this server are also admins of MUC service:
{access, muc_admin, [{allow, admin}]}.
%% Only accounts of the local ejabberd server can create rooms:
{access, muc_create, [{allow, local}]}.
%% All users are allowed to use the MUC service:
%% All users are allowed to use MUC service:
{access, muc, [{allow, all}]}.
%% Only accounts on the local ejabberd server can create Pubsub nodes:
%% Only accounts in the local ejabberd server can create Pubsub nodes:
{access, pubsub_createnode, [{allow, local}]}.
%% In-band registration allows registration of any possible username.
%% To disable in-band registration, replace 'allow' with 'deny'.
{access, register, [{allow, all}]}.
%% By default the frequency of account registrations from the same IP
%% is limited to 1 account every 10 minutes. To disable, specify: infinity
%% By default frequency of account registrations from the same IP
%% is limited to 1 account every 10 minutes. To disable put: infinity
%%{registration_timeout, 600}.
%%
%% Define specific Access Rules in a virtual host.
%% Define specific Access rules in a virtual host.
%%
%%{host_config, "localhost",
%% [
@@ -496,7 +490,7 @@
{mod_irc, []},
{mod_http_bind, []},
%%{mod_http_fileserver, [
%% {docroot, "/var/www"},
%% {docroot, "/var/www"},
%% {accesslog, "/var/log/ejabberd/access.log"}
%% ]},
{mod_last, []},
@@ -515,8 +509,7 @@
%%{mod_proxy65,[]},
{mod_pubsub, [
{access_createnode, pubsub_createnode},
{ignore_pep_from_offline, true}, % reduces resource comsumption, but XEP incompliant
%%{ignore_pep_from_offline, false}, % XEP compliant, but increases resource comsumption
{ignore_pep_from_offline, true},
{last_item_cache, false},
{plugins, ["flat", "hometree", "pep"]} % pep requires mod_caps
]},
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+3 -109
View File
@@ -5,7 +5,7 @@
%%% Created : 7 May 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -30,9 +30,6 @@
-export([start/0, stop/0,
%% Server
status/0, reopen_log/0,
stop_kindly/2, send_service_message_all_mucs/2,
%% Erlang
update_list/0, update/1,
%% Accounts
register/3, unregister/2,
registered_users/1,
@@ -41,7 +38,6 @@
%% Purge DB
delete_expired_messages/0, delete_old_messages/1,
%% Mnesia
set_master/1,
backup_mnesia/1, restore_mnesia/1,
dump_mnesia/1, dump_table/2, load_mnesia/1,
install_fallback_mnesia/1,
@@ -83,11 +79,6 @@ commands() ->
desc = "Reopen the log files",
module = ?MODULE, function = reopen_log,
args = [], result = {res, rescode}},
#ejabberd_commands{name = stop_kindly, tags = [server],
desc = "Inform users and rooms, wait, and stop the server",
module = ?MODULE, function = stop_kindly,
args = [{delay, integer}, {announcement, string}],
result = {res, rescode}},
#ejabberd_commands{name = get_loglevel, tags = [logs, server],
desc = "Get the current loglevel",
module = ejabberd_loglevel, function = get,
@@ -97,17 +88,6 @@ commands() ->
{leveldesc, string}
]}}},
#ejabberd_commands{name = update_list, tags = [server],
desc = "List modified modules that can be updated",
module = ?MODULE, function = update_list_modified,
args = [],
result = {modules, {list, {module, string}}}},
#ejabberd_commands{name = update, tags = [server],
desc = "Update the given module, or use the keyword: all",
module = ?MODULE, function = update,
args = [{module, string}],
result = {res, rescode}},
#ejabberd_commands{name = register, tags = [accounts],
desc = "Register a user",
module = ?MODULE, function = register,
@@ -157,16 +137,10 @@ commands() ->
args = [{days, integer}], result = {res, rescode}},
#ejabberd_commands{name = rename_default_nodeplugin, tags = [mnesia],
desc = "Update PubSub table from old ejabberd trunk SVN to 2.1.0",
desc = "Update PubSub table from ejabberd trunk SVN to 2.1.0",
module = mod_pubsub, function = rename_default_nodeplugin,
args = [], result = {res, rescode}},
#ejabberd_commands{name = set_master, tags = [mnesia],
desc = "Set master node of the clustered Mnesia tables",
longdesc = "If you provide as nodename \"self\", this "
"node will be set as its own master.",
module = ?MODULE, function = set_master,
args = [{nodename, string}], result = {res, restuple}},
#ejabberd_commands{name = mnesia_change_nodename, tags = [mnesia],
desc = "Change the erlang node name in a backup file",
module = ?MODULE, function = mnesia_change_nodename,
@@ -241,72 +215,6 @@ get_sasl_error_logger_type () ->
_ -> all
end.
%%%
%%% Stop Kindly
%%%
stop_kindly(DelaySeconds, AnnouncementText) ->
Subject = io_lib:format("Server stop in ~p seconds!", [DelaySeconds]),
WaitingDesc = io_lib:format("Waiting ~p seconds", [DelaySeconds]),
Steps = [
{"Stopping ejabberd port listeners",
ejabberd_listener, stop_listeners, []},
{"Sending announcement to connected users",
mod_announce, send_announcement_to_all,
[?MYNAME, Subject, AnnouncementText]},
{"Sending service message to MUC rooms",
ejabberd_admin, send_service_message_all_mucs,
[Subject, AnnouncementText]},
{WaitingDesc, timer, sleep, [DelaySeconds * 1000]},
{"Stopping ejabberd", application, stop, [ejabberd]},
{"Stopping Mnesia", mnesia, stop, []},
{"Stopping Erlang node", init, stop, []}
],
NumberLast = length(Steps),
TimestampStart = calendar:datetime_to_gregorian_seconds({date(), time()}),
lists:foldl(
fun({Desc, Mod, Func, Args}, NumberThis) ->
SecondsDiff =
calendar:datetime_to_gregorian_seconds({date(), time()})
- TimestampStart,
io:format("[~p/~p ~ps] ~s... ",
[NumberThis, NumberLast, SecondsDiff, Desc]),
Result = apply(Mod, Func, Args),
io:format("~p~n", [Result]),
NumberThis+1
end,
1,
Steps),
ok.
send_service_message_all_mucs(Subject, AnnouncementText) ->
Message = io_lib:format("~s~n~s", [Subject, AnnouncementText]),
lists:foreach(
fun(ServerHost) ->
MUCHost = gen_mod:get_module_opt_host(
ServerHost, mod_muc, "conference.@HOST@"),
mod_muc:broadcast_service_message(MUCHost, Message)
end,
?MYHOSTS).
%%%
%%% ejabberd_update
%%%
update_list() ->
{ok, _Dir, UpdatedBeams, _Script, _LowLevelScript, _Check} =
ejabberd_update:update_info(),
[atom_to_list(Beam) || Beam <- UpdatedBeams].
update("all") ->
[update_module(ModStr) || ModStr <- update_list()];
update(ModStr) ->
update_module(ModStr).
update_module(ModuleNameString) ->
ModuleName = list_to_atom(ModuleNameString),
ejabberd_update:update([ModuleName]).
%%%
%%% Account management
%%%
@@ -314,7 +222,7 @@ update_module(ModuleNameString) ->
register(User, Host, Password) ->
case ejabberd_auth:try_register(User, Host, Password) of
{atomic, ok} ->
{ok, io_lib:format("User ~s@~s successfully registered", [User, Host])};
{ok, io_lib:format("User ~s@~s succesfully registered", [User, Host])};
{atomic, exists} ->
String = io_lib:format("User ~s@~s already registered at node ~p",
[User, Host, node()]),
@@ -377,20 +285,6 @@ delete_old_messages(Days) ->
%%% Mnesia management
%%%
set_master("self") ->
set_master(node());
set_master(NodeString) when is_list(NodeString) ->
set_master(list_to_atom(NodeString));
set_master(Node) when is_atom(Node) ->
case mnesia:set_master_nodes([Node]) of
ok ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't set master node ~p at node ~p:~n~p",
[Node, node(), Reason]),
{error, String}
end.
backup_mnesia(Path) ->
case mnesia:backup(Path) of
ok ->
+2 -11
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -77,15 +77,13 @@ start(_, _) ->
prep_stop(State) ->
stop_modules(),
ejabberd_admin:stop(),
broadcast_c2s_shutdown(),
timer:sleep(5000),
State.
%% All the processes were killed when this function is called
stop(_State) ->
?INFO_MSG("ejabberd ~s is stopped in the node ~p", [?VERSION, node()]),
delete_pid_file(),
%%ejabberd_debug:stop(),
ejabberd_debug:stop(),
ok.
@@ -200,13 +198,6 @@ add_windows_nameservers() ->
lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs).
broadcast_c2s_shutdown() ->
Children = supervisor:which_children(ejabberd_c2s_sup),
lists:foreach(
fun({_, C2SPid, _, _}) ->
C2SPid ! system_shutdown
end, Children).
%%%
%%% PID file
%%%
+2 -11
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -251,16 +251,7 @@ get_password_with_authmodule(User, Server) ->
is_user_exists(User, Server) ->
lists:any(
fun(M) ->
case M:is_user_exists(User, Server) of
{error, Error} ->
?ERROR_MSG("The authentication module ~p returned an "
"error~nwhen checking user ~p in server ~p~n"
"Error message: ~p",
[M, User, Server, Error]),
false;
Else ->
Else
end
M:is_user_exists(User, Server)
end, auth_modules(Server)).
%% Check if the user exists in all authentications module except the module
+9 -6
View File
@@ -5,7 +5,7 @@
%%% Created : 17 Feb 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -79,7 +79,7 @@ allow_anonymous(Host) ->
%% anonymous protocol can be: sasl_anon|login_anon|both
is_sasl_anonymous_enabled(Host) ->
case allow_anonymous(Host) of
false -> false;
false -> false;
true ->
case anonymous_protocol(Host) of
sasl_anon -> true;
@@ -97,7 +97,7 @@ is_login_anonymous_enabled(Host) ->
true ->
case anonymous_protocol(Host) of
login_anon -> true;
both -> true;
both -> true;
_Other -> false
end
end.
@@ -115,8 +115,10 @@ anonymous_protocol(Host) ->
%% Return true if multiple connections have been allowed in the config file
%% defaults to false
allow_multiple_connections(Host) ->
ejabberd_config:get_local_option(
{allow_multiple_connections, Host}) =:= true.
case ejabberd_config:get_local_option({allow_multiple_connections, Host}) of
true -> true;
_Other -> false
end.
%% Check if user exist in the anonymus database
anonymous_user_exist(User, Server) ->
@@ -174,7 +176,7 @@ check_password(User, Server, Password) ->
check_password(User, Server, _Password, _Digest, _DigestGen) ->
%% We refuse login for registered accounts (They cannot logged but
%% they however are "reserved")
case ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
case ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
User, Server) of
%% If user exists in other module, reject anonnymous authentication
true -> false;
@@ -246,3 +248,4 @@ remove_user(_User, _Server, _Password) ->
plain_password_required() ->
false.
+19 -224
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -35,9 +35,6 @@
try_register/3,
dirty_get_registered_users/0,
get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2,
get_password/2,
get_password_s/2,
is_user_exists/2,
@@ -46,87 +43,45 @@
plain_password_required/0
]).
-include("ejabberd.hrl").
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(Host) ->
extauth:start(
Host, ejabberd_config:get_local_option({extauth_program, Host})),
case check_cache_last_options(Host) of
cache ->
ok = ejabberd_auth_internal:start(Host);
no_cache ->
ok
end.
check_cache_last_options(Server) ->
%% if extauth_cache is enabled, then a mod_last module must also be enabled
case get_cache_option(Server) of
false -> no_cache;
{true, _CacheTime} ->
case get_mod_last_enabled(Server) of
no_mod_last ->
?ERROR_MSG("In host ~p extauth is used, extauth_cache is enabled but "
"mod_last is not enabled.", [Server]),
no_cache;
_ -> cache
end
end.
ok.
plain_password_required() ->
true.
check_password(User, Server, Password) ->
case get_cache_option(Server) of
false -> check_password_extauth(User, Server, Password);
{true, CacheTime} -> check_password_cache(User, Server, Password, CacheTime)
end.
extauth:check_password(User, Server, Password) andalso Password /= "".
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password).
set_password(User, Server, Password) ->
case extauth:set_password(User, Server, Password) of
true -> set_password_internal(User, Server, Password),
ok;
true -> ok;
_ -> {error, unknown_problem}
end.
try_register(User, Server, Password) ->
case get_cache_option(Server) of
false -> try_register_extauth(User, Server, Password);
{true, _CacheTime} -> try_register_external_cache(User, Server, Password)
end.
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
%% TODO
%% Return the list of all users handled by external
dirty_get_registered_users() ->
ejabberd_auth_internal:dirty_get_registered_users().
[].
get_vh_registered_users(Server) ->
ejabberd_auth_internal:get_vh_registered_users(Server).
get_vh_registered_users(_Server) ->
[].
get_vh_registered_users(Server, Data) ->
ejabberd_auth_internal:get_vh_registered_users(Server, Data).
get_password(_User, _Server) ->
false.
get_vh_registered_users_number(Server) ->
ejabberd_auth_internal:get_vh_registered_users_number(Server).
get_vh_registered_users_number(Server, Data) ->
ejabberd_auth_internal:get_vh_registered_users_number(Server, Data).
%% The password can only be returned if cache is enabled, cached info exists and is fresh enough.
get_password(User, Server) ->
case get_cache_option(Server) of
false -> false;
{true, CacheTime} -> get_password_cache(User, Server, CacheTime)
end.
get_password_s(User, Server) ->
case get_password(User, Server) of
false -> [];
Other -> Other
end.
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
@@ -136,169 +91,9 @@ is_user_exists(User, Server) ->
_:Error -> {error, Error}
end.
remove_user(User, Server) ->
case extauth:remove_user(User, Server) of
false -> false;
true ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
ejabberd_auth_internal:remove_user(User, Server)
end
end.
remove_user(_User, _Server) ->
{error, not_allowed}.
remove_user(User, Server, Password) ->
case extauth:remove_user(User, Server, Password) of
false -> false;
true ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
ejabberd_auth_internal:remove_user(User, Server, Password)
end
end.
remove_user(_User, _Server, _Password) ->
not_allowed.
%%%
%%% Extauth cache management
%%%
%% @spec (Host::string()) -> false | {true, CacheTime::integer()}
get_cache_option(Host) ->
case ejabberd_config:get_local_option({extauth_cache, Host}) of
CacheTime when is_integer(CacheTime) -> {true, CacheTime};
_ -> false
end.
%% @spec (User, Server, Password) -> true | false
check_password_extauth(User, Server, Password) ->
extauth:check_password(User, Server, Password) andalso Password /= "".
%% @spec (User, Server, Password) -> true | false
try_register_extauth(User, Server, Password) ->
extauth:try_register(User, Server, Password).
check_password_cache(User, Server, Password, CacheTime) ->
case get_last_access(User, Server) of
online ->
check_password_internal(User, Server, Password);
never ->
check_password_external_cache(User, Server, Password);
mod_last_required ->
?ERROR_MSG("extauth is used, extauth_cache is enabled but mod_last is not enabled in that host", []),
check_password_external_cache(User, Server, Password);
TimeStamp ->
%% If last access exists, compare last access with cache refresh time
case is_fresh_enough(TimeStamp, CacheTime) of
%% If no need to refresh, check password against Mnesia
true ->
case check_password_internal(User, Server, Password) of
%% If password valid in Mnesia, accept it
true ->
true;
%% Else (password nonvalid in Mnesia), check in extauth and cache result
false ->
check_password_external_cache(User, Server, Password)
end;
%% Else (need to refresh), check in extauth and cache result
false ->
check_password_external_cache(User, Server, Password)
end
end.
get_password_internal(User, Server) ->
ejabberd_auth_internal:get_password(User, Server).
%% @spec (User, Server, CacheTime) -> false | Password::string()
get_password_cache(User, Server, CacheTime) ->
case get_last_access(User, Server) of
online ->
get_password_internal(User, Server);
never ->
false;
mod_last_required ->
?ERROR_MSG("extauth is used, extauth_cache is enabled but mod_last is not enabled in that host", []),
false;
TimeStamp ->
case is_fresh_enough(TimeStamp, CacheTime) of
true ->
get_password_internal(User, Server);
false ->
false
end
end.
%% Check the password using extauth; if success then cache it
check_password_external_cache(User, Server, Password) ->
case check_password_extauth(User, Server, Password) of
true ->
set_password_internal(User, Server, Password), true;
false ->
false
end.
%% Try to register using extauth; if success then cache it
try_register_external_cache(User, Server, Password) ->
case try_register_extauth(User, Server, Password) of
{atomic, ok} = R ->
set_password_internal(User, Server, Password),
R;
_ -> {error, not_allowed}
end.
%% @spec (User, Server, Password) -> true | false
check_password_internal(User, Server, Password) ->
ejabberd_auth_internal:check_password(User, Server, Password).
%% @spec (User, Server, Password) -> ok | {error, invalid_jid}
set_password_internal(User, Server, Password) ->
ejabberd_auth_internal:set_password(User, Server, Password).
%% @spec (TimeLast, CacheTime) -> true | false
%% TimeLast = online | never | integer()
%% CacheTime = integer() | false
is_fresh_enough(online, _CacheTime) ->
true;
is_fresh_enough(never, _CacheTime) ->
false;
is_fresh_enough(TimeStampLast, CacheTime) ->
{MegaSecs, Secs, _MicroSecs} = now(),
Now = MegaSecs * 1000000 + Secs,
(TimeStampLast + CacheTime > Now).
%% @spec (User, Server) -> online | never | mod_last_required | TimeStamp::integer()
%% Code copied from mod_configure.erl
%% Code copied from web/ejabberd_web_admin.erl
%% TODO: Update time format to XEP-0202: Entity Time
get_last_access(User, Server) ->
case ejabberd_sm:get_user_resources(User, Server) of
[] ->
_US = {User, Server},
case get_last_info(User, Server) of
mod_last_required ->
mod_last_required;
not_found ->
never;
{ok, Timestamp, _Status} ->
Timestamp
end;
_ ->
online
end.
%% @spec (User, Server) -> {ok, Timestamp, Status} | not_found | mod_last_required
get_last_info(User, Server) ->
case get_mod_last_enabled(Server) of
mod_last -> mod_last:get_last_info(User, Server);
mod_last_odbc -> mod_last_odbc:get_last_info(User, Server);
mod_mod_last -> mod_last_required
end.
%% @spec (Server) -> mod_last | mod_last_odbc | no_mod_last
get_mod_last_enabled(Server) ->
ML = lists:member(mod_last, gen_mod:loaded_modules(Server)),
MLO = lists:member(mod_last_odbc, gen_mod:loaded_modules(Server)),
case {ML, MLO} of
{true, _} -> mod_last;
{false, true} -> mod_last_odbc;
{false, false} -> no_mod_last
end.
+39 -13
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -68,11 +68,7 @@ update_reg_users_counter_table(Server) ->
Set = get_vh_registered_users(Server),
Size = length(Set),
LServer = jlib:nameprep(Server),
F = fun() ->
mnesia:write(#reg_users_counter{vhost = LServer,
count = Size})
end,
mnesia:sync_dirty(F).
set_vh_registered_users_counter(LServer, Size).
plain_password_required() ->
false.
@@ -141,9 +137,7 @@ try_register(User, Server, Password) ->
[] ->
mnesia:write(#passwd{us = US,
password = Password}),
mnesia:dirty_update_counter(
reg_users_counter,
LServer, 1),
inc_vh_registered_users_counter(LServer),
ok;
[_E] ->
exists
@@ -230,6 +224,40 @@ get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix)
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
inc_vh_registered_users_counter(LServer) ->
F = fun() ->
case mnesia:wread({reg_users_counter, LServer}) of
[C] ->
Count = C#reg_users_counter.count + 1,
C2 = C#reg_users_counter{count = Count},
mnesia:write(C2);
_ ->
mnesia:write(#reg_users_counter{vhost = LServer,
count = 1})
end
end,
mnesia:sync_dirty(F).
dec_vh_registered_users_counter(LServer) ->
F = fun() ->
case mnesia:wread({reg_users_counter, LServer}) of
[C] ->
Count = C#reg_users_counter.count - 1,
C2 = C#reg_users_counter{count = Count},
mnesia:write(C2);
_ ->
error
end
end,
mnesia:sync_dirty(F).
set_vh_registered_users_counter(LServer, Count) ->
F = fun() ->
mnesia:write(#reg_users_counter{vhost = LServer,
count = Count})
end,
mnesia:sync_dirty(F).
get_password(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
@@ -275,8 +303,7 @@ remove_user(User, Server) ->
US = {LUser, LServer},
F = fun() ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter,
LServer, -1)
dec_vh_registered_users_counter(LServer)
end,
mnesia:transaction(F),
ok.
@@ -291,8 +318,7 @@ remove_user(User, Server, Password) ->
case mnesia:read({passwd, US}) of
[#passwd{password = Password}] ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter,
LServer, -1),
dec_vh_registered_users_counter(LServer),
ok;
[_] ->
not_allowed;
+26 -47
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -66,7 +66,7 @@
servers,
backups,
port,
tls_options,
encrypt,
dn,
password,
base,
@@ -119,19 +119,19 @@ terminate(_Reason, _State) ->
init(Host) ->
State = parse_options(Host),
eldap_pool:start_link(State#state.eldap_id,
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.tls_options),
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.encrypt),
eldap_pool:start_link(State#state.bind_eldap_id,
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.tls_options),
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.encrypt),
{ok, State}.
plain_password_required() ->
@@ -153,14 +153,8 @@ check_password(User, Server, Password) ->
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password).
set_password(User, Server, Password) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, State) of
false ->
{error, user_not_found};
DN ->
eldap_pool:modify_passwd(State#state.eldap_id, DN, Password)
end.
set_password(_User, _Server, _Password) ->
{error, not_allowed}.
%% @spec (User, Server, Password) -> {error, not_allowed}
try_register(_User, _Server, _Password) ->
@@ -223,13 +217,13 @@ get_vh_registered_users_ldap(Server) ->
UIDs = State#state.uids,
Eldap_ID = State#state.eldap_id,
Server = State#state.host,
ResAttrs = result_attrs(State),
SortedDNAttrs = eldap_utils:usort_attrs(State#state.dn_filter_attrs),
case eldap_filter:parse(State#state.sfilter) of
{ok, EldapFilter} ->
case eldap_pool:search(Eldap_ID, [{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{attributes, ResAttrs}]) of
{attributes, SortedDNAttrs}]) of
#eldap_search_result{entries = Entries} ->
lists:flatmap(
fun(#eldap_entry{attributes = Attrs,
@@ -275,16 +269,15 @@ handle_call(_Request, _From, State) ->
{reply, bad_request, State}.
find_user_dn(User, State) ->
ResAttrs = result_attrs(State),
DNAttrs = eldap_utils:usort_attrs(State#state.dn_filter_attrs),
case eldap_filter:parse(State#state.ufilter, [{"%u", User}]) of
{ok, Filter} ->
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base},
{filter, Filter},
{attributes, ResAttrs}]) of
case eldap_pool:search(State#state.eldap_id, [{base, State#state.base},
{filter, Filter},
{attributes, DNAttrs}]) of
#eldap_search_result{entries = [#eldap_entry{attributes = Attrs,
object_name = DN} | _]} ->
dn_filter(DN, Attrs, State);
dn_filter(DN, Attrs, State);
_ ->
false
end;
@@ -353,14 +346,6 @@ local_filter(equal, Attrs, FilterMatch) ->
local_filter(notequal, Attrs, FilterMatch) ->
not local_filter(equal, Attrs, FilterMatch).
result_attrs(#state{uids = UIDs, dn_filter_attrs = DNFilterAttrs}) ->
lists:foldl(
fun({UID}, Acc) ->
[UID | Acc];
({UID, _}, Acc) ->
[UID | Acc]
end, DNFilterAttrs, UIDs).
%%%----------------------------------------------------------------------
%%% Auxiliary functions
%%%----------------------------------------------------------------------
@@ -373,7 +358,6 @@ parse_options(Host) ->
Backups -> Backups
end,
LDAPEncrypt = ejabberd_config:get_local_option({ldap_encrypt, Host}),
LDAPTLSVerify = ejabberd_config:get_local_option({ldap_tls_verify, Host}),
LDAPPort = case ejabberd_config:get_local_option({ldap_port, Host}) of
undefined -> case LDAPEncrypt of
tls -> ?LDAPS_PORT;
@@ -404,12 +388,8 @@ parse_options(Host) ->
LDAPBase = ejabberd_config:get_local_option({ldap_base, Host}),
{DNFilter, DNFilterAttrs} =
case ejabberd_config:get_local_option({ldap_dn_filter, Host}) of
undefined ->
{undefined, []};
{DNF, undefined} ->
{DNF, []};
{DNF, DNFA} ->
{DNF, DNFA}
undefined -> {undefined, undefined};
{DNF, DNFA} -> {DNF, DNFA}
end,
LocalFilter = ejabberd_config:get_local_option({ldap_local_filter, Host}),
#state{host = Host,
@@ -418,8 +398,7 @@ parse_options(Host) ->
servers = LDAPServers,
backups = LDAPBackups,
port = LDAPPort,
tls_options = [{encrypt, LDAPEncrypt},
{tls_verify, LDAPTLSVerify}],
encrypt = LDAPEncrypt,
dn = RootDN,
password = Password,
base = LDAPBase,
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+3 -16
View File
@@ -5,7 +5,7 @@
%%% Created : 5 Jul 2007 by Evgeniy Khramtsov <xram@jabber.ru>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -60,11 +60,7 @@ check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Host, Password) ->
Service = get_pam_service(Host),
UserInfo = case get_pam_userinfotype(Host) of
username -> User;
jid -> User++"@"++Host
end,
case catch epam:authenticate(Service, UserInfo, Password) of
case catch epam:authenticate(Service, User, Password) of
true -> true;
_ -> false
end.
@@ -88,11 +84,7 @@ get_password_s(_User, _Server) ->
%% TODO: Improve this function to return an error instead of 'false' when connection to PAM failed
is_user_exists(User, Host) ->
Service = get_pam_service(Host),
UserInfo = case get_pam_userinfotype(Host) of
username -> User;
jid -> User++"@"++Host
end,
case catch epam:acct_mgmt(Service, UserInfo) of
case catch epam:acct_mgmt(Service, User) of
true -> true;
_ -> false
end.
@@ -114,8 +106,3 @@ get_pam_service(Host) ->
undefined -> "ejabberd";
Service -> Service
end.
get_pam_userinfotype(Host) ->
case ejabberd_config:get_local_option({pam_userinfotype, Host}) of
undefined -> username;
Type -> Type
end.
+33 -139
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -28,9 +28,7 @@
-author('alexey@process-one.net').
-update_info({update, 0}).
-define(GEN_FSM, p1_fsm).
-behaviour(?GEN_FSM).
-behaviour(gen_fsm).
%% External exports
-export([start/2,
@@ -55,9 +53,7 @@
handle_sync_event/4,
code_change/4,
handle_info/3,
terminate/3,
print_state/1
]).
terminate/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@@ -108,8 +104,8 @@
%% Module start with or without supervisor:
-ifdef(NO_TRANSIENT_SUPERVISORS).
-define(SUPERVISOR_START, ?GEN_FSM:start(ejabberd_c2s, [SockData, Opts],
fsm_limit_opts(Opts) ++ ?FSMOPTS)).
-define(SUPERVISOR_START, gen_fsm:start(ejabberd_c2s, [SockData, Opts],
?FSMOPTS)).
-else.
-define(SUPERVISOR_START, supervisor:start_child(ejabberd_c2s_sup,
[SockData, Opts])).
@@ -144,18 +140,17 @@ start(SockData, Opts) ->
?SUPERVISOR_START.
start_link(SockData, Opts) ->
?GEN_FSM:start_link(ejabberd_c2s, [SockData, Opts],
fsm_limit_opts(Opts) ++ ?FSMOPTS).
gen_fsm:start_link(ejabberd_c2s, [SockData, Opts], ?FSMOPTS).
socket_type() ->
xml_stream.
%% Return Username, Resource and presence information
get_presence(FsmRef) ->
?GEN_FSM:sync_send_all_state_event(FsmRef, {get_presence}, 1000).
gen_fsm:sync_send_all_state_event(FsmRef, {get_presence}, 1000).
stop(FsmRef) ->
?GEN_FSM:send_event(FsmRef, closed).
gen_fsm:send_event(FsmRef, closed).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
@@ -192,6 +187,7 @@ init([{SockMod, Socket}, Opts]) ->
(_) -> false
end, Opts),
TLSOpts = [verify_none | TLSOpts1],
Zlib = lists:member(zlib, Opts) andalso (not StartTLSRequired),
IP = peerip(SockMod, Socket),
%% Check if IP is blacklisted:
case is_ip_blacklisted(IP) of
@@ -226,7 +222,7 @@ init([{SockMod, Socket}, Opts]) ->
%% Return list of all available resources of contacts,
get_subscribed(FsmRef) ->
?GEN_FSM:sync_send_all_state_event(FsmRef, get_subscribed, 1000).
gen_fsm:sync_send_all_state_event(FsmRef, get_subscribed, 1000).
%%----------------------------------------------------------------------
%% Func: StateName/2
@@ -317,10 +313,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
[{xmlelement, "mechanisms",
[{"xmlns", ?NS_SASL}],
Mechs}] ++
ejabberd_hooks:run_fold(
c2s_stream_features,
Server,
[], [Server])}),
ejabberd_hooks:run_fold(
c2s_stream_features,
Server,
[], [])}),
fsm_next_state(wait_for_feature_request,
StateData#state{
server = Server,
@@ -329,20 +325,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
_ ->
case StateData#state.resource of
"" ->
RosterVersioningFeature =
ejabberd_hooks:run_fold(
roster_get_versioning_feature,
Server, [], [Server]),
StreamFeatures =
[{xmlelement, "bind",
[{"xmlns", ?NS_BIND}], []},
{xmlelement, "session",
[{"xmlns", ?NS_SESSION}], []}]
++ RosterVersioningFeature
++ ejabberd_hooks:run_fold(
c2s_stream_features,
Server,
[], [Server]),
RosterVersioningFeature = ejabberd_hooks:run_fold(roster_get_versioning_feature, Server, [], [Server]),
StreamFeatures = [{xmlelement, "bind",
[{"xmlns", ?NS_BIND}], []},
{xmlelement, "session",
[{"xmlns", ?NS_SESSION}], []} | RosterVersioningFeature],
send_element(
StateData,
{xmlelement, "stream:features", [],
@@ -471,11 +458,11 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip}, {conn, Conn},
{auth_module, AuthModule}],
ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info),
Res1 = jlib:make_result_iq_reply(El),
Res = setelement(4, Res1, []),
send_element(StateData, Res),
ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info),
change_shaper(StateData, JID),
{Fs, Ts} = ejabberd_hooks:run_fold(
roster_get_subscription_lists,
@@ -787,15 +774,6 @@ wait_for_bind({xmlstreamelement, El}, StateData) ->
fsm_next_state(wait_for_bind, StateData);
_ ->
JID = jlib:make_jid(U, StateData#state.server, R),
%%Server = StateData#state.server,
%%RosterVersioningFeature =
%% ejabberd_hooks:run_fold(
%% roster_get_versioning_feature, Server, [], [Server]),
%%StreamFeatures = [{xmlelement, "session",
%% [{"xmlns", ?NS_SESSION}], []} |
%% RosterVersioningFeature],
%%send_element(StateData, {xmlelement, "stream:features",
%% [], StreamFeatures}),
Res = IQ#iq{type = result,
sub_el = [{xmlelement, "bind",
[{"xmlns", ?NS_BIND}],
@@ -839,6 +817,12 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
?INFO_MSG("(~w) Opened session for ~s",
[StateData#state.socket,
jlib:jid_to_string(JID)]),
SID = {now(), self()},
Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip}, {conn, Conn},
{auth_module, StateData#state.auth_module}],
ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info),
Res = jlib:make_result_iq_reply(El),
send_element(StateData, Res),
change_shaper(StateData, JID),
@@ -855,12 +839,6 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
privacy_get_user_list, StateData#state.server,
#userlist{},
[U, StateData#state.server]),
SID = {now(), self()},
Conn = get_conn_type(StateData),
Info = [{ip, StateData#state.ip}, {conn, Conn},
{auth_module, StateData#state.auth_module}],
ejabberd_sm:open_session(
SID, U, StateData#state.server, R, Info),
NewStateData =
StateData#state{
sid = SID,
@@ -917,7 +895,7 @@ session_established({xmlstreamelement, El}, StateData) ->
session_established(timeout, StateData) ->
%% TODO: Options must be stored in state:
Options = [],
proc_lib:hibernate(?GEN_FSM, enter_loop,
proc_lib:hibernate(gen_fsm, enter_loop,
[?MODULE, Options, session_established, StateData]),
fsm_next_state(session_established, StateData);
@@ -1242,7 +1220,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
"iq" ->
IQ = jlib:iq_query_info(Packet),
case IQ of
#iq{xmlns = ?NS_VCARD} when (To#jid.luser == "") or (To#jid.lresource == "") ->
#iq{xmlns = ?NS_VCARD} ->
Host = StateData#state.server,
case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of
[{_, Module, Function, Opts}] ->
@@ -1284,19 +1262,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
{From, To, Packet},
in]) of
allow ->
case ejabberd_hooks:run_fold(
feature_check_packet, StateData#state.server,
allow,
[StateData#state.jid,
StateData#state.server,
StateData#state.pres_last,
{From, To, Packet},
in]) of
allow ->
{true, Attrs, StateData};
deny ->
{false, Attrs, StateData}
end;
{true, Attrs, StateData};
deny ->
{false, Attrs, StateData}
end;
@@ -1328,55 +1294,10 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData)
when Monitor == StateData#state.socket_monitor ->
{stop, normal, StateData};
handle_info(system_shutdown, StateName, StateData) ->
case StateName of
wait_for_stream ->
send_header(StateData, ?MYNAME, "1.0", "en"),
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
send_trailer(StateData),
ok;
_ ->
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
send_trailer(StateData),
ok
end,
{stop, normal, StateData};
handle_info({force_update_presence, LUser}, StateName,
#state{user = LUser, server = LServer} = StateData) ->
NewStateData =
case StateData#state.pres_last of
{xmlelement, "presence", _Attrs, _Els} ->
PresenceEl = ejabberd_hooks:run_fold(
c2s_update_presence,
LServer,
StateData#state.pres_last,
[LUser, LServer]),
StateData2 = StateData#state{pres_last = PresenceEl},
presence_update(StateData2#state.jid,
PresenceEl,
StateData2),
StateData2;
_ ->
StateData
end,
{next_state, StateName, NewStateData};
handle_info(Info, StateName, StateData) ->
?ERROR_MSG("Unexpected info: ~p", [Info]),
fsm_next_state(StateName, StateData).
%%----------------------------------------------------------------------
%% Func: print_state/1
%% Purpose: Prepare the state to be printed on error log
%% Returns: State to print
%%----------------------------------------------------------------------
print_state(State = #state{pres_t = T, pres_f = F, pres_a = A, pres_i = I}) ->
State#state{pres_t = {pres_t, ?SETS:size(T)},
pres_f = {pres_f, ?SETS:size(F)},
pres_a = {pres_a, ?SETS:size(A)},
pres_i = {pres_i, ?SETS:size(I)}
}.
%%----------------------------------------------------------------------
%% Func: terminate/3
%% Purpose: Shutdown the fsm
@@ -1435,8 +1356,7 @@ terminate(_Reason, StateName, StateData) ->
presence_broadcast(
StateData, From, StateData#state.pres_i, Packet)
end
end,
bounce_messages();
end;
_ ->
ok
end,
@@ -2081,12 +2001,8 @@ resend_offline_messages(#state{user = User,
jlib:jid_to_string(From),
jlib:jid_to_string(To),
Attrs),
FixedPacket = {xmlelement, Name, Attrs2, Els},
send_element(StateData, FixedPacket),
ejabberd_hooks:run(user_receive_packet,
StateData#state.server,
[StateData#state.jid,
From, To, FixedPacket]);
send_element(StateData,
{xmlelement, Name, Attrs2, Els});
true ->
ok
end
@@ -2216,28 +2132,6 @@ check_from(El, FromJID) ->
end
end.
fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) ->
[{max_queue, N}];
_ ->
case ejabberd_config:get_local_option(max_fsm_queue) of
N when is_integer(N) ->
[{max_queue, N}];
_ ->
[]
end
end.
bounce_messages() ->
receive
{route, From, To, El} ->
ejabberd_router:route(From, To, El),
bounce_messages()
after 0 ->
ok
end.
%%%----------------------------------------------------------------------
%%% JID Set memory footprint reduction code
%%%----------------------------------------------------------------------
+1 -1
View File
@@ -6,7 +6,7 @@
%%% Created : 2 Nov 2007 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+4 -7
View File
@@ -5,7 +5,7 @@
%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -328,9 +328,7 @@ get_prog_name() ->
FileName when is_list(FileName) ->
FileName;
_ ->
?DEBUG("The option captcha_cmd is not configured, but some "
"module wants to use the CAPTCHA feature.", []),
throw({error, option_not_configured_captcha_cmd})
""
end.
get_url(Str) ->
@@ -390,10 +388,9 @@ return(Port, TRef, Result) ->
Result.
is_feature_enabled() ->
try get_prog_name() of
case get_prog_name() of
"" -> false;
Prog when is_list(Prog) -> true
catch
_:_ -> false
end.
is_feature_available() ->
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Feb 2008 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+6 -8
View File
@@ -5,7 +5,7 @@
%%% Created : 20 May 2008 by Badlop <badlop@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -356,14 +356,15 @@ get_tags_commands() ->
%% @doc Check access is allowed to that command.
%% At least one AccessCommand must be satisfied.
%% It may throw {error, Error} where:
%% Error = account_unprivileged | invalid_account_data
%% Error = account_unprivileged | invalid_account_data | no_auth_provided
check_access_commands([], _Auth, _Method, _Command, _Arguments) ->
ok;
check_access_commands(AccessCommands, Auth, Method, Command, Arguments) ->
{ok, User, Server} = check_auth(Auth),
AccessCommandsAllowed =
lists:filter(
fun({Access, Commands, ArgumentRestrictions}) ->
case check_access(Access, Auth) of
case check_access(Access, User, Server) of
true ->
check_access_command(Commands, Command, ArgumentRestrictions,
Method, Arguments);
@@ -378,7 +379,7 @@ check_access_commands(AccessCommands, Auth, Method, Command, Arguments) ->
end.
check_auth(noauth) ->
no_auth_provided;
throw({error, no_auth_provided});
check_auth({User, Server, Password}) ->
%% Check the account exists and password is valid
AccountPass = ejabberd_auth:get_password_s(User, Server),
@@ -393,10 +394,7 @@ get_md5(AccountPass) ->
lists:flatten([io_lib:format("~.16B", [X])
|| X <- binary_to_list(crypto:md5(AccountPass))]).
check_access(all, _) ->
true;
check_access(Access, Auth) ->
{ok, User, Server} = check_auth(Auth),
check_access(Access, User, Server) ->
%% Check this user has access permission
case acl:match_rule(Server, Access, jlib:make_jid(User, Server, "")) of
allow -> true;
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+9 -59
View File
@@ -5,7 +5,7 @@
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -101,14 +101,15 @@ get_plain_terms_file(File1) ->
case file:consult(File) of
{ok, Terms} ->
include_config_files(Terms);
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
ExitText = describe_config_problem(File, Reason, LineNumber),
?ERROR_MSG(ExitText, []),
exit_or_halt(ExitText);
{error, {_LineNumber, erl_parse, _ParseMessage} = Reason} ->
ExitText = lists:flatten(File ++ " approximately in the line "
++ file:format_error(Reason)),
?ERROR_MSG("Problem loading ejabberd config file ~n~s", [ExitText]),
exit(ExitText);
{error, Reason} ->
ExitText = describe_config_problem(File, Reason),
?ERROR_MSG(ExitText, []),
exit_or_halt(ExitText)
ExitText = lists:flatten(File ++ ": " ++ file:format_error(Reason)),
?ERROR_MSG("Problem loading ejabberd config file ~n~s", [ExitText]),
exit(ExitText)
end.
%% @doc Convert configuration filename to absolute path.
@@ -169,57 +170,6 @@ normalize_hosts([Host|Hosts], PrepHosts) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Errors reading the config file
describe_config_problem(Filename, Reason) ->
Text1 = lists:flatten("Problem loading ejabberd config file " ++ Filename),
Text2 = lists:flatten(" : " ++ file:format_error(Reason)),
ExitText = Text1 ++ Text2,
ExitText.
describe_config_problem(Filename, Reason, LineNumber) ->
Text1 = lists:flatten("Problem loading ejabberd config file " ++ Filename),
Text2 = lists:flatten(" approximately in the line "
++ file:format_error(Reason)),
ExitText = Text1 ++ Text2,
Lines = get_config_lines(Filename, LineNumber, 10, 3),
?ERROR_MSG("The following lines from your configuration file might be"
" relevant to the error: ~n~s", [Lines]),
ExitText.
get_config_lines(Filename, TargetNumber, PreContext, PostContext) ->
{ok, Fd} = file:open(Filename, [read]),
LNumbers = lists:seq(TargetNumber-PreContext, TargetNumber+PostContext),
NextL = io:get_line(Fd, no_prompt),
R = get_config_lines2(Fd, NextL, 1, LNumbers, []),
file:close(Fd),
R.
get_config_lines2(_Fd, eof, _CurrLine, _LNumbers, R) ->
lists:reverse(R);
get_config_lines2(_Fd, _NewLine, _CurrLine, [], R) ->
lists:reverse(R);
get_config_lines2(Fd, Data, CurrLine, [NextWanted | LNumbers], R) when is_list(Data) ->
NextL = io:get_line(Fd, no_prompt),
if
CurrLine >= NextWanted ->
Line2 = [integer_to_list(CurrLine), ": " | Data],
get_config_lines2(Fd, NextL, CurrLine+1, LNumbers, [Line2 | R]);
true ->
get_config_lines2(Fd, NextL, CurrLine+1, [NextWanted | LNumbers], R)
end.
%% If ejabberd isn't yet running in this node, then halt the node
exit_or_halt(ExitText) ->
case [Vsn || {ejabberd, _Desc, Vsn} <- application:which_applications()] of
[] ->
timer:sleep(1000),
halt(ExitText);
[_] ->
exit(ExitText)
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Support for 'include_config_file'
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+14 -20
View File
@@ -5,7 +5,7 @@
%%% Created : 11 Jan 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -189,21 +189,16 @@ process(["help" | Mode]) ->
["help"] ->
print_usage_help(MaxC, ShCode),
?STATUS_SUCCESS;
[CmdString | _] ->
{ok, CmdStringU, _} = regexp:gsub(CmdString, "-", "_"),
print_usage_commands(CmdStringU, MaxC, ShCode),
[CommandString | _] ->
print_usage_commands(CommandString, MaxC, ShCode),
?STATUS_SUCCESS
end;
process(Args) ->
AccessCommands = get_accesscommands(),
{String, Code} = process2(Args, AccessCommands),
case String of
[] -> ok;
_ ->
io:format(String),
io:format("\n")
end,
io:format(String),
io:format("\n"),
Code.
%% @spec (Args::[string()], AccessCommands) -> {String::string(), Code::integer()}
@@ -319,19 +314,18 @@ format_args(Args, ArgsFormat) ->
[],
lists:zip(ArgsFormat, Args)).
format_arg(Arg, integer) ->
format_arg2(Arg, "~d");
format_arg("", string) ->
"";
format_arg(Arg, string) ->
NumChars = integer_to_list(string:len(Arg)),
Parse = "~" ++ NumChars ++ "c",
format_arg2(Arg, Parse).
format_arg2(Arg, Parse)->
format_arg(Arg, Format) ->
Parse = case Format of
integer ->
"~d";
string ->
NumChars = integer_to_list(string:len(Arg)),
"~" ++ NumChars ++ "c"
end,
{ok, [Arg2], _RemainingArguments} = io_lib:fread(Parse, Arg),
Arg2.
%%-----------------------------
%% Format result
%%-----------------------------
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 6 may 2009 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Aug 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+5 -16
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -31,7 +31,6 @@
init/3,
start_listeners/0,
start_listener/3,
stop_listeners/0,
stop_listener/2,
parse_listener_portip/2,
add_listener/3,
@@ -128,12 +127,10 @@ init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
end.
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
SockOpts2 = try erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true} | SockOpts];
false -> SockOpts
catch
_:_ -> []
end,
SockOpts2 = case erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true} | SockOpts];
false -> SockOpts
end,
Res = gen_tcp:listen(Port, [binary,
{packet, 0},
{active, false},
@@ -307,14 +304,6 @@ start_listener_sup(Port, Module, Opts) ->
[?MODULE]},
supervisor:start_child(ejabberd_listeners, ChildSpec).
stop_listeners() ->
Ports = ejabberd_config:get_local_option(listen),
lists:foreach(
fun({PortIpNetp, Module, _Opts}) ->
delete_listener(PortIpNetp, Module)
end,
Ports).
%% @spec (PortIP, Module) -> ok
%% where
%% PortIP = {Port, IPT | IPS}
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 30 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -9,7 +9,7 @@
%%% Created : 29 Nov 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 1 Nov 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+12 -24
View File
@@ -5,7 +5,7 @@
%%% Created : 17 Jul 2008 by Pablo Polvorin <pablo.polvorin@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -212,7 +212,7 @@ add_user(El, Domain, User, Password) ->
El),
ok;
{atomic, exists} ->
io:format("Account ~s@~s already exists, updating it...~n",
?INFO_MSG("User ~p@~p already exists, using stored profile...~n",
[User, Domain]),
io:format(""),
ok = exmpp_xml:foreach(
@@ -417,10 +417,10 @@ to_list(B) when is_atom(B) -> atom_to_list(B).
%%%==================================
%%%% Export hosts
%%%% Export server
%% @spec (Dir::string(), Hosts::[string()]) -> ok
export_hosts(Dir, Hosts) ->
%% @spec (Dir::string()) -> ok
export_server(Dir) ->
try_start_exmpp(),
FnT = make_filename_template(),
@@ -430,6 +430,7 @@ export_hosts(Dir, Hosts) ->
print(Fd, make_piefxis_xml_head()),
print(Fd, make_piefxis_server_head()),
Hosts = ?MYHOSTS,
FilesAndHosts = [{make_host_filename(FnT, Host), Host} || Host <- Hosts],
[print(Fd, make_xinclude(FnH)) || {FnH, _Host} <- FilesAndHosts],
@@ -441,21 +442,15 @@ export_hosts(Dir, Hosts) ->
ok.
%%%==================================
%%%% Export server
%% @spec (Dir::string()) -> ok
export_server(Dir) ->
Hosts = ?MYHOSTS,
export_hosts(Dir, Hosts).
%%%==================================
%%%% Export host
%% @spec (Dir::string(), Host::string()) -> ok
export_host(Dir, Host) ->
Hosts = [Host],
export_hosts(Dir, Hosts).
try_start_exmpp(),
FnT = make_filename_template(),
FnH = make_host_filename(FnT, Host),
export_host(Dir, FnH, Host).
%% @spec (Dir::string(), Fn::string(), Host::string()) -> ok
export_host(Dir, FnH, Host) ->
@@ -468,7 +463,6 @@ export_host(Dir, FnH, Host) ->
Users = ejabberd_auth:get_vh_registered_users(Host),
[export_user(Fd, Username, Host) || {Username, _Host} <- Users],
timer:sleep(500), % Delay to ensure ERROR_MSG are displayed in the shell
print(Fd, make_piefxis_host_tail()),
print(Fd, make_piefxis_xml_tail()),
@@ -517,14 +511,8 @@ make_xinclude(Fn) ->
%% @spec (Fd, Username::string(), Host::string()) -> ok
%% @doc Extract user information and print it.
export_user(Fd, Username, Host) ->
try extract_user(Username, Host) of
UserString ->
print(Fd, UserString)
catch
E1:E2 ->
?ERROR_MSG("The account ~s@~s is not exported because a problem "
"was found in it:~n~p: ~p", [Username, Host, E1, E2])
end.
UserString = extract_user(Username, Host),
print(Fd, UserString).
%% @spec (Username::string(), Host::string()) -> string()
extract_user(Username, Host) ->
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 10 Nov 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+2 -14
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -31,7 +31,6 @@
%% API
-export([route/3,
route_error/4,
register_route/1,
register_route/2,
register_routes/1,
@@ -73,17 +72,6 @@ route(From, To, Packet) ->
ok
end.
%% Route the error packet only if the originating packet is not an error itself.
%% RFC3920 9.3.1
route_error(From, To, ErrPacket, OrigPacket) ->
{xmlelement, _Name, Attrs, _Els} = OrigPacket,
case "error" == xml:get_attr_s("type", Attrs) of
false ->
route(From, To, ErrPacket);
true ->
ok
end.
register_route(Domain) ->
register_route(Domain, undefined).
@@ -103,7 +91,7 @@ register_route(Domain, LocalHint) ->
mnesia:transaction(F);
N ->
F = fun() ->
case mnesia:wread({route, LDomain}) of
case mnesia:read({route, LDomain}) of
[] ->
mnesia:write(
#route{domain = LDomain,
+11 -27
View File
@@ -5,7 +5,7 @@
%%% Created : 7 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -245,7 +245,7 @@ clean_table_from_bad_node(Node) ->
mnesia:delete_object(E)
end, Es)
end,
mnesia:async_dirty(F).
mnesia:transaction(F).
do_route(From, To, Packet) ->
?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n",
@@ -486,31 +486,15 @@ update_tables() ->
%% Check if host is in blacklist or white list
allow_host(MyServer, S2SHost) ->
case lists:filter(
fun(Host) ->
is_subdomain(MyServer, Host)
end, ?MYHOSTS) of
[MyHost|_] ->
allow_host1(MyHost, S2SHost);
[] ->
allow_host1(MyServer, S2SHost)
end.
allow_host1(MyHost, S2SHost) ->
case ejabberd_config:get_local_option({{s2s_host, S2SHost}, MyHost}) of
deny -> false;
allow -> true;
_ ->
case ejabberd_config:get_local_option({s2s_default_policy, MyHost}) of
deny -> false;
_ ->
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
allow, [MyHost, S2SHost]) of
deny -> false;
allow -> true;
_ -> true
end
end
case ejabberd_config:get_local_option({{s2s_host, S2SHost},MyServer}) of
deny -> false;
allow -> true;
_ ->
case ejabberd_config:get_local_option({s2s_default_policy, MyServer}) of
deny -> false;
allow -> true;
_ -> true %% The default s2s policy is allow
end
end.
%% Get information about S2S connections of the specified type.
+6 -15
View File
@@ -5,7 +5,7 @@
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -177,9 +177,8 @@ init([{SockMod, Socket}, Opts]) ->
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
case {xml:get_attr_s("xmlns", Attrs),
xml:get_attr_s("xmlns:db", Attrs),
xml:get_attr_s("to", Attrs),
xml:get_attr_s("version", Attrs) == "1.0"} of
{"jabber:server", _, Server, true} when
{"jabber:server", _, true} when
StateData#state.tls and (not StateData#state.authenticated) ->
send_text(StateData, ?STREAM_HEADER(" version='1.0'")),
SASL =
@@ -213,23 +212,15 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
end,
send_element(StateData,
{xmlelement, "stream:features", [],
SASL ++ StartTLS ++
ejabberd_hooks:run_fold(
s2s_stream_features,
Server,
[], [Server])}),
SASL ++ StartTLS}),
{next_state, wait_for_feature_request, StateData};
{"jabber:server", _, Server, true} when
{"jabber:server", _, true} when
StateData#state.authenticated ->
send_text(StateData, ?STREAM_HEADER(" version='1.0'")),
send_element(StateData,
{xmlelement, "stream:features", [],
ejabberd_hooks:run_fold(
s2s_stream_features,
Server,
[], [Server])}),
{xmlelement, "stream:features", [], []}),
{next_state, stream_established, StateData};
{"jabber:server", "jabber:server:dialback", _Server, _} ->
{"jabber:server", "jabber:server:dialback", _} ->
send_text(StateData, ?STREAM_HEADER("")),
{next_state, stream_established, StateData};
_ ->
+32 -50
View File
@@ -5,7 +5,7 @@
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -51,7 +51,6 @@
handle_sync_event/4,
handle_info/3,
terminate/3,
print_state/1,
code_change/4,
test_get_addr_port/1,
get_addr_port/1]).
@@ -266,12 +265,10 @@ open_socket1(Host, Port) ->
open_socket2(Type, Addr, Port) ->
?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]),
Timeout = outgoing_s2s_timeout(),
SockOpts = try erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true}];
false -> []
catch
_:_ -> []
end,
SockOpts = case erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true}];
false -> []
end,
case (catch ejabberd_socket:connect(Addr, Port,
[binary, {packet, 0},
{send_timeout, ?TCP_SEND_TIMEOUT},
@@ -300,12 +297,11 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
{next_state, wait_for_features, StateData, ?FSMTIMEOUT};
{"jabber:server", "", true} when StateData#state.use_v10 ->
{next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT};
{NSProvided, DB, _} ->
{NSProvided, _, _} ->
send_text(StateData, ?INVALID_NAMESPACE_ERR),
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace).~n"
"Namespace provided: ~p~nNamespace expected: \"jabber:server\"~n"
"xmlns:db provided: ~p~nAll attributes: ~p",
[StateData#state.myname, StateData#state.server, NSProvided, DB, Attrs]),
"Namespace provided: ~p~nNamespace expected: \"jabber:server\"",
[StateData#state.myname, StateData#state.server, NSProvided]),
{stop, normal, StateData}
end;
@@ -876,14 +872,6 @@ terminate(Reason, StateName, StateData) ->
end,
ok.
%%----------------------------------------------------------------------
%% Func: print_state/1
%% Purpose: Prepare the state to be printed on error log
%% Returns: State to print
%%----------------------------------------------------------------------
print_state(State) ->
State.
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
@@ -961,36 +949,30 @@ send_db_request(StateData) ->
Key ->
Key
end,
NewStateData = StateData#state{new = New},
try
case New of
false ->
ok;
Key1 ->
send_element(StateData,
{xmlelement,
"db:result",
[{"from", StateData#state.myname},
{"to", Server}],
[{xmlcdata, Key1}]})
end,
case StateData#state.verify of
false ->
ok;
{_Pid, Key2, SID} ->
send_element(StateData,
{xmlelement,
"db:verify",
[{"from", StateData#state.myname},
{"to", StateData#state.server},
{"id", SID}],
[{xmlcdata, Key2}]})
end,
{next_state, wait_for_validation, NewStateData, ?FSMTIMEOUT*6}
catch
_:_ ->
{stop, normal, NewStateData}
end.
case New of
false ->
ok;
Key1 ->
send_element(StateData,
{xmlelement,
"db:result",
[{"from", StateData#state.myname},
{"to", Server}],
[{xmlcdata, Key1}]})
end,
case StateData#state.verify of
false ->
ok;
{_Pid, Key2, SID} ->
send_element(StateData,
{xmlelement,
"db:verify",
[{"from", StateData#state.myname},
{"to", StateData#state.server},
{"id", SID}],
[{xmlcdata, Key2}]})
end,
{next_state, wait_for_validation, StateData#state{new = New}, ?FSMTIMEOUT*6}.
is_verify_res({xmlelement, Name, Attrs, _Els}) when Name == "db:result" ->
+3 -12
View File
@@ -5,7 +5,7 @@
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -47,8 +47,7 @@
handle_sync_event/4,
code_change/4,
handle_info/3,
terminate/3,
print_state/1]).
terminate/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@@ -351,7 +350,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
send_text(StateData, Text);
deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route_error(To, From, Err, Packet)
ejabberd_router:route(To, From, Err)
end,
{next_state, StateName, StateData}.
@@ -375,14 +374,6 @@ terminate(Reason, StateName, StateData) ->
(StateData#state.sockmod):close(StateData#state.socket),
ok.
%%----------------------------------------------------------------------
%% Func: print_state/1
%% Purpose: Prepare the state to be printed on error log
%% Returns: State to print
%%----------------------------------------------------------------------
print_state(State) ->
State.
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
+41 -40
View File
@@ -5,7 +5,7 @@
%%% Created : 24 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -47,7 +47,6 @@
register_iq_handler/4,
register_iq_handler/5,
unregister_iq_handler/2,
force_update_presence/1,
connected_users/0,
connected_users_number/0,
user_resources/2,
@@ -93,8 +92,7 @@ route(From, To, Packet) ->
open_session(SID, User, Server, Resource, Info) ->
set_session(SID, User, Server, Resource, undefined, Info),
mnesia:dirty_update_counter(session_counter,
jlib:nameprep(Server), 1),
inc_session_counter(jlib:nameprep(Server)),
check_for_sessions_to_replace(User, Server, Resource),
JID = jlib:make_jid(User, Server, Resource),
ejabberd_hooks:run(sm_register_connection_hook, JID#jid.lserver,
@@ -107,8 +105,7 @@ close_session(SID, User, Server, Resource) ->
end,
F = fun() ->
mnesia:delete({session, SID}),
mnesia:dirty_update_counter(session_counter,
jlib:nameprep(Server), -1)
dec_session_counter(jlib:nameprep(Server))
end,
mnesia:sync_dirty(F),
JID = jlib:make_jid(User, Server, Resource),
@@ -266,7 +263,6 @@ init([]) ->
mnesia:add_table_index(session, usr),
mnesia:add_table_index(session, us),
mnesia:add_table_copy(session, node(), ram_copies),
mnesia:add_table_copy(session_counter, node(), ram_copies),
mnesia:subscribe(system),
ets:new(sm_iqtable, [named_table]),
lists:foreach(
@@ -320,7 +316,7 @@ handle_info({route, From, To, Packet}, State) ->
end,
{noreply, State};
handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
recount_session_table(Node),
clean_table_from_bad_node(Node),
{noreply, State};
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
ets:insert(sm_iqtable, {{XMLNS, Host}, Module, Function}),
@@ -377,9 +373,7 @@ set_session(SID, User, Server, Resource, Priority, Info) ->
end,
mnesia:sync_dirty(F).
%% Recalculates alive sessions when Node goes down
%% and updates session and session_counter tables
recount_session_table(Node) ->
clean_table_from_bad_node(Node) ->
F = fun() ->
Es = mnesia:select(
session,
@@ -387,22 +381,12 @@ recount_session_table(Node) ->
[{'==', {node, '$1'}, Node}],
['$_']}]),
lists:foreach(fun(E) ->
{_, LServer} = E#session.us,
dec_session_counter(LServer),
mnesia:delete({session, E#session.sid})
end, Es),
%% reset session_counter table with active sessions
mnesia:clear_table(session_counter),
lists:foreach(fun(Server) ->
LServer = jlib:nameprep(Server),
Hs = mnesia:select(session,
[{#session{usr = '$1', _ = '_'},
[{'==', {element, 2, '$1'}, LServer}],
['$1']}]),
mnesia:write(
#session_counter{vhost = LServer,
count = length(Hs)})
end, ?MYHOSTS)
end, Es)
end,
mnesia:async_dirty(F).
mnesia:sync_dirty(F).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -497,7 +481,7 @@ do_route(From, To, Packet) ->
_ ->
Err =
jlib:make_error_reply(
Packet, ?ERR_SERVICE_UNAVAILABLE),
Packet, ?ERR_RECIPIENT_UNAVAILABLE),
ejabberd_router:route(To, From, Err)
end;
_ ->
@@ -573,10 +557,9 @@ route_message(From, To, Packet) ->
_ ->
case ejabberd_auth:is_user_exists(LUser, LServer) of
true ->
is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run(offline_message_hook,
LServer,
[From, To, Packet]);
ejabberd_hooks:run(offline_message_hook,
LServer,
[From, To, Packet]);
_ ->
Err = jlib:make_error_reply(
Packet, ?ERR_SERVICE_UNAVAILABLE),
@@ -680,6 +663,34 @@ get_max_user_sessions(LUser, Host) ->
_ -> ?MAX_USER_SESSIONS
end.
inc_session_counter(LServer) ->
F = fun() ->
case mnesia:wread({session_counter, LServer}) of
[C] ->
Count = C#session_counter.count + 1,
C2 = C#session_counter{count = Count},
mnesia:write(C2);
_ ->
mnesia:write(#session_counter{vhost = LServer,
count = 1})
end
end,
mnesia:sync_dirty(F).
dec_session_counter(LServer) ->
F = fun() ->
case mnesia:wread({session_counter, LServer}) of
[C] ->
Count = C#session_counter.count - 1,
C2 = C#session_counter{count = Count},
mnesia:write(C2);
_ ->
error
end
end,
mnesia:sync_dirty(F).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
process_iq(From, To, Packet) ->
@@ -713,16 +724,6 @@ process_iq(From, To, Packet) ->
ok
end.
force_update_presence({LUser, _LServer} = US) ->
case catch mnesia:dirty_index_read(session, US, #session.us) of
{'EXIT', _Reason} ->
ok;
Ss ->
lists:foreach(fun(#session{sid = {_, Pid}}) ->
Pid ! {force_update_presence, LUser}
end, Ss)
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% ejabberd commands
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 21 Mar 2007 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 18 Jul 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+5 -12
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -84,7 +84,7 @@ update_info() ->
update_info(Dir, Files) ->
Beams = lists:sort(get_beams(Files)),
UpdatedBeams = get_updated_beams(Beams),
?DEBUG("beam files: ~p~n", [UpdatedBeams]),
?INFO_MSG("beam files: ~p~n", [UpdatedBeams]),
{Script, LowLevelScript, Check} = build_script(Dir, UpdatedBeams),
{ok, Dir, UpdatedBeams, Script, LowLevelScript, Check}.
@@ -124,21 +124,14 @@ get_current_version(Module) ->
%% @spec(Dir::string(), UpdatedBeams::[atom()]) -> {Script,LowLevelScript,Check}
build_script(Dir, UpdatedBeams) ->
Script = make_script(UpdatedBeams),
?INFO_MSG("script: ~p~n", [Script]),
LowLevelScript = make_low_level_script(UpdatedBeams, Script),
?INFO_MSG("low level script: ~p~n", [LowLevelScript]),
Check =
release_handler_1:check_script(
LowLevelScript,
[{ejabberd, "", filename:join(Dir, "..")}]),
case Check of
ok ->
?DEBUG("script: ~p~n", [Script]),
?DEBUG("low level script: ~p~n", [LowLevelScript]),
?DEBUG("check: ~p~n", [Check]);
_ ->
?ERROR_MSG("script: ~p~n", [Script]),
?ERROR_MSG("low level script: ~p~n", [LowLevelScript]),
?ERROR_MSG("check: ~p~n", [Check])
end,
?INFO_MSG("check: ~p~n", [Check]),
{Script, LowLevelScript, Check}.
%% Copied from Erlang/OTP file: lib/sasl/src/systools.hrl
+1 -1
View File
@@ -26,7 +26,7 @@ EFLAGS += -pz ..
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
EFLAGS+=+debug_info
endif
ERLSHLIBS = ../ejabberd_zlib_drv.so
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 19 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* ejabberd, Copyright (C) 2002-2010 ProcessOne
* ejabberd, Copyright (C) 2002-2009 ProcessOne
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
+2 -2
View File
@@ -51,7 +51,7 @@
#FIREWALL_WINDOW=
#.
#' ERL_PROCESSES: Maximum number of Erlang processes
#' PROCESSES: Maximum number of Erlang processes
#
# Erlang consumes a lot of lightweight processes. If there is a lot of activity
# on ejabberd so that the maximum number of processes is reached, people will
@@ -62,7 +62,7 @@
# Default: 250000
# Maximum: 268435456
#
#ERL_PROCESSES=250000
#PROCESSES=250000
#.
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
+19 -99
View File
@@ -57,20 +57,17 @@ fi
# check the proper system user is used
ID=`id -g`
GIDS=`id -G`
EJID=`id -g $INSTALLUSER`
EXEC_CMD="false"
for GID in $GIDS; do
if [ $GID -eq 0 ] ; then
EXEC_CMD="su ${INSTALLUSER} -p -c"
fi
done
if [ $ID -eq 0 ] ; then
EXEC_CMD="su ${INSTALLUSER} -c"
fi
if [ "$ID" -eq "$EJID" ] ; then
EXEC_CMD="sh -c"
fi
if [ "$EXEC_CMD" = "false" ] ; then
echo "This command can only be run by root or the user $INSTALLUSER" >&2
exit 4
exit 1
fi
NAME=-name
@@ -94,7 +91,7 @@ fi
if [ "$EJABBERD_PRIV_PATH" = "" ]; then
EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
fi
if [ "$EJABBERD_BIN_PATH" = "" ]; then
if [ "$EJABBRD_BIN_PATH" = "" ]; then
EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
fi
if [ "$EJABBERD_SO_PATH" = "" ]; then
@@ -153,7 +150,7 @@ debug ()
echo ""
echo "IMPORTANT: we will attempt to attach an INTERACTIVE shell"
echo "to an already running ejabberd node."
echo "If an ERROR is printed, it means the connection was not successful."
echo "If an ERROR is printed, it means the connection was not succesfull."
echo "You can interact with the ejabberd node if you know how to use it."
echo "Please be extremely cautious with your actions,"
echo "and exit immediately if you are not completely sure."
@@ -162,16 +159,11 @@ debug ()
echo " control+c, control+c"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
echo "Press any key to continue"
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
read foo
fi
read foo
echo ""
TTY=`tty | sed -e 's/.*\///g'`
$EXEC_CMD "$ERL \
$NAME debug-${TTY}-${ERLANG_NODE} \
$NAME debug-${ERLANG_NODE} \
-remsh $ERLANG_NODE \
-hidden \
$ERLANG_OPTS $ARGS \"$@\""
@@ -192,12 +184,8 @@ live ()
echo " q(). and press the Enter key"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
echo "Press any key to continue"
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
read foo
fi
read foo
echo ""
$EXEC_CMD "$ERL \
$NAME $ERLANG_NODE \
@@ -229,88 +217,20 @@ help ()
ctl ()
{
COMMAND=$@
# Control number of connections identifiers
# using flock if available. Expects a linux-style
# flock that can lock a file descriptor.
MAXCONNID=100
CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl
FLOCK='/usr/bin/flock'
if [ ! -x "$FLOCK" ] ; then
JOT='/usr/bin/jot'
if [ ! -x "$JOT" ] ; then
# no flock or jot, simply invoke ctlexec()
CTL_CONN="ctl-${ERLANG_NODE}"
ctlexec $CTL_CONN $COMMAND
result=$?
else
# no flock, but at least there is jot
RAND=`jot -r 1 0 $MAXCONNID`
CTL_CONN="ctl-${RAND}-${ERLANG_NODE}"
ctlexec $CTL_CONN $COMMAND
result=$?
fi
else
# we have flock so we get a lock
# on one of a limited number of
# conn names -- this allows
# concurrent invocations using a bound
# number of atoms
for N in $(seq 1 $MAXCONNID); do
CTL_CONN="ejabberdctl-$N"
CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN"
(
exec 8>"$CTL_LOCKFILE"
if flock --nb 8; then
ctlexec $CTL_CONN $COMMAND
ssresult=$?
# segregate from possible flock exit(1)
ssresult=$(expr $ssresult \* 10)
exit $ssresult
else
exit 1
fi
)
result=$?
if [ $result -eq 1 ]; then
# means we errored out in flock
# rather than in the exec - stay in the loop
# trying other conn names...
badlock=1
else
badlock=""
break;
fi
done
result=$(expr $result / 10)
fi
if [ "$badlock" ];then
echo "Ran out of connections to try. Your ejabberd processes" >&2
echo "may be stuck or this is a very busy server. For very" >&2
echo "busy servers, consider raising MAXCONNID in ejabberdctl">&2
exit 1;
fi
case $result in
0) :;;
1) :;;
2) help;;
3) help;;
esac
return $result
}
ctlexec ()
{
CONN_NAME=$1; shift
COMMAND=$@
$EXEC_CMD "$ERL \
$NAME ${CONN_NAME} \
$NAME ctl-${ERLANG_NODE} \
-noinput \
-hidden \
-pa $EJABBERD_EBIN_PATH \
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
result=$?
case $result in
0) :;;
1) :;;
2) help;;
3) help;;
esac
return $result
}
# display ctl usage
@@ -335,7 +255,7 @@ wait_for_status()
status=4
while [ $status -ne $1 ]; do
sleep $3
timeout=$(($timeout - 1))
let timeout=timeout-1
[ $timeout -eq 0 ] && {
status=$1
} || {
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 22 Aug 2005 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
-10
View File
@@ -286,16 +286,6 @@ ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
responseName [10] LDAPOID OPTIONAL,
response [11] OCTET STRING OPTIONAL }
passwdModifyOID LDAPOID ::= "1.3.6.1.4.1.4203.1.11.1"
PasswdModifyRequestValue ::= SEQUENCE {
userIdentity [0] OCTET STRING OPTIONAL,
oldPasswd [1] OCTET STRING OPTIONAL,
newPasswd [2] OCTET STRING OPTIONAL }
PasswdModifyResponseValue ::= SEQUENCE {
genPasswd [0] OCTET STRING OPTIONAL }
END
+5 -12
View File
@@ -1,4 +1,4 @@
# $Id: Makefile.in 2842 2009-12-29 19:10:52Z badlop $
# $Id$
CC = @CC@
CFLAGS = @CFLAGS@
@@ -16,27 +16,22 @@ EFLAGS += -pz ..
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
EFLAGS+=+debug_info
endif
OUTDIR = ..
SOURCES = $(wildcard *.erl) ELDAPv3.erl eldap_filter_yecc.erl
SOURCES = $(wildcard *.erl) ELDAPv3.erl
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
all: $(BEAMS) ELDAPv3.beam eldap_filter_yecc.beam
all: $(BEAMS) ELDAPv3.beam
ELDAPv3.beam: ELDAPv3.erl
ELDAPv3.erl: ELDAPv3.asn
@ERLC@ $(ASN_FLAGS) -W $(EFLAGS) $<
eldap_filter_yecc.beam: eldap_filter_yecc.erl
eldap_filter_yecc.erl: eldap_filter_yecc.yrl
@ERLC@ -W $<
$(OUTDIR)/%.beam: %.erl ELDAPv3.erl eldap_filter_yecc.erl
$(OUTDIR)/%.beam: %.erl ELDAPv3.erl
@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
clean:
@@ -44,8 +39,6 @@ clean:
rm -f ELDAPv3.erl
rm -f ELDAPv3.hrl
rm -f ELDAPv3.beam
rm -f eldap_filter_yecc.erl
rm -f eldap_filter_yecc.beam
rm -f $(BEAMS)
distclean: clean
+1 -9
View File
@@ -4,7 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam ..\eldap_filter_yecc.beam
BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam
ASN_FLAGS = -bber_bin +optimize +driver
@@ -15,16 +15,11 @@ Clean :
-@erase ELDAPv3.erl
-@erase ELDAPv3.hrl
-@erase ELDAPv3.beam
-@erase eldap_filter_yecc.erl
-@erase eldap_filter_yecc.beam
-@erase $(BEAMS)
ELDAPv3.erl : ELDAPv3.asn
erlc $(ASN_FLAGS) -W $(EFLAGS) ELDAPv3.asn
eldap_filter_yecc.erl: eldap_filter_yecc.yrl
erlc -W eldap_filter_yecc.yrl
$(OUTDIR)\eldap.beam : eldap.erl ELDAPv3.erl
erlc -W $(EFLAGS) -o $(OUTDIR) eldap.erl
@@ -39,6 +34,3 @@ $(OUTDIR)\eldap_utils.beam : eldap_utils.erl
$(OUTDIR)\eldap_pool.beam : eldap_pool.erl
erlc -W $(EFLAGS) -o $(OUTDIR) eldap_pool.erl
$(OUTDIR)\eldap_filter_yecc.beam : eldap_filter_yecc.erl
erlc -W $(EFLAGS) -o $(OUTDIR) eldap_filter_yecc.erl
+24 -91
View File
@@ -33,11 +33,8 @@
%%% Modified by Alexey Shchepin <alexey@sevcom.net>
%%% Modified by Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%% Modified by Evgeniy Khramtsov <xram@jabber.ru>
%%% Implemented queue for bind() requests to prevent pending binds.
%%% Implemented extensibleMatch/2 function.
%%% Implemented LDAP Extended Operations (currently only Password Modify
%%% is supported - RFC 3062).
%%% Modified by Christophe Romain <christophe.romain@process-one.net>
%%% Improve error case handling
@@ -74,9 +71,9 @@
-export([baseObject/0,singleLevel/0,wholeSubtree/0,close/1,
equalityMatch/2,greaterOrEqual/2,lessOrEqual/2,
approxMatch/2,search/2,substrings/2,present/1,extensibleMatch/2,
approxMatch/2,search/2,substrings/2,present/1,
'and'/1,'or'/1,'not'/1,modify/3, mod_add/2, mod_delete/2,
mod_replace/2, add/3, delete/2, modify_dn/5, modify_passwd/3, bind/3]).
mod_replace/2, add/3, delete/2, modify_dn/5, bind/3]).
-export([get_status/1]).
%% gen_fsm callbacks
@@ -130,10 +127,9 @@ start_link(Name) ->
Reg_name = list_to_atom("eldap_" ++ Name),
gen_fsm:start_link({local, Reg_name}, ?MODULE, [], []).
start_link(Name, Hosts, Port, Rootdn, Passwd, Opts) ->
start_link(Name, Hosts, Port, Rootdn, Passwd, Encrypt) ->
Reg_name = list_to_atom("eldap_" ++ Name),
gen_fsm:start_link({local, Reg_name}, ?MODULE,
{Hosts, Port, Rootdn, Passwd, Opts}, []).
gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd, Encrypt}, []).
%%% --------------------------------------------------------------------
%%% Get status of connection.
@@ -243,10 +239,6 @@ modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup)
{modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)},
?CALL_TIMEOUT).
modify_passwd(Handle, DN, Passwd) when is_list(DN), is_list(Passwd) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(
Handle1, {modify_passwd, DN, Passwd}, ?CALL_TIMEOUT).
%%% --------------------------------------------------------------------
%%% Bind.
@@ -382,29 +374,6 @@ substrings(Type, SubStr) when is_list(Type), is_list(SubStr) ->
{substrings,#'SubstringFilter'{type = Type,
substrings = Ss}}.
%%%
%%% extensibleMatch filter.
%%% FIXME: Describe the purpose of this filter.
%%%
%%% Value ::= string( <attribute> )
%%% Opts ::= listof( {matchingRule, Str} | {type, Str} | {dnAttributes, true} )
%%%
%%% Example: extensibleMatch("Fred", [{matchingRule, "1.2.3.4.5"}, {type, "cn"}]).
%%%
extensibleMatch(Value, Opts) when is_list(Value), is_list(Opts) ->
MRA = #'MatchingRuleAssertion'{matchValue=Value},
{extensibleMatch, extensibleMatch_opts(Opts, MRA)}.
extensibleMatch_opts([{matchingRule, Rule} | Opts], MRA) when is_list(Rule) ->
extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{matchingRule=Rule});
extensibleMatch_opts([{type, Desc} | Opts], MRA) when is_list(Desc) ->
extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{type=Desc});
extensibleMatch_opts([{dnAttributes, true} | Opts], MRA) ->
extensibleMatch_opts(Opts, MRA#'MatchingRuleAssertion'{dnAttributes=true});
extensibleMatch_opts([_ | Opts], MRA) ->
extensibleMatch_opts(Opts, MRA);
extensibleMatch_opts([], MRA) ->
MRA.
get_handle(Pid) when is_pid(Pid) -> Pid;
get_handle(Atom) when is_atom(Atom) -> Atom;
@@ -424,18 +393,15 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name).
%%----------------------------------------------------------------------
init([]) ->
case get_config() of
{ok, Hosts, Rootdn, Passwd, Opts} ->
init({Hosts, Rootdn, Passwd, Opts});
{ok, Hosts, Rootdn, Passwd, Encrypt} ->
init({Hosts, Rootdn, Passwd, Encrypt});
{error, Reason} ->
{stop, Reason}
end;
init({Hosts, Port, Rootdn, Passwd, Opts}) ->
init({Hosts, Port, Rootdn, Passwd, Encrypt}) ->
catch ssl:start(),
ssl:seed(randoms:get_string()),
Encrypt = case proplists:get_value(encrypt, Opts) of
tls -> tls;
_ -> none
end,
{X1,X2,X3} = erlang:now(),
ssl:seed(integer_to_list(X1) ++ integer_to_list(X2) ++ integer_to_list(X3)),
PortTemp = case Port of
undefined ->
case Encrypt of
@@ -448,14 +414,7 @@ init({Hosts, Port, Rootdn, Passwd, Opts}) ->
end;
PT -> PT
end,
TLSOpts = case proplists:get_value(tls_verify, Opts) of
soft ->
[{verify, 1}];
hard ->
[{verify, 2}];
_ ->
[{verify, 0}]
end,
TLSOpts = [verify_none],
{ok, connecting, #eldap{hosts = Hosts,
port = PortTemp,
rootdn = Rootdn,
@@ -712,16 +671,6 @@ gen_req({modify_dn, Entry, NewRDN, DelOldRDN, NewSup}) ->
deleteoldrdn = DelOldRDN,
newSuperior = NewSup}};
gen_req({modify_passwd, DN, Passwd}) ->
{ok, ReqVal} = asn1rt:encode(
'ELDAPv3', 'PasswdModifyRequestValue',
#'PasswdModifyRequestValue'{
userIdentity = DN,
newPasswd = Passwd}),
{extendedReq,
#'ExtendedRequest'{requestName = ?passwdModifyOID,
requestValue = list_to_binary(ReqVal)}};
gen_req({bind, RootDN, Passwd}) ->
{bindRequest,
#'BindRequest'{version = ?LDAP_VERSION,
@@ -796,11 +745,6 @@ recvd_packet(Pkt, S) ->
cancel_timer(Timer),
Reply = check_bind_reply(Result, From),
{reply, Reply, From, S#eldap{dict = New_dict}};
{extendedReq, {extendedResp, Result}} ->
New_dict = dict:erase(Id, Dict),
cancel_timer(Timer),
Reply = check_extended_reply(Result, From),
{reply, Reply, From, S#eldap{dict = New_dict}};
{OtherName, OtherResult} ->
New_dict = dict:erase(Id, Dict),
cancel_timer(Timer),
@@ -825,15 +769,6 @@ check_bind_reply(#'BindResponse'{resultCode = Reason}, _From) ->
check_bind_reply(Other, _From) ->
{error, Other}.
%% TODO: process reply depending on requestName:
%% this requires BER-decoding of #'ExtendedResponse'.response
check_extended_reply(#'ExtendedResponse'{resultCode = success}, _From) ->
ok;
check_extended_reply(#'ExtendedResponse'{resultCode = Reason}, _From) ->
{error, Reason};
check_extended_reply(Other, _From) ->
{error, Other}.
get_op_rec(Id, Dict) ->
case dict:find(Id, Dict) of
{ok, [{Timer, _Command, From, Name}|Res]} ->
@@ -969,7 +904,7 @@ connect_bind(S) ->
tls ->
SockMod = ssl,
SslOpts = [{packet, asn1}, {active, true}, {keepalive, true},
binary | S#eldap.tls_options],
binary],
ssl:connect(Host, S#eldap.port, SslOpts);
%% starttls -> %% TODO: Implement STARTTLS;
_ ->
@@ -1038,8 +973,6 @@ v_filter({lessOrEqual,AV}) -> {lessOrEqual,AV};
v_filter({approxMatch,AV}) -> {approxMatch,AV};
v_filter({present,A}) -> {present,A};
v_filter({substrings,S}) when is_record(S,'SubstringFilter') -> {substrings,S};
v_filter({extensibleMatch, S}) when is_record(S, 'MatchingRuleAssertion') ->
{extensibleMatch, S};
v_filter(_Filter) -> throw({error,concat(["unknown filter: ",_Filter])}).
v_modifications(Mods) ->
@@ -1085,8 +1018,8 @@ get_config() ->
case file:consult(File) of
{ok, Entries} ->
case catch parse(Entries) of
{ok, Hosts, Port, Rootdn, Passwd, Opts} ->
{ok, Hosts, Port, Rootdn, Passwd, Opts};
{ok, Hosts, Port, Rootdn, Passwd, Encrypt} ->
{ok, Hosts, Port, Rootdn, Passwd, Encrypt};
{error, Reason} ->
{error, Reason};
{'EXIT', Reason} ->
@@ -1102,7 +1035,7 @@ parse(Entries) ->
get_integer(port, Entries),
get_list(rootdn, Entries),
get_list(passwd, Entries),
get_list(options, Entries)}.
get_atom(encrypt, Entries)}.
get_integer(Key, List) ->
case lists:keysearch(Key, 1, List) of
@@ -1124,15 +1057,15 @@ get_list(Key, List) ->
throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
end.
%% get_atom(Key, List) ->
%% case lists:keysearch(Key, 1, List) of
%% {value, {Key, Value}} when is_atom(Value) ->
%% Value;
%% {value, {Key, _Value}} ->
%% throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
%% false ->
%% throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
%% end.
get_atom(Key, List) ->
case lists:keysearch(Key, 1, List) of
{value, {Key, Value}} when is_atom(Value) ->
Value;
{value, {Key, _Value}} ->
throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
false ->
throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
end.
get_hosts(Key, List) ->
lists:map(fun({Key1, {A,B,C,D}}) when is_integer(A),
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+190 -65
View File
@@ -3,10 +3,10 @@
%%% Purpose: Converts String Representation of
%%% LDAP Search Filter (RFC 2254)
%%% to eldap's representation of filter
%%% Author: Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%% Author: Evgeniy Khramtsov <xramtsov@gmail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -24,17 +24,19 @@
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(eldap_filter).
%% TODO: remove this when new regexp module will be used
-compile({nowarn_deprecated_function, {regexp, sub, 3}}).
%%%======================
%%% Export functions
%%%======================
-export([parse/1, parse/2, do_sub/2]).
-export([parse/1,
parse/2,
do_sub/2
]).
%%====================================================================
%% API
%%====================================================================
%%%-------------------------------------------------------------------
%%%-------------------------------------------------------------------------
%%% Arity: parse/1
%%% Function: parse(RFC2254_Filter) -> {ok, EldapFilter} |
%%% {error, bad_filter}
@@ -45,15 +47,15 @@
%%% to eldap's representation of filter.
%%%
%%% Example:
%%% > eldap_filter:parse("(&(!(uid<=100))(mail=*))").
%%% > eldap_filter:parse("(&(!(uid<=100))(mail=*))").
%%%
%%% {ok,{'and',[{'not',{lessOrEqual,{'AttributeValueAssertion',"uid","100"}}},
%%% {present,"mail"}]}}
%%%-------------------------------------------------------------------
parse(L) when is_list(L) ->
parse(L, []).
%%% {ok,{'and',[{'not',{lessOrEqual,{'AttributeValueAssertion',"uid","100"}}},
%%% {present,"mail"}]}}
%%%-------------------------------------------------------------------------
parse(RFC2254_Filter) ->
parse(RFC2254_Filter, []).
%%%-------------------------------------------------------------------
%%%-------------------------------------------------------------------------
%%% Arity: parse/2
%%% Function: parse(RFC2254_Filter, [SubstValue |...]) ->
%%% {ok, EldapFilter} |
@@ -79,53 +81,135 @@ parse(L) when is_list(L) ->
%%% {equalityMatch,{'AttributeValueAssertion',
%%% "jid",
%%% "xramtsov@gmail.com"}}]}}
%%%-------------------------------------------------------------------
parse(L, SList) when is_list(L), is_list(SList) ->
case catch eldap_filter_yecc:parse(scan(L, SList)) of
{error, {_, _, Msg}} ->
{error, Msg};
{ok, Result} ->
{ok, Result};
{regexp, Err} ->
{error, Err}
%%%--------------------------------------------------------------------------
parse(RFC2254_Filter, ListOfSubValues) ->
case catch convert_filter(parse_filter(RFC2254_Filter), ListOfSubValues) of
[EldapFilter] when is_tuple(EldapFilter) ->
{ok, EldapFilter};
{regexp, Error} ->
{error, Error};
_ ->
{error, bad_filter}
end.
%%====================================================================
%% Internal functions
%%====================================================================
-define(do_scan(L), scan(Rest, [], [{L, 1} | check(Buf, S) ++ Result], L, S)).
%%%==========================
%%% Internal functions
%%%==========================
scan(L, SList) ->
scan(L, "", [], undefined, SList).
%%%----------------------
%%% split/1,4
%%%----------------------
split(Filter) ->
split(Filter, 0, [], []).
scan("=*)" ++ Rest, Buf, Result, '(', S) ->
scan(Rest, [], [{')', 1}, {'=*', 1} | check(Buf, S) ++ Result], ')', S);
scan(":dn" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':dn');
scan(":=" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':=');
scan(":=" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':=');
scan(":=" ++ Rest, Buf, Result, ':', S) -> ?do_scan(':=');
scan("~=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('~=');
scan(">=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('>=');
scan("<=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('<=');
scan("=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('=');
scan(":" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':');
scan(":" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':');
scan("&" ++ Rest, Buf, Result, '(', S) when Buf=="" -> ?do_scan('&');
scan("|" ++ Rest, Buf, Result, '(', S) when Buf=="" -> ?do_scan('|');
scan("!" ++ Rest, Buf, Result, '(', S) when Buf=="" -> ?do_scan('!');
scan("*" ++ Rest, Buf, Result, '*', S) -> ?do_scan('*');
scan("*" ++ Rest, Buf, Result, '=', S) -> ?do_scan('*');
scan("(" ++ Rest, Buf, Result, _, S) -> ?do_scan('(');
scan(")" ++ Rest, Buf, Result, _, S) -> ?do_scan(')');
scan([Letter | Rest], Buf, Result, PreviosAtom, S) ->
scan(Rest, [Letter|Buf], Result, PreviosAtom, S);
scan([], Buf, Result, _, S) ->
lists:reverse(check(Buf, S) ++ Result).
split([], _, _, Result) ->
Result;
check([], _) ->
[];
check(Buf, S) ->
[{str, 1, do_sub(lists:reverse(Buf), S)}].
split([H|T], Num, Rest, Result) ->
NewNum = case H of
$( -> Num + 1;
$) -> Num - 1;
_ -> Num
end,
if
NewNum == 0 ->
X = Rest++[H],
LenX = length(X),
if
LenX > 2 ->
split(T, 0, [], Result ++ [lists:sublist(X, 2, LenX-2)]);
true ->
split(T, 0, Rest, Result)
end;
true ->
split(T, NewNum, Rest++[H], Result)
end.
%%%-----------------------
%%% parse_filter/1
%%%-----------------------
parse_filter(Filter) ->
case Filter of
[$! | T] ->
{'not', parse_filter(T)};
[$| | T] ->
{'or', parse_filter(T)};
[$& | T] ->
{'and', parse_filter(T)};
[$( | _] ->
parse_filter(split(Filter));
[List | _] when is_list(List) ->
[parse_filter(X) || X <- Filter];
_ ->
Filter
end.
%%%--------------------
%%% convert_filter/2
%%%--------------------
convert_filter({'not', [Val | _]}, Replace) ->
eldap:'not'(convert_filter(Val, Replace));
convert_filter({'or', Vals}, Replace) ->
eldap:'or'([convert_filter(X, Replace) || X <- Vals]);
convert_filter({'and', Vals}, Replace) ->
eldap:'and'([convert_filter(X, Replace) || X <- Vals]);
convert_filter([H|_] = Filter, Replace) when is_integer(H) ->
parse_attr(Filter, Replace);
convert_filter(Filter, Replace) when is_list(Filter) ->
[convert_filter(X, Replace) || X <- Filter].
%%%-----------------
%%% parse_attr/2,3
%%%-----------------
parse_attr(Attr, ListOfSubValues) ->
{Action, [_|_] = Name, [_|_] = Value} = split_attribute(Attr),
parse_attr(Action, {Name, Value}, ListOfSubValues).
parse_attr(approx, {Name, Value}, ListOfSubValues) ->
NewValue = do_sub(Value, ListOfSubValues),
eldap:approxMatch(Name, NewValue);
parse_attr(greater, {Name, Value}, ListOfSubValues) ->
NewValue = do_sub(Value, ListOfSubValues),
eldap:greaterOrEqual(Name, NewValue);
parse_attr(less, {Name, Value}, ListOfSubValues) ->
NewValue = do_sub(Value, ListOfSubValues),
eldap:lessOrEqual(Name, NewValue);
parse_attr(equal, {Name, Value}, ListOfSubValues) ->
{ok, RegSList} = regexp:split(remove_extra_asterisks(Value), "[*]"),
Pattern = case [do_sub(X, ListOfSubValues) || X <- RegSList] of
[Head | Tail] when Tail /= [] ->
{Head, lists:sublist(Tail, length(Tail)-1), lists:last(Tail)};
R ->
R
end,
case Pattern of
[V] ->
eldap:equalityMatch(Name, V);
{[], [], []} ->
eldap:present(Name);
{"", Any, ""} ->
eldap:substrings(Name, [{any, X} || X<-Any]);
{H, Any, ""} ->
eldap:substrings(Name, [{initial, H}]++[{any, X} || X<-Any]);
{"", Any, T} ->
eldap:substrings(Name, [{any, X} || X<-Any]++[{final, T}]);
{H, Any, T} ->
eldap:substrings(Name, [{initial, H}]++[{any, X} || X<-Any]++[{final, T}])
end;
parse_attr(_, _, _) ->
false.
%%%--------------------
%%% do_sub/2,3
%%%--------------------
-define(MAX_RECURSION, 100).
@@ -150,9 +234,9 @@ do_sub(S, {RegExp, New}, Iter) ->
{ok, NewS, _} when Iter =< ?MAX_RECURSION ->
do_sub(NewS, {RegExp, New}, Iter+1);
{ok, _, _} when Iter > ?MAX_RECURSION ->
erlang:error(max_substitute_recursion);
throw({regexp, max_substitute_recursion});
_ ->
erlang:error(bad_regexp)
throw({regexp, bad_regexp})
end;
do_sub(S, {_, _, N}, _) when N<1 ->
@@ -167,11 +251,52 @@ do_sub(S, {RegExp, New, Times}, Iter) ->
{ok, NewS, _} ->
NewS;
_ ->
erlang:error(bad_regexp)
throw({regexp, bad_regexp})
end.
remove_extra_asterisks(String) ->
{Res, _} = lists:foldl(
fun(X, {Acc, Last}) ->
case X of
$* when Last==$* ->
{Acc, X};
_ ->
{Acc ++ [X], X}
end
end,
{"", ""}, String),
Res.
replace_amps(String) ->
lists:map(
fun($&) -> "\\&";
(Chr) -> Chr
end, String).
lists:foldl(
fun(X, Acc) ->
if
X == $& ->
Acc ++ "\\&";
true ->
Acc ++ [X]
end
end,
"", String).
split_attribute(String) ->
split_attribute(String, "", $0).
split_attribute([], _, _) ->
{error, "", ""};
split_attribute([H|Tail], Acc, Last) ->
case H of
$= when Last==$> ->
{greater, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= when Last==$< ->
{less, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= when Last==$~ ->
{approx, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= when Last==$: ->
{equal, lists:sublist(Acc, 1, length(Acc)-1), Tail};
$= ->
{equal, Acc, Tail};
_ ->
split_attribute(Tail, Acc++[H], H)
end.
-71
View File
@@ -1,71 +0,0 @@
Nonterminals
filter filtercomp filterlist item
simple present substring extensible
initial any final matchingrule xattr
attr value.
Terminals str
'(' ')' '&' '|' '!' '=' '~=' '>=' '<=' '=*' '*' ':dn' ':' ':='.
Rootsymbol filter.
filter -> '(' filtercomp ')': '$2'.
filtercomp -> '&' filterlist: 'and'('$2').
filtercomp -> '|' filterlist: 'or'('$2').
filtercomp -> '!' filter: 'not'('$2').
filtercomp -> item: '$1'.
filterlist -> filter: '$1'.
filterlist -> filter filterlist: flatten(['$1', '$2']).
item -> simple: '$1'.
item -> present: '$1'.
item -> substring: '$1'.
item -> extensible: '$1'.
simple -> attr '=' value: equal('$1', '$3').
simple -> attr '~=' value: approx('$1', '$3').
simple -> attr '>=' value: greater('$1', '$3').
simple -> attr '<=' value: less('$1', '$3').
present -> attr '=*': present('$1').
substring -> attr '=' initial '*' any: substrings('$1', ['$3', '$5']).
substring -> attr '=' '*' any final: substrings('$1', ['$4', '$5']).
substring -> attr '=' initial '*' any final: substrings('$1', ['$3', '$5', '$6']).
substring -> attr '=' '*' any: substrings('$1', ['$4']).
any -> any value '*': 'any'('$1', '$2').
any -> '$empty': [].
initial -> value: initial('$1').
final -> value: final('$1').
extensible -> xattr ':dn' ':' matchingrule ':=' value: extensible('$6', ['$1', '$4']).
extensible -> xattr ':' matchingrule ':=' value: extensible('$5', ['$1', '$3']).
extensible -> xattr ':dn' ':=' value: extensible('$4', ['$1']).
extensible -> xattr ':=' value: extensible('$3', ['$1']).
extensible -> ':dn' ':' matchingrule ':=' value: extensible('$5', ['$3']).
extensible -> ':' matchingrule ':=' value: extensible('$4', ['$2']).
xattr -> value: xattr('$1').
matchingrule -> value: matchingrule('$1').
attr -> str: value_of('$1').
value -> str: value_of('$1').
Erlang code.
'and'(Value) -> eldap:'and'(Value).
'or'(Value) -> eldap:'or'(Value).
'not'(Value) -> eldap:'not'(Value).
equal(Desc, Value) -> eldap:equalityMatch(Desc, Value).
approx(Desc, Value) -> eldap:approxMatch(Desc, Value).
greater(Desc, Value) -> eldap:greaterOrEqual(Desc, Value).
less(Desc, Value) -> eldap:lessOrEqual(Desc, Value).
present(Value) -> eldap:present(Value).
extensible(Value, Opts) -> eldap:extensibleMatch(Value, Opts).
substrings(Desc, ValueList) -> eldap:substrings(Desc, flatten(ValueList)).
initial(Value) -> {initial, Value}.
final(Value) -> {final, Value}.
'any'(Token, Value) -> [Token, {any, Value}].
xattr(Value) -> {type, Value}.
matchingrule(Value) -> {matchingRule, Value}.
value_of(Token) -> element(3, Token).
flatten(List) -> lists:flatten(List).
+12 -18
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Nov 2006 by Evgeniy Khramtsov <xram@jabber.ru>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -31,8 +31,7 @@
-export([
start_link/7,
bind/3,
search/2,
modify_passwd/3
search/2
]).
-include("ejabberd.hrl").
@@ -46,23 +45,18 @@ bind(PoolName, DN, Passwd) ->
search(PoolName, Opts) ->
do_request(PoolName, {search, [Opts]}).
modify_passwd(PoolName, DN, Passwd) ->
do_request(PoolName, {modify_passwd, [DN, Passwd]}).
start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Opts) ->
start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Encrypt) ->
PoolName = make_id(Name),
pg2:create(PoolName),
lists:foreach(
fun(Host) ->
ID = erlang:ref_to_list(make_ref()),
case catch eldap:start_link(ID, [Host|Backups], Port,
Rootdn, Passwd, Opts) of
{ok, Pid} ->
pg2:join(PoolName, Pid);
_ ->
error
end
end, Hosts).
lists:foreach(fun(Host) ->
ID = erlang:ref_to_list(make_ref()),
case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd, Encrypt) of
{ok, Pid} ->
pg2:join(PoolName, Pid);
_ ->
error
end
end, Hosts).
%%====================================================================
%% Internal functions
+6 -8
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -53,17 +53,15 @@ subfilter({UIDAttr}) ->
%% Not tail-recursive, but it is not very terribly.
%% It stops finding on the first not empty value.
find_ldap_attrs([{Attr} | Rest], Attributes) ->
find_ldap_attrs([{Attr, "%u"} | Rest], Attributes);
find_ldap_attrs([{Attr, Format} | Rest], Attributes) ->
case get_ldap_attr(Attr, Attributes) of
case get_ldap_attr(Attr, Attributes) of
Value when is_list(Value), Value /= "" ->
{Value, Format};
{Value, Format};
_ ->
find_ldap_attrs(Rest, Attributes)
end;
find_ldap_attrs(Rest, Attributes)
end;
find_ldap_attrs([], _) ->
"".
"".
get_ldap_attr(LDAPAttr, Attributes) ->
Res = lists:filter(
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* ejabberd, Copyright (C) 2002-2010 ProcessOne
* ejabberd, Copyright (C) 2002-2009 ProcessOne
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
+3 -22
View File
@@ -5,7 +5,7 @@
%%% Created : 30 Jul 2004 by Leif Johansson <leifj@it.su.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,15 +27,8 @@
-module(extauth).
-author('leifj@it.su.se').
-export([start/2,
stop/1,
init/2,
check_password/3,
set_password/3,
try_register/3,
remove_user/2,
remove_user/3,
is_user_exists/2]).
-export([start/2, stop/1, init/2,
check_password/3, set_password/3, is_user_exists/2]).
-include("ejabberd.hrl").
@@ -63,18 +56,6 @@ is_user_exists(User, Server) ->
set_password(User, Server, Password) ->
call_port(Server, ["setpass", User, Server, Password]).
try_register(User, Server, Password) ->
case call_port(Server, ["tryregister", User, Server, Password]) of
true -> {atomic, ok};
false -> {error, not_allowed}
end.
remove_user(User, Server) ->
call_port(Server, ["removeuser", User, Server]).
remove_user(User, Server, Password) ->
call_port(Server, ["removeuser3", User, Server, Password]).
call_port(Server, Msg) ->
LServer = jlib:nameprep(Server),
gen_mod:get_module_proc(LServer, eauth) ! {call, self(), Msg},
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 22 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 24 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 10 Apr 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 2 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+10 -12
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -382,7 +382,7 @@ iq_info_internal({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" ->
"result" -> {result, reply};
"error" -> {error, reply};
_ -> {invalid, invalid}
end,
end,
if
Type1 == invalid ->
invalid;
@@ -404,24 +404,22 @@ iq_info_internal({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" ->
<- FilteredEls,
SubName /= "error"],
{case NonErrorEls of
[NonErrorEl] ->
xml:get_tag_attr_s("xmlns", NonErrorEl);
_ ->
""
[NonErrorEl] -> xml:get_tag_attr_s("xmlns", NonErrorEl);
_ -> invalid
end,
FilteredEls};
_ ->
{"", []}
{invalid, invalid}
end,
if XMLNS == "", Class == request ->
invalid;
true ->
#iq{id = ID,
type = Type1,
xmlns = XMLNS,
lang = Lang,
#iq{id = ID,
type = Type1,
xmlns = XMLNS,
lang = Lang,
sub_el = SubEl}
end;
end;
Class == reply, Filter /= any ->
reply
end;
+1 -6
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -22,7 +22,6 @@
-define(NS_DISCO_ITEMS, "http://jabber.org/protocol/disco#items").
-define(NS_DISCO_INFO, "http://jabber.org/protocol/disco#info").
-define(NS_VCARD, "vcard-temp").
-define(NS_VCARD_UPDATE, "vcard-temp:x:update").
-define(NS_AUTH, "jabber:iq:auth").
-define(NS_AUTH_ERROR, "jabber:iq:auth:error").
-define(NS_REGISTER, "jabber:iq:register").
@@ -48,7 +47,6 @@
-define(NS_MUC_USER, "http://jabber.org/protocol/muc#user").
-define(NS_MUC_ADMIN, "http://jabber.org/protocol/muc#admin").
-define(NS_MUC_OWNER, "http://jabber.org/protocol/muc#owner").
-define(NS_MUC_UNIQUE, "http://jabber.org/protocol/muc#unique").
-define(NS_PUBSUB, "http://jabber.org/protocol/pubsub").
-define(NS_PUBSUB_EVENT, "http://jabber.org/protocol/pubsub#event").
-define(NS_PUBSUB_OWNER, "http://jabber.org/protocol/pubsub#owner").
@@ -85,7 +83,6 @@
-define(NS_CAPS, "http://jabber.org/protocol/caps").
-define(NS_SHIM, "http://jabber.org/protocol/shim").
-define(NS_ADDRESS, "http://jabber.org/protocol/address").
%% CAPTCHA related NSes.
-define(NS_OOB, "jabber:x:oob").
@@ -141,8 +138,6 @@
?STANZA_ERROR("407", "auth", "subscription-required")).
-define(ERR_UNEXPECTED_REQUEST,
?STANZA_ERROR("400", "wait", "unexpected-request")).
-define(ERR_UNEXPECTED_REQUEST_CANCEL,
?STANZA_ERROR("401", "cancel", "unexpected-request")).
%-define(ERR_,
% ?STANZA_ERROR("", "", "")).
+2 -2
View File
@@ -1,11 +1,11 @@
%%%----------------------------------------------------------------------
%%% File : mod_adhoc.erl
%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
%%% Purpose : Handle incoming ad-doc requests (XEP-0050)
%%% Purpose : Handle incoming ad-doc requests (JEP-0050)
%%% Created : 15 Nov 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -23
View File
@@ -5,7 +5,7 @@
%%% Created : 11 Aug 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -40,7 +40,6 @@
disco_identity/5,
disco_features/5,
disco_items/5,
send_announcement_to_all/3,
announce_commands/4,
announce_items/4]).
@@ -847,27 +846,6 @@ get_stored_motd(LServer) ->
{"", ""}
end.
%% This function is similar to others, but doesn't perform any ACL verification
send_announcement_to_all(Host, SubjectS, BodyS) ->
SubjectEls = if SubjectS /= [] ->
[{xmlelement, "subject", [], [{xmlcdata, SubjectS}]}];
true ->
[]
end,
BodyEls = if BodyS /= [] ->
[{xmlelement, "body", [], [{xmlcdata, BodyS}]}];
true ->
[]
end,
Packet = {xmlelement, "message", [{"type", "normal"}], SubjectEls ++ BodyEls},
Sessions = ejabberd_sm:dirty_get_sessions_list(),
Local = jlib:make_jid("", Host, ""),
lists:foreach(
fun({U, S, R}) ->
Dest = jlib:make_jid(U, S, R),
ejabberd_router:route(Local, Dest, Packet)
end, Sessions).
%%-------------------------------------------------------------------------
update_tables() ->
+357 -317
View File
@@ -5,7 +5,7 @@
%%% Created : 7 Oct 2006 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -33,11 +33,13 @@
-behaviour(gen_mod).
-export([read_caps/1,
caps_stream_features/2,
disco_features/5,
disco_identity/5,
disco_info/5,
get_features/1]).
get_caps/1,
note_caps/3,
wait_caps/2,
clear_caps/1,
get_features/2,
get_user_resources/2,
handle_disco_response/3]).
%% gen_mod callbacks
-export([start/2, start_link/2,
@@ -53,21 +55,120 @@
]).
%% hook handlers
-export([user_send_packet/3]).
-export([receive_packet/3,
receive_packet/4,
presence_probe/3,
remove_connection/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-define(PROCNAME, ejabberd_mod_caps).
-define(DICT, dict).
-define(CAPS_QUERY_TIMEOUT, 60000). % 1mn without answer, consider client never answer
-record(caps, {node, version, hash, exts}).
-record(caps, {node, version, exts}).
-record(caps_features, {node_pair, features = []}).
-record(user_caps, {jid, caps}).
-record(user_caps_resources, {uid, resource}).
-record(state, {host,
disco_requests = ?DICT:new(),
feature_queries = []}).
-record(state, {host}).
%% read_caps takes a list of XML elements (the child elements of a
%% <presence/> stanza) and returns an opaque value representing the
%% Entity Capabilities contained therein, or the atom nothing if no
%% capabilities are advertised.
read_caps(Els) ->
read_caps(Els, nothing).
read_caps([{xmlelement, "c", Attrs, _Els} | Tail], Result) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_CAPS ->
Node = xml:get_attr_s("node", Attrs),
Version = xml:get_attr_s("ver", Attrs),
Exts = string:tokens(xml:get_attr_s("ext", Attrs), " "),
read_caps(Tail, #caps{node = Node, version = Version, exts = Exts});
_ ->
read_caps(Tail, Result)
end;
read_caps([{xmlelement, "x", Attrs, _Els} | Tail], Result) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_MUC_USER ->
nothing;
_ ->
read_caps(Tail, Result)
end;
read_caps([_ | Tail], Result) ->
read_caps(Tail, Result);
read_caps([], Result) ->
Result.
%% get_caps reads user caps from database
%% here we handle a simple retry loop, to avoid race condition
%% when asking caps while we still did not called note_caps
%% timeout is set to 10s
%% this is to be improved, but without altering performances.
%% if we did not get user presence 10s after getting presence_probe
%% we assume it has no caps
get_caps(LJID) ->
get_caps(LJID, 5).
get_caps(_, 0) ->
nothing;
get_caps(LJID, Retry) ->
case catch mnesia:dirty_read({user_caps, jid_to_binary(LJID)}) of
[#user_caps{caps=waiting}] ->
timer:sleep(2000),
get_caps(LJID, Retry-1);
[#user_caps{caps=Caps}] ->
Caps;
_ ->
nothing
end.
%% clear_caps removes user caps from database
clear_caps(JID) ->
{U, S, R} = jlib:jid_tolower(JID),
BJID = jid_to_binary(JID),
BUID = jid_to_binary({U, S, []}),
catch mnesia:dirty_delete({user_caps, BJID}),
catch mnesia:dirty_delete_object(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}),
ok.
%% give default user resource
get_user_resources(LUser, LServer) ->
case catch mnesia:dirty_read({user_caps_resources, jid_to_binary({LUser, LServer, []})}) of
{'EXIT', _} ->
[];
Resources ->
lists:map(fun(#user_caps_resources{resource=R}) -> binary_to_list(R) end, Resources)
end.
%% note_caps should be called to make the module request disco
%% information. Host is the host that asks, From is the full JID that
%% sent the caps packet, and Caps is what read_caps returned.
note_caps(Host, From, Caps) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:cast(Proc, {note_caps, From, Caps}).
%% wait_caps should be called just before note_caps
%% it allows to lock get_caps usage for code using presence_probe
%% that may run before we get any chance to note_caps.
wait_caps(Host, From) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:cast(Proc, {wait_caps, From}).
%% get_features returns a list of features implied by the given caps
%% record (as extracted by read_caps). It may block, and may signal a
%% timeout error.
get_features(Host, Caps) ->
case Caps of
nothing ->
[];
#caps{} ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:call(Proc, {get_features, Caps})
end.
%%====================================================================
%% API
%%====================================================================
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
@@ -85,227 +186,61 @@ start(Host, Opts) ->
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:call(Proc, stop),
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc).
gen_server:call(Proc, stop).
%% get_features returns a list of features implied by the given caps
%% record (as extracted by read_caps) or 'unknown' if features are
%% not completely collected at the moment.
get_features(nothing) ->
[];
get_features(#caps{node = Node, version = Version, exts = Exts}) ->
SubNodes = [Version | Exts],
lists:foldl(
fun(SubNode, Acc) ->
case mnesia:dirty_read({caps_features,
node_to_binary(Node, SubNode)}) of
[] ->
Acc;
[#caps_features{features = Features}] ->
binary_to_features(Features) ++ Acc
end
end, [], SubNodes).
%% read_caps takes a list of XML elements (the child elements of a
%% <presence/> stanza) and returns an opaque value representing the
%% Entity Capabilities contained therein, or the atom nothing if no
%% capabilities are advertised.
read_caps(Els) ->
read_caps(Els, nothing).
read_caps([{xmlelement, "c", Attrs, _Els} | Tail], Result) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_CAPS ->
Node = xml:get_attr_s("node", Attrs),
Version = xml:get_attr_s("ver", Attrs),
Hash = xml:get_attr_s("hash", Attrs),
Exts = string:tokens(xml:get_attr_s("ext", Attrs), " "),
read_caps(Tail, #caps{node = Node, hash = Hash,
version = Version, exts = Exts});
_ ->
read_caps(Tail, Result)
receive_packet(From, To, {xmlelement, "presence", Attrs, Els}) ->
case xml:get_attr_s("type", Attrs) of
"probe" ->
ok;
"error" ->
ok;
"invisible" ->
ok;
"subscribe" ->
ok;
"subscribed" ->
ok;
"unsubscribe" ->
ok;
"unsubscribed" ->
ok;
"unavailable" ->
{_, S1, _} = jlib:jid_tolower(From),
case jlib:jid_tolower(To) of
{_, S1, _} -> ok;
_ -> clear_caps(From)
end;
%% TODO: probe client, and clean only if no answers
%% as far as protocol does not allow inter-server communication to
%% let remote server handle it's own caps to decide which user is to be
%% notified, we must keep a cache of online status of external contacts
%% this is absolutely not scallable, but we have no choice for now
%% we can only use unavailable presence, but if remote user just remove a local user
%% from its roster, then it's considered as offline, so he does not receive local PEP
%% anymore until he login again.
%% This is tracked in EJAB-943
_ ->
note_caps(To#jid.lserver, From, read_caps(Els))
end;
read_caps([{xmlelement, "x", Attrs, _Els} | Tail], Result) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_MUC_USER ->
nothing;
_ ->
read_caps(Tail, Result)
end;
read_caps([_ | Tail], Result) ->
read_caps(Tail, Result);
read_caps([], Result) ->
Result.
%%====================================================================
%% Hooks
%%====================================================================
user_send_packet(#jid{luser = User, lserver = Server} = From,
#jid{luser = User, lserver = Server, lresource = ""},
{xmlelement, "presence", Attrs, Els}) ->
Type = xml:get_attr_s("type", Attrs),
if Type == ""; Type == "available" ->
case read_caps(Els) of
nothing ->
ok;
#caps{version = Version, exts = Exts} = Caps ->
feature_request(Server, From, Caps, [Version | Exts])
end;
true ->
ok
end;
user_send_packet(_From, _To, _Packet) ->
receive_packet(_, _, _) ->
ok.
caps_stream_features(Acc, MyHost) ->
case make_my_disco_hash(MyHost) of
"" ->
Acc;
Hash ->
[{xmlelement, "c", [{"xmlns", ?NS_CAPS},
{"hash", "sha-1"},
{"node", ?EJABBERD_URI},
{"ver", Hash}], []} | Acc]
end.
receive_packet(_JID, From, To, Packet) ->
receive_packet(From, To, Packet).
disco_features(_Acc, From, To, ?EJABBERD_URI ++ "#" ++ [_|_], Lang) ->
ejabberd_hooks:run_fold(disco_local_features,
To#jid.lserver,
empty,
[From, To, "", Lang]);
disco_features(Acc, _From, _To, _Node, _Lang) ->
Acc.
presence_probe(From, To, _) ->
wait_caps(To#jid.lserver, From).
disco_identity(_Acc, From, To, ?EJABBERD_URI ++ "#" ++ [_|_], Lang) ->
ejabberd_hooks:run_fold(disco_local_identity,
To#jid.lserver,
[],
[From, To, "", Lang]);
disco_identity(Acc, _From, _To, _Node, _Lang) ->
Acc.
remove_connection(_SID, JID, _Info) ->
clear_caps(JID).
disco_info(_Acc, Host, Module, ?EJABBERD_URI ++ "#" ++ [_|_], Lang) ->
ejabberd_hooks:run_fold(disco_info,
Host,
[],
[Host, Module, "", Lang]);
disco_info(Acc, _Host, _Module, _Node, _Lang) ->
Acc.
jid_to_binary(JID) ->
{U, S, R} = jlib:jid_tolower(JID),
list_to_binary(jlib:jid_to_string({U, S, R})).
%%====================================================================
%% gen_server callbacks
%%====================================================================
init([Host, _Opts]) ->
mnesia:create_table(caps_features,
[{disc_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, caps_features)}]),
mnesia:add_table_copy(caps_features, node(), disc_copies),
ejabberd_hooks:add(user_send_packet, Host,
?MODULE, user_send_packet, 75),
ejabberd_hooks:add(c2s_stream_features, Host,
?MODULE, caps_stream_features, 75),
ejabberd_hooks:add(s2s_stream_features, Host,
?MODULE, caps_stream_features, 75),
ejabberd_hooks:add(disco_local_features, Host,
?MODULE, disco_features, 75),
ejabberd_hooks:add(disco_local_identity, Host,
?MODULE, disco_identity, 75),
ejabberd_hooks:add(disco_info, Host,
?MODULE, disco_info, 75),
{ok, #state{host = Host}}.
handle_call(stop, _From, State) ->
{stop, normal, ok, State};
handle_call(_Req, _From, State) ->
{reply, {error, badarg}, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, State) ->
Host = State#state.host,
ejabberd_hooks:delete(user_send_packet, Host,
?MODULE, user_send_packet, 75),
ejabberd_hooks:delete(c2s_stream_features, Host,
?MODULE, caps_stream_features, 75),
ejabberd_hooks:delete(s2s_stream_features, Host,
?MODULE, caps_stream_features, 75),
ejabberd_hooks:delete(disco_local_features, Host,
?MODULE, disco_features, 75),
ejabberd_hooks:delete(disco_local_identity, Host,
?MODULE, disco_identity, 75),
ejabberd_hooks:delete(disco_info, Host,
?MODULE, disco_info, 75),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%====================================================================
%% Aux functions
%%====================================================================
feature_request(Host, From, Caps, [SubNode | Tail] = SubNodes) ->
Node = Caps#caps.node,
BinaryNode = node_to_binary(Node, SubNode),
case mnesia:dirty_read({caps_features, BinaryNode}) of
[] ->
IQ = #iq{type = get,
xmlns = ?NS_DISCO_INFO,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_DISCO_INFO},
{"node", Node ++ "#" ++ SubNode}],
[]}]},
F = fun(IQReply) ->
feature_response(
IQReply, Host, From, Caps, SubNodes)
end,
ejabberd_local:route_iq(
jlib:make_jid("", Host, ""), From, IQ, F);
_ ->
feature_request(Host, From, Caps, Tail)
end;
feature_request(_Host, _From, _Caps, []) ->
ok.
feature_response(#iq{type = result,
sub_el = [{xmlelement, _, _, Els}]},
Host, From, Caps, [SubNode | SubNodes]) ->
BinaryNode = node_to_binary(Caps#caps.node, SubNode),
IsValid = case Caps#caps.hash of
"sha-1" ->
Caps#caps.version == make_disco_hash(Els, sha1);
"md5" ->
Caps#caps.version == make_disco_hash(Els, md5);
_ ->
true
end,
if IsValid ->
Features = lists:flatmap(
fun({xmlelement, "feature", FAttrs, _}) ->
[xml:get_attr_s("var", FAttrs)];
(_) ->
[]
end, Els),
mnesia:dirty_write(
#caps_features{node_pair = BinaryNode,
features = features_to_binary(Features)});
true ->
mnesia:dirty_write(#caps_features{node_pair = BinaryNode})
end,
feature_request(Host, From, Caps, SubNodes);
feature_response(timeout, _Host, _From, _Caps, _SubNodes) ->
ok;
feature_response(_IQResult, Host, From, Caps, [SubNode | SubNodes]) ->
%% We got type=error or invalid type=result stanza, so
%% we cache empty feature not to probe the client permanently
BinaryNode = node_to_binary(Caps#caps.node, SubNode),
mnesia:dirty_write(#caps_features{node_pair = BinaryNode}),
feature_request(Host, From, Caps, SubNodes).
caps_to_binary(#caps{node = Node, version = Version, exts = Exts}) ->
BExts = [list_to_binary(Ext) || Ext <- Exts],
#caps{node = list_to_binary(Node), version = list_to_binary(Version), exts = BExts}.
node_to_binary(Node, SubNode) ->
{list_to_binary(Node), list_to_binary(SubNode)}.
@@ -313,101 +248,206 @@ node_to_binary(Node, SubNode) ->
features_to_binary(L) -> [list_to_binary(I) || I <- L].
binary_to_features(L) -> [binary_to_list(I) || I <- L].
make_my_disco_hash(Host) ->
JID = jlib:make_jid("", Host, ""),
case {ejabberd_hooks:run_fold(disco_local_features,
Host,
empty,
[JID, JID, "", ""]),
ejabberd_hooks:run_fold(disco_local_identity,
Host,
[],
[JID, JID, "", ""]),
ejabberd_hooks:run_fold(disco_info,
Host,
[],
[Host, undefined, "", ""])} of
{{result, Features}, Identities, Info} ->
Feats = lists:map(
fun({{Feat, _Host}}) ->
{xmlelement, "feature", [{"var", Feat}], []};
(Feat) ->
{xmlelement, "feature", [{"var", Feat}], []}
end, Features),
make_disco_hash(Identities ++ Info ++ Feats, sha1);
_Err ->
""
%%====================================================================
%% gen_server callbacks
%%====================================================================
init([Host, _Opts]) ->
mnesia:create_table(caps_features,
[{disc_copies, [node()]},
{attributes, record_info(fields, caps_features)}]),
mnesia:create_table(user_caps,
[{ram_copies, [node()]},
{attributes, record_info(fields, user_caps)}]),
mnesia:create_table(user_caps_resources,
[{ram_copies, [node()]},
{type, bag},
{attributes, record_info(fields, user_caps_resources)}]),
mnesia:delete_table(user_caps_default),
mnesia:clear_table(user_caps), % clean in case of explicitely set to disc_copies
mnesia:clear_table(user_caps_resources), % clean in case of explicitely set to disc_copies
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, receive_packet, 30),
ejabberd_hooks:add(s2s_receive_packet, Host, ?MODULE, receive_packet, 30),
ejabberd_hooks:add(presence_probe_hook, Host, ?MODULE, presence_probe, 20),
ejabberd_hooks:add(sm_remove_connection_hook, Host, ?MODULE, remove_connection, 20),
{ok, #state{host = Host}}.
maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) ->
SubNodes = [Version | Exts],
%% Make sure that we have all nodes we need to know.
%% If a single one is missing, we wait for more disco
%% responses.
case lists:foldl(fun(SubNode, Acc) ->
case Acc of
fail -> fail;
_ ->
case mnesia:dirty_read({caps_features, {Node, SubNode}}) of
[] -> fail;
[#caps_features{features = Features}] -> Features ++ Acc %% TODO binary
end
end
end, [], SubNodes) of
fail -> wait;
Features -> {ok, Features}
end.
make_disco_hash(DiscoEls, Algo) when Algo == sha1; Algo == md5 ->
Concat = [concat_identities(DiscoEls),
concat_features(DiscoEls),
concat_info(DiscoEls)],
base64:encode_to_string(
if Algo == sha1 ->
crypto:sha(Concat);
Algo == md5 ->
crypto:md5(Concat)
end).
timestamp() ->
{MegaSecs, Secs, _MicroSecs} = now(),
MegaSecs * 1000000 + Secs.
concat_features(Els) ->
lists:usort(
lists:flatmap(
fun({xmlelement, "feature", Attrs, _}) ->
[[xml:get_attr_s("var", Attrs), $<]];
(_) ->
[]
end, Els)).
handle_call({get_features, Caps}, From, State) ->
case maybe_get_features(Caps) of
{ok, Features} ->
{reply, binary_to_features(Features), State};
wait ->
gen_server:cast(self(), visit_feature_queries),
Timeout = timestamp() + 10,
FeatureQueries = State#state.feature_queries,
NewFeatureQueries = [{From, Caps, Timeout} | FeatureQueries],
NewState = State#state{feature_queries = NewFeatureQueries},
{noreply, NewState}
end;
concat_identities(Els) ->
lists:sort(
lists:flatmap(
fun({xmlelement, "identity", Attrs, _}) ->
[[xml:get_attr_s("category", Attrs), $/,
xml:get_attr_s("type", Attrs), $/,
xml:get_attr_s("xml:lang", Attrs), $/,
xml:get_attr_s("name", Attrs), $<]];
(_) ->
[]
end, Els)).
handle_call(stop, _From, State) ->
{stop, normal, ok, State}.
concat_info(Els) ->
lists:sort(
lists:flatmap(
fun({xmlelement, "x", Attrs, Fields}) ->
case {xml:get_attr_s("xmlns", Attrs),
xml:get_attr_s("type", Attrs)} of
{?NS_XDATA, "result"} ->
[concat_xdata_fields(Fields)];
_ ->
[]
end;
(_) ->
[]
end, Els)).
handle_cast({note_caps, From, nothing}, State) ->
BJID = jid_to_binary(From),
catch mnesia:dirty_delete({user_caps, BJID}),
{noreply, State};
handle_cast({note_caps, From,
#caps{node = Node, version = Version, exts = Exts} = Caps},
#state{host = Host, disco_requests = Requests} = State) ->
%% XXX: this leads to race conditions where ejabberd will send
%% lots of caps disco requests.
{U, S, R} = jlib:jid_tolower(From),
BJID = jid_to_binary(From),
mnesia:transaction(fun() ->
mnesia:write(#user_caps{jid = BJID, caps = caps_to_binary(Caps)}),
case ejabberd_sm:get_user_resources(U, S) of
[] ->
% only store resources of caps aware external contacts
BUID = jid_to_binary({U, S, []}),
mnesia:write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)});
_ ->
ok
end
end),
%% Now, find which of these are not already in the database.
SubNodes = [Version | Exts],
case lists:foldl(fun(SubNode, Acc) ->
case mnesia:dirty_read({caps_features, node_to_binary(Node, SubNode)}) of
[] ->
[SubNode | Acc];
_ ->
Acc
end
end, [], SubNodes) of
[] ->
{noreply, State};
Missing ->
%% For each unknown caps "subnode", we send a disco request.
NewRequests = lists:foldl(
fun(SubNode, Dict) ->
ID = randoms:get_string(),
Stanza =
{xmlelement, "iq",
[{"type", "get"},
{"id", ID}],
[{xmlelement, "query",
[{"xmlns", ?NS_DISCO_INFO},
{"node", lists:concat([Node, "#", SubNode])}],
[]}]},
ejabberd_local:register_iq_response_handler
(Host, ID, ?MODULE, handle_disco_response),
ejabberd_router:route(jlib:make_jid("", Host, ""), From, Stanza),
timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID, BJID}),
?DICT:store(ID, node_to_binary(Node, SubNode), Dict)
end, Requests, Missing),
{noreply, State#state{disco_requests = NewRequests}}
end;
handle_cast({wait_caps, From}, State) ->
BJID = jid_to_binary(From),
mnesia:dirty_write(#user_caps{jid = BJID, caps = waiting}),
{noreply, State};
handle_cast({disco_response, From, _To,
#iq{type = Type, id = ID,
sub_el = SubEls}},
#state{disco_requests = Requests} = State) ->
case {Type, SubEls} of
{result, [{xmlelement, "query", _Attrs, Els}]} ->
case ?DICT:find(ID, Requests) of
{ok, BinaryNode} ->
Features =
lists:flatmap(fun({xmlelement, "feature", FAttrs, _}) ->
[xml:get_attr_s("var", FAttrs)];
(_) ->
[]
end, Els),
mnesia:dirty_write(#caps_features{node_pair = BinaryNode, features = features_to_binary(Features)}),
gen_server:cast(self(), visit_feature_queries);
error ->
?DEBUG("ID '~s' matches no query", [ID])
end;
{error, _} ->
%% XXX: if we get error, we cache empty feature not to probe the client continuously
case ?DICT:find(ID, Requests) of
{ok, BinaryNode} ->
mnesia:dirty_write(#caps_features{node_pair = BinaryNode}),
gen_server:cast(self(), visit_feature_queries);
error ->
?DEBUG("ID '~s' matches no query", [ID])
end;
%gen_server:cast(self(), visit_feature_queries),
%?DEBUG("Error IQ reponse from ~s:~n~p", [jlib:jid_to_string(From), SubEls]);
{result, _} ->
?DEBUG("Invalid IQ contents from ~s:~n~p", [jlib:jid_to_string(From), SubEls]);
_ ->
%% Can't do anything about errors
ok
end,
NewRequests = ?DICT:erase(ID, Requests),
{noreply, State#state{disco_requests = NewRequests}};
handle_cast({disco_timeout, ID, BJID}, #state{host = Host, disco_requests = Requests} = State) ->
%% do not wait a response anymore for this IQ, client certainly will never answer
NewRequests = case ?DICT:is_key(ID, Requests) of
true ->
catch mnesia:dirty_delete({user_caps, BJID}),
ejabberd_local:unregister_iq_response_handler(Host, ID),
?DICT:erase(ID, Requests);
false ->
Requests
end,
{noreply, State#state{disco_requests = NewRequests}};
handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = State) ->
Timestamp = timestamp(),
NewFeatureQueries =
lists:foldl(fun({From, Caps, Timeout}, Acc) ->
case maybe_get_features(Caps) of
wait when Timeout > Timestamp -> [{From, Caps, Timeout} | Acc];
wait -> Acc;
{ok, Features} ->
gen_server:reply(From, Features),
Acc
end
end, [], FeatureQueries),
{noreply, State#state{feature_queries = NewFeatureQueries}}.
concat_xdata_fields(Fields) ->
[Form, Res] =
lists:foldl(
fun({xmlelement, "field", Attrs, Els} = El,
[FormType, VarFields] = Acc) ->
case xml:get_attr_s("var", Attrs) of
"" ->
Acc;
"FORM_TYPE" ->
[xml:get_subtag_cdata(El, "value"), VarFields];
Var ->
[FormType,
[[[Var, $<],
lists:sort(
lists:flatmap(
fun({xmlelement, "value", _, VEls}) ->
[[xml:get_cdata(VEls), $<]];
(_) ->
[]
end, Els))] | VarFields]]
end;
(_, Acc) ->
Acc
end, ["", []], Fields),
[Form, $<, lists:sort(Res)].
handle_disco_response(From, To, IQ) ->
#jid{lserver = Host} = To,
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
gen_server:cast(Proc, {disco_response, From, To, IQ}).
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, State) ->
Host = State#state.host,
ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, receive_packet, 30),
ejabberd_hooks:delete(s2s_receive_packet, Host, ?MODULE, receive_packet, 30),
ejabberd_hooks:delete(presence_probe_hook, Host, ?MODULE, presence_probe, 20),
ejabberd_hooks:delete(sm_remove_connection_hook, Host, ?MODULE, remove_connection, 20),
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
+3 -35
View File
@@ -5,7 +5,7 @@
%%% Created : 19 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -237,23 +237,7 @@ get_local_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
["config", _] ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("add-user") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("delete-user") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("end-user-session") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("get-user-password") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("change-user-password") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("get-user-lastlogin") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("user-stats") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("get-registered-users-num") ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
?NS_ADMINL("get-online-users-num") ->
["http:" | _] ->
?INFO_RESULT(Allow, [?NS_COMMANDS]);
_ ->
Acc
@@ -465,23 +449,7 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, Node, Lang) ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
["config", _] ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("add-user") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("delete-user") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("end-user-session") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("get-user-password") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("change-user-password") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("get-user-lastlogin") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("user-stats") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("get-registered-users-num") ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
?NS_ADMINL("get-online-users-num") ->
?NS_ADMINL(_) ->
?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN});
_ ->
Acc
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 26 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+61 -103
View File
@@ -5,7 +5,7 @@
%%% Created : 1 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -172,7 +172,7 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang,
[{"xmlns", ?NS_DISCO_INFO} | ANode],
Identity ++
Info ++
features_to_xml(Features)
lists:map(fun feature_to_xml/1, Features)
}]};
{error, Error} ->
IQ#iq{type = error, sub_el = [SubEl, Error]}
@@ -209,16 +209,10 @@ get_local_features(Acc, _From, _To, _Node, _Lang) ->
end.
features_to_xml(FeatureList) ->
%% Avoid duplicating features
[{xmlelement, "feature", [{"var", Feat}], []} ||
Feat <- lists:usort(
lists:map(
fun({{Feature, _Host}}) ->
Feature;
(Feature) when is_list(Feature) ->
Feature
end, FeatureList))].
feature_to_xml({{Feature, _Host}}) ->
feature_to_xml(Feature);
feature_to_xml(Feature) when is_list(Feature) ->
{xmlelement, "feature", [{"var", Feature}], []}.
domain_to_xml({Domain}) ->
{xmlelement, "item", [{"jid", Domain}], []};
@@ -269,48 +263,42 @@ process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ
set ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
get ->
case is_presence_subscribed(From, To) of
true ->
Host = To#jid.lserver,
Node = xml:get_tag_attr_s("node", SubEl),
case ejabberd_hooks:run_fold(disco_sm_items,
Host,
empty,
[From, To, Node, Lang]) of
{result, Items} ->
ANode = case Node of
"" -> [];
_ -> [{"node", Node}]
end,
IQ#iq{type = result,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_DISCO_ITEMS} | ANode],
Items
}]};
{error, Error} ->
IQ#iq{type = error, sub_el = [SubEl, Error]}
end;
false ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}
end
Host = To#jid.lserver,
Node = xml:get_tag_attr_s("node", SubEl),
case ejabberd_hooks:run_fold(disco_sm_items,
Host,
empty,
[From, To, Node, Lang]) of
{result, Items} ->
ANode = case Node of
"" -> [];
_ -> [{"node", Node}]
end,
IQ#iq{type = result,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_DISCO_ITEMS} | ANode],
Items
}]};
{error, Error} ->
IQ#iq{type = error, sub_el = [SubEl, Error]}
end
end.
get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
Acc;
get_sm_items(Acc, From,
#jid{user = User, server = Server} = To,
get_sm_items(Acc,
#jid{luser = LFrom, lserver = LSFrom},
#jid{user = User, server = Server, luser = LTo, lserver = LSTo} = _To,
[], _Lang) ->
Items = case Acc of
{result, Its} -> Its;
empty -> []
end,
Items1 = case is_presence_subscribed(From, To) of
true ->
get_user_resources(User, Server);
_ ->
[]
end,
Items1 = case {LFrom, LSFrom} of
{LTo, LSTo} -> get_user_resources(User, Server);
_ -> []
end,
{result, Items ++ Items1};
get_sm_items({result, _} = Acc, _From, _To, _Node, _Lang) ->
@@ -326,63 +314,39 @@ get_sm_items(empty, From, To, _Node, _Lang) ->
{error, ?ERR_NOT_ALLOWED}
end.
is_presence_subscribed(#jid{luser=User, lserver=Server}, #jid{luser=LUser, lserver=LServer}) ->
lists:any(fun({roster, _, _, {TUser, TServer, _}, _, S, _, _, _, _}) ->
if
LUser == TUser, LServer == TServer, S/=none ->
true;
true ->
false
end
end,
ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]))
orelse User == LUser andalso Server == LServer.
process_sm_iq_info(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
case Type of
set ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
get ->
case is_presence_subscribed(From, To) of
true ->
Host = To#jid.lserver,
Node = xml:get_tag_attr_s("node", SubEl),
Identity = ejabberd_hooks:run_fold(disco_sm_identity,
Host,
[],
[From, To, Node, Lang]),
case ejabberd_hooks:run_fold(disco_sm_features,
Host,
empty,
[From, To, Node, Lang]) of
{result, Features} ->
ANode = case Node of
"" -> [];
_ -> [{"node", Node}]
end,
IQ#iq{type = result,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_DISCO_INFO} | ANode],
Identity ++
features_to_xml(Features)
}]};
{error, Error} ->
IQ#iq{type = error, sub_el = [SubEl, Error]}
end;
false ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}
end
end.
get_sm_identity(Acc, _From, #jid{luser = LUser, lserver=LServer}, _Node, _Lang) ->
Acc ++ case ejabberd_auth:is_user_exists(LUser, LServer) of
true ->
[{xmlelement, "identity", [{"category", "account"},
{"type", "registered"}], []}];
_ ->
[]
Host = To#jid.lserver,
Node = xml:get_tag_attr_s("node", SubEl),
Identity = ejabberd_hooks:run_fold(disco_sm_identity,
Host,
[],
[From, To, Node, Lang]),
case ejabberd_hooks:run_fold(disco_sm_features,
Host,
empty,
[From, To, Node, Lang]) of
{result, Features} ->
ANode = case Node of
"" -> [];
_ -> [{"node", Node}]
end,
IQ#iq{type = result,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_DISCO_INFO} | ANode],
Identity ++
lists:map(fun feature_to_xml/1, Features)
}]};
{error, Error} ->
IQ#iq{type = error, sub_el = [SubEl, Error]}
end
end.
get_sm_identity(Acc, _From, _To, _Node, _Lang) ->
Acc.
get_sm_features(empty, From, To, _Node, _Lang) ->
#jid{luser = LFrom, lserver = LSFrom} = From,
@@ -409,13 +373,7 @@ get_user_resources(User, Server) ->
%%% Support for: XEP-0157 Contact Addresses for XMPP Services
get_info(_A, Host, Mod, Node, _Lang) when Node == [] ->
Module = case Mod of
undefined ->
?MODULE;
_ ->
Mod
end,
get_info(_A, Host, Module, Node, _Lang) when Node == [] ->
Serverinfo_fields = get_fields_xml(Host, Module),
[{xmlelement, "x",
[{"xmlns", ?NS_XDATA}, {"type", "result"}],
@@ -429,8 +387,8 @@ get_info(_A, Host, Mod, Node, _Lang) when Node == [] ->
++ Serverinfo_fields
}];
get_info(Acc, _, _, _Node, _) ->
Acc.
get_info(_, _, _, _Node, _) ->
[].
get_fields_xml(Host, Module) ->
Fields = gen_mod:get_module_opt(Host, ?MODULE, server_info, []),
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 15 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -7,7 +7,7 @@
%%% {mod_ip_blacklist, []}
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2009 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -24,7 +24,7 @@ EFLAGS += -pz ..
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
EFLAGS+=+debug_info
endif
ERLSHLIBS = ../iconv_erl.so

Some files were not shown because too many files have changed in this diff Show More