mv to emqttd_plugin_mysql project

This commit is contained in:
Feng Lee 2015-05-28 01:28:33 +08:00
parent 2b19f12e25
commit b96206e1ae
19 changed files with 0 additions and 1149 deletions

View File

@ -1,32 +0,0 @@
REBAR?=./rebar
all: build
clean:
$(REBAR) clean
rm -rf logs
rm -rf .eunit
rm -f test/*.beam
distclean: clean
git clean -fxd
build: depends
$(REBAR) compile
eunit:
$(REBAR) eunit skip_deps=true
check: build eunit
%.beam: %.erl
erlc -o test/ $<
.PHONY: all clean distclean depends build eunit check

View File

@ -1,49 +0,0 @@
## Overview
Authentication with user table of MySQL database.
## etc/plugin.config
```erlang
[
{emysql, [
{pool, 4},
{host, "localhost"},
{port, 3306},
{username, ""},
{password, ""},
{database, "mqtt"},
{encoding, utf8}
]},
{emqttd_auth_mysql, [
{user_table, mqtt_users},
%% plain password only
{password_hash, plain},
{field_mapper, [
{username, username},
{password, password}
]}
]}
].
```
## Users Table(Demo)
Notice: This is a demo table. You could authenticate with any user tables.
```
CREATE TABLE `mqtt_users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(60) DEFAULT NULL,
`password` varchar(60) DEFAULT NULL,
`salt` varchar(20) DEFAULT NULL,
`created` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `mqtt_users_username` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
```
## Load Plugin
Merge the'etc/plugin.config' to emqttd/etc/plugins.config, and the plugin will be loaded by the broker.

View File

@ -1,151 +0,0 @@
/*
* Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Kungliga Tekniska
* Hgskolan and its contributors.
*
* 4. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
/*RCSID("$Id: base64.c,v 1.1 2005/02/11 07:34:35 jpm Exp jpm $");*/
#endif
#include <stdlib.h>
#include <string.h>
#include "base64.h"
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static int pos(char c)
{
char *p;
for(p = base64; *p; p++)
if(*p == c)
return p - base64;
return -1;
}
int base64_encode(const void *data, int size, char **str)
{
char *s, *p;
int i;
int c;
unsigned char *q;
p = s = (char*)malloc(size*4/3+4);
if (p == NULL)
return -1;
q = (unsigned char*)data;
i=0;
for(i = 0; i < size;){
c=q[i++];
c*=256;
if(i < size)
c+=q[i];
i++;
c*=256;
if(i < size)
c+=q[i];
i++;
p[0]=base64[(c&0x00fc0000) >> 18];
p[1]=base64[(c&0x0003f000) >> 12];
p[2]=base64[(c&0x00000fc0) >> 6];
p[3]=base64[(c&0x0000003f) >> 0];
if(i > size)
p[3]='=';
if(i > size+1)
p[2]='=';
p+=4;
}
*p=0;
*str = s;
return strlen(s);
}
int base64_decode(const char *str, void *data)
{
const char *p;
unsigned char *q;
int c;
int x;
int done = 0;
q=(unsigned char*)data;
for(p=str; *p && !done; p+=4){
x = pos(p[0]);
if(x >= 0)
c = x;
else{
done = 3;
break;
}
c*=64;
x = pos(p[1]);
if(x >= 0)
c += x;
else
return -1;
c*=64;
if(p[2] == '=')
done++;
else{
x = pos(p[2]);
if(x >= 0)
c += x;
else
return -1;
}
c*=64;
if(p[3] == '=')
done++;
else{
if(done)
return -1;
x = pos(p[3]);
if(x >= 0)
c += x;
else
return -1;
}
if(done < 3)
*q++=(c&0x00ff0000)>>16;
if(done < 2)
*q++=(c&0x0000ff00)>>8;
if(done < 1)
*q++=(c&0x000000ff)>>0;
}
return q - (unsigned char*)data;
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Kungliga Tekniska
* Hgskolan and its contributors.
*
* 4. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* $Id: base64.h,v 1.1 2005/02/11 07:34:35 jpm Exp jpm $ */
#ifndef _BASE64_H_
#define _BASE64_H_
int base64_encode(const void *data, int size, char **str);
int base64_decode(const char *str, void *data);
#endif

View File

@ -1,60 +0,0 @@
// This file is part of Jiffy released under the MIT license.
// See the LICENSE file for more information.
#include "emqttd_plugin_mysql_app.h"
static int
load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
emqttd_plugin_mysql_app_st* st = enif_alloc(sizeof(emqttd_plugin_mysql_app_st));
if(st == NULL) {
return 1;
}
st->atom_ok = make_atom(env, "ok");
st->atom_error = make_atom(env, "error");
st->atom_null = make_atom(env, "null");
st->atom_true = make_atom(env, "true");
st->atom_false = make_atom(env, "false");
st->atom_bignum = make_atom(env, "bignum");
st->atom_bignum_e = make_atom(env, "bignum_e");
st->atom_bigdbl = make_atom(env, "bigdbl");
st->atom_partial = make_atom(env, "partial");
st->atom_uescape = make_atom(env, "uescape");
st->atom_pretty = make_atom(env, "pretty");
st->atom_force_utf8 = make_atom(env, "force_utf8");
// Markers used in encoding
st->ref_object = make_atom(env, "$object_ref$");
st->ref_array = make_atom(env, "$array_ref$");
*priv = (void*) st;
return 0;
}
static int
reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
return 0;
}
static int
upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
return load(env, priv, info);
}
static void
unload(ErlNifEnv* env, void* priv)
{
enif_free(priv);
return;
}
static ErlNifFunc funcs[] =
{
{"nif_pbkdf2_check", 2, pbkdf2_check}
};
ERL_NIF_INIT(emqttd_plugin_mysql_app, funcs, &load, &reload, &upgrade, &unload);

View File

@ -1,44 +0,0 @@
// This file is part of Jiffy released under the MIT license.
// See the LICENSE file for more information.
#ifndef EMQTTD_PLUGIN_MYSQL_APP_H
#define EMQTTD_PLUGIN_MYSQL_APP_H
#include "erl_nif.h"
typedef struct {
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_error;
ERL_NIF_TERM atom_null;
ERL_NIF_TERM atom_true;
ERL_NIF_TERM atom_false;
ERL_NIF_TERM atom_bignum;
ERL_NIF_TERM atom_bignum_e;
ERL_NIF_TERM atom_bigdbl;
ERL_NIF_TERM atom_partial;
ERL_NIF_TERM atom_uescape;
ERL_NIF_TERM atom_pretty;
ERL_NIF_TERM atom_force_utf8;
ERL_NIF_TERM ref_object;
ERL_NIF_TERM ref_array;
} emqttd_plugin_mysql_app_st;
ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name);
ERL_NIF_TERM make_ok(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, ERL_NIF_TERM data);
ERL_NIF_TERM make_error(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, const char* error);
ERL_NIF_TERM pbkdf2_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
int int_from_hex(const unsigned char* p);
int int_to_hex(int val, char* p);
int utf8_len(int c);
int utf8_esc_len(int c);
int utf8_validate(unsigned char* data, size_t size);
int utf8_to_unicode(unsigned char* buf, size_t size);
int unicode_to_utf8(int c, unsigned char* buf);
int unicode_from_pair(int hi, int lo);
int unicode_uescape(int c, char* buf);
int double_to_shortest(char *buf, size_t size, size_t* len, double val);
#endif // Included EMQTTD_PLUGIN_MYSQL_APP_H

View File

@ -1,278 +0,0 @@
/*
* Copyright (c) 2013 Jan-Piet Mens <jpmens()gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of mosquitto nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include "base64.h"
#include "erl_nif.h"
#include "emqttd_plugin_mysql_app.h"
#define KEY_LENGTH 24
#define SEPARATOR "$"
#define SEPARATOR1 "_"
#define TRUE (1)
#define FALSE (0)
/*
* Split PBKDF2$... string into their components. The caller must free()
* the strings.
*/
static int detoken(char *pbkstr, char **sha, int *iter, char **salt, char **key)
{
char *p, *s, *save;
int rc = 1;
save = s = strdup(pbkstr);
if ((p = strsep(&s, SEPARATOR1)) == NULL)
goto out;
if (strcmp(p, "pbkdf2") != 0)
goto out;
if ((p = strsep(&s, SEPARATOR)) == NULL)
goto out;
*sha = strdup(p);
if ((p = strsep(&s, SEPARATOR)) == NULL)
goto out;
*iter = atoi(p);
if ((p = strsep(&s, SEPARATOR)) == NULL)
goto out;
*salt = strdup(p);
if ((p = strsep(&s, SEPARATOR)) == NULL)
goto out;
*key = strdup(p);
rc = 0;
out:
free(save);
return rc;
}
ERL_NIF_TERM
pbkdf2_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM ret;
ErlNifBinary binps, binhash;
emqttd_plugin_mysql_app_st* st = enif_alloc(sizeof(emqttd_plugin_mysql_app_st));
if(st == NULL) {
return make_atom(env, "alloc_error");
}
st->atom_ok = make_atom(env, "ok");
st->atom_error = make_atom(env, "error");
st->atom_null = make_atom(env, "null");
st->atom_true = make_atom(env, "true");
st->atom_false = make_atom(env, "false");
st->atom_bignum = make_atom(env, "bignum");
st->atom_bignum_e = make_atom(env, "bignum_e");
st->atom_bigdbl = make_atom(env, "bigdbl");
st->atom_partial = make_atom(env, "partial");
st->atom_uescape = make_atom(env, "uescape");
st->atom_pretty = make_atom(env, "pretty");
st->atom_force_utf8 = make_atom(env, "force_utf8");
// Markers used in encoding
st->ref_object = make_atom(env, "$object_ref$");
st->ref_array = make_atom(env, "$array_ref$");
if(argc != 2) {
return make_error(st, env, "Bad args");
} else if(!enif_inspect_binary(env, argv[0], &binps)|!enif_inspect_binary(env, argv[1], &binhash)) {
return make_error(st, env, "Bad args password or username inspect error");
}
char* password = (char*)binps.data;
char* hash = (char*)binhash.data;
static char *sha, *salt, *h_pw;
int iterations, saltlen, blen;
char *b64, *keybuf;
unsigned char *out;
int match = FALSE;
const EVP_MD *evpmd;
int keylen, rc;
if (detoken(hash, &sha, &iterations, &salt, &h_pw) != 0)
return match;
/* Determine key length by decoding base64 */
if ((keybuf = malloc(strlen(h_pw) + 1)) == NULL) {
return make_error(st, env, "internal_error: Out Of memory");
}
keylen = base64_decode(h_pw, keybuf);
if (keylen < 1) {
free(keybuf);
return make_atom(env, "false");
}
free(keybuf);
if ((out = malloc(keylen)) == NULL) {
return make_error(st, env, "Cannot allocate out; out of memory\n");
}
#ifdef PWDEBUG
fprintf(stderr, "sha =[%s]\n", sha);
fprintf(stderr, "iterations =%d\n", iterations);
fprintf(stderr, "salt =[%s]\n", salt);
fprintf(stderr, "h_pw =[%s]\n", h_pw);
fprintf(stderr, "kenlen =[%d]\n", keylen);
#endif
saltlen = strlen((char *)salt);
evpmd = EVP_sha256();
if (strcmp(sha, "sha1") == 0) {
evpmd = EVP_sha1();
} else if (strcmp(sha, "sha512") == 0) {
evpmd = EVP_sha512();
}
rc = PKCS5_PBKDF2_HMAC(password, strlen(password),
(unsigned char *)salt, saltlen,
iterations,
evpmd, keylen, out);
if (rc != 1) {
goto out;
}
blen = base64_encode(out, keylen, &b64);
if (blen > 0) {
int i, diff = 0, hlen = strlen(h_pw);
#ifdef PWDEBUG
fprintf(stderr, "HMAC b64 =[%s]\n", b64);
#endif
/* "manual" strcmp() to ensure constant time */
for (i = 0; (i < blen) && (i < hlen); i++) {
diff |= h_pw[i] ^ b64[i];
}
match = diff == 0;
if (hlen != blen)
match = 0;
free(b64);
}
out:
free(sha);
free(salt);
free(h_pw);
free(out);
if(match == 0){
ret = make_atom(env, "false");
}else{
ret = make_atom(env, "true");
}
return ret;
}
int pbkdf2_check_native(char *password, char *hash)
{
static char *sha, *salt, *h_pw;
int iterations, saltlen, blen;
char *b64;
unsigned char key[128];
int match = FALSE;
const EVP_MD *evpmd;
if (detoken(hash, &sha, &iterations, &salt, &h_pw) != 0)
return match;
#ifdef PWDEBUG
fprintf(stderr, "sha =[%s]\n", sha);
fprintf(stderr, "iterations =%d\n", iterations);
fprintf(stderr, "salt =[%s]\n", salt);
fprintf(stderr, "h_pw =[%s]\n", h_pw);
#endif
saltlen = strlen((char *)salt);
evpmd = EVP_sha256();
if (strcmp(sha, "sha1") == 0) {
evpmd = EVP_sha1();
} else if (strcmp(sha, "sha512") == 0) {
evpmd = EVP_sha512();
}
PKCS5_PBKDF2_HMAC(password, strlen(password),
(unsigned char *)salt, saltlen,
iterations,
evpmd, KEY_LENGTH, key);
blen = base64_encode(key, KEY_LENGTH, &b64);
if (blen > 0) {
int i, diff = 0, hlen = strlen(h_pw);
#ifdef PWDEBUG
fprintf(stderr, "HMAC b64 =[%s]\n", b64);
#endif
/* "manual" strcmp() to ensure constant time */
for (i = 0; (i < blen) && (i < hlen); i++) {
diff |= h_pw[i] ^ b64[i];
}
match = diff == 0;
if (hlen != blen)
match = 0;
free(b64);
}
free(sha);
free(salt);
free(h_pw);
return match;
}
int main()
{
// char password[] = "hello";
// char PB1[] = "PBKDF2$sha256$10000$eytf9sEo8EprP9P3$2eO6tROHiqI3bm+gg+vpmWooWMpz1zji";
char password[] = "supersecret";
//char PB1[] = "PBKDF2$sha256$10000$YEbSTt8FaMRDq/ib$Kt97+sMCYg00mqMOBAYinqZlnxX8HqHk";
char PB1[] = "pbkdf2_sha256$10000$YEbSTt8FaMRDq/ib$Kt97+sMCYg00mqMOBAYinqZlnxX8HqHk";
// char PB1[] = "PBKDF2$sha1$10000$XWfyPLeC9gsD6SbI$HOnjU4Ux7RpeBHdqYxpIGH1R5qCCtNA1";
// char PB1[] = "PBKDF2$sha512$10000$v/aaCgBZ+VZN5L8n$BpgjSTyb4weVxr9cA2mvQ+jaCyaAPeYe";
int match;
printf("Checking password [%s] for %s\n", password, PB1);
match = pbkdf2_check_native(password, PB1);
printf("match == %d\n", match);
return match;
}

View File

@ -1,26 +0,0 @@
// This file is part of Jiffy released under the MIT license.
// See the LICENSE file for more information.
#include "emqttd_plugin_mysql_app.h"
ERL_NIF_TERM
make_atom(ErlNifEnv* env, const char* name)
{
ERL_NIF_TERM ret;
if(enif_make_existing_atom(env, name, &ret, ERL_NIF_LATIN1)) {
return ret;
}
return enif_make_atom(env, name);
}
ERL_NIF_TERM
make_ok(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, ERL_NIF_TERM value)
{
return enif_make_tuple2(env, st->atom_ok, value);
}
ERL_NIF_TERM
make_error(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, const char* error)
{
return enif_make_tuple2(env, st->atom_error, make_atom(env, error));
}

View File

@ -1,23 +0,0 @@
[
{emysql, [
{pool, 4},
{host, "localhost"},
{port, 3306},
{username, "root"},
{password, "root"},
{database, "emqtt"},
{encoding, utf8}
]},
{emqttd_plugin_mysql, [
{users_table, auth_user},
{acls_table, auth_acl},
{field_mapper, [
{username, username},
{password, password, pbkdf2},
{user_super, is_super_user},
{acl_username, username},
{acl_rw, rw},
{acl_topic, topic}
]}
]}
].

View File

@ -1,23 +0,0 @@
[
{emysql, [
{pool, 4},
{host, "59.188.253.198"},
{port, 3306},
{username, "root"},
{password, "lhroot."},
{database, "musicfield"},
{encoding, utf8}
]},
{emqttd_plugin_mysql, [
{users_table, auth_user},
{acls_table, auth_acl},
{field_mapper, [
{username, username},
{password, password, pbkdf2},
{user_super, is_super_user},
{acl_username, username},
{acl_rw, rw},
{acl_topic, topic}
]}
]}
].

View File

@ -1,112 +0,0 @@
%%------------------------------------------------------------------------------
%% Copyright (c) 2012-2015, Feng Lee <feng@emqtt.io>
%%
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%%
%% The above copyright notice and this permission notice shall be included in all
%% copies or substantial portions of the Software.
%%
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%% SOFTWARE.
%%------------------------------------------------------------------------------
%%% @doc
%%% MQTT Broker Header.
%%%
%%% @end
%%%-----------------------------------------------------------------------------
%%------------------------------------------------------------------------------
%% Banner
%%------------------------------------------------------------------------------
-define(COPYRIGHT, "Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>").
-define(LICENSE_MESSAGE, "Licensed under MIT").
-define(PROTOCOL_VERSION, "MQTT/3.1.1").
-define(ERTS_MINIMUM, "6.0").
%%------------------------------------------------------------------------------
%% PubSub
%%------------------------------------------------------------------------------
-type pubsub() :: publish | subscribe.
%%------------------------------------------------------------------------------
%% MQTT Topic
%%------------------------------------------------------------------------------
-record(mqtt_topic, {
topic :: binary(),
node :: node()
}).
-type mqtt_topic() :: #mqtt_topic{}.
%%------------------------------------------------------------------------------
%% MQTT Subscriber
%%------------------------------------------------------------------------------
-record(mqtt_subscriber, {
topic :: binary(),
qos = 0 :: 0 | 1 | 2,
pid :: pid()
}).
-type mqtt_subscriber() :: #mqtt_subscriber{}.
%%------------------------------------------------------------------------------
%% P2P Queue Subscriber
%%------------------------------------------------------------------------------
-record(mqtt_queue, {
name :: binary(),
subpid :: pid(),
qos = 0 :: 0 | 1 | 2
}).
-type mqtt_queue() :: #mqtt_queue{}.
%%------------------------------------------------------------------------------
%% MQTT Client
%%------------------------------------------------------------------------------
-record(mqtt_client, {
clientid :: binary(),
username :: binary() | undefined,
ipaddr :: inet:ip_address()
}).
-type mqtt_client() :: #mqtt_client{}.
%%------------------------------------------------------------------------------
%% MQTT Session
%%------------------------------------------------------------------------------
-record(mqtt_session, {
clientid,
session_pid,
subscriptions = [],
awaiting_ack,
awaiting_rel
}).
-type mqtt_session() :: #mqtt_session{}.
%%------------------------------------------------------------------------------
%% MQTT Plugin
%%------------------------------------------------------------------------------
-record(mqtt_plugin, {
name,
version,
attrs,
description
}).
-type mqtt_plugin() :: #mqtt_plugin{}.

Binary file not shown.

View File

@ -1,32 +0,0 @@
{port_specs, [
{"priv/emqttd_plugin_mysql_app.so", [
"c_src/*.c"
]}
]}.
{port_env, [
{".*", "CXXFLAGS", "$CXXFLAGS -g -Wall -Werror -O3"},
{"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin)",
"LDFLAGS", "$LDFLAGS -lstdc++ -lcrypto"},
%% OS X Leopard flags for 64-bit
{"darwin9.*-64$", "CXXFLAGS", "-m64"},
{"darwin9.*-64$", "LDFLAGS", "-arch x86_64"},
%% OS X Snow Leopard flags for 32-bit
{"darwin10.*-32$", "CXXFLAGS", "-m32"},
{"darwin10.*-32$", "LDFLAGS", "-arch i386"},
%% This will merge into basho/rebar/rebar.config eventually
{"win32", "CFLAGS", "/Wall /DWIN32 /D_WINDOWS /D_WIN32 /DWINDOWS"},
{"win32", "CXXFLAGS", "-g -Wall -O3"}
]}.
{eunit_opts, [
verbose,
{report, {
eunit_surefire, [{dir,"."}]
}}
]}.

View File

@ -1,70 +0,0 @@
%%%-----------------------------------------------------------------------------
%%% @Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in all
%%% copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd demo acl module.
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_acl_mysql).
-include("emqttd.hrl").
-behaviour(emqttd_acl_mod).
%% ACL callbacks
-export([init/1, check_acl/2, reload_acl/1, description/0]).
-record(state, {user_table, acl_table, acl_username_field, acl_topic_field, acl_rw_field, user_name_field, user_super_field}).
init(Opts) ->
Mapper = proplists:get_value(field_mapper, Opts),
State =
#state{
user_table = proplists:get_value(users_table, Opts, auth_user),
user_super_field = proplists:get_value(is_super, Mapper, is_superuser),
user_name_field = proplists:get_value(username, Mapper, username),
acl_table = proplists:get_value(acls_table, Opts, auth_acl),
acl_username_field = proplists:get_value(acl_username, Mapper, username),
acl_rw_field = proplists:get_value(acl_rw, Mapper, rw),
acl_topic_field = proplists:get_value(acl_topic, Mapper, topic)
},
{ok, State}.
check_acl({#mqtt_client{username = Username}, PubSub, Topic}, #state{user_table = UserTab, acl_table = AclTab, user_name_field = UsernameField, user_super_field = SuperField, acl_topic_field = TopicField, acl_username_field = AclUserField, acl_rw_field = AclRwField}) ->
Flag = case PubSub of publish -> 2; subscribe -> 1; pubsub -> 2 end,
Where = {'and', {'>=', AclRwField, Flag}, {TopicField, Topic}},
Where1 = {'or', {AclUserField, Username}, {AclUserField, "*"}},
Where2 = {'and', Where, Where1},
case emysql:select(UserTab, {'and', {UsernameField, Username}, {SuperField, 1}}) of
{ok, []} ->
case emysql:select(UserTab, {UsernameField, Username}) of
{ok, []} -> ignore;
{ok, _} -> case emysql:select(AclTab, Where2) of
{ok, []} -> deny;
{ok, _Record} -> allow
end
end;
{ok, _} -> allow
end.
reload_acl(_State) -> ok.
description() -> "ACL Module by Mysql".

View File

@ -1,110 +0,0 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in all
%%% copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd authentication by mysql 'user' table.
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_auth_mysql).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-behaviour(emqttd_auth_mod).
-export([init/1, check/3, description/0]).
-define(NOT_LOADED, not_loaded(?LINE)).
-record(state, {user_table, name_field, pass_field, pass_hash}).
init(Opts) ->
Mapper = proplists:get_value(field_mapper, Opts),
{ok, #state{user_table = proplists:get_value(user_table, Opts, auth_user),
name_field = proplists:get_value(username, Mapper),
pass_field = proplists:get_value(password, Mapper),
pass_hash = proplists:get_value(Opts, password_hash)}}.
check(#mqtt_client{username = undefined}, _Password, _State) ->
{error, "Username undefined"};
check(_Client, undefined, _State) ->
{error, "Password undefined"};
check(#mqtt_client{username = Username}, Password,
#state{user_table = UserTab, pass_hash = Type,
name_field = NameField, pass_field = PassField}) ->
Where = {'and', {NameField, Username}, {PassField, hash(Type, Password)}},
if Type =:= pbkdf2 ->
case emysql:select(UserTab, [PassField], {NameField, Username}) of
{ok, []} -> {error, "User not exist"};
{ok, Records} ->
if length(Records) =:= 1 ->
case pbkdf2_check(Password, lists:nth(Records, 1)) of
true ->
{ok, []};
false ->
{error, "UserName or Password is invalid"};
ErrorInfo ->
{error, ErrorInfo}
end;
true ->
{error, "UserName is ambiguous"}
end
end;
true ->
case emysql:select(UserTab, Where) of
{ok, []} -> {error, "Username or Password "};
{ok, _Record} -> ok
end
end.
description() -> "Authentication by MySQL".
hash(plain, Password) ->
Password;
hash(md5, Password) ->
hexstring(crypto:hash(md5, Password));
hash(sha, Password) ->
hexstring(crypto:hash(sha, Password)).
hexstring(<<X:128/big-unsigned-integer>>) ->
lists:flatten(io_lib:format("~32.16.0b", [X]));
hexstring(<<X:160/big-unsigned-integer>>) ->
lists:flatten(io_lib:format("~40.16.0b", [X])).
not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
pbkdf2_check(Password, Pbkstr) ->
case nif_pbkdf2_check(Password, Pbkstr) of
{error, _} = Error ->
throw(Error);
IOData ->
IOData
end.
nif_pbkdf2_check(Password, Pbkstr) ->
?NOT_LOADED.

View File

@ -1,12 +0,0 @@
{application, emqttd_plugin_mysql,
[
{description, "emqttd MySQL Authentication Plugin"},
{vsn, "1.0"},
{registered, []},
{applications, [
kernel,
stdlib
]},
{mod, {emqttd_plugin_mysql_app, []}},
{env, []}
]}.

View File

@ -1,80 +0,0 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in all
%%% copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd mysql authentication app.
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_plugin_mysql_app).
-on_load(init/0).
-behaviour(application).
%% Application callbacks
-export([start/2, prep_stop/1, stop/1, nif_pbkdf2_check/2]).
-behaviour(supervisor).
%% Supervisor callbacks
-export([init/1]).
-define(NOT_LOADED, not_loaded(?LINE)).
%%%=============================================================================
%%% Application callbacks
%%%=============================================================================
start(_StartType, _StartArgs) ->
Env = application:get_all_env(),
emqttd_access_control:register_mod(auth, emqttd_auth_mysql, Env),
emqttd_access_control:register_mod(acl, emqttd_acl_mysql, Env),
crypto:start(),
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
prep_stop(State) ->
emqttd_access_control:unregister_mod(auth, emqttd_auth_mysql), State,
emqttd_access_control:unregister_mod(acl, emqttd_acl_mysql), State,
crypto:stop().
stop(_State) ->
ok.
init() ->
PrivDir = case code:priv_dir(?MODULE) of
{error, _} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path ->
Path
end,
erlang:load_nif(filename:join(PrivDir, "emqttd_plugin_mysql_app"), 0).
%%%=============================================================================
%%% Supervisor callbacks(Dummy)
%%%=============================================================================
init([]) ->
{ok, {{one_for_one, 5, 10}, []}}.
not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
nif_pbkdf2_check(Password, Hash) ->
?NOT_LOADED.