package krb

  1. Overview
  2. Docs
A library for using Kerberos for both Rpc and Tcp communication

Install

Dune Dependency

Authors

Maintainers

Sources

krb-v0.16.0.tar.gz
sha256=353675621e4c5a888f2483dc1bb7281bd17ce4ed7dfd2f40142257f98db7c77d

doc/src/krb.internal/credentials.ml.html

Source file credentials.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
open! Core
open Async
module Time = Time_float_unix

module Raw = struct
  type t

  external of_password
    :  Context.t
    -> ?tkt_service:string
    -> Get_init_creds_opts.Raw.t
    -> Principal.Raw.t
    -> string
    -> t Krb_result.t
    = "caml_krb5_get_init_creds_password"

  external of_keytab
    :  Context.t
    -> ?tkt_service:string
    -> Get_init_creds_opts.Raw.t
    -> Principal.Raw.t
    -> Keytab.Raw.t
    -> t Krb_result.t
    = "caml_krb5_get_init_creds_keytab"

  external free : Context.t -> t -> unit = "caml_krb5_free_cred_contents"

  external client
    :  Context.t
    -> t
    -> Principal.Raw.t Krb_result.t
    = "caml_krb5_creds_client"

  external server
    :  Context.t
    -> t
    -> Principal.Raw.t Krb_result.t
    = "caml_krb5_creds_server"

  external ticket_data
    :  Context.t
    -> t
    -> Data.t Krb_result.t
    = "caml_krb5_creds_ticket_data"

  external is_skey : t -> bool = "caml_krb5_creds_is_skey"
  external ticket_string : t -> string = "caml_krb5_creds_ticket_string"
  external second_ticket : t -> string = "caml_krb5_creds_second_ticket"
  external starttime : t -> int = "caml_krb5_creds_starttime"
  external endtime : t -> int = "caml_krb5_creds_endtime"
  external renew_until_time : t -> int = "caml_krb5_creds_renew_till"
  external forwardable : t -> bool = "caml_krb5_creds_forwardable"
  external proxiable : t -> bool = "caml_krb5_creds_proxiable"

  external keyblock
    :  Context.t
    -> t
    -> Keyblock.t Krb_result.t
    = "caml_krb5_creds_keyblock"

  external create
    :  Context.t
    -> client:Principal.Raw.t
    -> server:Principal.Raw.t
    -> ticket:string option
    -> second_ticket:string option
    -> t Krb_result.t
    = "caml_krb5_creds_create"
end

module Flags = struct
  type t =
    { forwardable : bool
    ; proxiable : bool
    }
  [@@deriving sexp_of]

  let get raw = { forwardable = Raw.forwardable raw; proxiable = Raw.proxiable raw }
end

type t =
  { raw : Raw.t
  ; starttime : Time.t
  ; endtime : Time.t
  ; renew_until : Time.t
  ; client : Principal.t
  ; server : Principal.t
  }
[@@deriving fields]

let sexp_of_t t =
  [%sexp
    { starttime = (t.starttime : Time.t Sexp_opaque_when_testing.t)
    ; endtime = (t.endtime : Time.t Sexp_opaque_when_testing.t)
    ; renew_until = (t.renew_until : Time.t Sexp_opaque_when_testing.t)
    ; client = (t.client : Principal.t)
    ; server = (t.server : Principal.t)
    }]
;;

let to_raw = raw

let krb_time_to_time krb_time =
  krb_time |> Float.of_int |> Time.Span.of_sec |> Time.of_span_since_epoch
;;

let is_skey t = Raw.is_skey t.raw
let ticket_string t = Raw.ticket_string t.raw
let second_ticket t = Raw.second_ticket t.raw
let flags t = Flags.get t.raw

let client' raw =
  let info = Krb_info.create "[krb5_creds_client]" in
  Context_sequencer.enqueue_job_with_info ~info ~f:(fun c -> Raw.client c raw)
  >>=? fun principal ->
  Context_sequencer.add_finalizer principal ~f:Principal.Raw.free;
  Principal.of_raw principal
;;

let server' raw =
  let info = Krb_info.create "[krb5_creds_server]" in
  Context_sequencer.enqueue_job_with_info ~info ~f:(fun c -> Raw.server c raw)
  >>=? fun principal ->
  Context_sequencer.add_finalizer principal ~f:Principal.Raw.free;
  Principal.of_raw principal
;;

let of_raw raw =
  client' raw
  >>=? fun client ->
  server' raw
  >>|? fun server ->
  { raw
  ; starttime = Raw.starttime raw |> krb_time_to_time
  ; endtime = Raw.endtime raw |> krb_time_to_time
  ; renew_until = Raw.renew_until_time raw |> krb_time_to_time
  ; client
  ; server
  }
;;

let of_password ?(options = Get_init_creds_opts.default) ?tkt_service principal password =
  Get_init_creds_opts.to_raw options
  >>=? fun options ->
  let tag_arguments = lazy [%message (principal : Principal.t)] in
  let info = Krb_info.create ~tag_arguments "[krb5_get_init_creds_password]" in
  Context_sequencer.enqueue_job_with_info ~info ~f:(fun c ->
    Raw.of_password c ?tkt_service options (Principal.to_raw principal) password)
  >>=? fun raw ->
  Context_sequencer.add_finalizer raw ~f:Raw.free;
  of_raw raw
;;

let of_keytab' ?(options = Get_init_creds_opts.default) ?tkt_service principal keytab =
  let open Deferred.Result.Let_syntax in
  let non_auth_failure d =
    Deferred.Result.map_error d ~f:(fun error -> `Non_auth_failure error)
  in
  let%bind options = Get_init_creds_opts.to_raw options |> non_auth_failure in
  let tag_arguments = lazy [%message (principal : Principal.t) (keytab : Keytab.t)] in
  let tag_error = function
    (* KRB5_PREAUTH_FAILED - Generic preauthentication failure *)
    | -1765328174l ->
      Deferred.return [%message "Failed to get credentials using the supplied keytab"]
    | _ -> Deferred.return Sexp.unit
  in
  let is_auth_failure = function
    (* KRB5_PREAUTH_FAILED - Generic preauthentication failure *)
    | -1765328174l
    (* KRB5_ERR_PREAUTH_FAILED - Preauthentication failed *)
    | -1765328360l -> true
    | _ -> false
  in
  let info = Krb_info.create ~tag_arguments ~tag_error "[krb5_get_init_creds_keytab]" in
  let%bind raw =
    Context_sequencer.enqueue_job_with_info' ~info ~f:(fun c ->
      Raw.of_keytab
        c
        ?tkt_service
        options
        (Principal.to_raw principal)
        (Keytab.to_raw keytab))
    |> Deferred.Result.map_error ~f:(function
      | `Raised error -> `Non_auth_failure error
      | `Krb_error (error, code) ->
        if is_auth_failure code then `Auth_failure error else `Non_auth_failure error)
  in
  Context_sequencer.add_finalizer raw ~f:Raw.free;
  of_raw raw |> non_auth_failure
;;

let of_keytab ?options ?tkt_service principal keytab =
  of_keytab' ?options ?tkt_service principal keytab
  >>| Result.map_error ~f:(function
    | `Auth_failure error -> error
    | `Non_auth_failure error -> error)
;;

let check_password principal ~password =
  Get_init_creds_opts.to_raw Get_init_creds_opts.default
  >>=? fun options ->
  let tag_arguments = lazy [%message (principal : Principal.t)] in
  let info = Krb_info.create ~tag_arguments "[krb5_get_init_creds_password]" in
  Context_sequencer.enqueue_job_with_info ~info ~f:(fun c ->
    Raw.of_password c options (Principal.to_raw principal) password
    |> Result.map ~f:(fun raw -> Raw.free c raw))
;;

let create ?ticket ?second_ticket ~client ~server () =
  let info = Krb_info.create "[krb5_creds_create]" in
  Context_sequencer.enqueue_job_with_info ~info ~f:(fun c ->
    Raw.create
      c
      ~client:(Principal.to_raw client)
      ~server:(Principal.to_raw server)
      ~ticket
      ~second_ticket)
  >>=? fun raw ->
  Context_sequencer.add_finalizer raw ~f:Raw.free;
  of_raw raw
;;

let keyblock t =
  let info = Krb_info.create "[krb5_creds_keyblock]" in
  Context_sequencer.enqueue_job_with_info ~info ~f:(fun c -> Raw.keyblock c t.raw)
  >>|? fun keyblock ->
  Context_sequencer.add_finalizer keyblock ~f:Keyblock.Raw.free;
  keyblock
;;

let ticket_data t =
  let info = Krb_info.create "[krb5_creds_ticket_data]" in
  Context_sequencer.enqueue_job_with_info ~info ~f:(fun c -> Raw.ticket_data c t.raw)
  >>|? fun ticket_data ->
  Context_sequencer.add_finalizer ticket_data ~f:Data.free;
  ticket_data
;;

let ticket t = ticket_data t >>=? fun data -> Deferred.return (Ticket.decode data)

module Expert = struct
  let of_keytab = of_keytab'
end
OCaml

Innovation. Community. Security.