(* $Id$ *)
(* Utilities for the generated object encapsulation *)
open Netsys_gssapi
open Netgss_bindings
let identity x = x
let _OM_uint32_of_int32 = identity
let _int32_of_OM_uint32 = identity
let calling_errors =
[| `None;
`Inaccessible_read;
`Inaccessible_write;
`Bad_structure
|]
let routine_errors =
[| `None;
`Bad_mech;
`Bad_name;
`Bad_nametype;
`Bad_bindings;
`Bad_status;
`Bad_mic;
`No_cred;
`No_context;
`Defective_token;
`Defective_credential;
`Credentials_expired;
`Context_expired;
`Failure;
`Bad_QOP;
`Unauthorized;
`Unavailable;
`Duplicate_element;
`Name_not_mn;
|]
let suppl_status_flags =
[| `Continue_needed;
`Duplicate_token;
`Old_token;
`Unseq_token;
`Gap_token;
|]
let decode_status n : major_status =
let bits_calling_error =
Int32.to_int(Int32.shift_right_logical n 24) in
let bits_routine_error =
Int32.to_int(Int32.logand (Int32.shift_right_logical n 16) 0xffl) in
let bits_suppl_info =
Int32.to_int(Int32.logand n 0xffffl) in
try
if bits_calling_error >= Array.length calling_errors then raise Not_found;
if bits_routine_error >= Array.length routine_errors then raise Not_found;
let suppl_info, _ =
Array.fold_left
(fun (l, k) flag ->
let is_set = (1 lsl k) land bits_suppl_info <> 0 in
if is_set then
(flag :: l, k+1)
else
(l, k+1)
)
([], 0)
suppl_status_flags in
(calling_errors.(bits_calling_error),
routine_errors.(bits_routine_error),
suppl_info
)
with
| Not_found ->
failwith "Netgss.decode_status"
let _gss_ctx_id_t_of_context_option =
function
| None -> no_context()
| Some ctx -> ctx
let _context_option_of_gss_ctx_id_t ctx =
if is_no_context ctx then
None
else
Some ctx
let _gss_buffer_t_of_token s =
buffer_of_string s 0 (String.length s)
let _gss_buffer_t_of_token_option =
function
| Some s ->
buffer_of_string s 0 (String.length s)
| None ->
buffer_of_string "" 0 0 (* should be ok for GSS_C_NO_BUFFER *)
(* In the following, all *_of_gss_buffer_t functions are destructive, and
release (if possible) the buffer arg. This is ok, because these buffer
args are output buffers from GSSAPI.
*)
let _token_of_gss_buffer_t buf =
let s = string_of_buffer buf in
release_buffer buf;
s
let _gss_buffer_t_of_message (ml : Netxdr_mstring.mstring list) =
match ml with
| [] ->
buffer_of_string "" 0 0
| [ m ] ->
( match m#preferred with
| `Memory ->
(* No copy in this case: buffer_of_memory takes the data
area of mem2 as data area of the gss_buffer_t. It is
ensured that mem2 cannot be collected before buf.
*)
let (mem1, pos) = m#as_memory in
let mem2 = Bigarray.Array1.sub mem1 pos m#length in
buffer_of_memory mem2
| `Bytes ->
let (str, pos) = m#as_bytes in
buffer_of_bytes str pos m#length
)
| _ ->
let len = Netxdr_mstring.length_mstrings ml in
let mem = Bigarray.Array1.create Bigarray.char Bigarray.c_layout len in
Netxdr_mstring.blit_mstrings_to_memory ml mem;
buffer_of_memory mem
let _message_of_gss_buffer_t pref_type buf =
match pref_type with
| `Memory ->
let mem = memory_of_buffer buf in
[ Netxdr_mstring.memory_to_mstring mem ]
(* It is ok not to copy here, i.e. mem and buf share the same data
area. buf will not be used for anything else after this call.
Also, memory_of_buffer ensures that buf cannot be collected before
mem (with a tricky finalizer).
*)
| `Bytes ->
let str = bytes_of_buffer buf in
release_buffer buf;
[ Netxdr_mstring.bytes_to_mstring str ]
let cb_typed_string =
function
| `Unspecified s -> (0, s)
| `Local s -> (1, s)
| `Inet addr -> (2, Netsys.protostring_of_inet_addr addr)
| `Nulladdr -> (255, "")
| `Other(n,s) -> (Int32.to_int n,s) (* FIXME *)
let _gss_channel_bindings_t_of_cb_option cb_opt =
match cb_opt with
| None ->
no_channel_bindings()
| Some (i,a,data) ->
let (i_ty, i_str) = cb_typed_string i in
let (a_ty, a_str) = cb_typed_string a in
map_cb i_ty i_str a_ty a_str data
let _oid_of_gss_OID gss_oid =
try
let der = der_of_oid gss_oid in
let p = ref 0 in
Netgssapi_support.der_value_to_oid der p (String.length der)
with Not_found -> [| |]
let _gss_OID_of_oid oid =
if oid = [| |] then
no_oid()
else
let der = Netgssapi_support.oid_to_der_value oid in
oid_of_der der
let _oid_set_of_gss_OID_set gss_set =
try
let gss_oid_a = array_of_oid_set gss_set in
let oid_a = Array.map _oid_of_gss_OID gss_oid_a in
Array.to_list oid_a
with Not_found -> []
let _gss_OID_set_of_oid_set set =
let set_a = Array.of_list set in
let gss_oid_a = Array.map _gss_OID_of_oid set_a in
oid_set_of_array gss_oid_a
let _time_of_OM_uint32 n =
if n = gss_indefinite() then
`Indefinite
else
(* be careful with negative values. In C, the numbers are unsigned *)
if n >= 0l then
`This (Int32.to_float n)
else
let offset = (-2.0) *. Int32.to_float Int32.min_int in
`This (Int32.to_float n +. offset)
let uint32_of_float t =
if t >= Int32.to_float Int32.max_int +. 1.0 then
let offset = (-2.0) *. Int32.to_float Int32.min_int in
let t1 = t -. offset in
let t2 = min t1 (Int32.to_float Int32.max_int) in
Int32.of_float t2
else
Int32.of_float(max t 0.0)
let _OM_uint32_of_time =
function
| `Indefinite -> gss_indefinite()
| `This t -> uint32_of_float t
let _OM_uint32_of_time_opt =
function
| None -> 0l
| Some t -> uint32_of_float t
let _OM_uint32_of_wrap_size n =
if n < 0 || Int64.of_int n > Int64.of_int32 Int32.max_int then
failwith "Netgss: wrap size out of range";
Int32.of_int n
let _wrap_size_of_OM_uint32 n =
(* the output is normally smaller than the input *)
if n < 0l || Int64.of_int32 n > Int64.of_int max_int then
failwith "Netgss: wrap size out of range";
Int32.to_int n
let _flags_of_req_flags flags = (flags : Netsys_gssapi.req_flag list :> flags)
let gss_display_minor_status min_status mech_type =
let out_major = ref 0l in
let out_minor = ref 0l in
let l = ref [] in
let mctx = ref 0l in
let cont = ref true in
while !cont do
let (major, minor, new_mctx, display_string) =
Netgss_bindings.gss_display_status
min_status `Mech_code mech_type !mctx in
out_major := major;
out_minor := minor;
mctx := new_mctx;
let success = Int32.logand major 0xffff0000l = 0l in
if success then
l := display_string :: !l;
cont := !mctx <> 0l && success;
done;
let strings =
List.map string_of_buffer (List.rev !l) in
(!out_major, !out_minor, strings)