Ejabberd Analysis (2) User Registration

Source: Internet
Author: User

Ejabberd is processed by ejabberd_c2s:

After the ejabberd_c2s module is started, gen_fsm is in the wait_for_stream status.

Client sending

<Span style = "color: # ff0000;"> <stream: stream to = "localhost" xmlns = "jabber: client" xmlns: stream = "http://etherx.jabber.org/streams" version = "1.0"> </span>The wait_for_stream function on the server goes through

Case XML: get_attr_s ("xmlns: Stream", attrs) of <br/>? Ns_stream-> <br/> ...... <br/> case XML: get_attr_s ("version", attrs) of <br/> "1.0"-> <br/> send_header (statedata, server, "1.0 ", defaultlang), <br/>Send the following response to the client:

<span style = "color: # ff0000;"> <? XML version = '1. 0' encoding = 'utf-8'?> <Stream: stream xmlns: stream = "http://etherx.jabber.org/streams" xmlns = "jabber: client" from = "kinglong" id = "fecabb98" XML: lang = "en" version = "1.0"> </span>
because the client does not pass authentication during registration, therefore, wait_for_stream goes through the following path

Case statedata # state. authenticated of <br/> false-> <br/> ...... <br/> send_element (statedata, <br/> {xmlelement, "stream: features", [], <br/> tlsfeature ++ compressfeature ++ <br/> [{xmlelement, "mechanisms", <br/> [{"xmlns ",? Ns_sasl}], <br/> Mechs}] ++ <br/> ejabberd_hooks: run_fold (<br/> c2s_stream_features, <br/> server, <br/> [], [server])}, <br/> fsm_next_state (wait_for_feature_request, <br/> statedata # state {<br/> Server = server, <br/> sasl_state = saslstate, <br/> lang = Lang}); <br/>Send a feature message to the client and set the current status to wait_for_feature_request.

<Span style = "color: # ff0000;"> <stream: features> <starttls xmlns = "urn: IETF: Params: XML: NS: XMPP-TLS "> </starttls> <mechanic ISMs xmlns =" urn: IETF: Params: XML: NS: XMPP-sasl "> <mechanical> DIGEST-MD5 </mechanical> <mechanical> JIVE-SHAREDSECRET </mechanical> <mechanical> plain </mechanical> <mechanical> anonymous </mechanical> <mechanical> CRAM-MD5 </mechanisms> <compression xmlns = "http://jabber.org/features/compress"> <method> zlib </method> </compression> <auth xmlns = "http://jabber.org/features/iq-auth"/> <register xmlns = "http://jabber.org/features/iq-register"/> </stream: features> </span>

The client sends messages to the server.

<Span style = "color: # ff0000;"> <starttls xmlns = "urn: IETF: Params: XML: NS: XMPP-TLS"/> </span>

The server function wait_for_feature_request goes through the following path and sets the status to wait_for_stream again:

{? Ns_tls, "starttls"} When TLS = true, <br/> tlsenabled = false, <br/> sockmod = gen_tcp->
The client sends messages to the server.

<Span style = "color: # ff0000;"> <stream: stream to = "kinglong" xmlns = "jabber: client" xmlns: stream = "http://etherx.jabber.org/streams" version = "1.0"> </span>The server wait_for_stream still follows the path below:

Case XML: get_attr_s ("xmlns: Stream", attrs) of <br/>? Ns_stream-> <br/> ...... <br/> case XML: get_attr_s ("version", attrs) of <br/> "1.0"-> <br/> ...... <br/> case statedata # state. authenticated of <br/> false-> <br/> ...... <br/> send_element (statedata, <br/> {xmlelement, "stream: features", [], <br/> tlsfeature ++ compressfeature ++ <br/> [{xmlelement, "mechanisms", <br/> [{"xmlns ",? Ns_sasl}], <br/> Mechs}] ++ <br/> ejabberd_hooks: run_fold (<br/> c2s_stream_features, <br/> server, <br/> [], [server])}, </P> <p>The send_element function sends the following message to the client, displays the authentication methods available on the server side, and sets the status to wait_for_feature_request again.

<Span style = "color: # ff0000;"> <? XML version = '1. 0' encoding = 'utf-8'?> <Br/> <stream: stream xmlns: stream = "http://etherx.jabber.org/streams" xmlns = "jabber: client" from = "kinglong" id = "fecabb98" XML: lang = "en" version = "1.0"> <br/> <stream: features> <br/> <mechanic ISMs xmlns = "urn: IETF: Params: XML: NS: XMPP-sasl "> <br/> <mechanical ISM> DIGEST-MD5 </mechanical ISM> <br/> <mechanical ISM> JIVE-SHAREDSECRET </mechanical ISM> <br/> <mechanical ISM> plain </mechanical ism> <br/> <mechanical ISM> anonymous </mechanical ISM> <br/> <mechanical ISM> CRAM-MD5 </mechanical ISM> <br/> </mechanical ISMs> <br/> <compression xmlns = "http://jabber.org/features/compress"> <br/> <method> zlib </method> <br/> </compression> <br/> <auth xmlns = "http://jabber.org/features/iq-auth"/> <br /> <register xmlns = "http://jabber.org/features/iq-register"/> <br/> </stream: features> </span>

Because it is a registration process, the client does not pick a way from the authentication process, but sends the following IQ message to the server. The following message query parameters required for Server Registration:

<Span style = "color: # ff0000;"> <IQ id = "2hsng-4" to = "kinglong" type = "get"> <query xmlns = "jabber: IQ: register "> </query> </IQ> </span>
The wait_for_feature_request function on the server is processed according to the xmlns attribute:

Case {XML: get_attr_s ("xmlns", attrs), name }of <br/> {? Ns_sasl, "auth"} when not (sockmod = gen_tcp) and tlsrequired)-> <br/> ...... <br/> {? Ns_tls, "starttls"} When TLS = true, <br/> tlsenabled = false, <br/> sockmod = gen_tcp-> <br/> ...... <br/> {? Ns_compress, "compress"} When zlib = true, <br/> (sockmod = gen_tcp) or <br/> (sockmod = TLS )) -> <br/> ...... <br/> _-> <br/> ....... <br/> process_unauthenticated_stanza (statedata, El), <br/>Because the client sends an IQ message, xmlns matches the last message.

In the process_unauthenticated_stanza function:

Case jlib: iq_query_info (newel) of <br/> # IQ {}= IQ-> <br/> res = ejabberd_hooks: run_fold (c2s_unauthenticated_iq, <br/> statedata # state. server, <br/> empty, <br/> [statedata # state. server, IQ, <br/> statedata # state. IP address]), <br/>Call the module containing the c2s_unauathenticated_iq callback function to process IQ messages.

This callback function is defined in the mod_register module:

<textarea readonly name="code" class="plain">Start (host, opts)-> <br/> ...... <br/> ejabberd_hooks: add (c2s_unauthenticated_iq, host, <br/>? Module, unauthenticated_iq_register, 50), <br/> ...... <br/></textarea> It corresponds to the unathenticated_iq_register method in the mod_register module.
<textarea readonly name="code" class="plain">Unauthenticated_iq_register (_ ACC, <br/> server, # IQ {xmlns =? Ns_register} = IQ, ip)-> <br/> address = case IP of <br/> {A, _ port}->; <br/> _-> undefined <br/> end, <br/> <span style = "color: #000099;"> resiq = process_iq (jlib: make_jid ("", "", ""), <br/> jlib: make_jid ("", server, ""), <br/> IQ, <br/> address), </span> <br/> RES1 = jlib: replace_from_to (jlib: make_jid ("", server, ""), <br/> jlib: make_jid ("", "", ""), <br/> jlib: iq_to_xml (resiq), <br/> jlib: remove_attr ("to", RES1 );</textarea> The above blue part is the specific processing function. Process_iq divides IQ into two types based on type:

Process_iq (from, to, <br/> # IQ {type = type, lang = Lang, sub_el = subel, id = ID} = IQ, <br/> source) -> <br/> ...... <br/> case type of <br/> set-> <br/> <span style = "color: #000099;"> ...... <br/> Get-> </span> </P> <p>

The IQ type sent by this client is get, so it matches get

As for the following judgment, we can ignore it directly. If it matches true, it will be OK.

If iscaptchaenabled and not isregistered-> <br/> ..... </P> <p> true-> <br/> IQ # IQ {type = result, <br/> sub_el = [{xmlelement, <br/> "query ", <br/> [{"xmlns", "jabber: IQ: Register"}], <br/> [{xmlelement, "Instructions", [], <br/> [{xmlcdata, <br/> translate: translate (<br/> Lang, <br/> "choose a username and password" <br/> "to register with this server")}] },< br/> {xmlelement, "username ", [], usernamesubels}, <br/> {xmlelement, "password", [], []} <br/> | querysubels]} <br/>The server sends a response similar to the following to the client:

<Span style = "color: # ff0000; "> <IQ type =" result "id =" 2hsng-4 "from =" kinglong "> <br/> <query xmlns =" jabber: IQ: register "> <br/> <username/> <password/> <br/> <email/> <name/> <br/> <X xmlns =" jabber: X: data "type =" form "> <br/> <title> XMPP client registration </title> <br/> <instructions> choose a username and password to register with this server </Instructions> <br/> <field Var = "form_type" type = "hidden"> <br/> <value> jabber: IQ: register </value> <br/> </field> <br/> <field Var = "username" type = "text-single" label = "username"> <br/> <required/> <br/> </field> <br/> <field Var = "name" type = "text-single" label = "Full name"/> <br/> <field Var = "email" type = "text-single" label = "email"/> <br/> <field Var = "password" type = "text- private "label =" password "> <br/> <required/> <br/> </field> <br/> </x> <br/> </query> <br/> </IQ> </span>Note: After the process_unauthenticated_stanza function completes the current IQ processing, the status is still set to wait_for_feature_request.

The client sends the registration information to the server according to the parameters required by the server:

<Span style = "color: # ff0000;"> <IQ id = "2hsng-5" to = "kinglong" type = "set"> <query xmlns = "jabber: IQ: register "> <username> 15555215557 </username> <email> </Email> <Name> </Name> <password> 123 </password> </query> </IQ> </span>Because our status has not changed, the message is also an IQ message, type = set, so this round is set processing:

Process_iq (from, to, <br/> # IQ {type = type, lang = Lang, sub_el = subel, id = ID} = IQ, <br/> source) -> <br/> ...... <br/> <span style = "color: # 3333ff;"> case type of <br/> </span> <span style = "color: # 3333ff; "> set-> </span> <br/> ...... <br/> Get->The Set item is an if structure statement:

If (utag/= false) and (rtag/= false) and allowremove-> <br/> ...... <br/> (utag = false) and (rtag/= false) and allowremove-> <br/> ...... <br/> (utag/= false) and (ptag/= false)-> <br/> ....... <br/> iscaptchaenabled-> <br/> ....... <br/> true-> <br/> IQ # IQ {type = error, <br/> sub_el = [subel ,? Err_bad_request]} <br/>Utag, ptag, and rtag correspond to username, password, and remove respectively.

Follow the normal registration process

(Utag = false) and (rtag/= false) and allowremove-> </P> <p> ...... <br/> try_register_or_set_password (user, server, password, from, IQ, subel, source, Lang, not iscaptchaenabled) <br/>Here is a key variable iscaptchaenabled, which is one of the configuration parameters of the module. The default value is false.

So we will match the following when calling try_register_or_set_password:Code:

_ When captchasucceed->

The specific registration is completed by the try_register function.

Call ejabberd_auth: try_register (
User, server, password)

In ejabberd_auth, traverse every mod in the configuration file and call the try_register/3 method. Note: Only part of the module name is written in the configuration file. The complete configuration file is ejabberd_auth_xxxx.

For example, if {auth_method, internal} is configured in ejabberd. cfg, ejabberd_auth_internal: try_register/3 is actually called.

Finally, we can see the following code in try_register/3:

F = fun ()-> <br/> case mnesia: Read ({passwd, us }) of <br/> []-> <br/> password2 = case is_scrammed () and is_list (password) of <br/> true-> password_to_scram (password ); <br/> false-> password <br/> end, <br/> mnesia: Write (# passwd {US = us, <br/> Password = password2 }), <br/> mnesia: dirty_update_counter (<br/> reg_users_counter, <br/> lserver, 1), <br/> OK; <br/> [_ E]-> <br/> exists <br/> end, <br/> mnesia: transaction (f)
This is the final registration code.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.