@@ -36,10 +36,15 @@ let ( <!> ) x f = Rresult.R.reword_error f x
3636
3737let ( >> | ) = Rresult. ( >> | )
3838
39+ let min_debug_level = 0
40+
3941let max_debug_level = 10
4042
4143let default_debug_level = 2
4244
45+ let clamp v ~low ~high ~default =
46+ match v with n when n > = low && n < = high -> n | _ -> default
47+
4348let maybe_raise (x : ('a, exn) result ) : 'a =
4449 match x with Ok x -> x | Error e -> raise e
4550
@@ -69,13 +74,10 @@ let tdb_tool = !Xapi_globs.tdb_tool
6974
7075let domain_krb5_dir = Filename. concat Xapi_globs. samba_dir " lock/smb_krb5"
7176
72- let debug_level =
73- ( match ! Xapi_globs. winbind_debug_level with
74- | n when n > = 0 && n < = max_debug_level ->
75- n
76- | _ ->
77- default_debug_level
78- )
77+ let debug_level () =
78+ clamp
79+ ! Xapi_globs. winbind_debug_level
80+ ~low: min_debug_level ~high: max_debug_level ~default: default_debug_level
7981 |> string_of_int
8082
8183let err_msg_to_tag_map =
@@ -108,8 +110,11 @@ let is_samba_updated =
108110let kerberos_opt =
109111 match is_samba_updated with true -> [] | false -> [" --kerberos" ]
110112
111- (* Global cache for netbios name to domain name mapping *)
112- let domain_netbios_name_map : (string, string) Hashtbl.t = Hashtbl. create 10
113+ (* Global cache for netbios name to domain name mapping using atomic map for thread safety *)
114+ module StringMap = Map. Make (String )
115+
116+ let domain_netbios_name_map : string StringMap.t Atomic.t =
117+ Atomic. make StringMap. empty
113118
114119let krb5_conf_path ~domain_netbios =
115120 Filename. concat domain_krb5_dir (Printf. sprintf " krb5.conf.%s" domain_netbios)
@@ -414,7 +419,7 @@ module Ldap = struct
414419 ; " sid"
415420 ; sid
416421 ; " -d"
417- ; debug_level
422+ ; debug_level ()
418423 ; " --server"
419424 ; kdc
420425 ; " --machine-pass"
@@ -438,7 +443,7 @@ module Ldap = struct
438443 domain_netbios
439444 in
440445 let args =
441- [" ads" ; " search" ; " -d" ; debug_level; " --machine-pass" ; query; key]
446+ [" ads" ; " search" ; " -d" ; debug_level () ; " --machine-pass" ; query; key]
442447 in
443448 try
444449 Helpers. call_script ~env ! Xapi_globs. net_cmd args
@@ -452,7 +457,7 @@ module Ldap = struct
452457 (* Escape name to avoid injection detection *)
453458 let query = Printf. sprintf " (|(sAMAccountName=%s)(name=%s))" name name in
454459 let args =
455- [" ads" ; " search" ; " -d" ; debug_level; " --server" ; kdc; " --machine-pass" ]
460+ [" ads" ; " search" ; " -d" ; debug_level () ; " --server" ; kdc; " --machine-pass" ]
456461 @ kerberos_opt
457462 @ [query; key]
458463 in
741746let kdcs_of_domain domain =
742747 try
743748 Helpers. call_script ~log_output: On_failure net_cmd
744- ([" lookup" ; " kdc" ; domain; " -d" ; debug_level] @ kerberos_opt)
749+ ([" lookup" ; " kdc" ; domain; " -d" ; debug_level () ] @ kerberos_opt)
745750 (* Result like 10.71.212.25:88\n10.62.1.25:88\n*)
746751 |> String. split_on_char '\n'
747752 |> List. filter (fun x -> String. trim x <> " " ) (* Remove empty lines *)
@@ -755,7 +760,9 @@ let workgroup_from_server kdc =
755760 let key = " Pre-Win2k Domain" in
756761 try
757762 Helpers. call_script ~log_output: On_failure net_cmd
758- ([" ads" ; " lookup" ; " -S" ; KDC. server kdc; " -d" ; debug_level] @ kerberos_opt)
763+ ([" ads" ; " lookup" ; " -S" ; KDC. server kdc; " -d" ; debug_level () ]
764+ @ kerberos_opt
765+ )
759766 |> Xapi_cmd_result. of_output ~sep: ':' ~key
760767 |> Result. ok
761768 with _ ->
@@ -829,8 +836,8 @@ let config_winbind_daemon ~workgroup ~netbios_name ~domain =
829836 ; Printf. sprintf " workgroup = %s" wkgroup
830837 ; Printf. sprintf " netbios name = %s" netbios
831838 ; " idmap config * : backend = autorid"
832- ; " idmap config * : range = 2000000-99999999 "
833- ; Printf. sprintf " log level = %s" debug_level
839+ ; Printf. sprintf " idmap config * : range = %d-%d " 2_000_000 99_999_999
840+ ; Printf. sprintf " log level = %s" ( debug_level () )
834841 ; " " (* Empty line at the end *)
835842 ]
836843 | _ ->
@@ -910,7 +917,9 @@ let clear_machine_account ~service_name = function
910917 | Some u , Some p -> (
911918 (* Disable machine account in DC *)
912919 let env = [|Printf. sprintf " PASSWD=%s" p|] in
913- let args = [" ads" ; " leave" ; " -U" ; u; " -d" ; debug_level] @ kerberos_opt in
920+ let args =
921+ [" ads" ; " leave" ; " -U" ; u; " -d" ; debug_level () ] @ kerberos_opt
922+ in
914923 try
915924 Helpers. call_script ~env net_cmd args |> ignore ;
916925 debug " Succeed to clear the machine account for domain %s" service_name
@@ -1079,7 +1088,7 @@ module Winbind = struct
10791088 ; " set"
10801089 ; " --machine-pass"
10811090 ; " -d"
1082- ; debug_level
1091+ ; debug_level ()
10831092 ; Printf. sprintf " %s$" netbios_name
10841093 ; Printf. sprintf " %d"
10851094 (Kerberos_encryption_types.Winbind. to_encoding
@@ -1305,26 +1314,33 @@ let domain_name_of_netbios netbios =
13051314 (*
13061315 * Query the domain name from netbios name with caching
13071316 * Check cache first, if not found, perform LDAP query and cache the result
1317+ * Thread-safe using atomic map
13081318 *)
1309- match Hashtbl. find_opt domain_netbios_name_map netbios with
1319+ let cache_domain netbios domain_name current_map =
1320+ let new_map = StringMap. add netbios domain_name current_map in
1321+ if Atomic. compare_and_set domain_netbios_name_map current_map new_map = true
1322+ then (* Just ignore it if update fail, as it will be cached next time *)
1323+ debug " Cached netbios '%s' -> domain '%s'" netbios domain_name
1324+ in
1325+
1326+ let current_map = Atomic. get domain_netbios_name_map in
1327+ match StringMap. find_opt netbios current_map with
13101328 | Some domain_name ->
13111329 debug " Cache hit for netbios '%s' -> domain '%s'" netbios domain_name ;
13121330 Ok domain_name
13131331 | None -> (
13141332 let {service_name; workgroup; _} = get_domain_info_from_db () in
13151333 match netbios = Option. value workgroup ~default: " " with
13161334 | true ->
1317- Hashtbl. replace domain_netbios_name_map netbios service_name ;
1318- debug " Cached netbios '%s' -> domain '%s' as joined domain" netbios
1319- service_name ;
1335+ cache_domain netbios service_name current_map ;
1336+ debug " Netbios '%s' is the joined domain" netbios ;
13201337 Ok service_name (* It is joined domain *)
13211338 | false ->
13221339 debug " Cache miss for netbios '%s', performing LDAP query" netbios ;
13231340 let result = Ldap. query_trusted_domain_name netbios in
13241341 ( match result with
13251342 | Ok domain_name ->
1326- Hashtbl. replace domain_netbios_name_map netbios domain_name ;
1327- debug " Cached netbios '%s' -> domain '%s'" netbios domain_name
1343+ cache_domain netbios domain_name current_map
13281344 | Error _ ->
13291345 debug " Failed to query domain name for netbios '%s'" netbios
13301346 ) ;
@@ -1358,7 +1374,7 @@ module AuthADWinbind : Auth_signature.AUTH_MODULE = struct
13581374 )
13591375 in
13601376 (* Query kdc of the domain, so user in trusted domain is supported as well *)
1361- let * kdc = Wbinfo. kdc_of_domain (Result. get_ok domain) in
1377+ let * kdc = Wbinfo. kdc_of_domain (domain |> maybe_raise ) in
13621378 Ldap. query_sid ~name ~kdc
13631379
13641380 (* subject_id get_subject_identifier(string subject_name)
@@ -1442,18 +1458,7 @@ module AuthADWinbind : Auth_signature.AUTH_MODULE = struct
14421458 let sam_uname = user_name in
14431459 let * domain_netbios, user = user_of_sam user_name in
14441460 (* permit unnkown domain if ldap query failed, update subject task will update it later *)
1445- let unkown_domain = " Unkown_domain" in
1446- let domain =
1447- match domain_name_of_netbios domain_netbios with
1448- | Ok domain_name ->
1449- Some domain_name
1450- | Error _ ->
1451- debug
1452- " Failed to query domain name for netbios '%s', using '%s as \
1453- fallback"
1454- domain_netbios unkown_domain ;
1455- None
1456- in
1461+ let domain = domain_name_of_netbios domain_netbios |> Result. to_option in
14571462 let default_account =
14581463 Ldap.
14591464 {
@@ -1512,8 +1517,7 @@ module AuthADWinbind : Auth_signature.AUTH_MODULE = struct
15121517 , if upn <> " " then
15131518 upn
15141519 else
1515- Printf. sprintf " %s@%s" user
1516- (Option. value domain ~default: unkown_domain)
1520+ Printf. sprintf " %s@%s" user (Option. value domain ~default: " unknown" )
15171521 )
15181522 ; (" subject-account-disabled" , string_of_bool account_disabled)
15191523 ; (" subject-account-locked" , string_of_bool account_locked)
@@ -1622,7 +1626,7 @@ module AuthADWinbind : Auth_signature.AUTH_MODULE = struct
16221626 ; " -n"
16231627 ; netbios_name
16241628 ; " -d"
1625- ; debug_level
1629+ ; debug_level ()
16261630 ; " --no-dns-updates"
16271631 ]
16281632 @ kerberos_opt
0 commit comments