[rabbitmq-discuss] Creating an auth plugin (Kerberos)

Tim Watson tim at rabbitmq.com
Wed Dec 5 15:04:42 GMT 2012


Personally, I think you should do this another way. Write a Native Implemented Function (NIF) in C and wrap it up as an Erlang module. Then you can just call the NIF directly from your auth module. You don't have to do all this spawning and looping and exit handling and insulating. It's *much* easier.

Having said that, I can't help you with writing a NIF at the moment as we're all quite busy getting 3.0.1 ready. I'd suggest going over to the erlang-questions mailing list and saying "I want to do kerberos authentication using a NIF - can somebody point me in the right direction...". Honestly it's much simpler than all this open_port malarky, especially if you're comfortable writing C, which you do seem to be. The erlang part of it is minimal, and the rabbit auth module you've written just calls the NIF stub functions as though they were regular erlang functions. No processes, no message handling: simple.


On 5 Dec 2012, at 14:48, Tim Watson wrote:

> Simon,
> This is why I suggested using an insulator process. The process that calls open_port is the controlling process and when the port is closed, it will send the controlling process and exit signal. You override that by passing exit_status, but you also supply 'eof' and the ordering between the eof and exit_status messages is not guaranteed. When you time out in the after clause, you have *no idea* whether or not the port program is still running, which could lead to any of
> - leaking resources such as file descriptors used for the port
> - erroneous messages sent to the reader process (such as the 'EXIT' that is arriving when you call port_close)
> I would strongly suggest considering an insulator process for this. Do you need some pointers to doing that? Let me cook something up for you.....
> In this code, notice that the command I'm running is guaranteed to finish within the 2000 ms timeout. I don't care about that, because it is only the exit status that matters to me. If you need to examine the stdio, then that's another matter but you aren't currently doing that. 
> Now if you change the command to something that will run for a *long* time such as `ls -laR /` it will *not* finish quickly enough and yes all is still well and there are no stray messages. BUT ..... that command `ls -laR /` will not respond to stdin and will therefore *continue running even AFTER the port is closed* - so you need to be very careful to ensure that your program will actually terminate. I use hack to enforce this sometimes:
> Cmd = "/usr/bin/env sh -c \"(cat; kill 0) | " ++ Exec ++ " \""
> Anyway, here is the module. Note that lots of the wait_for_this and that is just to demonstrate what's going on. Hope this helps.
> <code>
> -module(foo).
> -export([main/1]).
> main(_) ->
>    Result = run_insulator(),
>    io:format("Result = ~p~n", [Result]),
>    wait_for_stray_messages().
> wait_for_stray_messages() ->
>    receive
>        Any -> io:format("got stray message ~p~n", [Any]),
>               wait_for_stray_messages()
>    after 5000 ->
>        io:format("we're done - no stray messages/EXIT's and we're good to go...~n")
>    end.
> run_insulator() ->
>    {Pid, MRef} = spawn_monitor(fun insulated/0),
>    receive
>        {'DOWN', MRef, process, Pid, Reason} ->
>            case Reason of
>                {done, Result} -> Result;
>                Other          -> {error, Other}
>            end
>    after 2000 ->
>        %% get rid of any pending monitor notifications
>        erlang:demonitor(MRef, [flush]),
>        exit(Pid, shutdown),
>        false
>    end.
> insulated() ->
>    process_flag(trap_exit, true),
>    Port = open_port({spawn, "ls -la"}, [
>                     exit_status, use_stdio, eof,
>                     {line, 1024}]),
>    Result = loop(Port),
>    erlang:port_close(Port),
>    exit({done, Result}).
> loop(Port) ->
>    Self = self(),
>    receive
>        %% we do not appear to care about the stdio
>        {Port, {data, {_, _}}}    -> loop(Port);
>        {Port, eof}               -> loop(Port);
>        {Port, {exit_status, 0}}  -> true;
>        {Port, {exit_status, _N}} -> false;
>        {'EXIT', Self, shutdown}  -> false
>    end.
> </code>
> Cheers,
> Tim
> _______________________________________________
> rabbitmq-discuss mailing list
> rabbitmq-discuss at lists.rabbitmq.com
> https://lists.rabbitmq.com/cgi-bin/mailman/listinfo/rabbitmq-discuss

More information about the rabbitmq-discuss mailing list