parent
0e363bf8cb
commit
ae30798efd
|
@ -0,0 +1,271 @@
|
||||||
|
/*
|
||||||
|
* The contents of this file are subject to the Mozilla Public
|
||||||
|
* License Version 1.1 (the "License"); you may not use this file
|
||||||
|
* except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS
|
||||||
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is SHA 180-1 Reference Implementation (Compact version)
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Paul Kocher of
|
||||||
|
* Cryptography Research. Portions created by Paul Kocher are
|
||||||
|
* Copyright (C) 1995-9 by Cryptography Research, Inc. All
|
||||||
|
* Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <erl_driver.h>
|
||||||
|
#include <ei.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ErlDrvPort port;
|
||||||
|
} sha_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long H[5];
|
||||||
|
unsigned long W[80];
|
||||||
|
int lenW;
|
||||||
|
unsigned long sizeHi,sizeLo;
|
||||||
|
} j_SHA_CTX;
|
||||||
|
|
||||||
|
static void shaHashBlock(j_SHA_CTX *ctx);
|
||||||
|
|
||||||
|
void shaInit(j_SHA_CTX *ctx) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ctx->lenW = 0;
|
||||||
|
ctx->sizeHi = ctx->sizeLo = 0;
|
||||||
|
|
||||||
|
/* Initialize H with the magic constants (see FIPS180 for constants)
|
||||||
|
*/
|
||||||
|
ctx->H[0] = 0x67452301L;
|
||||||
|
ctx->H[1] = 0xefcdab89L;
|
||||||
|
ctx->H[2] = 0x98badcfeL;
|
||||||
|
ctx->H[3] = 0x10325476L;
|
||||||
|
ctx->H[4] = 0xc3d2e1f0L;
|
||||||
|
|
||||||
|
for (i = 0; i < 80; i++)
|
||||||
|
ctx->W[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void shaUpdate(j_SHA_CTX *ctx, unsigned char *dataIn, int len) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Read the data into W and process blocks as they get full
|
||||||
|
*/
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
ctx->W[ctx->lenW / 4] <<= 8;
|
||||||
|
ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i];
|
||||||
|
if ((++ctx->lenW) % 64 == 0) {
|
||||||
|
shaHashBlock(ctx);
|
||||||
|
ctx->lenW = 0;
|
||||||
|
}
|
||||||
|
ctx->sizeLo += 8;
|
||||||
|
ctx->sizeHi += (ctx->sizeLo < 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void shaFinal(j_SHA_CTX *ctx, unsigned char hashout[20]) {
|
||||||
|
unsigned char pad0x80 = 0x80;
|
||||||
|
unsigned char pad0x00 = 0x00;
|
||||||
|
unsigned char padlen[8];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
|
||||||
|
*/
|
||||||
|
padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
|
||||||
|
padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
|
||||||
|
padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
|
||||||
|
padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
|
||||||
|
padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
|
||||||
|
padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
|
||||||
|
padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
|
||||||
|
padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
|
||||||
|
shaUpdate(ctx, &pad0x80, 1);
|
||||||
|
while (ctx->lenW != 56)
|
||||||
|
shaUpdate(ctx, &pad0x00, 1);
|
||||||
|
shaUpdate(ctx, padlen, 8);
|
||||||
|
|
||||||
|
/* Output hash
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 20; i++) {
|
||||||
|
hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
|
||||||
|
ctx->H[i / 4] <<= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Re-initialize the context (also zeroizes contents)
|
||||||
|
*/
|
||||||
|
shaInit(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) {
|
||||||
|
j_SHA_CTX ctx;
|
||||||
|
|
||||||
|
shaInit(&ctx);
|
||||||
|
shaUpdate(&ctx, dataIn, len);
|
||||||
|
shaFinal(&ctx, hashout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
|
||||||
|
|
||||||
|
static void shaHashBlock(j_SHA_CTX *ctx) {
|
||||||
|
int t;
|
||||||
|
unsigned long A,B,C,D,E,TEMP;
|
||||||
|
|
||||||
|
for (t = 16; t <= 79; t++)
|
||||||
|
ctx->W[t] =
|
||||||
|
SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
|
||||||
|
|
||||||
|
A = ctx->H[0];
|
||||||
|
B = ctx->H[1];
|
||||||
|
C = ctx->H[2];
|
||||||
|
D = ctx->H[3];
|
||||||
|
E = ctx->H[4];
|
||||||
|
|
||||||
|
for (t = 0; t <= 19; t++) {
|
||||||
|
TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL;
|
||||||
|
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
|
||||||
|
}
|
||||||
|
for (t = 20; t <= 39; t++) {
|
||||||
|
TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL;
|
||||||
|
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
|
||||||
|
}
|
||||||
|
for (t = 40; t <= 59; t++) {
|
||||||
|
TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL;
|
||||||
|
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
|
||||||
|
}
|
||||||
|
for (t = 60; t <= 79; t++) {
|
||||||
|
TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL;
|
||||||
|
E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->H[0] += A;
|
||||||
|
ctx->H[1] += B;
|
||||||
|
ctx->H[2] += C;
|
||||||
|
ctx->H[3] += D;
|
||||||
|
ctx->H[4] += E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* This code added by Thomas "temas" Muldowney for Jabber compatability
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------------------*/
|
||||||
|
char *shahash(char *str)
|
||||||
|
{
|
||||||
|
static char final[41];
|
||||||
|
char *pos;
|
||||||
|
unsigned char hashval[20];
|
||||||
|
int x;
|
||||||
|
|
||||||
|
if(!str || strlen(str) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
shaBlock((unsigned char *)str, strlen(str), hashval);
|
||||||
|
|
||||||
|
pos = final;
|
||||||
|
for(x=0;x<20;x++)
|
||||||
|
{
|
||||||
|
snprintf(pos, 3, "%02x", hashval[x]);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
return (char *)final;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shahash_r(const char* str, char hashbuf[41])
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
char *pos;
|
||||||
|
unsigned char hashval[20];
|
||||||
|
|
||||||
|
if(!str || strlen(str) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
shaBlock((unsigned char *)str, strlen(str), hashval);
|
||||||
|
|
||||||
|
pos = hashbuf;
|
||||||
|
for(x=0;x<20;x++)
|
||||||
|
{
|
||||||
|
snprintf(pos, 3, "%02x", hashval[x]);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ErlDrvData sha_erl_start(ErlDrvPort port, char *buff)
|
||||||
|
{
|
||||||
|
sha_data* d = (sha_data*)driver_alloc(sizeof(sha_data));
|
||||||
|
d->port = port;
|
||||||
|
|
||||||
|
return (ErlDrvData)d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sha_erl_stop(ErlDrvData handle)
|
||||||
|
{
|
||||||
|
driver_free((char*)handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sha_erl_output(ErlDrvData handle, char *buff, int bufflen)
|
||||||
|
{
|
||||||
|
sha_data* d = (sha_data*)handle;
|
||||||
|
ei_x_buff buf;
|
||||||
|
|
||||||
|
static char final[41];
|
||||||
|
char *pos;
|
||||||
|
unsigned char hashval[20];
|
||||||
|
int x;
|
||||||
|
|
||||||
|
if(bufflen == 0)
|
||||||
|
final[0] = '\000';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shaBlock(buff, bufflen, hashval);
|
||||||
|
|
||||||
|
pos = final;
|
||||||
|
for(x=0;x<20;x++)
|
||||||
|
{
|
||||||
|
snprintf(pos, 3, "%02x", hashval[x]);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ei_x_new_with_version(&buf);
|
||||||
|
ei_x_encode_string(&buf, final);
|
||||||
|
|
||||||
|
driver_output(d->port, buf.buff, buf.index);
|
||||||
|
ei_x_free(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ErlDrvEntry sha_driver_entry = {
|
||||||
|
NULL, /* F_PTR init, N/A */
|
||||||
|
sha_erl_start, /* L_PTR start, called when port is opened */
|
||||||
|
sha_erl_stop, /* F_PTR stop, called when port is closed */
|
||||||
|
sha_erl_output, /* F_PTR output, called when erlang has sent */
|
||||||
|
NULL, /* F_PTR ready_input, called when input descriptor ready */
|
||||||
|
NULL, /* F_PTR ready_output, called when output descriptor ready */
|
||||||
|
"sha_erl", /* char *driver_name, the argument to open_port */
|
||||||
|
NULL, /* F_PTR finish, called when unloaded */
|
||||||
|
NULL, /* F_PTR control, port_command callback */
|
||||||
|
NULL, /* F_PTR timeout, reserved */
|
||||||
|
NULL /* F_PTR outputv, reserved */
|
||||||
|
};
|
||||||
|
|
||||||
|
DRIVER_INIT(sha_erl) /* must match name in driver_entry */
|
||||||
|
{
|
||||||
|
return &sha_driver_entry;
|
||||||
|
}
|
||||||
|
|
18
src/Makefile
18
src/Makefile
|
@ -5,14 +5,16 @@ INCLUDES = -I/usr/lib/erlang/usr/include \
|
||||||
|
|
||||||
LIBDIRS = -L/usr/lib/erlang/lib/erl_interface-3.3.0/lib
|
LIBDIRS = -L/usr/lib/erlang/lib/erl_interface-3.3.0/lib
|
||||||
|
|
||||||
all: expat_erl.so
|
ERLSHLIBS = expat_erl.so sha_erl.so
|
||||||
|
|
||||||
|
all: $(ERLSHLIBS)
|
||||||
erl -make
|
erl -make
|
||||||
|
|
||||||
expat_erl.so: expat_erl.c
|
$(ERLSHLIBS): %.so: %.c
|
||||||
gcc -Wall $(INCLUDES) $(LIBDIRS) \
|
gcc -Wall $(INCLUDES) $(LIBDIRS) \
|
||||||
-lexpat \
|
-lexpat \
|
||||||
expat_erl.c \
|
$(subst .so,.c,$@) \
|
||||||
-lerl_interface \
|
-lerl_interface \
|
||||||
-lei \
|
-lei \
|
||||||
-o expat_erl.so -fpic -shared \
|
-o $@ -fpic -shared \
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ init() ->
|
||||||
ok = erl_ddll:load_driver(".", expat_erl),
|
ok = erl_ddll:load_driver(".", expat_erl),
|
||||||
Port = open_port({spawn, expat_erl}, [binary]),
|
Port = open_port({spawn, expat_erl}, [binary]),
|
||||||
db_init(),
|
db_init(),
|
||||||
|
sha:start(),
|
||||||
ejabberd_auth:start(),
|
ejabberd_auth:start(),
|
||||||
ejabberd_router:start(),
|
ejabberd_router:start(),
|
||||||
ejabberd_sm:start(),
|
ejabberd_sm:start(),
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
-export([start/0, start_link/0,
|
-export([start/0, start_link/0,
|
||||||
set_password/2,
|
set_password/2,
|
||||||
check_password/2,
|
check_password/2,
|
||||||
|
check_password/4,
|
||||||
try_register/2]).
|
try_register/2]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
|
@ -110,6 +111,31 @@ check_password(User, Password) ->
|
||||||
false
|
false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
check_password(User, Password, StreamID, Digest) ->
|
||||||
|
LUser = jlib:tolower(User),
|
||||||
|
F = fun() ->
|
||||||
|
case mnesia:read({passwd, LUser}) of
|
||||||
|
[E] ->
|
||||||
|
E#passwd.password
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
case mnesia:transaction(F) of
|
||||||
|
{atomic, Passwd} ->
|
||||||
|
DigRes = if
|
||||||
|
Digest /= "" ->
|
||||||
|
Digest == sha:sha(StreamID ++ Passwd);
|
||||||
|
true ->
|
||||||
|
false
|
||||||
|
end,
|
||||||
|
if DigRes ->
|
||||||
|
true;
|
||||||
|
true ->
|
||||||
|
Passwd == Password
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
set_password(User, Password) ->
|
set_password(User, Password) ->
|
||||||
LUser = jlib:tolower(User),
|
LUser = jlib:tolower(User),
|
||||||
|
|
|
@ -113,9 +113,9 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||||
{auth, ID, {U, P, D, R}} ->
|
{auth, ID, {U, P, D, R}} ->
|
||||||
io:format("AUTH: ~p~n", [{U, P, D, R}]),
|
io:format("AUTH: ~p~n", [{U, P, D, R}]),
|
||||||
% TODO: digested password
|
% TODO: digested password
|
||||||
case ejabberd_auth:check_password(U, P) of
|
case ejabberd_auth:check_password(U, P,
|
||||||
|
StateData#state.streamid, D) of
|
||||||
true ->
|
true ->
|
||||||
% TODO
|
|
||||||
ejabberd_sm:open_session(U, R),
|
ejabberd_sm:open_session(U, R),
|
||||||
Res = jlib:make_result_iq_reply(El),
|
Res = jlib:make_result_iq_reply(El),
|
||||||
send_element(StateData#state.sender, Res),
|
send_element(StateData#state.sender, Res),
|
||||||
|
@ -181,7 +181,9 @@ session_established({xmlstreamelement, El}, StateData) ->
|
||||||
[FromJID, El, StateData]),
|
[FromJID, El, StateData]),
|
||||||
presence_update(FromJID, El, StateData);
|
presence_update(FromJID, El, StateData);
|
||||||
_ ->
|
_ ->
|
||||||
ejabberd_router:route(FromJID, ToJID, El),
|
ejabberd_router:route({StateData#state.user,
|
||||||
|
Server, ""},
|
||||||
|
ToJID, El),
|
||||||
presence_track(FromJID, ToJID, El, StateData)
|
presence_track(FromJID, ToJID, El, StateData)
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -267,24 +269,12 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||||
Attrs1 = lists:keydelete("type", 1, Attrs),
|
Attrs1 = lists:keydelete("type", 1, Attrs),
|
||||||
{true, [{"type", "unavailable"} | Attrs1], StateData};
|
{true, [{"type", "unavailable"} | Attrs1], StateData};
|
||||||
"subscribe" ->
|
"subscribe" ->
|
||||||
mod_roster:in_subscription(StateData#state.user,
|
|
||||||
{FU, FS, ""},
|
|
||||||
subscribe),
|
|
||||||
{true, Attrs, StateData};
|
{true, Attrs, StateData};
|
||||||
"subscribed" ->
|
"subscribed" ->
|
||||||
mod_roster:in_subscription(StateData#state.user,
|
|
||||||
{FU, FS, ""},
|
|
||||||
subscribed),
|
|
||||||
{true, Attrs, StateData};
|
{true, Attrs, StateData};
|
||||||
"unsubscribe" ->
|
"unsubscribe" ->
|
||||||
mod_roster:in_subscription(StateData#state.user,
|
|
||||||
{FU, FS, ""},
|
|
||||||
unsubscribe),
|
|
||||||
{true, Attrs, StateData};
|
{true, Attrs, StateData};
|
||||||
"unsubscribed" ->
|
"unsubscribed" ->
|
||||||
mod_roster:in_subscription(StateData#state.user,
|
|
||||||
{FU, FS, ""},
|
|
||||||
unsubscribed),
|
|
||||||
{true, Attrs, StateData};
|
{true, Attrs, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
{true, Attrs, StateData}
|
{true, Attrs, StateData}
|
||||||
|
@ -450,10 +440,17 @@ presence_update(From, Packet, StateData) ->
|
||||||
true ->
|
true ->
|
||||||
StateData
|
StateData
|
||||||
end,
|
end,
|
||||||
|
|
||||||
StateData;
|
StateData;
|
||||||
"error" ->
|
"error" ->
|
||||||
StateData;
|
StateData;
|
||||||
|
"subscribe" ->
|
||||||
|
StateData;
|
||||||
|
"subscribed" ->
|
||||||
|
StateData;
|
||||||
|
"unsubscribe" ->
|
||||||
|
StateData;
|
||||||
|
"unsubscribed" ->
|
||||||
|
StateData;
|
||||||
_ ->
|
_ ->
|
||||||
FromUnavail = (StateData#state.pres_last == undefined) or
|
FromUnavail = (StateData#state.pres_last == undefined) or
|
||||||
StateData#state.pres_invis,
|
StateData#state.pres_invis,
|
||||||
|
@ -479,28 +476,36 @@ presence_update(From, Packet, StateData) ->
|
||||||
|
|
||||||
presence_track(From, To, Packet, StateData) ->
|
presence_track(From, To, Packet, StateData) ->
|
||||||
{xmlelement, Name, Attrs, Els} = Packet,
|
{xmlelement, Name, Attrs, Els} = Packet,
|
||||||
|
LTo = jlib:jid_tolower(To),
|
||||||
|
User = StateData#state.user,
|
||||||
case xml:get_attr_s("type", Attrs) of
|
case xml:get_attr_s("type", Attrs) of
|
||||||
"unavailable" ->
|
"unavailable" ->
|
||||||
I = remove_element(To, StateData#state.pres_i),
|
I = remove_element(LTo, StateData#state.pres_i),
|
||||||
A = remove_element(To, StateData#state.pres_a),
|
A = remove_element(LTo, StateData#state.pres_a),
|
||||||
StateData#state{pres_i = I,
|
StateData#state{pres_i = I,
|
||||||
pres_a = A};
|
pres_a = A};
|
||||||
"invisible" ->
|
"invisible" ->
|
||||||
I = ?SETS:add_element(To, StateData#state.pres_i),
|
I = ?SETS:add_element(LTo, StateData#state.pres_i),
|
||||||
A = remove_element(To, StateData#state.pres_a),
|
A = remove_element(LTo, StateData#state.pres_a),
|
||||||
StateData#state{pres_i = I,
|
StateData#state{pres_i = I,
|
||||||
pres_a = A};
|
pres_a = A};
|
||||||
"subscribe" ->
|
"subscribe" ->
|
||||||
|
mod_roster:out_subscription(User, To, subscribe),
|
||||||
StateData;
|
StateData;
|
||||||
"subscribed" ->
|
"subscribed" ->
|
||||||
|
mod_roster:out_subscription(User, To, subscribed),
|
||||||
StateData;
|
StateData;
|
||||||
"unsubscribe" ->
|
"unsubscribe" ->
|
||||||
|
mod_roster:out_subscription(User, To, unsubscribe),
|
||||||
StateData;
|
StateData;
|
||||||
"unsubscribed" ->
|
"unsubscribed" ->
|
||||||
|
mod_roster:out_subscription(User, To, unsubscribed),
|
||||||
|
StateData;
|
||||||
|
"error" ->
|
||||||
StateData;
|
StateData;
|
||||||
_ ->
|
_ ->
|
||||||
I = remove_element(To, StateData#state.pres_i),
|
I = remove_element(LTo, StateData#state.pres_i),
|
||||||
A = ?SETS:add_element(To, StateData#state.pres_a),
|
A = ?SETS:add_element(LTo, StateData#state.pres_a),
|
||||||
StateData#state{pres_i = I,
|
StateData#state{pres_i = I,
|
||||||
pres_a = A}
|
pres_a = A}
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -100,17 +100,7 @@ do_route(From, To, Packet) ->
|
||||||
end,
|
end,
|
||||||
case mnesia:transaction(F) of
|
case mnesia:transaction(F) of
|
||||||
{atomic, error} ->
|
{atomic, error} ->
|
||||||
% TODO: start s2s instead of below
|
|
||||||
ejabberd_s2s ! {route, From, To, Packet};
|
ejabberd_s2s ! {route, From, To, Packet};
|
||||||
%{xmlelement, Name, Attrs, SubTags} = Packet,
|
|
||||||
%case xml:get_attr_s("type", Attrs) of
|
|
||||||
% "error" ->
|
|
||||||
% ok;
|
|
||||||
% _ ->
|
|
||||||
% Err = jlib:make_error_reply(Packet,
|
|
||||||
% "502", "Service Unavailable"),
|
|
||||||
% ejabberd_router ! {route, To, From, Err}
|
|
||||||
%end;
|
|
||||||
{atomic, {ok, Node, Pid}} ->
|
{atomic, {ok, Node, Pid}} ->
|
||||||
case node() of
|
case node() of
|
||||||
Node ->
|
Node ->
|
||||||
|
|
|
@ -186,26 +186,49 @@ wait_for_verification(closed, StateData) ->
|
||||||
|
|
||||||
stream_established({xmlstreamelement, El}, StateData) ->
|
stream_established({xmlstreamelement, El}, StateData) ->
|
||||||
{xmlelement, Name, Attrs, Els} = El,
|
{xmlelement, Name, Attrs, Els} = El,
|
||||||
% TODO
|
case Name of
|
||||||
From = xml:get_attr_s("from", Attrs),
|
"db:verify" ->
|
||||||
FromJID1 = jlib:string_to_jid(From),
|
case is_key_packet(El) of
|
||||||
FromJID = case FromJID1 of
|
{verify, To, From, Id, Key} ->
|
||||||
{Node, Server, Resource} ->
|
io:format("VERIFY KEY: ~p~n", [{To, From, Id, Key}]),
|
||||||
if Server == StateData#state.server -> FromJID1;
|
Key1 = ejabberd_s2s:get_key(From),
|
||||||
true -> error
|
Type = if Key == Key1 -> "valid";
|
||||||
end;
|
true -> "invalid"
|
||||||
_ -> error
|
end,
|
||||||
end,
|
send_element(StateData#state.socket,
|
||||||
To = xml:get_attr_s("to", Attrs),
|
{xmlelement,
|
||||||
ToJID = case To of
|
"db:verify",
|
||||||
"" -> error;
|
[{"from", ?MYNAME},
|
||||||
_ -> jlib:string_to_jid(To)
|
{"to", From},
|
||||||
end,
|
{"id", Id},
|
||||||
if ((Name == "iq") or (Name == "message") or (Name == "presence")) and
|
{"type", Type}],
|
||||||
(ToJID /= error) and (FromJID /= error) ->
|
[]});
|
||||||
ejabberd_router:route(FromJID, ToJID, El);
|
_ ->
|
||||||
true ->
|
ok
|
||||||
error
|
end;
|
||||||
|
_ ->
|
||||||
|
From = xml:get_attr_s("from", Attrs),
|
||||||
|
FromJID1 = jlib:string_to_jid(From),
|
||||||
|
FromJID = case FromJID1 of
|
||||||
|
{Node, Server, Resource} ->
|
||||||
|
if Server == StateData#state.server -> FromJID1;
|
||||||
|
true -> error
|
||||||
|
end;
|
||||||
|
_ -> error
|
||||||
|
end,
|
||||||
|
To = xml:get_attr_s("to", Attrs),
|
||||||
|
ToJID = case To of
|
||||||
|
"" -> error;
|
||||||
|
_ -> jlib:string_to_jid(To)
|
||||||
|
end,
|
||||||
|
if ((Name == "iq") or
|
||||||
|
(Name == "message") or
|
||||||
|
(Name == "presence")) and
|
||||||
|
(ToJID /= error) and (FromJID /= error) ->
|
||||||
|
ejabberd_router:route(FromJID, ToJID, El);
|
||||||
|
true ->
|
||||||
|
error
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
{next_state, stream_established, StateData};
|
{next_state, stream_established, StateData};
|
||||||
|
|
||||||
|
|
|
@ -169,18 +169,45 @@ do_route(From, To, Packet) ->
|
||||||
% TODO
|
% TODO
|
||||||
case Name of
|
case Name of
|
||||||
"presence" ->
|
"presence" ->
|
||||||
lists:foreach(
|
{FU, FS, FR} = From,
|
||||||
fun(R) ->
|
Pass = case xml:get_attr_s("type", Attrs) of
|
||||||
if From /= {User, Server, R} ->
|
"subscribe" ->
|
||||||
ejabberd_sm ! {route,
|
mod_roster:in_subscription(User,
|
||||||
From,
|
{FU, FS, ""},
|
||||||
{User, Server, R},
|
subscribe);
|
||||||
Packet};
|
"subscribed" ->
|
||||||
true ->
|
mod_roster:in_subscription(User,
|
||||||
ok
|
{FU, FS, ""},
|
||||||
end
|
subscribed);
|
||||||
end, get_user_resources(User)),
|
"unsubscribe" ->
|
||||||
ok;
|
mod_roster:in_subscription(User,
|
||||||
|
{FU, FS, ""},
|
||||||
|
unsubscribe);
|
||||||
|
"unsubscribed" ->
|
||||||
|
mod_roster:in_subscription(User,
|
||||||
|
{FU, FS, ""},
|
||||||
|
unsubscribed);
|
||||||
|
_ ->
|
||||||
|
true
|
||||||
|
end,
|
||||||
|
if Pass ->
|
||||||
|
LFrom = jlib:jid_tolower(From),
|
||||||
|
LUser = jlib:tolower(User),
|
||||||
|
LServer = jlib:tolower(Server),
|
||||||
|
lists:foreach(
|
||||||
|
fun(R) ->
|
||||||
|
if LFrom /= {LUser, LServer, R} ->
|
||||||
|
ejabberd_sm ! {route,
|
||||||
|
From,
|
||||||
|
{User, Server, R},
|
||||||
|
Packet};
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end, get_user_resources(User));
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end;
|
||||||
"message" ->
|
"message" ->
|
||||||
% TODO
|
% TODO
|
||||||
ok;
|
ok;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
string_to_jid/1,
|
string_to_jid/1,
|
||||||
jid_to_string/1,
|
jid_to_string/1,
|
||||||
tolower/1,
|
tolower/1,
|
||||||
|
jid_tolower/1,
|
||||||
get_iq_namespace/1,
|
get_iq_namespace/1,
|
||||||
iq_query_info/1,
|
iq_query_info/1,
|
||||||
is_iq_request_type/1,
|
is_iq_request_type/1,
|
||||||
|
@ -179,6 +180,8 @@ tolower(S) ->
|
||||||
lists:map(fun tolower_c/1, S).
|
lists:map(fun tolower_c/1, S).
|
||||||
|
|
||||||
|
|
||||||
|
jid_tolower({U, S, R}) ->
|
||||||
|
{tolower(U), tolower(S), R}.
|
||||||
|
|
||||||
get_iq_namespace({xmlelement, Name, Attrs, Els}) when Name == "iq" ->
|
get_iq_namespace({xmlelement, Name, Attrs, Els}) when Name == "iq" ->
|
||||||
case xml:remove_cdata(Els) of
|
case xml:remove_cdata(Els) of
|
||||||
|
|
|
@ -15,15 +15,18 @@
|
||||||
-export([start/0, init/0,
|
-export([start/0, init/0,
|
||||||
process_iq/3,
|
process_iq/3,
|
||||||
get_subscription_lists/1,
|
get_subscription_lists/1,
|
||||||
in_subscription/3]).
|
in_subscription/3,
|
||||||
|
out_subscription/3]).
|
||||||
|
|
||||||
-include_lib("mnemosyne/include/mnemosyne.hrl").
|
-include_lib("mnemosyne/include/mnemosyne.hrl").
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
|
|
||||||
-record(roster, {user,
|
-record(roster, {uj,
|
||||||
|
user,
|
||||||
jid,
|
jid,
|
||||||
name = "",
|
name = "",
|
||||||
subscription = none,
|
subscription = none,
|
||||||
|
ask = none,
|
||||||
groups = [],
|
groups = [],
|
||||||
xattrs = [],
|
xattrs = [],
|
||||||
xs = []}).
|
xs = []}).
|
||||||
|
@ -35,9 +38,8 @@ start() ->
|
||||||
|
|
||||||
init() ->
|
init() ->
|
||||||
mnesia:create_table(roster,[{disc_copies, [node()]},
|
mnesia:create_table(roster,[{disc_copies, [node()]},
|
||||||
{type, bag},
|
|
||||||
{attributes, record_info(fields, roster)}]),
|
{attributes, record_info(fields, roster)}]),
|
||||||
mnesia:add_table_index(roster, jid),
|
mnesia:add_table_index(roster, user),
|
||||||
ejabberd_local:register_iq_handler("jabber:iq:roster",
|
ejabberd_local:register_iq_handler("jabber:iq:roster",
|
||||||
?MODULE, process_iq),
|
?MODULE, process_iq),
|
||||||
loop().
|
loop().
|
||||||
|
@ -83,7 +85,7 @@ process_iq_get(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
|
||||||
{User, _, _} = From,
|
{User, _, _} = From,
|
||||||
LUser = jlib:tolower(User),
|
LUser = jlib:tolower(User),
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:read({roster, LUser})
|
mnesia:index_read(roster, LUser, #roster.user)
|
||||||
end,
|
end,
|
||||||
case mnesia:transaction(F) of
|
case mnesia:transaction(F) of
|
||||||
{atomic, Items} ->
|
{atomic, Items} ->
|
||||||
|
@ -108,15 +110,24 @@ item_to_xml(Item) ->
|
||||||
Attrs3 = case Item#roster.subscription of
|
Attrs3 = case Item#roster.subscription of
|
||||||
none ->
|
none ->
|
||||||
[{"subscription", "none"} | Attrs2];
|
[{"subscription", "none"} | Attrs2];
|
||||||
|
from ->
|
||||||
|
[{"subscription", "from"} | Attrs2];
|
||||||
|
to ->
|
||||||
|
[{"subscription", "to"} | Attrs2];
|
||||||
both ->
|
both ->
|
||||||
[{"subscription", "both"} | Attrs2];
|
[{"subscription", "both"} | Attrs2];
|
||||||
remove ->
|
remove ->
|
||||||
[{"subscription", "remove"} | Attrs2];
|
[{"subscription", "remove"} | Attrs2]
|
||||||
_ ->
|
|
||||||
% TODO
|
|
||||||
Attrs2
|
|
||||||
end,
|
end,
|
||||||
Attrs = Attrs3 ++ Item#roster.xattrs,
|
Attrs4 = case Item#roster.ask of
|
||||||
|
none ->
|
||||||
|
Attrs3;
|
||||||
|
subscribe ->
|
||||||
|
[{"ask", "subscribe"} | Attrs3];
|
||||||
|
unsubscribe ->
|
||||||
|
[{"ask", "unsubscribe"} | Attrs3]
|
||||||
|
end,
|
||||||
|
Attrs = Attrs4 ++ Item#roster.xattrs,
|
||||||
SubEls1 = lists:map(fun(G) ->
|
SubEls1 = lists:map(fun(G) ->
|
||||||
{xmlelement, "group", [], [{xmlcdata, G}]}
|
{xmlelement, "group", [], [{xmlcdata, G}]}
|
||||||
end, Item#roster.groups),
|
end, Item#roster.groups),
|
||||||
|
@ -139,21 +150,18 @@ process_item_set(User, To, XItem) ->
|
||||||
error ->
|
error ->
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
|
LJID = jlib:jid_tolower(JID),
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
Res = mnemosyne:eval(query [X || X <- table(roster),
|
Res = mnesia:read({roster, {LUser, LJID}}),
|
||||||
X.user = LUser,
|
|
||||||
X.jid = JID]
|
|
||||||
end),
|
|
||||||
Item = case Res of
|
Item = case Res of
|
||||||
[] ->
|
[] ->
|
||||||
#roster{user = LUser,
|
#roster{uj = {LUser, LJID},
|
||||||
jid = JID,
|
user = LUser,
|
||||||
groups = [],
|
jid = JID};
|
||||||
xattrs = [],
|
|
||||||
xs = []};
|
|
||||||
[I] ->
|
[I] ->
|
||||||
mnesia:delete_object(I),
|
I#roster{user = LUser,
|
||||||
I#roster{name = "",
|
jid = JID,
|
||||||
|
name = "",
|
||||||
groups = [],
|
groups = [],
|
||||||
xattrs = [],
|
xattrs = [],
|
||||||
xs = []}
|
xs = []}
|
||||||
|
@ -162,7 +170,7 @@ process_item_set(User, To, XItem) ->
|
||||||
Item2 = process_item_els(Item1, Els),
|
Item2 = process_item_els(Item1, Els),
|
||||||
case Item2#roster.subscription of
|
case Item2#roster.subscription of
|
||||||
remove ->
|
remove ->
|
||||||
ok;
|
mnesia:delete({roster, {LUser, LJID}});
|
||||||
_ ->
|
_ ->
|
||||||
mnesia:write(Item2)
|
mnesia:write(Item2)
|
||||||
end,
|
end,
|
||||||
|
@ -249,7 +257,7 @@ push_item(User, Resource, From, Item) ->
|
||||||
get_subscription_lists(User) ->
|
get_subscription_lists(User) ->
|
||||||
LUser = jlib:tolower(User),
|
LUser = jlib:tolower(User),
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:read({roster, LUser})
|
mnesia:index_read(roster, LUser, #roster.user)
|
||||||
end,
|
end,
|
||||||
case mnesia:transaction(F) of
|
case mnesia:transaction(F) of
|
||||||
{atomic, Items} ->
|
{atomic, Items} ->
|
||||||
|
@ -259,7 +267,8 @@ get_subscription_lists(User) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
fill_subscription_lists([I | Is], F, T) ->
|
fill_subscription_lists([I | Is], F, T) ->
|
||||||
J = I#roster.jid,
|
%J = I#roster.jid,
|
||||||
|
J = element(2, I#roster.uj),
|
||||||
case I#roster.subscription of
|
case I#roster.subscription of
|
||||||
both ->
|
both ->
|
||||||
fill_subscription_lists(Is, [J | F], [J | T]);
|
fill_subscription_lists(Is, [J | F], [J | T]);
|
||||||
|
@ -276,14 +285,146 @@ fill_subscription_lists([], F, T) ->
|
||||||
|
|
||||||
in_subscription(User, From, Type) ->
|
in_subscription(User, From, Type) ->
|
||||||
LUser = jlib:tolower(User),
|
LUser = jlib:tolower(User),
|
||||||
|
LFrom = jlib:jid_tolower(From),
|
||||||
|
{FU, FS, FR} = From,
|
||||||
F = fun() ->
|
F = fun() ->
|
||||||
mnesia:read({roster, LUser})
|
case mnesia:read({roster, {LUser, LFrom}}) of
|
||||||
|
[] ->
|
||||||
|
case Type of
|
||||||
|
subscribe ->
|
||||||
|
true;
|
||||||
|
unsubscribe ->
|
||||||
|
true;
|
||||||
|
unsubscribed ->
|
||||||
|
false;
|
||||||
|
subscribed ->
|
||||||
|
NewItem = #roster{uj = {LUser, LFrom},
|
||||||
|
user = LUser,
|
||||||
|
jid = From},
|
||||||
|
mnesia:write(NewItem),
|
||||||
|
true
|
||||||
|
end;
|
||||||
|
[I] ->
|
||||||
|
case Type of
|
||||||
|
subscribe ->
|
||||||
|
S = I#roster.subscription,
|
||||||
|
if
|
||||||
|
(S == both) or (S == from) ->
|
||||||
|
ejabberd_router:route(
|
||||||
|
{User, ?MYNAME, ""}, {FU, FS, ""},
|
||||||
|
{xmlelement, "presence",
|
||||||
|
[{"type", "subscribed"}], []}),
|
||||||
|
% TODO: update presence
|
||||||
|
false;
|
||||||
|
true ->
|
||||||
|
true
|
||||||
|
end;
|
||||||
|
unsubscribe ->
|
||||||
|
S = I#roster.subscription,
|
||||||
|
if
|
||||||
|
(S == none) or (S == to) ->
|
||||||
|
ejabberd_router:route(
|
||||||
|
{User, ?MYNAME, ""}, {FU, FS, ""},
|
||||||
|
{xmlelement, "presence",
|
||||||
|
[{"type", "unsubscribed"}], []}),
|
||||||
|
% TODO: update presence
|
||||||
|
false;
|
||||||
|
true ->
|
||||||
|
true
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
S = I#roster.subscription,
|
||||||
|
NS = case Type of
|
||||||
|
subscribed ->
|
||||||
|
case S of
|
||||||
|
from -> both;
|
||||||
|
none -> to;
|
||||||
|
_ -> S
|
||||||
|
end;
|
||||||
|
unsubscribed ->
|
||||||
|
case S of
|
||||||
|
both -> from;
|
||||||
|
to -> none;
|
||||||
|
_ -> S
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
NewItem = I#roster{subscription = NS,
|
||||||
|
ask = none},
|
||||||
|
mnesia:write(NewItem),
|
||||||
|
{push, NewItem}
|
||||||
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
case mnesia:transaction(F) of
|
case mnesia:transaction(F) of
|
||||||
{atomic, Items} ->
|
{atomic, true} ->
|
||||||
% TODO
|
true;
|
||||||
ok;
|
{atomic, false} ->
|
||||||
|
false;
|
||||||
|
{atomic, {push, Item}} ->
|
||||||
|
push_item(User, {"", ?MYNAME, ""}, Item),
|
||||||
|
true;
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
false
|
||||||
|
end.
|
||||||
|
|
||||||
|
out_subscription(User, JID, Type) ->
|
||||||
|
LUser = jlib:tolower(User),
|
||||||
|
LJID = jlib:jid_tolower(JID),
|
||||||
|
F = fun() ->
|
||||||
|
Item = case mnesia:read({roster, {LUser, LJID}}) of
|
||||||
|
[] ->
|
||||||
|
if (Type == unsubscribe) or
|
||||||
|
(Type == unsubscribed) ->
|
||||||
|
false;
|
||||||
|
true ->
|
||||||
|
#roster{uj = {LUser, LJID},
|
||||||
|
user = LUser,
|
||||||
|
jid = JID}
|
||||||
|
end;
|
||||||
|
[I] ->
|
||||||
|
I
|
||||||
|
end,
|
||||||
|
if Item == false ->
|
||||||
|
ok;
|
||||||
|
true ->
|
||||||
|
NewItem =
|
||||||
|
case Type of
|
||||||
|
subscribe ->
|
||||||
|
Item#roster{ask = subscribe};
|
||||||
|
unsubscribe ->
|
||||||
|
Item#roster{ask = unsubscribe};
|
||||||
|
subscribed ->
|
||||||
|
S = Item#roster.subscription,
|
||||||
|
NS = case S of
|
||||||
|
to -> both;
|
||||||
|
none -> from;
|
||||||
|
_ -> S
|
||||||
|
end,
|
||||||
|
% TODO: update presence
|
||||||
|
Item#roster{subscription = NS,
|
||||||
|
ask = none};
|
||||||
|
unsubscribed ->
|
||||||
|
S = Item#roster.subscription,
|
||||||
|
NS = case S of
|
||||||
|
both -> to;
|
||||||
|
from -> none;
|
||||||
|
_ -> S
|
||||||
|
end,
|
||||||
|
% TODO: update presence
|
||||||
|
Item#roster{subscription = NS,
|
||||||
|
ask = none}
|
||||||
|
end,
|
||||||
|
mnesia:write(NewItem),
|
||||||
|
{push, NewItem}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
case mnesia:transaction(F) of
|
||||||
|
{atomic, ok} ->
|
||||||
|
ok;
|
||||||
|
{atomic, {push, Item}} ->
|
||||||
|
push_item(User, {"", ?MYNAME, ""}, Item),
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
%%% File : sha.erl
|
||||||
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Purpose :
|
||||||
|
%%% Created : 20 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
%%% Id : $Id$
|
||||||
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(sha).
|
||||||
|
-author('alexey@sevcom.net').
|
||||||
|
-vsn('$Revision$ ').
|
||||||
|
|
||||||
|
-export([start/0, init/0, sha/1]).
|
||||||
|
|
||||||
|
start() ->
|
||||||
|
register(sha, spawn(?MODULE, init, [])).
|
||||||
|
|
||||||
|
init() ->
|
||||||
|
ok = erl_ddll:load_driver(".", sha_erl),
|
||||||
|
Port = open_port({spawn, sha_erl}, [binary]),
|
||||||
|
loop(Port).
|
||||||
|
|
||||||
|
loop(Port) ->
|
||||||
|
receive
|
||||||
|
{From, {text, Str}} ->
|
||||||
|
Port ! {self(), {command, Str}},
|
||||||
|
SHA = receive
|
||||||
|
{Port, {data, Bin}} ->
|
||||||
|
binary_to_term(Bin)
|
||||||
|
end,
|
||||||
|
From ! {sha, SHA},
|
||||||
|
loop(Port)
|
||||||
|
end.
|
||||||
|
|
||||||
|
sha(Text) ->
|
||||||
|
sha ! {self(), {text, Text}},
|
||||||
|
receive
|
||||||
|
{sha, S} ->
|
||||||
|
S
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue