~ubuntu-branches/ubuntu/trusty/ocamlnet/trusty

« back to all changes in this revision

Viewing changes to src/rpc/rpc_auth_gssapi.ml

  • Committer: Bazaar Package Importer
  • Author(s): Stéphane Glondu
  • Date: 2011-09-02 14:12:33 UTC
  • mfrom: (18.2.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110902141233-zbj0ygxb92u6gy4z
Tags: 3.4-1
* New upstream release
  - add a new NetcgiRequire directive to ease dependency management
    (Closes: #637147)
  - remove patches that were applied upstream:
    + Added-missing-shebang-lines-in-example-shell-scripts
    + Try-also-ocamlc-for-POSIX-threads

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(* $Id: rpc_auth_gssapi.ml 1631 2011-06-16 15:04:56Z gerd $ *)
 
2
 
 
3
open Netgssapi
 
4
open Rpc_auth_gssapi_aux
 
5
open Printf
 
6
 
 
7
type support_level =
 
8
    [ `Required | `If_possible | `None ]
 
9
 
 
10
type window =
 
11
    { window : string;
 
12
      mutable window_length : int64;
 
13
      mutable window_offset : int;
 
14
      mutable window_last : int64;
 
15
    }
 
16
 
 
17
type rpc_context =
 
18
    { context : context;
 
19
      mutable ctx_continue : bool;
 
20
      ctx_handle : string;
 
21
      ctx_conn_id : Rpc_server.connection_id option;
 
22
      mutable ctx_svc_none : bool;       
 
23
        (* whether unprotected messages are ok *)
 
24
      mutable ctx_svc_integrity : bool;
 
25
        (* whether integrity-protected msgs are ok *)
 
26
      mutable ctx_svc_privacy : bool;
 
27
        (* whether privacy-protected msgs are ok *)
 
28
 
 
29
      ctx_window : window option;
 
30
    }
 
31
 
 
32
type user_name_format =
 
33
    [ `Exported_name
 
34
    | `Prefixed_name
 
35
    | `Plain_name
 
36
    ]
 
37
 
 
38
type user_name_interpretation =
 
39
    [ `Exported_name
 
40
    | `Prefixed_name
 
41
    | `Plain_name of oid
 
42
    ]
 
43
 
 
44
module Debug = struct
 
45
  let enable = ref false
 
46
end
 
47
 
 
48
let dlog = Netlog.Debug.mk_dlog "Rpc_auth_gssapi" Debug.enable
 
49
let dlogr = Netlog.Debug.mk_dlogr "Rpc_auth_gssapi" Debug.enable
 
50
 
 
51
let () =
 
52
  Netlog.Debug.register_module "Rpc_auth_gssapi" Debug.enable
 
53
 
 
54
 
 
55
let split_rpc_gss_data_t ms =
 
56
  let ms_len =  Xdr_mstring.length_mstrings ms in
 
57
  if ms_len < 4 then
 
58
    failwith "Rpc_auth_gssapi.split_rpc_gss_data_t";
 
59
  let seq_s = Xdr_mstring.prefix_mstrings ms 4 in
 
60
  let rest_s = Xdr_mstring.shared_sub_mstrings ms 4 (ms_len - 4) in
 
61
  let seq = Rtypes.read_uint4 seq_s 0 in
 
62
  (seq, rest_s)
 
63
 
 
64
 
 
65
let omax = Rtypes.mk_uint4 ('\255', '\255', '\255', '\255')
 
66
 
 
67
let integrity_encoder (gss_api : Netgssapi.gss_api)
 
68
                      ctx is_server cred1 rpc_gss_integ_data s =
 
69
  dlog "integrity_encoder";
 
70
  let data =
 
71
    Xdr_mstring.string_to_mstring 
 
72
      (Rtypes.uint4_as_string cred1.seq_num) ::  s in
 
73
  let mic =
 
74
    gss_api # get_mic
 
75
      ~context:ctx
 
76
      ~qop_req:None
 
77
      ~message:data
 
78
      ~out:(fun ~msg_token ~minor_status ~major_status () ->
 
79
              let (c_err, r_err, flags) = major_status in
 
80
              if c_err <> `None || r_err <> `None then (
 
81
                if is_server then (
 
82
                  (* The RFC demands that no response is sent if a
 
83
                     get_mic problem occurs in the server
 
84
                   *)
 
85
                  Netlog.logf `Err
 
86
                    "Rpc_auth_gssapi: Cannot obtain MIC: %s"
 
87
                    (string_of_major_status major_status);
 
88
                  raise Rpc_server.Late_drop
 
89
                )
 
90
                else
 
91
                  failwith("Rpc_auth_gssapi: \
 
92
                          Cannot obtain MIC: " ^ 
 
93
                             string_of_major_status major_status);
 
94
              );
 
95
              msg_token
 
96
           )
 
97
      () in
 
98
  (* The commented out code block performs two superflous string copies.
 
99
     We avoid this by doing the XDR-ing manually.
 
100
   *)
 
101
(*
 
102
  let integ =
 
103
    { databody_integ = (Xdr_mstring.concat_mstrings data);
 
104
      checksum = mic;
 
105
    } in
 
106
  let xdr_val = Rpc_auth_gssapi_aux._of_rpc_gss_integ_data integ in
 
107
  Xdr.pack_xdr_value_as_string xdr_val rpc_gss_integ_data []
 
108
 *)
 
109
  let data_len = Xdr_mstring.length_mstrings data in
 
110
  let data_decolen = Xdr.get_string_decoration_size data_len omax in
 
111
  let data_hdr = Rtypes.uint4_as_string (Rtypes.uint4_of_int data_len) in
 
112
  let data_padlen = data_decolen - 4 in
 
113
  let data_pad = String.make data_padlen '\000' in
 
114
  
 
115
  let mic_len = String.length mic in
 
116
  let mic_decolen =  Xdr.get_string_decoration_size mic_len omax in
 
117
  let mic_hdr = Rtypes.uint4_as_string (Rtypes.uint4_of_int mic_len) in
 
118
  let mic_padlen = mic_decolen - 4 in
 
119
  let mic_pad = String.make mic_padlen '\000' in
 
120
 
 
121
  [ Xdr_mstring.string_to_mstring data_hdr ] @
 
122
  data @
 
123
  [ Xdr_mstring.string_to_mstring (data_pad ^ 
 
124
                                     mic_hdr ^ mic ^ mic_pad)
 
125
  ]
 
126
 
 
127
    
 
128
 
 
129
let ms_factories = Hashtbl.create 3
 
130
 
 
131
let () =
 
132
  Hashtbl.add ms_factories "*" Xdr_mstring.string_based_mstrings
 
133
 
 
134
 
 
135
let integrity_decoder (gss_api : Netgssapi.gss_api)
 
136
                      ctx is_server cred1 rpc_gss_integ_data s pos len =
 
137
  dlog "integrity_decoder";
 
138
  try
 
139
    let xdr_val, xdr_len =
 
140
      Xdr.unpack_xdr_value_l
 
141
        ~pos ~len ~fast:true s rpc_gss_integ_data ~prefix:true
 
142
        ~mstring_factories:ms_factories
 
143
        [] in
 
144
    let integ =
 
145
      _to_rpc_gss_integ_data xdr_val in
 
146
    let data =
 
147
      integ.databody_integ in
 
148
    (* In the server, any integrity problem should be mapped
 
149
       to GARBAGE. We get this by raising Xdr_format exceptions here.
 
150
     *)
 
151
    gss_api # verify_mic
 
152
      ~context:ctx
 
153
      ~message:[data]
 
154
      ~token:integ.checksum
 
155
      ~out:(fun ~qop_state ~minor_status ~major_status () ->
 
156
              let (c_err, r_err, flags) = major_status in
 
157
              if c_err <> `None || r_err <> `None then
 
158
                raise(Xdr.Xdr_format(
 
159
                        "Rpc_auth_gssapi: \
 
160
                          Cannot verify MIC: " ^ 
 
161
                          string_of_major_status major_status));
 
162
           )
 
163
      ();
 
164
    let (seq, args) =
 
165
      split_rpc_gss_data_t [data] in
 
166
    if seq <> cred1.seq_num then
 
167
      raise(Xdr.Xdr_format "Rpc_auth_gssapi: bad sequence number");
 
168
    dlog "integrity_decoder returns normally";
 
169
    (Xdr_mstring.concat_mstrings args, xdr_len)
 
170
      (* This "concat" is hard to avoid. We are still decoding strings,
 
171
         not mstrings.
 
172
       *)
 
173
  with
 
174
    | Xdr.Xdr_format _ as e ->
 
175
        raise e
 
176
    | e ->
 
177
        raise(Xdr.Xdr_format
 
178
                "Rpc_auth_gssapi: cannot decode integrity-proctected message")
 
179
 
 
180
 
 
181
let privacy_encoder (gss_api : Netgssapi.gss_api)
 
182
                     ctx is_server cred1 rpc_gss_priv_data s =
 
183
  dlog "privacy_encoder";
 
184
  let data =
 
185
    Xdr_mstring.string_to_mstring 
 
186
      (Rtypes.uint4_as_string cred1.seq_num) ::  s in
 
187
  gss_api # wrap
 
188
    ~context:ctx
 
189
    ~conf_req:true
 
190
    ~qop_req:None
 
191
    ~input_message:data
 
192
    ~output_message_preferred_type:`String
 
193
    ~out:(fun ~conf_state ~output_message ~minor_status ~major_status () ->
 
194
            try
 
195
              let (c_err, r_err, flags) = major_status in
 
196
              if c_err <> `None || r_err <> `None then (
 
197
                failwith("Rpc_auth_gssapi: \
 
198
                          Cannot wrap message: " ^ 
 
199
                           string_of_major_status major_status);
 
200
              );
 
201
              if not conf_state then
 
202
                failwith
 
203
                  "Rpc_auth_gssapi: no privacy-ensuring wrapping possible";
 
204
  (* The commented out code block performs two superflous string copies.
 
205
     We avoid this by doing the XDR-ing manually.
 
206
   *)
 
207
              let priv_len = Xdr_mstring.length_mstrings output_message in
 
208
              let priv_decolen = Xdr.get_string_decoration_size priv_len omax in
 
209
              let priv_hdr = 
 
210
                Rtypes.uint4_as_string (Rtypes.uint4_of_int priv_len) in
 
211
              let priv_padlen = priv_decolen - 4 in
 
212
              let priv_pad = String.make priv_padlen '\000' in
 
213
              [ Xdr_mstring.string_to_mstring priv_hdr ] @
 
214
                output_message @
 
215
                [ Xdr_mstring.string_to_mstring priv_pad ]
 
216
(*
 
217
              let priv =
 
218
                { databody_priv = output_message } in
 
219
              let xdr_val = Rpc_auth_gssapi_aux._of_rpc_gss_priv_data priv in
 
220
              Xdr.pack_xdr_value_as_mstring xdr_val rpc_gss_priv_data []
 
221
 *)
 
222
            with
 
223
              | (Failure s | Xdr.Xdr_failure s) when is_server ->
 
224
                  (* The RFC demands that no response is sent if a
 
225
                     wrap problem occurs in the server
 
226
                   *)
 
227
                  Netlog.log `Err s;
 
228
                  raise Rpc_server.Late_drop
 
229
         )
 
230
    ()
 
231
 
 
232
let privacy_decoder (gss_api : Netgssapi.gss_api)
 
233
                     ctx is_server cred1 rpc_gss_priv_data s pos len =
 
234
  dlog "privacy_decoder";
 
235
  try
 
236
    let xdr_val, xdr_len =
 
237
      Xdr.unpack_xdr_value_l
 
238
        ~pos ~len ~fast:true ~prefix:true s rpc_gss_priv_data 
 
239
        ~mstring_factories:ms_factories
 
240
        [] in
 
241
    let priv =
 
242
      _to_rpc_gss_priv_data xdr_val in
 
243
    let data =
 
244
      priv.databody_priv in
 
245
    (* In the server, any integrity problem should be mapped
 
246
       to GARBAGE. We get this by raising Xdr_format exceptions here.
 
247
     *)
 
248
    gss_api # unwrap
 
249
      ~context:ctx
 
250
      ~input_message:[data]
 
251
      ~output_message_preferred_type:`String
 
252
      ~out:(fun ~output_message ~conf_state ~qop_state ~minor_status 
 
253
              ~major_status
 
254
              () ->
 
255
                let (c_err, r_err, flags) = major_status in
 
256
                if c_err <> `None || r_err <> `None then
 
257
                  raise(Xdr.Xdr_format
 
258
                          ("Rpc_auth_gssapi: \
 
259
                            Cannot unwrap message: " ^ 
 
260
                             string_of_major_status major_status));
 
261
                if not conf_state then
 
262
                  raise
 
263
                    (Xdr.Xdr_format
 
264
                       "Rpc_auth_gssapi: no privacy-ensuring unwrapping \
 
265
                        possible");
 
266
                let (seq, args) =
 
267
                  split_rpc_gss_data_t output_message in
 
268
                if seq <> cred1.seq_num then
 
269
                  raise(Xdr.Xdr_format "Rpc_auth_gssapi: bad sequence number");
 
270
                dlog "privacy_decoder returns normally";
 
271
                (Xdr_mstring.concat_mstrings args, xdr_len)
 
272
           )
 
273
      ()
 
274
  with
 
275
    | Xdr.Xdr_format _ as e ->
 
276
        raise e
 
277
    | e ->
 
278
        raise(Xdr.Xdr_format
 
279
                "Rpc_auth_gssapi: cannot decode privacy-proctected message")
 
280
 
 
281
 
 
282
let init_window n =
 
283
  let n' = ((n-1) / 8) + 1 in
 
284
  { window = String.make n' '\000';
 
285
    window_length = 0L;
 
286
    window_offset = 0;
 
287
    window_last = 0L;
 
288
  }
 
289
 
 
290
 
 
291
let check_seq_num w seq_num =
 
292
  (* The interpretation is as follows:
 
293
     - The window starts at window_last - window_length + 1
 
294
     - The window ends at window_last
 
295
     - The string window is seen as a bit string
 
296
     - The first bit of the window is mapped to the bit window_offset
 
297
       in window
 
298
 
 
299
     returns true if the seq num is ok
 
300
   *)
 
301
  let l = String.length w.window * 8 in
 
302
  let lL = Int64.of_int l in
 
303
  let seq_numL = Rtypes.int64_of_uint4 seq_num in
 
304
  if w.window_length = 0L then (
 
305
    (* initialization. Assume ctx.ctx_window is filled with zeros *)
 
306
    if seq_numL >= lL then
 
307
      w.window_length <- lL
 
308
    else
 
309
      w.window_length <- Int64.succ seq_numL;
 
310
    w.window_offset <- 0;
 
311
    w.window_last <- seq_numL;
 
312
    let n2 = Int64.to_int w.window_length - 1 in
 
313
    let k = n2 lsr 3 in
 
314
    let j = n2 land 7 in
 
315
    let c = Char.code w.window.[k] in
 
316
    let c' =  c lor (1 lsl j) in
 
317
    w.window.[k] <- Char.chr c';
 
318
    true
 
319
  )
 
320
  else
 
321
    if seq_numL > w.window_last then (
 
322
      (* all ok, just advance the window *)
 
323
      while seq_numL > w.window_last do
 
324
        let next = Int64.succ w.window_last in
 
325
        if w.window_length < lL then
 
326
          w.window_length <- Int64.succ w.window_length
 
327
        else
 
328
          w.window_offset <- (succ w.window_offset) mod l;
 
329
        let n2 = 
 
330
          (w.window_offset + Int64.to_int w.window_length - 1) mod l in
 
331
        let k = n2 lsr 3 in
 
332
        let j = n2 land 7 in
 
333
        let c = Char.code w.window.[k] in
 
334
        let c' = 
 
335
          if seq_numL = next then
 
336
            c lor (1 lsl j) 
 
337
        else
 
338
          c land (lnot (1 lsl j)) in
 
339
        w.window.[k] <- Char.chr c';
 
340
        w.window_last <- next
 
341
      done;
 
342
      true
 
343
    ) else
 
344
      let before_start =
 
345
        Int64.sub w.window_last w.window_length in
 
346
      seq_numL > before_start && (
 
347
        let n1 = Int64.to_int (Int64.pred (Int64.sub seq_numL before_start)) in
 
348
        let n2 = (w.window_offset + n1) mod l in
 
349
        let k = n2 lsr 3 in
 
350
        let j = n2 land 7 in
 
351
        let c = Char.code w.window.[k] in
 
352
        let ok = (c land (1 lsl j)) = 0 in
 
353
        if ok then (
 
354
          let c' = c lor (1 lsl j) in
 
355
          w.window.[k] <- Char.chr c';
 
356
        );
 
357
        ok
 
358
      )
 
359
 
 
360
 
 
361
let server_auth_method 
 
362
      ?(require_privacy=false)
 
363
      ?(require_integrity=false)
 
364
      ?(shared_context=false)
 
365
      ?acceptor_cred
 
366
      ?(user_name_format = `Prefixed_name)
 
367
      ?seq_number_window
 
368
      (gss_api : gss_api) mech : Rpc_server.auth_method =
 
369
 
 
370
  let acceptor_cred =
 
371
    match acceptor_cred with
 
372
      | None ->
 
373
          gss_api # acquire_cred
 
374
            ~desired_name:gss_api#no_name
 
375
            ~time_req:`None
 
376
            ~desired_mechs:[mech]
 
377
            ~cred_usage:`Accept
 
378
            ~out:(
 
379
              fun ~cred ~actual_mechs ~time_rec ~minor_status ~major_status() ->
 
380
                let (c_err, r_err, flags) = major_status in
 
381
                if c_err <> `None || r_err <> `None then
 
382
                  failwith("Rpc_auth_gssapi: Cannot acquire default creds: " ^ 
 
383
                             string_of_major_status major_status);
 
384
                cred
 
385
            )
 
386
            ()
 
387
      | Some c -> c in
 
388
 
 
389
  let rpc_gss_cred_t =
 
390
    Xdr.validate_xdr_type
 
391
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_cred_t in
 
392
 
 
393
  let rpc_gss_init_arg =
 
394
    Xdr.validate_xdr_type
 
395
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_init_arg in
 
396
 
 
397
  let rpc_gss_init_res =
 
398
    Xdr.validate_xdr_type
 
399
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_init_res in
 
400
 
 
401
  let rpc_gss_integ_data =
 
402
    Xdr.validate_xdr_type
 
403
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_integ_data in
 
404
 
 
405
  let rpc_gss_priv_data =
 
406
    Xdr.validate_xdr_type
 
407
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_priv_data in
 
408
 
 
409
        
 
410
  let ctx_by_handle = Hashtbl.create 42 in
 
411
 
 
412
  let handle_nr = ref 0 in
 
413
 
 
414
  let new_handle() =
 
415
    let n = !handle_nr in
 
416
    incr handle_nr;
 
417
    let random = String.make 16 '\000' in
 
418
    Netsys_rng.fill_random random;
 
419
    sprintf "%6d_%s" n (Digest.to_hex random) in
 
420
 
 
421
  ( object(self)
 
422
      method name = "RPCSEC_GSS"
 
423
 
 
424
      method flavors = [ "RPCSEC_GSS" ]
 
425
 
 
426
      method peek = `None
 
427
 
 
428
      method authenticate srv conn_id (details:Rpc_server.auth_details) auth =
 
429
        dlog "authenticate";
 
430
        (* First decode the rpc_gss_cred_t structure in the header: *)
 
431
        try
 
432
          let (_, cred_data) = details # credential in
 
433
          let xdr_val =
 
434
            try
 
435
              Xdr.unpack_xdr_value
 
436
                ~fast:true
 
437
                cred_data
 
438
                rpc_gss_cred_t
 
439
                [] 
 
440
            with _ ->
 
441
              (* Bad credential *)
 
442
              raise(Rpc.Rpc_server Rpc.Auth_bad_cred) in
 
443
          let cred =
 
444
            _to_rpc_gss_cred_t xdr_val in
 
445
          match cred with
 
446
            | `_1 cred1 ->
 
447
                let r =
 
448
                  match cred1.gss_proc with
 
449
                    | `rpcsec_gss_init ->
 
450
                        self # auth_init srv conn_id details cred1
 
451
                    | `rpcsec_gss_continue_init ->
 
452
                        self # auth_cont_init srv conn_id details cred1
 
453
                    | `rpcsec_gss_destroy ->
 
454
                        self # auth_destroy srv conn_id details cred1
 
455
                    | `rpcsec_gss_data ->
 
456
                        self # auth_data srv conn_id details cred1
 
457
                in
 
458
                let () = auth r in
 
459
                dlog "authenticate returns normally";
 
460
                ()
 
461
        with
 
462
          | Rpc.Rpc_server code ->
 
463
              auth(Rpc_server.Auth_negative code)
 
464
          | error ->
 
465
              Netlog.logf `Err
 
466
                "Failed RPC authentication (GSS-API): %s"
 
467
                (Netexn.to_string error);
 
468
              auth(Rpc_server.Auth_negative Rpc.Auth_failed)
 
469
 
 
470
      method private get_token details =
 
471
        let body_data =
 
472
          Rpc_packer.unpack_call_body_raw
 
473
            details#message details#frame_len in
 
474
        let xdr_val =
 
475
          Xdr.unpack_xdr_value
 
476
            ~fast:true
 
477
            body_data
 
478
            rpc_gss_init_arg
 
479
            [] in
 
480
        let token_struct =
 
481
          _to_rpc_gss_init_arg xdr_val in
 
482
        token_struct.gss_token
 
483
 
 
484
 
 
485
      method private fixup_svc_flags ctx ret_flags =
 
486
        let have_privacy = List.mem `Conf_flag ret_flags in
 
487
        let have_integrity = List.mem `Integ_flag ret_flags in
 
488
        
 
489
        if require_privacy && not have_privacy then
 
490
          failwith
 
491
            "Rpc_auth_gssapi: Privacy requested but unavailable";
 
492
        if require_integrity && not have_integrity then
 
493
          failwith
 
494
            "Rpc_auth_gssapi: Integrity requested but unavailable";
 
495
 
 
496
        ctx.ctx_svc_none      <- not require_privacy && not require_integrity;
 
497
        ctx.ctx_svc_integrity <- not require_privacy && have_integrity;
 
498
        ctx.ctx_svc_privacy   <- have_privacy;
 
499
 
 
500
 
 
501
      method private verify_context ctx conn_id =
 
502
        ( match ctx.ctx_conn_id with
 
503
            | None -> ()
 
504
            | Some id ->
 
505
                if id <> conn_id then
 
506
                  failwith "Rpc_auth_gssapi: this context is unavailable \
 
507
                            to this connection"
 
508
        )
 
509
          (* CHECK: do we need to inquire_context, and to check whether
 
510
             the context is fully established?
 
511
           *)
 
512
 
 
513
      method private get_user ctx =
 
514
        let name =
 
515
          gss_api # inquire_context
 
516
            ~context:ctx.context
 
517
            ~out:(fun ~src_name ~targ_name ~lifetime_req ~mech_type
 
518
                    ~ctx_flags ~locally_initiated ~is_open 
 
519
                    ~minor_status ~major_status
 
520
                    ()
 
521
                    ->
 
522
                      let (c_err, r_err, flags) = major_status in
 
523
                      if c_err <> `None || r_err <> `None then
 
524
                        failwith("Rpc_auth_gssapi: Cannot extract name: " 
 
525
                                   ^ string_of_major_status major_status);
 
526
                      if not is_open then
 
527
                        failwith("Rpc_auth_gssapi: get_user: context is not \
 
528
                               fully established");
 
529
                      src_name
 
530
                        (* this is guaranteed to be a mechanism name (MN),
 
531
                           so it is already canonicalized
 
532
                         *)
 
533
               )
 
534
          () in
 
535
        if user_name_format = `Exported_name then
 
536
          gss_api # export_name
 
537
            ~name
 
538
            ~out:(fun ~exported_name ~minor_status ~major_status () ->
 
539
                    let (c_err, r_err, flags) = major_status in
 
540
                    if c_err <> `None || r_err <> `None then
 
541
                      failwith("Rpc_auth_gssapi: Cannot export name: " 
 
542
                               ^ string_of_major_status major_status);
 
543
                    exported_name
 
544
                 )
 
545
            ()
 
546
        else (
 
547
          gss_api # display_name
 
548
            ~input_name:name
 
549
            ~out:(fun ~output_name ~output_name_type ~minor_status ~major_status
 
550
                    () ->
 
551
                      match user_name_format with
 
552
                        | `Exported_name -> assert false
 
553
                        | `Prefixed_name ->
 
554
                            let oid_s =
 
555
                              Netgssapi.oid_to_string output_name_type in
 
556
                            oid_s ^ output_name
 
557
                        | `Plain_name ->
 
558
                            output_name
 
559
                 )
 
560
            ()
 
561
        )
 
562
 
 
563
 
 
564
 
 
565
      method private auth_init srv conn_id details cred1 =
 
566
        dlog "auth_init";
 
567
        let (verf_flav, verf_data) = details # verifier in
 
568
        if details#procedure <> Rtypes.uint4_of_int 0 then
 
569
          failwith "For context initialization the RPC procedure must be 0";
 
570
        if cred1.handle <> "" then
 
571
          failwith "Context handle is not empty";
 
572
        if verf_flav <> "AUTH_NONE" then
 
573
          failwith "Bad verifier (1)";
 
574
        if verf_data <> "" then
 
575
          failwith "Bad verifier (2)";
 
576
        gss_api # accept_sec_context
 
577
          ~context:None
 
578
          ~acceptor_cred
 
579
          ~input_token:(self # get_token details)
 
580
          ~chan_bindings:None
 
581
          ~out:(
 
582
            fun ~src_name ~mech_type ~output_context
 
583
              ~output_token ~ret_flags ~time_rec 
 
584
              ~delegated_cred ~minor_status ~major_status
 
585
              () ->
 
586
                let (c_err, r_err, flags) = major_status in
 
587
                if c_err <> `None || r_err <> `None then
 
588
                  failwith("Rpc_auth_gssapi: Cannot accept token: " ^ 
 
589
                             string_of_major_status major_status);
 
590
                let h = new_handle() in
 
591
                let context =
 
592
                  match output_context with
 
593
                    | None ->
 
594
                        failwith "Rpc_auth_gssapi: no context"
 
595
                    | Some c -> c in
 
596
                let cont = List.mem `Continue_needed flags in
 
597
                let ctx =
 
598
                  { context = context;
 
599
                    ctx_continue = cont;
 
600
                    ctx_handle = h;
 
601
                    ctx_conn_id = 
 
602
                      if shared_context then None else Some conn_id;
 
603
                    ctx_svc_none = false;
 
604
                    ctx_svc_integrity = false;
 
605
                    ctx_svc_privacy = false;
 
606
                    ctx_window = ( match seq_number_window with
 
607
                                     | None -> None
 
608
                                     | Some n -> Some(init_window n)
 
609
                                 );
 
610
                  } in
 
611
                if not cont then
 
612
                  self#fixup_svc_flags ctx ret_flags;
 
613
                Hashtbl.replace ctx_by_handle h ctx;
 
614
                let reply =
 
615
                  { res_handle = h;
 
616
                    res_major =
 
617
                      if ctx.ctx_continue 
 
618
                      then gss_s_continue_needed
 
619
                      else gss_s_complete;
 
620
                    res_minor = zero;
 
621
                    res_seq_window = ( match seq_number_window with
 
622
                                         | None ->
 
623
                                             maxseq
 
624
                                         | Some n -> 
 
625
                                             Rtypes.uint4_of_int n
 
626
                                     );
 
627
                    res_token = output_token
 
628
                  } in
 
629
                self # auth_init_result ctx reply
 
630
          )
 
631
          ()
 
632
 
 
633
 
 
634
      method private auth_cont_init srv conn_id details cred1 =
 
635
        dlog "auth_cont_init";
 
636
        let (verf_flav, verf_data) = details # verifier in
 
637
        if details#procedure <> Rtypes.uint4_of_int 0 then
 
638
          failwith "For context initialization the RPC procedure must be 0";
 
639
        if verf_flav <> "AUTH_NONE" then
 
640
          failwith "Bad verifier (1)";
 
641
        if verf_data <> "" then
 
642
          failwith "Bad verifier (2)";
 
643
        let h = cred1.handle in
 
644
        let ctx =
 
645
          try Hashtbl.find ctx_by_handle h
 
646
          with Not_found ->
 
647
            failwith "Rpc_auth_gssapi: unknown context handle" in
 
648
        if not ctx.ctx_continue then
 
649
          failwith "Rpc_auth_gssapi: cannot continue context establishment";
 
650
        self # verify_context ctx conn_id;
 
651
        gss_api # accept_sec_context
 
652
          ~context:(Some ctx.context)
 
653
          ~acceptor_cred
 
654
          ~input_token:(self # get_token details)
 
655
          ~chan_bindings:None
 
656
          ~out:(
 
657
            fun ~src_name ~mech_type ~output_context
 
658
              ~output_token ~ret_flags ~time_rec 
 
659
              ~delegated_cred ~minor_status ~major_status
 
660
              () ->
 
661
                let (c_err, r_err, flags) = major_status in
 
662
                if c_err <> `None || r_err <> `None then
 
663
                  failwith("Rpc_auth_gssapi: Cannot accept token: " ^ 
 
664
                             string_of_major_status major_status);
 
665
                (* CHECK: do we need to check whether output_context is
 
666
                   the current context? Can this change? 
 
667
                 *)
 
668
                ctx.ctx_continue <- List.mem `Continue_needed flags;
 
669
                if not ctx.ctx_continue then
 
670
                  self#fixup_svc_flags ctx ret_flags;
 
671
                let reply =
 
672
                  { res_handle = h;
 
673
                    res_major =
 
674
                      if ctx.ctx_continue 
 
675
                      then gss_s_continue_needed
 
676
                      else gss_s_complete;
 
677
                    res_minor = zero;
 
678
                    res_seq_window = ( match seq_number_window with
 
679
                                         | None ->
 
680
                                             maxseq
 
681
                                         | Some n -> 
 
682
                                             Rtypes.uint4_of_int n
 
683
                                     );
 
684
                    res_token = output_token
 
685
                  } in
 
686
                self # auth_init_result ctx reply
 
687
          )
 
688
          ()
 
689
 
 
690
      method private auth_init_result ctx reply =
 
691
        dlog "auth_init_result";
 
692
        let xdr_val =
 
693
          Rpc_auth_gssapi_aux._of_rpc_gss_init_res reply in
 
694
        let m =
 
695
          Xdr.pack_xdr_value_as_mstrings
 
696
            xdr_val rpc_gss_init_res [] in
 
697
        let (verf_flav, verf_data) =
 
698
          if ctx.ctx_continue  then
 
699
            ("AUTH_NONE", "")
 
700
          else
 
701
            let window_s =
 
702
              Rtypes.uint4_as_string reply.res_seq_window in
 
703
            let mic =
 
704
              gss_api # get_mic
 
705
                ~context:ctx.context
 
706
                ~qop_req:None
 
707
                ~message:[Xdr_mstring.string_to_mstring window_s]
 
708
                ~out:(fun ~msg_token ~minor_status ~major_status () ->
 
709
                        let (c_err, r_err, flags) = major_status in
 
710
                        if c_err <> `None || r_err <> `None then
 
711
                          failwith("Rpc_auth_gssapi: \
 
712
                                  Cannot compute MIC: " ^ 
 
713
                                     string_of_major_status major_status);
 
714
                        msg_token
 
715
                     )
 
716
                () in
 
717
            ("RPCSEC_GSS", mic) in
 
718
        Rpc_server.Auth_reply(m, verf_flav, verf_data)
 
719
 
 
720
      method private auth_data srv conn_id details cred1 =
 
721
        dlog "auth_data";
 
722
        (* Get context: *)
 
723
        let h = cred1.handle in
 
724
        let ctx =
 
725
          try Hashtbl.find ctx_by_handle h
 
726
          with Not_found ->
 
727
            failwith "Rpc_auth_gssapi: unknown context handle" in
 
728
        self # verify_context ctx conn_id;
 
729
 
 
730
        (* Verify the header first *)
 
731
        let (verf_flav, verf_data) = details # verifier in
 
732
        if verf_flav <> "RPCSEC_GSS" then
 
733
          failwith "Rpc_auth_gssapi: Bad type of verifier";
 
734
        let pv = details # message in
 
735
        let n = Rpc_packer.extract_call_gssapi_header pv in
 
736
        let s = Rpc_packer.prefix_of_packed_value pv n in
 
737
        
 
738
        gss_api # verify_mic
 
739
          ~context:ctx.context
 
740
          ~message:[Xdr_mstring.string_to_mstring s]
 
741
          ~token:verf_data
 
742
          ~out:(fun ~qop_state ~minor_status ~major_status () ->
 
743
                  let (c_err, r_err, flags) = major_status in
 
744
                  if c_err <> `None || r_err <> `None then
 
745
                    raise(Rpc.Rpc_server Rpc.RPCSEC_GSS_credproblem)
 
746
                      (* demanded by the RFC *)
 
747
(*
 
748
                    failwith("Rpc_auth_gssapi: \
 
749
                                  Cannot verify MIC: " ^ 
 
750
                               string_of_major_status major_status);
 
751
 *)
 
752
               )
 
753
          ();
 
754
 
 
755
        (* FIXME: we should also check here whether the credentials'
 
756
           lifetime is over, and if so, report RPCSEC_GSS_ctxproblem.
 
757
           We cannot delay this until encoding/decoding because the
 
758
           exception handling would not work by then. So it must
 
759
           happen now. I have no idea how to do so, though.
 
760
         *)
 
761
 
 
762
        (* Check sequence number *)
 
763
        if Rtypes.gt_uint4 cred1.seq_num maxseq then
 
764
          raise(Rpc.Rpc_server Rpc.RPCSEC_GSS_ctxproblem);
 
765
 
 
766
        let drop =
 
767
          match ctx.ctx_window with
 
768
            | None -> false
 
769
            | Some w ->
 
770
                not (check_seq_num w cred1.seq_num) in
 
771
 
 
772
        if drop then
 
773
          Rpc_server.Auth_drop
 
774
        else
 
775
          match cred1.service with
 
776
            | `rpc_gss_svc_none ->
 
777
                if not ctx.ctx_svc_none then
 
778
                  failwith "Rpc_auth_gssapi: unexpected unprotected message";
 
779
                self#auth_data_result ctx cred1.seq_num None None;
 
780
                
 
781
            | `rpc_gss_svc_integrity ->
 
782
                if not ctx.ctx_svc_integrity then
 
783
                  failwith "Rpc_auth_gssapi: unexpected integrity-proctected \
 
784
                          message";
 
785
                let encoder =
 
786
                  integrity_encoder 
 
787
                    gss_api ctx.context true cred1 rpc_gss_integ_data in
 
788
                let decoder =
 
789
                  integrity_decoder 
 
790
                    gss_api ctx.context true cred1 rpc_gss_integ_data in
 
791
                self#auth_data_result
 
792
                  ctx cred1.seq_num (Some encoder) (Some decoder)
 
793
                  
 
794
            | `rpc_gss_svc_privacy ->
 
795
                if not ctx.ctx_svc_privacy then
 
796
                  failwith "Rpc_auth_gssapi: unexpected privacy-proctected \
 
797
                          message";
 
798
                let encoder =
 
799
                  privacy_encoder
 
800
                    gss_api ctx.context true cred1 rpc_gss_priv_data in
 
801
                let decoder =
 
802
                  privacy_decoder gss_api ctx.context true
 
803
                    cred1 rpc_gss_priv_data in
 
804
                self # auth_data_result
 
805
                  ctx cred1.seq_num (Some encoder) (Some decoder)
 
806
                  
 
807
              
 
808
      method private auth_data_result ctx seq enc_opt dec_opt =
 
809
        dlog "auth_data_result";
 
810
        let seq_s =
 
811
          Rtypes.uint4_as_string seq in
 
812
        let mic =
 
813
          gss_api # get_mic
 
814
            ~context:ctx.context
 
815
            ~qop_req:None
 
816
            ~message:[Xdr_mstring.string_to_mstring seq_s]
 
817
            ~out:(fun ~msg_token ~minor_status ~major_status () ->
 
818
                    let (c_err, r_err, flags) = major_status in
 
819
                    if c_err <> `None || r_err <> `None then
 
820
                      raise(Rpc.Rpc_server Rpc.RPCSEC_GSS_ctxproblem);
 
821
(*
 
822
                      failwith("Rpc_auth_gssapi: \
 
823
                                  Cannot compute MIC: " ^ 
 
824
                                 string_of_major_status major_status);
 
825
 *)
 
826
                    msg_token
 
827
                 )
 
828
            () in
 
829
        Rpc_server.Auth_positive(
 
830
          self#get_user ctx,
 
831
          "RPCSEC_GSS", mic, enc_opt, dec_opt
 
832
        )
 
833
 
 
834
      method private auth_destroy srv conn_id details cred1 =
 
835
        dlog "auth_destroy";
 
836
        if details#procedure <> Rtypes.uint4_of_int 0 then
 
837
          failwith "For context destruction the RPC procedure must be 0";
 
838
        let r =
 
839
          self # auth_data srv conn_id details cred1 in
 
840
        match r with
 
841
          | Rpc_server.Auth_positive(_, flav, mic, enc_opt, dec_opt) ->
 
842
              (* Check that the input args are empty: *)
 
843
              let raw_body =
 
844
                Rpc_packer.unpack_call_body_raw 
 
845
                  details#message details#frame_len in
 
846
              let body_length =
 
847
                match dec_opt with
 
848
                  | None -> String.length raw_body
 
849
                  | Some dec -> 
 
850
                      let (b,n) = dec raw_body 0 (String.length raw_body) in
 
851
                      n in
 
852
              if body_length <> 0 then
 
853
                failwith "Rpc_auth_gssapi: invalid destroy request";
 
854
 
 
855
              (* Now destroy: *)
 
856
              let h = cred1.handle in
 
857
              Hashtbl.remove ctx_by_handle h;
 
858
              
 
859
              (* Create response: *)
 
860
              let encoded_emptiness =
 
861
                match enc_opt with
 
862
                  | None -> []
 
863
                  | Some enc -> enc [] in
 
864
 
 
865
              (* Respond: *)
 
866
              Rpc_server.Auth_reply(encoded_emptiness, flav, mic)
 
867
          | _ ->
 
868
              r
 
869
    end
 
870
  )
 
871
 
 
872
    
 
873
let client_auth_method 
 
874
      ?(privacy=`If_possible)
 
875
      ?(integrity=`If_possible)
 
876
      ?(user_name_interpretation = `Prefixed_name)
 
877
      (gss_api : gss_api) mech : Rpc_client.auth_method =
 
878
 
 
879
  let default_initiator_cred() =
 
880
    gss_api # acquire_cred
 
881
      ~desired_name:gss_api#no_name
 
882
      ~time_req:`None
 
883
      ~desired_mechs:[mech]
 
884
      ~cred_usage:`Initiate
 
885
      ~out:(
 
886
        fun ~cred ~actual_mechs ~time_rec ~minor_status ~major_status() ->
 
887
          let (c_err, r_err, flags) = major_status in
 
888
          if c_err <> `None || r_err <> `None then
 
889
            failwith("Rpc_auth_gssapi: Cannot acquire default creds: " ^ 
 
890
                       string_of_major_status major_status);
 
891
          cred
 
892
      )
 
893
      () in
 
894
 
 
895
  let rpc_gss_cred_t =
 
896
    Xdr.validate_xdr_type
 
897
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_cred_t in
 
898
 
 
899
  let rpc_gss_integ_data =
 
900
    Xdr.validate_xdr_type
 
901
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_integ_data in
 
902
 
 
903
  let rpc_gss_priv_data =
 
904
    Xdr.validate_xdr_type
 
905
      Rpc_auth_gssapi_aux.xdrt_rpc_gss_priv_data in
 
906
 
 
907
  let session (m:Rpc_client.auth_method)
 
908
              (p:Rpc_client.auth_protocol)
 
909
              ctx service handle cur_seq_num
 
910
        : Rpc_client.auth_session =
 
911
    let seq_num_of_xid = Hashtbl.create 15 in
 
912
    ( object(self)
 
913
        method next_credentials client prog proc xid =
 
914
          (* N.B. Exceptions raised here probably abort the client,
 
915
             and fall through to the event loop
 
916
           *)
 
917
 
 
918
          dlogr
 
919
            (fun () ->
 
920
               sprintf "next_credentials proc=%s xid=%Ld"
 
921
                 proc (Rtypes.int64_of_uint4 xid)
 
922
            );
 
923
 
 
924
          let cred1 =
 
925
            { gss_proc = `rpcsec_gss_data;
 
926
              seq_num = !cur_seq_num;
 
927
              service = service;
 
928
              handle = handle
 
929
            } in
 
930
          let cred1_xdr = _of_rpc_gss_cred_t (`_1 cred1) in
 
931
          let cred1_s =
 
932
            Xdr.pack_xdr_value_as_string
 
933
              cred1_xdr rpc_gss_cred_t [] in
 
934
          
 
935
          let h_pv =
 
936
            Rpc_packer.pack_call_gssapi_header
 
937
              prog xid proc "RPCSEC_GSS" cred1_s in
 
938
          let h =
 
939
            Rpc_packer.string_of_packed_value h_pv in
 
940
          let mic =
 
941
            gss_api # get_mic
 
942
              ~context:ctx
 
943
              ~qop_req:None
 
944
              ~message:[Xdr_mstring.string_to_mstring h]
 
945
              ~out:(fun ~msg_token ~minor_status ~major_status () ->
 
946
                      let (c_err, r_err, flags) = major_status in
 
947
                      if c_err <> `None || r_err <> `None then
 
948
                        failwith("Rpc_auth_gssapi: \
 
949
                          Cannot obtain MIC: " ^ 
 
950
                                   string_of_major_status major_status);
 
951
                      msg_token
 
952
                   )
 
953
              () in
 
954
 
 
955
          (* Save seq_num: *)
 
956
          Hashtbl.replace seq_num_of_xid xid !cur_seq_num;
 
957
 
 
958
          (* Increment cur_seq_num: *)
 
959
          cur_seq_num := 
 
960
            Rtypes.uint4_of_int64(
 
961
              Int64.logand
 
962
                (Int64.succ (Rtypes.int64_of_uint4 !cur_seq_num))
 
963
                0xFFFF_FFFFL
 
964
            );
 
965
 
 
966
          let enc_opt, dec_opt =
 
967
            match service with
 
968
              | `rpc_gss_svc_none ->
 
969
                  None, None
 
970
                    
 
971
              | `rpc_gss_svc_integrity ->
 
972
                  let encoder =
 
973
                    integrity_encoder 
 
974
                      gss_api ctx false cred1 rpc_gss_integ_data in
 
975
                  let decoder =
 
976
                    integrity_decoder 
 
977
                      gss_api ctx false cred1 rpc_gss_integ_data in
 
978
                  (Some encoder), (Some decoder)
 
979
 
 
980
              | `rpc_gss_svc_privacy ->
 
981
                  let encoder =
 
982
                    privacy_encoder gss_api ctx false cred1 rpc_gss_priv_data in
 
983
                  let decoder =
 
984
                    privacy_decoder gss_api ctx false cred1 rpc_gss_priv_data in
 
985
                  (Some encoder), (Some decoder) in
 
986
 
 
987
          dlogr
 
988
            (fun () ->
 
989
               sprintf "next_credentials returns normally"
 
990
            );
 
991
 
 
992
          ("RPCSEC_GSS", cred1_s,
 
993
           "RPCSEC_GSS", mic,
 
994
           enc_opt, dec_opt
 
995
          )
 
996
 
 
997
        method server_rejects client xid code =
 
998
          dlogr
 
999
            (fun () ->
 
1000
               sprintf "server_rejects xid=%Ld"
 
1001
                 (Rtypes.int64_of_uint4 xid)
 
1002
            );
 
1003
          Hashtbl.remove seq_num_of_xid xid;
 
1004
          match code with
 
1005
            | Rpc.RPCSEC_GSS_credproblem | Rpc.RPCSEC_GSS_ctxproblem ->
 
1006
                `Renew
 
1007
            | Rpc.Auth_too_weak ->
 
1008
                `Next
 
1009
            | _ ->
 
1010
                `Fail
 
1011
 
 
1012
        method server_accepts client xid verf_flav verf_data =
 
1013
          dlogr
 
1014
            (fun () ->
 
1015
               sprintf "server_accepts xid=%Ld"
 
1016
                 (Rtypes.int64_of_uint4 xid)
 
1017
            );
 
1018
          if verf_flav <> "RPCSEC_GSS" then
 
1019
            raise(Rpc.Rpc_server Rpc.Auth_invalid_resp);
 
1020
          let seq =
 
1021
            try Hashtbl.find seq_num_of_xid xid
 
1022
            with Not_found -> 
 
1023
              raise(Rpc.Rpc_server Rpc.Auth_invalid_resp) in
 
1024
          let seq_s =
 
1025
            Rtypes.uint4_as_string seq in
 
1026
          Hashtbl.remove seq_num_of_xid xid;
 
1027
          gss_api # verify_mic
 
1028
            ~context:ctx
 
1029
            ~message:[Xdr_mstring.string_to_mstring seq_s]
 
1030
            ~token:verf_data
 
1031
            ~out:(fun ~qop_state ~minor_status ~major_status () ->
 
1032
                    let (c_err, r_err, flags) = major_status in
 
1033
                    if c_err <> `None || r_err <> `None then
 
1034
                      raise(Rpc.Rpc_server Rpc.Auth_invalid_resp);
 
1035
                 )
 
1036
            ();
 
1037
          dlog "server_accepts returns normally"
 
1038
 
 
1039
        method auth_protocol = p
 
1040
 
 
1041
      end
 
1042
    ) in
 
1043
 
 
1044
  let protocol (m:Rpc_client.auth_method) client cred
 
1045
       : Rpc_client.auth_protocol =
 
1046
    let first = ref true in
 
1047
    let state = ref `Emit in
 
1048
    let ctx = ref None in
 
1049
    let input_token = ref "" in
 
1050
    let handle = ref "" in
 
1051
    let init_prog = ref None in
 
1052
    let init_service = ref None in
 
1053
 
 
1054
    let get_context() =
 
1055
      match !ctx with Some c -> c | None -> assert false in
 
1056
 
 
1057
    (* CHECK: what happens with exceptions thrown here? *)
 
1058
 
 
1059
    ( object(self)
 
1060
        method state = !state
 
1061
 
 
1062
        method emit xid prog_nr vers_nr =
 
1063
          assert(!state = `Emit);
 
1064
          dlogr
 
1065
            (fun () ->
 
1066
               sprintf "emit prog_nr=%Ld vers_nr=%Ld xid=%Ld"
 
1067
                 (Rtypes.int64_of_uint4 prog_nr)
 
1068
                 (Rtypes.int64_of_uint4 vers_nr)
 
1069
                 (Rtypes.int64_of_uint4 xid)
 
1070
            );
 
1071
          try
 
1072
            let prog =
 
1073
              match !init_prog with
 
1074
                | None ->
 
1075
                    let p =
 
1076
                      Rpc_program.create
 
1077
                        prog_nr
 
1078
                        vers_nr
 
1079
                        (Xdr.validate_xdr_type_system [])
 
1080
                        [ "init", 
 
1081
                          (  (Rtypes.uint4_of_int 0), 
 
1082
                             Rpc_auth_gssapi_aux.xdrt_rpc_gss_init_arg,
 
1083
                             Rpc_auth_gssapi_aux.xdrt_rpc_gss_init_res
 
1084
                          );
 
1085
                        ] in
 
1086
                    init_prog := Some p;
 
1087
                    p
 
1088
                | Some p -> p in
 
1089
            let req_flags =
 
1090
              ( if integrity=`If_possible || integrity=`Required then
 
1091
                  [ `Integ_flag ]
 
1092
                else
 
1093
                  []
 
1094
              ) @
 
1095
                ( if privacy=`If_possible || privacy=`Required then
 
1096
                    [ `Conf_flag ]
 
1097
                  else
 
1098
                    []
 
1099
                ) in
 
1100
            let (output_token, cont_needed, have_priv, have_integ) =
 
1101
              gss_api # init_sec_context
 
1102
                ~initiator_cred:cred
 
1103
                ~context:!ctx
 
1104
                ~target_name:gss_api#no_name 
 
1105
                ~mech_type:[||]
 
1106
                ~req_flags
 
1107
                ~time_rec:None
 
1108
                ~chan_bindings:None
 
1109
                ~input_token:(if !first then None else Some !input_token)
 
1110
                ~out:(fun ~actual_mech_type ~output_context ~output_token 
 
1111
                        ~ret_flags ~time_rec ~minor_status ~major_status
 
1112
                        () ->
 
1113
                          let (c_err, r_err, flags) = major_status in
 
1114
                          if c_err <> `None || r_err <> `None then
 
1115
                            failwith("Rpc_auth_gssapi: Cannot init sec ctx: " ^ 
 
1116
                                       string_of_major_status major_status);
 
1117
                          ctx := output_context;
 
1118
                          (output_token, 
 
1119
                           List.mem `Continue_needed flags,
 
1120
                           List.mem `Conf_flag ret_flags,
 
1121
                           List.mem `Integ_flag ret_flags
 
1122
                          )
 
1123
                     )
 
1124
                () in
 
1125
            let service_i =
 
1126
              match integrity with
 
1127
                | `Required ->
 
1128
                    if not have_integ && not have_priv then
 
1129
                      failwith "Rpc_auth_gssapi: Integrity is not available";
 
1130
                    `rpc_gss_svc_integrity
 
1131
                | `If_possible ->
 
1132
                    if have_integ then
 
1133
                      `rpc_gss_svc_integrity
 
1134
                    else
 
1135
                      `rpc_gss_svc_none
 
1136
                | `None ->
 
1137
                    `rpc_gss_svc_none in
 
1138
            let service =
 
1139
              match privacy with
 
1140
                | `Required ->
 
1141
                    if not have_priv then
 
1142
                      failwith "Rpc_auth_gssapi: Privacy is not available";
 
1143
                    `rpc_gss_svc_privacy
 
1144
                | `If_possible ->
 
1145
                    if have_priv then
 
1146
                      `rpc_gss_svc_privacy
 
1147
                    else
 
1148
                      service_i
 
1149
                | `None ->
 
1150
                    service_i in
 
1151
            init_service := Some service;
 
1152
            let cred1 =
 
1153
              `_1 { gss_proc = ( if !first then `rpcsec_gss_init
 
1154
                                 else `rpcsec_gss_continue_init );
 
1155
                    seq_num = Rtypes.uint4_of_int 0;  (* FIXME *)
 
1156
                    service = service;
 
1157
                    handle = !handle
 
1158
                  } in
 
1159
            let cred1_xdr = _of_rpc_gss_cred_t cred1 in
 
1160
            let cred1_s =
 
1161
              Xdr.pack_xdr_value_as_string
 
1162
                cred1_xdr rpc_gss_cred_t [] in
 
1163
            let pv =
 
1164
              Rpc_packer.pack_call
 
1165
                prog xid "init"
 
1166
                "RPCSEC_GSS" cred1_s
 
1167
                "AUTH_NONE" ""
 
1168
                (Xdr.XV_struct_fast [| Xdr.XV_opaque output_token |] ) in
 
1169
            first := false;
 
1170
            state := `Receive xid;
 
1171
            dlog "emit returns normally";
 
1172
            pv
 
1173
          with error ->
 
1174
            Netlog.logf `Err
 
1175
              "Rpc_auth_gssapi: Error during message preparation: %s"
 
1176
              (Netexn.to_string error);
 
1177
            state := `Error;
 
1178
            raise error
 
1179
 
 
1180
 
 
1181
        method receive pv =
 
1182
          try
 
1183
            dlog "receive";
 
1184
            let prog =
 
1185
              match !init_prog with
 
1186
                | None -> assert false
 
1187
                | Some p -> p in
 
1188
            let (xid, flav_name, flav_data, result_xdr) =
 
1189
              Rpc_packer.unpack_reply prog "init" pv in
 
1190
            assert( !state = `Receive xid );
 
1191
 
 
1192
            dlogr
 
1193
              (fun () ->
 
1194
                 sprintf "receive xid=%Ld"
 
1195
                   (Rtypes.int64_of_uint4 xid)
 
1196
              );
 
1197
            
 
1198
            let res = _to_rpc_gss_init_res result_xdr in
 
1199
            let cont_needed =
 
1200
              res.res_major = gss_s_continue_needed in
 
1201
            
 
1202
            if not cont_needed && res.res_major <> gss_s_complete then
 
1203
              failwith
 
1204
                (sprintf "Rpc_auth_gssapi: Got GSS-API error code %Ld"
 
1205
                   (Rtypes.int64_of_uint4 res.res_major));
 
1206
            
 
1207
            if cont_needed then (
 
1208
              if flav_name <> "AUTH_NONE" || flav_data <> "" then
 
1209
                failwith "Rpc_auth_gssapi: bad verifier";
 
1210
            )
 
1211
            else (
 
1212
              if flav_name <> "RPCSEC_GSS" then
 
1213
                failwith "Rpc_auth_gssapi: bad verifier";
 
1214
              let window_s =
 
1215
                Rtypes.uint4_as_string res.res_seq_window in
 
1216
              gss_api # verify_mic
 
1217
                ~context:(get_context())
 
1218
                ~message:[Xdr_mstring.string_to_mstring window_s]
 
1219
                ~token:flav_data
 
1220
                ~out:(fun ~qop_state ~minor_status ~major_status () ->
 
1221
                        let (c_err, r_err, flags) = major_status in
 
1222
                        if c_err <> `None || r_err <> `None then
 
1223
                          failwith("Rpc_auth_gssapi: \
 
1224
                                  Cannot verify MIC: " ^ 
 
1225
                                     string_of_major_status major_status);
 
1226
                        ()
 
1227
                     )
 
1228
                ()
 
1229
            );
 
1230
            
 
1231
            handle := res.res_handle;     
 
1232
            input_token := res.res_token;
 
1233
            
 
1234
            if cont_needed then
 
1235
              state := `Emit
 
1236
            else
 
1237
              let c = get_context () in
 
1238
              let service =
 
1239
                match !init_service with Some s -> s | None -> assert false in
 
1240
              let cs = ref (Rtypes.uint4_of_int 0) in
 
1241
              let s = 
 
1242
                session 
 
1243
                  m (self :> Rpc_client.auth_protocol) c service !handle cs in
 
1244
              state := `Done s;
 
1245
              dlog "receive returns normally";
 
1246
          with error ->
 
1247
            Netlog.logf `Err
 
1248
              "Rpc_auth_gssapi: Error during message verification: %s"
 
1249
              (Netexn.to_string error);
 
1250
            state := `Error;
 
1251
            raise error
 
1252
 
 
1253
        method auth_method = m
 
1254
 
 
1255
      end
 
1256
    ) in
 
1257
 
 
1258
  ( object(self)
 
1259
      method name = "RPCSEC_GSS"
 
1260
 
 
1261
      method new_session client user_opt =
 
1262
        dlogr
 
1263
          (fun () ->
 
1264
             sprintf "new_session user=%s"
 
1265
               (match user_opt with
 
1266
                  | None -> "-" | Some u -> u
 
1267
               )
 
1268
          );
 
1269
 
 
1270
        let cred =
 
1271
          match user_opt with
 
1272
            | None ->
 
1273
                default_initiator_cred()
 
1274
            | Some user ->
 
1275
                let (input_name, input_name_type) =
 
1276
                  match user_name_interpretation with
 
1277
                    | `Exported_name ->
 
1278
                        (user, nt_export_name)
 
1279
                    | `Prefixed_name ->
 
1280
                        let l = String.length user in
 
1281
                        ( try
 
1282
                            let k = String.index user '}' in
 
1283
                            let oid = string_to_oid (String.sub user 0 (k+1)) in
 
1284
                            let n = String.sub user (k+1) (l-k-1) in
 
1285
                            (n, oid)
 
1286
                          with _ ->
 
1287
                            failwith
 
1288
                              ("Rpc_auth_gssapi: cannot parse user name")
 
1289
                        )
 
1290
                    | `Plain_name input_name_type ->
 
1291
                        (user, input_name_type) in
 
1292
                let name =
 
1293
                  gss_api # import_name
 
1294
                    ~input_name
 
1295
                    ~input_name_type
 
1296
                    ~out:(fun ~output_name ~minor_status ~major_status
 
1297
                            () ->
 
1298
                              let (c_err, r_err, flags) = major_status in
 
1299
                              if c_err <> `None || r_err <> `None then
 
1300
                                failwith
 
1301
                                  ("Rpc_auth_gssapi: Cannot import name: "
 
1302
                                   ^ string_of_major_status major_status);
 
1303
                              output_name
 
1304
                         )
 
1305
                    () in
 
1306
                gss_api # acquire_cred
 
1307
                  ~desired_name:name
 
1308
                  ~time_req:`None
 
1309
                  ~desired_mechs:[mech]
 
1310
                  ~cred_usage:`Initiate
 
1311
                  ~out:(
 
1312
                    fun ~cred ~actual_mechs ~time_rec ~minor_status
 
1313
                      ~major_status
 
1314
                      () ->
 
1315
                        let (c_err, r_err, flags) = major_status in
 
1316
                        if c_err <> `None || r_err <> `None then
 
1317
                          failwith
 
1318
                            ("Rpc_auth_gssapi: Cannot acquire default creds: " 
 
1319
                             ^ string_of_major_status major_status);
 
1320
                        cred
 
1321
                  )
 
1322
                  () in
 
1323
        protocol (self :> Rpc_client.auth_method) client cred
 
1324
 
 
1325
    end
 
1326
  )