package krb

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file config_gen.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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
open! Core
include Config_gen_intf

module Shared = struct
  module Format = struct
    type t =
      { pre_v5_assumed_realm : string option [@sexp.option]
      ; host_keytab_path : string option [@sexp.option]
      ; user_keytab_dir_template : string option [@sexp.option]
      ; default_domain : string option option [@sexp.option]
      ; debug_log_config : Debug_log_config.Stable.V1.t option [@sexp.option]
      ; verbose_errors : bool option [@sexp.option]
      ; sandboxing_state : [ `None | `Sandboxed | `Exempted ] option [@sexp.option]
      ; am_sandboxed : bool option [@sexp.option]
      }
    [@@sexp.allow_extra_fields] [@@deriving of_sexp]
  end

  type t =
    { pre_v5_assumed_realm : string option [@sexp.option]
    ; host_keytab_path : string option [@sexp.option]
    ; user_keytab_dir_template : string option [@sexp.option]
    ; default_domain : string option option [@sexp.option]
    ; debug_log_config : Debug_log_config.Stable.V1.t option [@sexp.option]
    ; verbose_errors : bool option [@sexp.option]
    ; sandboxing_state : [ `None | `Sandboxed | `Exempted ] option [@sexp.option]
    }
  [@@deriving fields, sexp_of]

  let t_of_sexp sexp =
    let { Format.pre_v5_assumed_realm
        ; host_keytab_path
        ; user_keytab_dir_template
        ; default_domain
        ; debug_log_config
        ; verbose_errors
        ; sandboxing_state
        ; am_sandboxed
        }
      =
      Format.t_of_sexp sexp
    in
    let sandboxing_state =
      match am_sandboxed, sandboxing_state with
      | Some _, Some _ ->
        raise_s [%message "cannot specify both [am_sandboxed] and [sandboxing_state]"]
      | None, None -> None
      | Some am_sandboxed, None -> Some (if am_sandboxed then `Sandboxed else `None)
      | None, Some sandboxing_state -> Some sandboxing_state
    in
    { pre_v5_assumed_realm
    ; host_keytab_path
    ; user_keytab_dir_template
    ; default_domain
    ; debug_log_config
    ; verbose_errors
    ; sandboxing_state
    }
  ;;

  let environment_variable = "OCAML_KRB_CONFIG"
  let username_template = "%{username}"

  let%expect_test "parsing" =
    let test str =
      let sexp = Sexp.of_string str in
      match t_of_sexp sexp with
      | t -> sexp_of_t t |> print_s
      | exception exn -> print_s [%sexp (exn : Exn.t)]
    in
    test "((am_sandboxed true))";
    [%expect {| ((sandboxing_state Sandboxed)) |}];
    test "((am_sandboxed false))";
    [%expect {| ((sandboxing_state None)) |}];
    test "((sandboxing_state Exempted))";
    [%expect {| ((sandboxing_state Exempted)) |}];
    test "((sandboxing_state Exempted) (am_sandboxed true))";
    [%expect {| "cannot specify both [am_sandboxed] and [sandboxing_state]" |}]
  ;;
end

include Shared

module type S = S with type t = t

let make ~default ~help_message =
  (module struct
    include Shared

    let field_descriptions () =
      let field to_sexp description ac field =
        let sexp =
          Option.value_map
            ~default:(Sexp.Atom "<unspecified>")
            (Field.get field default)
            ~f:to_sexp
        in
        (Field.name field, sexp, description) :: ac
      in
      let fields =
        Fields.fold
          ~init:[]
          ~pre_v5_assumed_realm:
            (field
               [%sexp_of: string]
               [ "\n\
                  When using Protocol V4 and below, clients don't know the realm of \
                  their peer and assume they are in [pre_v5_assumed_realm]. Protocol V5 \
                  added support for cross-realm authentication and started sending the \
                  realm as part of the handshake."
               ])
          ~host_keytab_path:
            (field
               [%sexp_of: string]
               [ "\n  The path of a keytab specified by [Keytab.Path.Host].\n" ])
          ~user_keytab_dir_template:
            (field
               [%sexp_of: string]
               [ sprintf
                   "\n\
                   \  The path of a keytab specified by [Keytab.Path.User] is determined \
                    by\n\
                   \  [filled in user_keytab_dir_template]/$USER.keytab.\n\
                   \  This must be an absolute path with the substring %s, which will be\n\
                   \  be filled in with the currently running user.\n"
                   username_template
               ])
          ~default_domain:
            (field
               [%sexp_of: string option]
               [ "\n\
                 \  The default domain name of hosts in this realm. This value will be \
                  used to fully qualify hostnames when constructing service principals.\n\n"
               ])
          ~debug_log_config:
            (field
               [%sexp_of: Debug_log_config.Stable.V1.t]
               [ sprintf
                   "\n\
                   \  Print library debugging information to the outputs specified. The \
                    following\n\
                   \  are some example configs:\n\
                   \  %s\n\
                   \ "
                   (List.map
                      Debug_log_config.examples
                      ~f:Debug_log_config.Stable.V1.sexp_of_t
                    |> List.map ~f:Sexp.to_string
                    |> String.concat ~sep:"\n  ")
               ])
          ~verbose_errors:
            (field [%sexp_of: bool] [ "\n  Whether error messages should be verbose.\n" ])
          (* Purposefully undocumented; this should only be set by the kerberos sandbox. *)
          ~sandboxing_state:(fun acc _ -> acc)
      in
      String.concat
        (List.map
           (List.sort fields ~compare:(fun (name1, _, _) (name2, _, _) ->
              String.compare name1 name2))
           ~f:(fun (name, default, description) ->
             String.concat
               ("\n"
                :: name
                :: " (default "
                :: Sexp.to_string default
                :: ")"
                :: description)))
    ;;

    let help_message () =
      let field_descriptions = field_descriptions () in
      help_message ~default ~environment_variable ~field_descriptions
    ;;

    let usage () =
      eprintf "%s%!" (help_message ());
      exit 1
    ;;

    let t =
      match Sys.getenv environment_variable with
      | None -> default
      | Some "" -> usage ()
      | Some string ->
        (match Result.try_with (fun () -> t_of_sexp (Sexp.of_string string)) with
         | Ok t -> t
         | Error exn ->
           eprintf
             "%s\n\n"
             (Sexp.to_string_hum
                (Error.sexp_of_t
                   (Error.create
                      (sprintf
                         "invalid value for %s environment variable"
                         environment_variable)
                      exn
                      [%sexp_of: exn])));
           usage ())
    ;;

    let get_with_default field =
      match Option.first_some (Field.get field t) (Field.get field default) with
      | None ->
        failwithf
          "The Kerberos configuration is missing a required field (%s).\n\
           Pass the environment variable as described or modify the Config module.\n\n\
           ===============================================================\n\n\
           %s"
          (Field.name field)
          (help_message ())
          ()
      | Some value -> value
    ;;

    let validate_user_keytab_dir_template x =
      let template_occurences =
        List.length
          (String.substr_index_all x ~may_overlap:false ~pattern:username_template)
      in
      if not (template_occurences = 1 && Filename.is_absolute x)
      then
        failwithf
          "[user_keytab_dir_template] must be an absolute path with the template %s"
          username_template
          ()
    ;;

    let pre_v5_assumed_realm = get_with_default Fields.pre_v5_assumed_realm
    let host_keytab_path = get_with_default Fields.host_keytab_path

    let user_keytab_dir_template =
      let x = get_with_default Fields.user_keytab_dir_template in
      validate_user_keytab_dir_template x;
      x
    ;;

    let user_keytab_dir ~username =
      String.substr_replace_all
        user_keytab_dir_template
        ~pattern:username_template
        ~with_:username
    ;;

    let default_domain = get_with_default Fields.default_domain
    let debug_log_config = get_with_default Fields.debug_log_config
    let verbose_errors = get_with_default Fields.verbose_errors
    let sandboxing_state = get_with_default Fields.sandboxing_state
    let print_debug_messages = List.length debug_log_config > 0

    let am_sandboxed =
      match sandboxing_state with
      | `Sandboxed -> true
      | `None | `Exempted -> false
    ;;

    let am_exempt_from_sandbox =
      match sandboxing_state with
      | `Exempted -> true
      | `None | `Sandboxed -> false
    ;;

    let t =
      { pre_v5_assumed_realm = Some pre_v5_assumed_realm
      ; host_keytab_path = Some host_keytab_path
      ; user_keytab_dir_template = Some user_keytab_dir_template
      ; default_domain = Some default_domain
      ; debug_log_config = Some debug_log_config
      ; verbose_errors = Some verbose_errors
      ; sandboxing_state = Some sandboxing_state
      }
    ;;
  end : S)
;;
OCaml

Innovation. Community. Security.