Current section
Files
Jump to
Current section
Files
src/sasl_auth.erl
%% @doc
%% Wrapper for cyrus sasl library for GSSAPI mechanism support in erlang applications. Each function (except kinit) corresponds to
%% functions at libsasl2
%% @end
-module(sasl_auth).
%% API
-export([
init/0,
kinit/2,
client_new/3,
client_listmech/1,
client_start/1,
client_step/2
]).
-on_load(init/0).
-define(SASL_CODES, #{
0 => sasl_ok,
1 => sasl_continue,
2 => sasl_interact,
-1 => sasl_fail,
-2 => sasl_nomem,
-3 => sasl_bufover,
-4 => sass_nomech,
-5 => sasl_badprot,
-6 => sasl_notdone,
-7 => sasl_badparam,
-8 => sasl_tryagain,
-9 => sasl_badmac,
-10 => sasl_badserv,
-11 => sasl_wrongmech,
-12 => sasl_notinit,
-13 => sasl_badauth,
-14 => sasl_noauthz,
-15 => sasl_tooweak,
-16 => sasl_encrypt,
-17 => sasl_trans,
-18 => sasl_expired,
-19 => sasl_disabled,
-20 => sasl_nouser,
-21 => sasl_pwlock,
-22 => sasl_nochange,
-23 => sasl_badvers,
-24 => sasl_unavail,
-26 => sasl_noverify,
-27 => sasl_weakpass,
-28 => sasl_nouserpass,
-29 => sasl_need_old_passwd,
-30 => sasl_constraint_violat,
-32 => sasl_badbinding,
-100 => sasl_configerr
}).
-type state() :: reference().
-type keytab_path() :: file:filename_all().
-type principal() :: binary().
-type service_name() :: binary().
-type host() :: binary().
-type available_mechs() :: [binary()].
-type sasl_code() ::
sasl_badserv
| sasl_noverify
| sasl_weakpass
| sasl_badauth
| sasl_tooweak
| sasl_nomem
| sasl_need_old_passwd
| sasl_badprot
| sasl_expired
| sasl_nouser
| sasl_badbinding
| sasl_badvers
| sasl_configerr
| sasl_noauthz
| sasl_ok
| sasl_nouserpass
| sasl_notdone
| sasl_notinit
| sasl_trans
| sasl_interact
| sasl_bufover
| sasl_pwlock
| sasl_constraint_violat
| sasl_continue
| sasl_fail
| sasl_encrypt
| sasl_badparam
| sasl_badmac
| sasl_tryagain
| sasl_unavail
| sasl_wrongmech
| sasl_nochange
| sasl_disabled
| sass_nomech
| unknown.
-spec init() ->
ok | {error, {load_failed | bad_lib | load | reload | upgrade | old_code, Text :: string()}}.
init() ->
NifLib =
case code:priv_dir(sasl_auth) of
{error, bad_name} ->
case code:which(?MODULE) of
Filename when is_list(Filename) ->
filename:join([filename:dirname(Filename), "../priv", "sasl_auth"]);
_ ->
filename:join("../priv", "sasl_auth")
end;
Dir ->
filename:join(Dir, "sasl_auth")
end,
erlang:load_nif(NifLib, 0).
-spec kinit(KeyTabPath :: keytab_path(), Principal :: principal()) ->
ok | {error, {binary(), integer(), binary()}}.
kinit(KeyTabPath, Principal) ->
sasl_kinit(null_terminate(KeyTabPath), null_terminate(Principal)).
-spec client_new(ServiceName :: service_name(), Host :: host(), Principal :: principal()) ->
{ok, state()}
| {error, sasl_code()}.
client_new(ServiceName, Host, Principal) ->
ServiceName0 = null_terminate(ServiceName),
Host0 = null_terminate(Host),
Principal0 = null_terminate(Principal),
case sasl_client_new(ServiceName0, Host0, Principal0) of
{ok, _} = Ret ->
Ret;
{error, Code} ->
{error, code_to_atom(Code)}
end.
-spec client_listmech(State :: state()) ->
{ok, available_mechs()} | {error, {sasl_code(), binary()}}.
client_listmech(State) ->
case sasl_listmech(State) of
{ok, Mechs} ->
{ok, binary:split(Mechs, <<" ">>, [global])};
{error, {Code, Detail}} ->
{error, {code_to_atom(Code), strip_null_terminate(Detail)}}
end.
-spec client_start(State :: state()) ->
{ok, {sasl_code(), binary()}} | {error, {sasl_code(), binary()}}.
client_start(State) ->
case sasl_client_start(State) of
{ok, {Code, Token}} ->
{ok, {code_to_atom(Code), Token}};
{error, {Code, Detail}} ->
{error, {code_to_atom(Code), strip_null_terminate(Detail)}}
end.
-spec client_step(state(), binary()) ->
{ok, {sasl_code(), binary()}} | {error, {sasl_code(), binary()}}.
client_step(State, Token) ->
case sasl_client_step(State, Token) of
{ok, {Code, MaybeNewToken}} ->
{ok, {code_to_atom(Code), MaybeNewToken}};
{error, {Code, Detail}} ->
{error, {code_to_atom(Code), strip_null_terminate(Detail)}}
end.
code_to_atom(Code) ->
maps:get(Code, ?SASL_CODES, unknown).
null_terminate(Bin) ->
iolist_to_binary([Bin, 0]).
strip_null_terminate(Bin) ->
case binary:split(Bin, <<0>>) of
[X, _] ->
X;
[X] ->
X
end.
sasl_kinit(_, _) -> not_loaded(?LINE).
sasl_client_new(_Service, _Host, _Principal) -> not_loaded(?LINE).
sasl_listmech(_State) -> not_loaded(?LINE).
sasl_client_start(_State) -> not_loaded(?LINE).
sasl_client_step(_State, _Token) -> not_loaded(?LINE).
not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).