Skip to content

Commit

Permalink
NIF for Unix crypt
Browse files Browse the repository at this point in the history
  • Loading branch information
msantos committed Jan 14, 2010
0 parents commit b9247fa
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Emakefile
@@ -0,0 +1,6 @@
{["src/*"],
[{i, "include"},
{outdir, "ebin"},
debug_info]
}.

36 changes: 36 additions & 0 deletions Makefile
@@ -0,0 +1,36 @@

ERL=erl
APP=crypt

CC=gcc

#Mac OS X: use "-m64" for a 64-bit erlang
#ARCH=-m32
#FLAGS=$(ARCH) -O3 -fPIC -bundle -flat_namespace -undefined suppress -fno-common -lcrypt

# Linux
FLAGS=-fPIC -shared -lcrypt

#ERL_ROOT=/usr/local/lib/erlang
ERL_ROOT=/media/opt/local/lib/erlang
CFLAGS=-g -Wall


all: dir erl nif

dir:
-@mkdir -p priv ebin

erl:
@$(ERL) -noinput +B \
-eval 'case make:all() of up_to_date -> halt(0); error -> halt(1) end.'

nif:
(cd c_src && \
$(CC) -g -Wall $(FLAGS) -o ../priv/$(APP).so \
$(APP).c -I $(ERL_ROOT)/usr/include/ )

clean:
@rm -fv ebin/*.beam priv/$(APP).so c_src/*.a c_src/*.o


25 changes: 25 additions & 0 deletions README
@@ -0,0 +1,25 @@

Erlang R13B03 (erts-5.7.4) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.4 (abort with ^G)
1> crypt:crypt("test","aa").
"aaqPiZY5xR5l."
2> crypt:crypt("test","$1$aaaaaaaa").
"$1$aaaaaaaa$lWxWtPmiNjS/cwJnGm6fe0"
3> crypt:crypt("test","$6$aaaaaaaa").
"$6$aaaaaaaa$HREHv6TuSmUS/7spCDO5Js3ssSZ6.iwVkUoVtatJUhJDKVmERrRKBTolrPMub2s5dX6IEjZg6d6wZzFRlidV41"
4>


TODO

1. What is the maximum password and salt length?

There doesn't appear to be a limit. DES has an 8 character limit and
MD5 has a 255 character limit, but for the other types, no idea.

sysconf(_SC_PASS_MAX) seems to return the limit on Solaris, but isn't
available on Ubuntu.

2. Provide an erlang version of the crypt() interface.

140 changes: 140 additions & 0 deletions c_src/crypt.c
@@ -0,0 +1,140 @@
/* Copyright (c) 2010, Michael Santos <michael.santos@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:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the author 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 HOLDER 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 "erl_nif.h"
#include "crypt.h"

static int my_enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char *buf, size_t buflen);
static ERL_NIF_TERM error_message(ErlNifEnv *env, char *atom, char *err, char *msg);


static int
load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
{
return (0);
}


static int
reload(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
{
return load(env, priv, load_info);
}


static ERL_NIF_TERM
nif_crypt(ErlNifEnv *env, ERL_NIF_TERM _key, ERL_NIF_TERM _salt)
{
char key[MAXBUFLEN];
char salt[MAXBUFLEN];
char *result = NULL;
int rerrno = 0;

(void)memset(&key, '\0', sizeof(key));
(void)memset(&salt, '\0', sizeof(salt));

if (!my_enif_get_string(env, _key, key, sizeof(key)))
return enif_make_badarg(env);

if (!my_enif_get_string(env, _salt, salt, sizeof(salt)))
return enif_make_badarg(env);

errno = 0;
result = crypt(key, salt);
rerrno = errno;

(void)memset(&key, '\0', sizeof(key));
(void)memset(&salt, '\0', sizeof(salt));

if (result == NULL)
return error_message(env, "error", "crypt", strerror(rerrno));

return enif_make_string(env, result);
}


static ERL_NIF_TERM
error_message(ErlNifEnv *env, char *atom, char *err, char *msg)
{
return enif_make_tuple(env, 2,
enif_make_atom(env, atom),
enif_make_tuple(env, 2,
enif_make_atom(env, err),
enif_make_string(env, msg)));
}


/* from:
* http://d.hatena.ne.jp/vostok92/20091201/1259680319
*
* Copies at most one less than buflen from buf and null
* terminates the string.
*
* Should probably indicate that a truncation has taken place, but
* the convention of the enif_get_* interfaces seems to be to return
* true/false.
*
* The alternative is to return failure if a string is too large
* for the buffer. This seems to allow for more predictable
* behaviour.
*
*/
static int
my_enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char *buf, size_t buflen)
{
ERL_NIF_TERM head, tail;
int val;
int n = 1;


while (enif_get_list_cell(env, list, &head, &tail)) {
if (!enif_get_int(env, head, &val))
return (0);

if (n++ >= buflen)
return (0);

*buf = (char)val;
buf++;
list = tail;
}
*buf = '\0';

return (1);
}

static ErlNifFunc nif_funcs[] = {
{"crypt", 2, nif_crypt}
};

ERL_NIF_INIT(crypt, nif_funcs, load, reload, NULL, NULL)


48 changes: 48 additions & 0 deletions c_src/crypt.h
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2010, Michael Santos <michael.santos@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:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the author 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 HOLDER 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.
*/
#define _XOPEN_SOURCE
#define __USE_XOPEN

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>

#include <sys/errno.h>


#define CRYPT_VERSION "0.01"
#define MAXBUFLEN 1024 /* XXX appropriate maximum values for passwd length and salt? */


45 changes: 45 additions & 0 deletions src/crypt.erl
@@ -0,0 +1,45 @@
%% Copyright (c) 2010, Michael Santos <michael.santos@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:
%%
%% Redistributions of source code must retain the above copyright
%% notice, this list of conditions and the following disclaimer.
%%
%% 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.
%%
%% Neither the name of the author 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 HOLDER 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.
-module(crypt).

-export([crypt/2]).

-define(NIF, "priv/crypt").

-on_load(on_load/0).

on_load() ->
ok = erlang:load_nif(?NIF, []),
true.

crypt(_,_) ->
erlang:error(not_implemented).

0 comments on commit b9247fa

Please sign in to comment.