ocamlpam-1.1/0000755000000000000000000000000011025047056011642 5ustar rootrootocamlpam-1.1/COPYING0000644000000000000000000000204411025047056012675 0ustar rootrootCopyright (c) 2008 Sharvil Nanavati 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. ocamlpam-1.1/pam_stubs.h0000644000000000000000000000214511025047056014012 0ustar rootroot/* Copyright (c) 2008 Sharvil Nanavati */ #ifndef PAM_STUBS_H #define PAM_STUBS_H typedef enum pam_error_tag { Pam_Abort, Pam_Session_Err, Pam_Authtok_Err, Pam_Authtok_Recover_Err, Pam_Authtok_Lock_Busy, Pam_Authtok_Disable_Aging, Pam_Try_Again, Pam_Acct_Expired, Pam_New_Authtok_Reqd, Pam_Perm_Denied, Pam_Cred_Err, Pam_Cred_Expired, Pam_Cred_Unavail, Pam_Auth_Err, Pam_Cred_Insufficient, Pam_Authinfo_Unavail, Pam_Maxtries, Pam_User_Unknown, Pam_Buf_Err, Pam_System_Err, Pam_Bad_Item } pam_error; enum { Pam_Prompt_Echo_Off, Pam_Prompt_Echo_On, Pam_Error_Msg, Pam_Text_Info }; enum { Pam_Disallow_Null_Authtok }; enum { Pam_Establish_Cred, Pam_Delete_Cred, Pam_Reinitialize_Cred, Pam_Refresh_Cred }; enum { Pam_Change_Expired_Authtok }; enum { Pam_Service, Pam_User, Pam_User_Prompt, Pam_Tty, Pam_RUser, Pam_RHost, Pam_AuthTok, Pam_OldAuthTok, Pam_Conv, Pam_Fail_Delay }; typedef struct caml_pam_handle_tag { pam_handle_t * handle; value callback; value fail_delay; int error_code; } caml_pam_handle; #define Handle_val(v) (caml_pam_handle *)Data_custom_val(v) #endif ocamlpam-1.1/pam.mli0000644000000000000000000000617011025047056013126 0ustar rootroot(* Copyright (c) 2008 Sharvil Nanavati *) type pam_error = | Pam_Abort (* 0 *) | Pam_Session_Err | Pam_Authtok_Err | Pam_Authtok_Recover_Err | Pam_Authtok_Lock_Busy | Pam_Authtok_Disable_Aging (* 5 *) | Pam_Try_Again | Pam_Acct_Expired | Pam_New_Authtok_Reqd | Pam_Perm_Denied | Pam_Cred_Err (* 10 *) | Pam_Cred_Expired | Pam_Cred_Unavail | Pam_Auth_Err | Pam_Cred_Insufficient | Pam_Authinfo_Unavail (* 15 *) | Pam_Maxtries | Pam_User_Unknown | Pam_Buf_Err | Pam_System_Err | Pam_Bad_Item;; (* 20 *) exception Pam_Error of pam_error;; type pam_handle;; type pam_conv_type = | Pam_Prompt_Echo_Off | Pam_Prompt_Echo_On | Pam_Error_Msg | Pam_Text_Info;; type pam_conv = pam_conv_type -> string -> string;; type pam_auth_flags = Pam_Disallow_Null_Authtok;; type pam_fail_delay = int -> int -> unit;; type pam_credentials = | Pam_Establish_Cred | Pam_Delete_Cred | Pam_Reinitialize_Cred | Pam_Refresh_Cred;; type pam_token_flags = Pam_Change_Expired_Authtok;; type pam_item = | Pam_Service of string | Pam_User of string | Pam_User_Prompt of string | Pam_Tty of string | Pam_RUser of string | Pam_RHost of string | Pam_AuthTok of string | Pam_OldAuthTok of string | Pam_Conv of pam_conv | Pam_Fail_Delay of pam_fail_delay;; val pam_item_service : pam_item;; val pam_item_user : pam_item;; val pam_item_user_prompt : pam_item;; val pam_item_tty : pam_item;; val pam_item_ruser : pam_item;; val pam_item_rhost : pam_item;; val pam_item_authtok : pam_item;; val pam_item_oldauthtok : pam_item;; val pam_item_conv : pam_item;; val pam_item_fail_delay : pam_item;; type pam_functions = { pam_end : unit -> bool; pam_set_item : pam_item -> unit; pam_get_item : pam_item -> pam_item; pam_fail_delay : int -> unit; pam_authenticate : pam_auth_flags list -> ?silent:bool -> unit; pam_setcred : pam_credentials -> ?silent:bool -> unit; pam_acct_mgmt : pam_auth_flags list -> ?silent:bool -> unit; pam_chauthtok : pam_token_flags list -> ?silent:bool -> unit; pam_open_session : ?silent:bool -> unit -> unit; pam_close_session : ?silent:bool -> unit -> unit; pam_putenv : string -> unit; pam_getenv : string -> string option; pam_getenvlist : unit -> string list };; val pam_start_ex : string -> ?user:string -> pam_conv -> pam_functions;; val pam_start : string -> ?user:string -> pam_conv -> pam_handle;; val pam_end : pam_handle -> bool;; val pam_set_item : pam_handle -> pam_item -> unit;; val pam_get_item : pam_handle -> pam_item -> pam_item;; val pam_fail_delay : pam_handle -> int -> unit;; val pam_authenticate : pam_handle -> pam_auth_flags list -> ?silent:bool -> unit;; val pam_setcred : pam_handle -> pam_credentials -> ?silent:bool -> unit;; val pam_acct_mgmt : pam_handle -> pam_auth_flags list -> ?silent:bool -> unit;; val pam_chauthtok : pam_handle -> pam_token_flags list -> ?silent:bool -> unit;; val pam_open_session : pam_handle -> ?silent:bool -> unit;; val pam_close_session : pam_handle -> ?silent:bool -> unit;; val pam_putenv : pam_handle -> string -> unit;; val pam_getenv : pam_handle -> string -> string option;; val pam_getenvlist : pam_handle -> string list;; ocamlpam-1.1/pam_stubs.c0000644000000000000000000003400611025047056014006 0ustar rootroot/* Copyright (c) 2008 Sharvil Nanavati */ #include #include #include #include #include #include #include #include #include #include "pam_stubs.h" static void raise(pam_error exception) Noreturn; static void finalizer(value v); static struct custom_operations caml_pam_operations = { "net.nanavati.sharvil.pam.operations", finalizer, custom_compare_default, custom_hash_default, custom_serialize_default, custom_deserialize_default }; static void raise(pam_error exception) { static value * e = 0; if(e == 0) e = caml_named_value("net.nanavati.sharvil.pam.error"); caml_raise_with_arg(*e, Val_int(exception)); } static void finalizer(value v) { caml_pam_handle * h = Handle_val(v); if(h->handle != 0) pam_end(h->handle, h->error_code); if(h->callback != Val_int(0)) caml_remove_global_root(&h->callback); if(h->fail_delay != Val_int(0)) caml_remove_global_root(&h->fail_delay); } static int converse(int nMsg, const struct pam_message ** messages, struct pam_response ** responses, void * data) { int i; struct pam_response * local_responses; caml_pam_handle * h; CAMLlocal1(ret); h = (caml_pam_handle *)data; local_responses = (struct pam_response *)calloc(nMsg, sizeof(struct pam_response)); if(local_responses == 0) { free(local_responses); return PAM_BUF_ERR; } for(i = 0; i < nMsg; ++i) switch(messages[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: { ret = caml_callback2(h->callback, Val_int(Pam_Prompt_Echo_Off), caml_copy_string(messages[i]->msg)); local_responses[i].resp = strdup(String_val(ret)); break; } case PAM_PROMPT_ECHO_ON: { ret = caml_callback2(h->callback, Val_int(Pam_Prompt_Echo_On), caml_copy_string(messages[i]->msg)); local_responses[i].resp = strdup(String_val(ret)); break; } case PAM_ERROR_MSG: { caml_callback2(h->callback, Val_int(Pam_Error_Msg), caml_copy_string(messages[i]->msg)); break; } case PAM_TEXT_INFO: { caml_callback2(h->callback, Val_int(Pam_Text_Info), caml_copy_string(messages[i]->msg)); break; } default: { for(i = 0; i < nMsg; ++i) if(local_responses[i].resp != 0) free(local_responses[i].resp); free(local_responses); return PAM_CONV_ERR; } } *responses = local_responses; return PAM_SUCCESS; } static void fail_delay(int retval, unsigned usec_delay, void * data) { caml_pam_handle * h = (caml_pam_handle *)data; if(h->fail_delay == Val_int(0)) return; caml_callback2(h->fail_delay, Val_int(retval), Val_int(usec_delay)); } CAMLprim value pam_start_stub(value serviceName, value user, value conversation) { CAMLparam3 (serviceName, user, conversation); CAMLlocal1(ret); struct pam_conv conv; const char * user_str = 0; caml_pam_handle * h; ret = caml_alloc_custom(&caml_pam_operations, sizeof(caml_pam_handle), 1, 100); h = Handle_val(ret); caml_register_global_root(&h->callback); h->callback = conversation; caml_register_global_root(&h->fail_delay); h->fail_delay = Val_int(0); conv.conv = converse; conv.appdata_ptr = h; if(Is_block(user)) user_str = String_val(Field(user, 0)); h->error_code = pam_start(String_val(serviceName), user_str, &conv, &h->handle); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_ABORT: raise(Pam_Abort); case PAM_BUF_ERR: raise(Pam_Buf_Err); case PAM_SYSTEM_ERR: raise(Pam_System_Err); default: caml_failwith("Unknown PAM error"); } CAMLreturn(ret); } CAMLprim value pam_end_stub(value handle) { CAMLparam1(handle); CAMLlocal1(ret); caml_pam_handle * h = Handle_val(handle); ret = Val_true; if(h->handle != 0) { h->error_code = pam_end(h->handle, h->error_code); if(h->error_code != PAM_SUCCESS) ret = Val_false; } if(h->callback != Val_int(0)) caml_remove_global_root(&h->callback); if(h->fail_delay != Val_int(0)) caml_remove_global_root(&h->fail_delay); h->handle = 0; h->callback = Val_int(0); h->fail_delay = Val_int(0); CAMLreturn(ret); } CAMLprim value pam_remove_fail_delay(value handle) { CAMLparam1(handle); caml_pam_handle * h = Handle_val(handle); h->error_code = pam_set_item(h->handle, PAM_FAIL_DELAY, 0); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_BAD_ITEM: raise(Pam_Bad_Item); case PAM_BUF_ERR: raise(Pam_Buf_Err); case PAM_SYSTEM_ERR: raise(Pam_System_Err); default: caml_failwith("Unknown PAM error"); } h->fail_delay = Val_int(0); CAMLreturn(Val_unit); } CAMLprim value pam_set_item_stub(value handle, value item) { int type; CAMLparam2(handle, item); caml_pam_handle * h = Handle_val(handle); switch(Tag_val(item)) { case Pam_Service: type = PAM_SERVICE; break; case Pam_User: type = PAM_USER; break; case Pam_User_Prompt: type = PAM_USER_PROMPT; break; case Pam_Tty: type = PAM_TTY; break; case Pam_RUser: type = PAM_RUSER; break; case Pam_RHost: type = PAM_RHOST; break; case Pam_AuthTok: type = PAM_AUTHTOK; break; case Pam_OldAuthTok: type = PAM_OLDAUTHTOK; break; case Pam_Conv: type = PAM_CONV; break; case Pam_Fail_Delay: type = PAM_FAIL_DELAY; break; default: raise(Pam_Bad_Item); } if(type == PAM_CONV) { h->callback = Field(item, 0); CAMLreturn(Val_unit); } if(type == PAM_FAIL_DELAY) { h->fail_delay = Field(item, 0); h->error_code = pam_set_item(h->handle, type, fail_delay); } else h->error_code = pam_set_item(h->handle, type, String_val(Field(item, 0))); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_BAD_ITEM: raise(Pam_Bad_Item); case PAM_BUF_ERR: raise(Pam_Buf_Err); case PAM_SYSTEM_ERR: raise(Pam_System_Err); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_get_item_stub(value handle, value item) { int type; const char * val; CAMLparam2(handle, item); CAMLlocal1(ret); caml_pam_handle * h = Handle_val(handle); switch(Tag_val(item)) { case Pam_Service: type = PAM_SERVICE; break; case Pam_User: type = PAM_USER; break; case Pam_User_Prompt: type = PAM_USER_PROMPT; break; case Pam_Tty: type = PAM_TTY; break; case Pam_RUser: type = PAM_RUSER; break; case Pam_RHost: type = PAM_RHOST; break; case Pam_AuthTok: type = PAM_AUTHTOK; break; case Pam_OldAuthTok: type = PAM_OLDAUTHTOK; break; case Pam_Conv: type = PAM_CONV; break; case Pam_Fail_Delay: type = PAM_FAIL_DELAY; break; default: raise(Pam_Bad_Item); } /* Special-case PAM_CONV since we're storing the closure internally. */ if(type == PAM_CONV) { ret = caml_alloc(1, Tag_val(item)); Store_field(ret, 0, h->callback); CAMLreturn(ret); } if(type == PAM_FAIL_DELAY) { ret = caml_alloc(1, Tag_val(item)); Store_field(ret, 0, (h->fail_delay == Val_int(0)) ? Field(item, 1) : h->fail_delay); CAMLreturn(ret); } h->error_code = pam_get_item(h->handle, type, (const void **)&val); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_BAD_ITEM: raise(Pam_Bad_Item); case PAM_BUF_ERR: raise(Pam_Buf_Err); case PAM_PERM_DENIED: raise(Pam_Perm_Denied); case PAM_SYSTEM_ERR: raise(Pam_System_Err); default: caml_failwith("Unknown PAM error"); } ret = caml_alloc(1, Tag_val(item)); Store_field(ret, 0, caml_copy_string((val == 0) ? "" : val)); CAMLreturn(ret); } CAMLprim value pam_fail_delay_stub(value handle, value usec) { CAMLparam2(handle, usec); caml_pam_handle * h = Handle_val(handle); h->error_code = pam_fail_delay(h->handle, Int_val(usec)); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_SYSTEM_ERR: raise(Pam_System_Err); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_authenticate_stub(value handle, value flags, value silent) { int flagValue = 0; CAMLparam3(handle, flags, silent); caml_pam_handle * h = Handle_val(handle); while(flags != Val_int(0)) { switch(Int_val(Field(flags, 0))) { case Pam_Disallow_Null_Authtok: flagValue |= PAM_DISALLOW_NULL_AUTHTOK; break; default: raise(Pam_Bad_Item); } flags = Field(flags, 1); } if(Is_block(silent) && Field(silent, 0) == Val_true) flagValue |= PAM_SILENT; h->error_code = pam_authenticate(h->handle, flagValue); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_ABORT: raise(Pam_Abort); case PAM_AUTH_ERR: raise(Pam_Auth_Err); case PAM_CRED_INSUFFICIENT: raise(Pam_Cred_Insufficient); case PAM_AUTHINFO_UNAVAIL: raise(Pam_Authinfo_Unavail); case PAM_MAXTRIES: raise(Pam_Maxtries); case PAM_USER_UNKNOWN: raise(Pam_User_Unknown); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_setcred_stub(value handle, value credList, value silent) { CAMLparam3(handle, credList, silent); CAMLlocal1(cred); int flags = 0; caml_pam_handle * h = Handle_val(handle); switch(Int_val(credList)) { case Pam_Establish_Cred: flags |= PAM_ESTABLISH_CRED; break; case Pam_Delete_Cred: flags |= PAM_DELETE_CRED; break; case Pam_Reinitialize_Cred: flags |= PAM_REINITIALIZE_CRED; break; case Pam_Refresh_Cred: flags |= PAM_REFRESH_CRED; break; default: raise(Pam_System_Err); } if(Is_block(silent) && Field(silent, 0) == Val_true) flags |= PAM_SILENT; h->error_code = pam_setcred(h->handle, flags); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_BUF_ERR: raise(Pam_Buf_Err); case PAM_CRED_ERR: raise(Pam_Cred_Err); case PAM_CRED_EXPIRED: raise(Pam_Cred_Expired); case PAM_CRED_UNAVAIL: raise(Pam_Cred_Unavail); case PAM_SYSTEM_ERR: raise(Pam_System_Err); case PAM_USER_UNKNOWN: raise(Pam_User_Unknown); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_acct_mgmt_stub(value handle, value authFlags, value silent) { CAMLparam3(handle, authFlags, silent); int flags = 0; caml_pam_handle * h = Handle_val(handle); while(authFlags != Val_int(0)) { switch(Field(authFlags, 0)) { case Pam_Disallow_Null_Authtok: flags |= PAM_DISALLOW_NULL_AUTHTOK; break; default: raise(Pam_System_Err); } authFlags = Field(authFlags, 1); } if(Is_block(silent) && Field(silent, 0) == Val_true) flags |= PAM_SILENT; h->error_code = pam_acct_mgmt(h->handle, flags); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_ACCT_EXPIRED: raise(Pam_Acct_Expired); case PAM_AUTH_ERR: raise(Pam_Auth_Err); case PAM_NEW_AUTHTOK_REQD: raise(Pam_New_Authtok_Reqd); case PAM_PERM_DENIED: raise(Pam_Perm_Denied); case PAM_USER_UNKNOWN: raise(Pam_User_Unknown); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_chauthtok_stub(value handle, value tokenFlags, value silent) { CAMLparam3(handle, tokenFlags, silent); int flags = 0; caml_pam_handle * h = Handle_val(handle); while(tokenFlags != Int_val(0)) { switch(Field(tokenFlags, 0)) { case Pam_Change_Expired_Authtok: flags |= PAM_CHANGE_EXPIRED_AUTHTOK; break; default: raise(Pam_System_Err); } tokenFlags = Field(tokenFlags, 1); } if(Is_block(silent) && Field(silent, 0) == Val_true) flags |= PAM_SILENT; h->error_code = pam_chauthtok(h->handle, flags); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_AUTHTOK_ERR: raise(Pam_Authtok_Err); case PAM_AUTHTOK_RECOVER_ERR: raise(Pam_Authtok_Recover_Err); case PAM_AUTHTOK_LOCK_BUSY: raise(Pam_Authtok_Lock_Busy); case PAM_AUTHTOK_DISABLE_AGING: raise(Pam_Authtok_Disable_Aging); case PAM_PERM_DENIED: raise(Pam_Perm_Denied); case PAM_TRY_AGAIN: raise(Pam_Try_Again); case PAM_USER_UNKNOWN: raise(Pam_User_Unknown); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_open_session_stub(value handle, value silent) { CAMLparam2(handle, silent); caml_pam_handle * h = Handle_val(handle); int flags = 0; if(Is_block(silent) && Field(silent, 0) == Val_true) flags |= PAM_SILENT; h->error_code = pam_open_session(h->handle, flags); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_ABORT: raise(Pam_Abort); case PAM_BUF_ERR: raise(Pam_Buf_Err); case PAM_SESSION_ERR: raise(Pam_Session_Err); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_close_session_stub(value handle, value silent) { CAMLparam2(handle, silent); caml_pam_handle * h = Handle_val(handle); int flags = 0; if(Is_block(silent) && Field(silent, 0) == Val_true) flags |= PAM_SILENT; h->error_code = pam_close_session(h->handle, flags); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_ABORT: raise(Pam_Abort); case PAM_BUF_ERR: raise(Pam_Buf_Err); case PAM_SESSION_ERR: raise(Pam_Session_Err); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_putenv_stub(value handle, value nameValue) { CAMLparam2(handle, nameValue); caml_pam_handle * h = Handle_val(handle); h->error_code = pam_putenv(h->handle, String_val(nameValue)); switch(h->error_code) { case PAM_SUCCESS: break; case PAM_PERM_DENIED: raise(Pam_Perm_Denied); case PAM_BAD_ITEM: raise(Pam_Bad_Item); case PAM_ABORT: raise(Pam_Abort); case PAM_BUF_ERR: raise(Pam_Buf_Err); default: caml_failwith("Unknown PAM error"); } CAMLreturn(Val_unit); } CAMLprim value pam_getenv_stub(value handle, value nameValue) { CAMLparam2(handle, nameValue); CAMLlocal1(ret); const char * val; caml_pam_handle * h = Handle_val(handle); ret = Val_int(0); val = pam_getenv(h->handle, String_val(nameValue)); if(val != 0) { ret = caml_alloc(1, 0); Store_field(ret, 0, caml_copy_string(val)); } CAMLreturn(ret); } CAMLprim value pam_getenvlist_stub(value handle) { CAMLparam1(handle); CAMLlocal2(ret, tmp); char ** envlist; caml_pam_handle * h = Handle_val(handle); envlist = pam_getenvlist(h->handle); ret = Val_int(0); for(; *envlist != 0; ++envlist) { tmp = caml_alloc(2, 0); Store_field(tmp, 1, ret); Store_field(tmp, 0, caml_copy_string(*envlist)); ret = tmp; free(*envlist); } CAMLreturn(ret); } ocamlpam-1.1/Makefile0000644000000000000000000000215111025047056013301 0ustar rootrootOCAMLC=ocamlc OCAMLOPT=ocamlopt OCAMLMKLIB=ocamlmklib OCAMLMKLIB_OPTS=-oc pam_stubs -lpam VERSION=1.1 DISTNAME=ocamlpam-$(VERSION) SOURCES=pam.mli pam.ml BASENAME=pam_stubs LIBNAME=lib$(BASENAME).a DESTDIR=$(shell ocamlc -where) .PHONY: all dist clean install all: META byte opt META: META.in sed 's/_VERSION_/$(VERSION)/' META.in > META $(LIBNAME): pam_stubs.c $(OCAMLC) -c pam_stubs.c $(OCAMLMKLIB) $(OCAMLMKLIB_OPTS) pam_stubs.o byte: $(LIBNAME) $(SOURCES) $(OCAMLC) -c pam.mli $(OCAMLC) -c pam.ml $(OCAMLMKLIB) $(OCAMLMKLIB_OPTS) -o pam pam.cmo opt: $(LIBNAME) $(SOURCES) $(OCAMLOPT) -c pam.mli $(OCAMLOPT) -c pam.ml $(OCAMLMKLIB) $(OCAMLMKLIB_OPTS) -o pam pam.cmx install: install -d $(DESTDIR)/pam install -m 644 -t $(DESTDIR)/pam META *.mli *.cmi *.cmx *.cma *.cmxa *.a install -d $(DESTDIR)/stublibs install -m 644 -t $(DESTDIR)/stublibs dll$(BASENAME).so dist: clean mkdir -p $(DISTNAME) -cp * $(DISTNAME) tar cvzf $(DISTNAME).tar.gz $(DISTNAME) zip -r $(DISTNAME).zip $(DISTNAME) rm -fr $(DISTNAME) clean: -rm -fr *.cm* *.a *.o *.so *~ $(DISTNAME).tar.gz $(DISTNAME).zip $(DISTNAME) META ocamlpam-1.1/pam.ml0000644000000000000000000001077711025047056012765 0ustar rootroot(* Copyright (c) 2008 Sharvil Nanavati *) type pam_error = | Pam_Abort (* 0 *) | Pam_Session_Err | Pam_Authtok_Err | Pam_Authtok_Recover_Err | Pam_Authtok_Lock_Busy | Pam_Authtok_Disable_Aging (* 5 *) | Pam_Try_Again | Pam_Acct_Expired | Pam_New_Authtok_Reqd | Pam_Perm_Denied | Pam_Cred_Err (* 10 *) | Pam_Cred_Expired | Pam_Cred_Unavail | Pam_Auth_Err | Pam_Cred_Insufficient | Pam_Authinfo_Unavail (* 15 *) | Pam_Maxtries | Pam_User_Unknown | Pam_Buf_Err | Pam_System_Err | Pam_Bad_Item;; (* 20 *) exception Pam_Error of pam_error;; type pam_handle;; type pam_conv_type = | Pam_Prompt_Echo_Off | Pam_Prompt_Echo_On | Pam_Error_Msg | Pam_Text_Info;; type pam_conv = pam_conv_type -> string -> string;; type pam_auth_flags = Pam_Disallow_Null_Authtok;; type pam_fail_delay = int -> int -> unit;; type pam_credentials = | Pam_Establish_Cred | Pam_Delete_Cred | Pam_Reinitialize_Cred | Pam_Refresh_Cred;; type pam_token_flags = Pam_Change_Expired_Authtok;; type pam_item = | Pam_Service of string | Pam_User of string | Pam_User_Prompt of string | Pam_Tty of string | Pam_RUser of string | Pam_RHost of string | Pam_AuthTok of string | Pam_OldAuthTok of string | Pam_Conv of pam_conv | Pam_Fail_Delay of pam_fail_delay;; let pam_item_service = Pam_Service "";; let pam_item_user = Pam_User "";; let pam_item_user_prompt = Pam_User_Prompt "";; let pam_item_tty = Pam_Tty "";; let pam_item_ruser = Pam_RUser "";; let pam_item_rhost = Pam_RHost "";; let pam_item_authtok = Pam_AuthTok "";; let pam_item_oldauthtok = Pam_OldAuthTok "";; let pam_item_conv = Pam_Conv (fun x y -> "");; let pam_item_fail_delay = Pam_Fail_Delay (fun x y -> ());; let _ = Callback.register_exception "net.nanavati.sharvil.pam.error" (Pam_Error Pam_Abort);; external pam_start : string -> ?user:string -> pam_conv -> pam_handle = "pam_start_stub";; external pam_end : pam_handle -> bool = "pam_end_stub";; external i_pam_remove_fail_delay : pam_handle -> unit = "pam_remove_fail_delay";; external i_pam_set_item : pam_handle -> pam_item -> unit = "pam_set_item_stub";; external pam_get_item : pam_handle -> pam_item -> pam_item = "pam_get_item_stub";; external pam_fail_delay : pam_handle -> int -> unit = "pam_fail_delay_stub";; external pam_authenticate : pam_handle -> pam_auth_flags list -> ?silent:bool -> unit = "pam_authenticate_stub";; external pam_setcred : pam_handle -> pam_credentials -> ?silent:bool -> unit = "pam_setcred_stub";; external pam_acct_mgmt : pam_handle -> pam_auth_flags list -> ?silent:bool -> unit = "pam_acct_mgmt_stub";; external pam_chauthtok : pam_handle -> pam_token_flags list -> ?silent:bool -> unit = "pam_chauthtok_stub";; external pam_open_session : pam_handle -> ?silent:bool -> unit = "pam_open_session_stub";; external pam_close_session : pam_handle -> ?silent:bool -> unit = "pam_close_session_stub";; external pam_putenv : pam_handle -> string -> unit = "pam_putenv_stub";; external pam_getenv : pam_handle -> string -> string option = "pam_getenv_stub";; external pam_getenvlist : pam_handle -> string list = "pam_getenvlist_stub";; let pam_set_item handle item = match item with | Pam_Fail_Delay _ -> if item == pam_item_fail_delay then i_pam_remove_fail_delay handle else i_pam_set_item handle item | _ -> i_pam_set_item handle item ;; type pam_functions = { pam_end : unit -> bool; pam_set_item : pam_item -> unit; pam_get_item : pam_item -> pam_item; pam_fail_delay : int -> unit; pam_authenticate : pam_auth_flags list -> ?silent:bool -> unit; pam_setcred : pam_credentials -> ?silent:bool -> unit; pam_acct_mgmt : pam_auth_flags list -> ?silent:bool -> unit; pam_chauthtok : pam_token_flags list -> ?silent:bool -> unit; pam_open_session : ?silent:bool -> unit -> unit; pam_close_session : ?silent:bool -> unit -> unit; pam_putenv : string -> unit; pam_getenv : string -> string option; pam_getenvlist : unit -> string list };; let pam_start_ex serviceName ?user conv= let h = pam_start serviceName ?user conv in { pam_end = (function () -> pam_end h); pam_set_item = pam_set_item h; pam_get_item = pam_get_item h; pam_fail_delay = pam_fail_delay h; pam_authenticate = pam_authenticate h; pam_setcred = pam_setcred h; pam_acct_mgmt = pam_acct_mgmt h; pam_chauthtok = pam_chauthtok h; pam_open_session = (fun ?silent () -> pam_open_session h ?silent); pam_close_session = (fun ?silent () -> pam_close_session h ?silent); pam_putenv = pam_putenv h; pam_getenv = pam_getenv h; pam_getenvlist = (function () -> pam_getenvlist h); } ;; ocamlpam-1.1/CHANGES0000644000000000000000000000061311025047056012635 0ustar rootroot2008-06-14 Bug Fixes - Update: New 'install' target (Stéphane Glondu). - Update: Shared libraries also generated (Stéphane Glondu). - Update: Add META file to support findlib (Stéphane Glondu). - Fix: segfault on repeated pam_start (Stéphane Glondu). - Fix: setting Pam_Fail_Delay is now correctly implemented. 2008-02-22 Release 1.0 - Initial release of OCamlPAM ocamlpam-1.1/META.in0000644000000000000000000000020011025047056012710 0ustar rootrootdescription = "OCaml bindings for the PAM library" version = "_VERSION_" archive(byte) = "pam.cma" archive(native) = "pam.cmxa" ocamlpam-1.1/README0000644000000000000000000001126011025047056012522 0ustar rootrootOCamlPAM - an OCaml library for PAM http://sharvil.nanavati.net/projects/ocamlpam/ Overview OCamlPAM is a wrapper for the Pluggable Authentication Modules (PAM) library. PAM provides a flexible mechanism for authenticating users via administrator-defined policies. PAM has modules for authenticating via Unix passwd files, Kerberos, LDAP, etc. Additional modules for custom authentication mechanisms can be created and deployed without recompiling existing services based on PAM. Moreover, policies defining the authentication requirements can be changed at runtime without restarting running services. Installation To develop applications with OCamlPAM, you must install both the PAM runtime and PAM development packages. Alternatively, you could install PAM from sources which will contain both the runtime and development files. The Linux version of PAM can be found at: http://www.kernel.org/pub/linux/libs/pam/ 1. Extract the archive: $ tar zxvf ocamlpam-1.1.tgz $ cd ocamlpam-1.1/ 2. Compile OCamlPAM: $ make 3. Install OCamlPAM: # make install Note: if 'ocamlc' and 'ocamlopt' are not in your PATH or if they have a different name, edit 'Makefile' and specify the name/location of the compilers. Makefile Targets: byte - build the OCamlPAM library for use with bytecode projects opt - build the OCamlPAM library for use with native projects all - builds both the 'byte' and 'opt' versions of the library install - installs the 'byte' and 'opt' versions of the library clean - removes all intermediate and target files Documentation OCamlPAM provides a similar interface as Linux-PAM. The documentation for Linux-PAM can be found at: http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/Linux-PAM_ADG.html It deviates from the C library in a few ways as described below: 1. All-caps identifiers are camel-cased. For example, PAM_ESTABLISH_CRED in the C library corresponds to Pam_Establish_Cred in OCamlPAM. 2. Exceptions are thrown instead of returning integer codes. Exceptions have type: exception Pam_Error of pam_error pam_error is a variant type with values matching the names of return codes. For example, the exception (Pam_Error Pam_Abort) corresponds to the return code PAM_ABORT. 3. No exception is thrown on success. 4. No exception is thrown when ending a transaction. The 'pam_end' function returns a boolean with the value 'true' indicating success. 5. PAM_SILENT must be specified with the named boolean argument ~silent. e.g.: pam_open_session handle ~silent:true 6. PAM items are variant types with default values of the form 'pam_item_*'. e.g.: pam_set_item handle (Pam_Service "my_service"); let service_name = pam_get_item handle pam_item_service in (* ... *) 7. To remove the fail delay function, specify pam_item_fail_delay as the argument to pam_set_item. Note that pam_get_item will return pam_item_fail_delay if the fail delay function is queried and no fail delay function has been set. 8. The PAM documentation contains a typo: PAM_AUTHTOK_RECOVERY_ERR should not contain a 'Y'. Consequently, the corresponding pam_error value is: Pam_Authtok_Recover_Err. 9. It is not necessary to explicitly call pam_end. Upon garbage collection, pam_end will be called and any error arising from it will be ignored. If you wish to control the lifetime of the PAM transaction or if you would like to be notified of success/failure, you must call pam_end explicitly. An additional function, pam_start_ex, provides a simpler interface to the PAM functions. It takes the same arguments as pam_start but instead of returning an opaque handle, it returns a record of functions that no longer require the handle argument. For example, the code: let handle = pam_start "my_service" my_conversation_fn in pam_authenticate handle [] ~silent:true; pam_end handle could be rewritten: let p = pam_start_ex "my_service" my_conversation_fn in p.pam_authenticate [] ~silent:true; p.pam_end () Building an Application To link against the bytecode library, use the following: $ ocamlc -I /path/to/ocamlpam-1.1 pam.cma or, for the native version: $ ocamlopt -I /path/to/ocamlpam-1.1 pam.cmxa Acknowledgements Stéphane Glondu References [1] OCamlPAM Home (http://sharvil.nanavati.net/projects/ocamlpam/) [2] A Linux-PAM page (http://www.kernel.org/pub/linux/libs/pam/) [3] The Linux-PAM Application Developers' Guide (http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/Linux-PAM_ADG.html)