Skip to content

Commit 1e887dd

Browse files
authored
CP-312368: Query subject group information from xapi db (#7017)
In XSI-2198, user login failed due to wbinfo failed to report subject details. However, this information is available in db To fix the problem, we enhance as follows - First try to find the details in xapi db - If not found, try wbinfo - Raise Error if neither got the details. Note: the wbinfo is required during subject-add where xapi db does not hve the details.
2 parents 828c31b + 0d4c780 commit 1e887dd

1 file changed

Lines changed: 79 additions & 43 deletions

File tree

ocaml/xapi/extauth_plugin_ADwinbind.ml

Lines changed: 79 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ let ( let@ ) = ( @@ )
3333

3434
let ( <!> ) x f = Rresult.R.reword_error f x
3535

36-
let ( >>| ) = Rresult.( >>| )
37-
3836
let min_debug_level = 0
3937

4038
let max_debug_level = 10
@@ -563,37 +561,9 @@ module Wbinfo = struct
563561
let* stdout = call_wbinfo args in
564562
Ok (String.trim stdout)
565563

566-
type name = User of string | Other of string
567-
568-
let string_of_name = function User x -> x | Other x -> x
569-
570-
let name_of_sid =
571-
(* example:
572-
* $ wbinfo -s S-1-5-21-3143668282-2591278241-912959342-502
573-
CONNAPP\krbtgt 1 *)
574-
(* the number returned after the name is the 'SID type' (grep for wbcSidType
575-
* in samba source code). for our purposes, it is sufficient to assume that
576-
* everything that is not a user is some 'other' type*)
577-
let regex = Re.Perl.(compile (re {|^([^\s].*)\ (\d+)\s*$|})) in
578-
let get_regex_match x =
579-
Option.bind (Re.exec_opt regex x) (fun g ->
580-
match Re.Group.all g with
581-
| [|_; name; "1"|] ->
582-
Some (User name)
583-
| [|_; name; _|] ->
584-
Some (Other name)
585-
| _ ->
586-
None
587-
)
588-
in
589-
fun sid ->
590-
let args = ["--sid-to-name"; sid] in
591-
let* stdout = call_wbinfo args in
592-
match get_regex_match stdout with
593-
| None ->
594-
Error (parsing_ex args)
595-
| Some x ->
596-
Ok x
564+
let sid_to_name sid =
565+
let args = ["--sid-to-name"; sid] in
566+
call_wbinfo args
597567

598568
let gid_of_sid sid =
599569
let args = ["--sid-to-gid"; sid] in
@@ -659,6 +629,70 @@ module Wbinfo = struct
659629
parse_uid_info stdout <!> fun () -> parsing_ex args
660630
end
661631

632+
module Subject = struct
633+
type t = User of string | Group of string
634+
635+
let string_of_subject = function User x -> x | Group x -> x
636+
637+
let from_wbinfo =
638+
(* example:
639+
* $ wbinfo -s S-1-5-21-3143668282-2591278241-912959342-502
640+
CONNAPP\krbtgt 1 *)
641+
(* the number returned after the name is the 'SID type' (grep for wbcSidType
642+
* in samba source code). for our purposes, it is sufficient to assume that
643+
* everything that is not a user is some 'other' type*)
644+
let regex = Re.Perl.(compile (re {|^([^\s].*)\s+(\d+)\s*$|})) in
645+
let parse_name input sid =
646+
match Re.exec_opt regex input with
647+
| Some g -> (
648+
match Re.Group.all g with
649+
| [|_; name; "1"|] ->
650+
Ok (User name)
651+
| [|_; name; _|] ->
652+
Ok (Group name)
653+
| _ ->
654+
Error (generic_ex "Failed to parse output '%s' for sid %s" input sid)
655+
)
656+
| None ->
657+
Error (generic_ex "Failed to parse output '%s' for sid %s" input sid)
658+
in
659+
fun sid ->
660+
let* stdout = Wbinfo.sid_to_name sid in
661+
parse_name stdout sid
662+
663+
let from_db ~__context sid =
664+
let open Xapi_database.Db_filter_types in
665+
match
666+
Db.Subject.get_records_where ~__context
667+
~expr:(Eq (Field "subject_identifier", Literal sid))
668+
with
669+
| (_, r) :: _ ->
670+
let other_config = r.API.subject_other_config in
671+
let* name =
672+
List.assoc_opt "subject-name" other_config
673+
|> Option.to_result
674+
~none:(generic_ex "subject-name not found in db for sid %s" sid)
675+
in
676+
677+
List.assoc_opt "subject-is-group" other_config
678+
|> Option.map (fun s ->
679+
match String.lowercase_ascii s with
680+
| "true" ->
681+
Group name
682+
| _ ->
683+
User name
684+
)
685+
|> Option.to_result
686+
~none:(generic_ex "subject-is-group not found in db for sid %s" sid)
687+
| [] ->
688+
Error (generic_ex "Subject not found in db for sid %s" sid)
689+
690+
let ( ||| ) a b = match a with Ok _ -> a | Error _ -> b
691+
692+
let of_sid ~__context sid =
693+
from_db ~__context sid ||| from_wbinfo sid |> maybe_raise
694+
end
695+
662696
module Migrate_from_pbis = struct
663697
(* upgrade-pbis-to-winbind handles most of the migration from PBIS database
664698
* to winbind database
@@ -1344,14 +1378,14 @@ module AuthADWinbind : Auth_signature.AUTH_MODULE = struct
13441378
(Printf.sprintf "couldn't get SID from username='%s'" uname)
13451379
in
13461380
let* () =
1347-
match Wbinfo.name_of_sid sid >>| Wbinfo.string_of_name with
1348-
| Error e ->
1381+
match Subject.of_sid ~__context sid |> Subject.string_of_subject with
1382+
| uname ->
1383+
Wbinfo.kerberos_auth uname password
1384+
| exception e ->
13491385
D.warn
13501386
"authenticate_username_password: trying original uname. ex: %s"
13511387
(Printexc.to_string e) ;
13521388
Wbinfo.kerberos_auth orig_uname password
1353-
| Ok uname ->
1354-
Wbinfo.kerberos_auth uname password
13551389
in
13561390
Ok sid
13571391
)
@@ -1459,17 +1493,19 @@ module AuthADWinbind : Auth_signature.AUTH_MODULE = struct
14591493
it's a string*string list anyway for possible future expansion.
14601494
Raises Not_found (*Subject_cannot_be_resolved*) if subject_id cannot be resolved by external auth service
14611495
*)
1496+
(* Fallback uid/gid when the winbind daemon fails to resolve the SID *)
1497+
let invalid_id = -1
1498+
14621499
let query_subject_information ~__context (sid : string) =
14631500
let@ __context = Context.with_tracing ~__context __FUNCTION__ in
14641501
let res =
1465-
let* name = Wbinfo.name_of_sid sid in
1466-
match name with
1467-
| User _ ->
1468-
let* uid = Wbinfo.uid_of_sid sid in
1502+
match Subject.of_sid ~__context sid with
1503+
| Subject.User _ ->
1504+
let uid = Wbinfo.uid_of_sid sid |> Result.value ~default:invalid_id in
14691505
query_subject_information_user uid sid
1470-
| Other name ->
1506+
| Subject.Group name ->
14711507
(* if the name doesn't correspond to a user then it ought to be a group *)
1472-
let* gid = Wbinfo.gid_of_sid sid in
1508+
let gid = Wbinfo.gid_of_sid sid |> Result.value ~default:invalid_id in
14731509
Ok (query_subject_information_group name gid sid)
14741510
in
14751511
(* we must raise Not_found here. see xapi_pool.ml:revalidate_subjects *)

0 commit comments

Comments
 (0)