From 8337fa94b76097428621d1e1987c5d66c1b82095 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 22 Jul 2024 13:00:52 +0100 Subject: [PATCH] Remove ineffectual parameter wiping (#5868) * Remove redundant parameter wiping Removes ineffectual parameter wiping introduced by 6e24ca434fb2e358e. Signed-off-by: Colin James --- ocaml/xapi/xapi_session.ml | 843 ++++++++++++++++++------------------- 1 file changed, 399 insertions(+), 444 deletions(-) diff --git a/ocaml/xapi/xapi_session.ml b/ocaml/xapi/xapi_session.ml index 1417b4d8313..2a5a933fe6a 100644 --- a/ocaml/xapi/xapi_session.ml +++ b/ocaml/xapi/xapi_session.ml @@ -268,29 +268,14 @@ let set_local_auth_max_threads n = let set_ext_auth_max_threads n = Locking_helpers.Semaphore.set_max throttle_auth_external @@ Int64.to_int n -let wipe_string_contents str = - for i = 0 to Bytes.length str - 1 do - Bytes.set str i '\000' - done - -let wipe ss = List.iter (fun s -> wipe_string_contents s) ss - -(* wrapper that erases sensitive string parameters from functions *) -let wipe_params_after_fn params fn = - try - let r = fn () in - wipe params ; r - with e -> wipe params ; raise e - let do_external_auth uname pwd = with_throttle throttle_auth_external (fun () -> - (Ext_auth.d ()).authenticate_username_password uname - (Bytes.unsafe_to_string pwd) + (Ext_auth.d ()).authenticate_username_password uname pwd ) let do_local_auth uname pwd = with_throttle throttle_auth_internal (fun () -> - try Pam.authenticate uname (Bytes.unsafe_to_string pwd) + try Pam.authenticate uname pwd with Failure msg -> raise Api_errors.(Server_error (session_authentication_failed, [uname; msg])) @@ -298,7 +283,7 @@ let do_local_auth uname pwd = let do_local_change_password uname newpwd = with_throttle throttle_auth_internal (fun () -> - Pam.change_password uname (Bytes.unsafe_to_string newpwd) + Pam.change_password uname newpwd ) let trackid session_id = Context.trackid_of_session (Some session_id) @@ -725,22 +710,19 @@ let slave_local_login ~__context ~psecret = (* Emergency mode login, uses local storage *) let slave_local_login_with_password ~__context ~uname ~pwd = Context.with_tracing ~__context __FUNCTION__ @@ fun __context -> - let pwd = Bytes.of_string pwd in - wipe_params_after_fn [pwd] (fun () -> - if Context.preauth ~__context <> Some `root then ( - try - (* CP696 - only tries to authenticate against LOCAL superuser account *) - do_local_auth uname pwd - with Failure msg -> - debug "Failed to authenticate user %s: %s" uname msg ; - raise - (Api_errors.Server_error - (Api_errors.session_authentication_failed, [uname; msg]) - ) - ) ; - debug "Add session to local storage" ; - Xapi_local_session.create ~__context ~pool:false - ) + if Context.preauth ~__context <> Some `root then ( + try + (* CP696 - only tries to authenticate against LOCAL superuser account *) + do_local_auth uname pwd + with Failure msg -> + debug "Failed to authenticate user %s: %s" uname msg ; + raise + (Api_errors.Server_error + (Api_errors.session_authentication_failed, [uname; msg]) + ) + ) ; + debug "Add session to local storage" ; + Xapi_local_session.create ~__context ~pool:false (* CP-714: Modify session.login_with_password to first try local super-user login; and then call into external auth plugin if this is enabled @@ -757,415 +739,396 @@ let slave_local_login_with_password ~__context ~uname ~pwd = *) let login_with_password ~__context ~uname ~pwd ~version:_ ~originator = Context.with_tracing ~originator ~__context __FUNCTION__ @@ fun __context -> - let pwd = Bytes.of_string pwd in - wipe_params_after_fn [pwd] (fun () -> - (* !!! Do something with the version number *) - match Context.preauth ~__context with - | Some `root -> - (* in this case, the context origin of this login request is a unix socket bound locally to a filename *) - (* we trust requests from local unix filename sockets, so no need to authenticate them before login *) + (* !!! Do something with the version number *) + match Context.preauth ~__context with + | Some `root -> + (* in this case, the context origin of this login request is a unix socket bound locally to a filename *) + (* we trust requests from local unix filename sockets, so no need to authenticate them before login *) + login_no_password_common ~__context ~uname:(Some uname) ~originator + ~host:(Helpers.get_localhost ~__context) + ~pool:false ~is_local_superuser:true ~subject:Ref.null ~auth_user_sid:"" + ~auth_user_name:uname ~rbac_permissions:[] ~db_ref:None + ~client_certificate:false + | Some `client_cert -> + (* The session was authenticated by stunnel's verification of the client certificate, + so we do not need to verify the username/password. Grant access to functions + based on the special "client_cert" RBAC role. *) + let role = + match + Xapi_role.get_by_name_label ~__context + ~label:Datamodel_roles.role_client_cert + with + | role :: _ -> + role + | [] -> + raise + (Api_errors.Server_error + ( Api_errors.internal_error + , [Datamodel_roles.role_client_cert ^ " role not found"] + ) + ) + in + let rbac_permissions = + Xapi_role.get_permissions_name_label ~__context ~self:role + in + login_no_password_common ~__context ~uname:(Some uname) ~originator + ~host:(Helpers.get_localhost ~__context) + ~pool:false ~is_local_superuser:false ~subject:Ref.null + ~auth_user_sid:"" ~auth_user_name:uname ~rbac_permissions ~db_ref:None + ~client_certificate:true + | None -> ( + let () = + if Pool_role.is_slave () then + raise + (Api_errors.Server_error + (Api_errors.host_is_slave, [Pool_role.get_master_address ()]) + ) + in + let login_as_local_superuser auth_type = + if auth_type <> "" && uname <> local_superuser then + (* makes local superuser = root only*) + failwith ("Local superuser must be " ^ local_superuser) + else ( + do_local_auth uname pwd ; + debug "Success: local auth, user %s from %s" uname + (Context.get_origin __context) ; login_no_password_common ~__context ~uname:(Some uname) ~originator ~host:(Helpers.get_localhost ~__context) ~pool:false ~is_local_superuser:true ~subject:Ref.null ~auth_user_sid:"" ~auth_user_name:uname ~rbac_permissions:[] ~db_ref:None ~client_certificate:false - | Some `client_cert -> - (* The session was authenticated by stunnel's verification of the client certificate, - so we do not need to verify the username/password. Grant access to functions - based on the special "client_cert" RBAC role. *) - let role = - match - Xapi_role.get_by_name_label ~__context - ~label:Datamodel_roles.role_client_cert - with - | role :: _ -> - role - | [] -> - raise - (Api_errors.Server_error - ( Api_errors.internal_error - , [Datamodel_roles.role_client_cert ^ " role not found"] - ) - ) - in - let rbac_permissions = - Xapi_role.get_permissions_name_label ~__context ~self:role - in - login_no_password_common ~__context ~uname:(Some uname) ~originator - ~host:(Helpers.get_localhost ~__context) - ~pool:false ~is_local_superuser:false ~subject:Ref.null - ~auth_user_sid:"" ~auth_user_name:uname ~rbac_permissions - ~db_ref:None ~client_certificate:true - | None -> ( - let () = - if Pool_role.is_slave () then - raise - (Api_errors.Server_error - (Api_errors.host_is_slave, [Pool_role.get_master_address ()]) - ) - in - let login_as_local_superuser auth_type = - if auth_type <> "" && uname <> local_superuser then - (* makes local superuser = root only*) - failwith ("Local superuser must be " ^ local_superuser) - else ( - do_local_auth uname pwd ; - debug "Success: local auth, user %s from %s" uname - (Context.get_origin __context) ; - login_no_password_common ~__context ~uname:(Some uname) - ~originator - ~host:(Helpers.get_localhost ~__context) - ~pool:false ~is_local_superuser:true ~subject:Ref.null - ~auth_user_sid:"" ~auth_user_name:uname ~rbac_permissions:[] - ~db_ref:None ~client_certificate:false + ) + in + let thread_delay_and_raise_error ~error uname msg = + let some_seconds = 5.0 in + Thread.delay some_seconds ; + (* sleep a bit to avoid someone brute-forcing the password *) + if error = Api_errors.session_authentication_failed then + raise (Api_errors.Server_error (error, [uname; msg])) + else if error = Api_errors.session_authorization_failed then + raise Api_errors.(Server_error (error, [uname; msg])) + else + raise + (Api_errors.Server_error + (error, ["session.login_with_password"; msg]) ) - in - let thread_delay_and_raise_error ~error uname msg = - let some_seconds = 5.0 in - Thread.delay some_seconds ; - (* sleep a bit to avoid someone brute-forcing the password *) - if error = Api_errors.session_authentication_failed then - raise (Api_errors.Server_error (error, [uname; msg])) - else if error = Api_errors.session_authorization_failed then - raise Api_errors.(Server_error (error, [uname; msg])) - else - raise - (Api_errors.Server_error - (error, ["session.login_with_password"; msg]) - ) - in - match - Db.Host.get_external_auth_type ~__context - ~self:(Helpers.get_localhost ~__context) - with - | "" as auth_type -> ( - try - (* no external authentication *) + in + match + Db.Host.get_external_auth_type ~__context + ~self:(Helpers.get_localhost ~__context) + with + | "" as auth_type -> ( + try + (* no external authentication *) - (*debug "External authentication is disabled";*) - (* only attempts to authenticate against the local superuser credentials *) - login_as_local_superuser auth_type - with Failure msg -> - info "Failed to locally authenticate user %s from %s: %s" uname + (*debug "External authentication is disabled";*) + (* only attempts to authenticate against the local superuser credentials *) + login_as_local_superuser auth_type + with Failure msg -> + info "Failed to locally authenticate user %s from %s: %s" uname + (Context.get_origin __context) + msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authentication_failed uname msg + ) + | _ as auth_type -> ( + (* external authentication required *) + debug "External authentication %s is enabled" auth_type ; + (* 1. first attempts to authenticate against the local superuser *) + try login_as_local_superuser auth_type + with Failure msg -> ( + try + debug "Failed to locally authenticate user %s from %s: %s" uname (Context.get_origin __context) msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authentication_failed uname msg - ) - | _ as auth_type -> ( - (* external authentication required *) - debug "External authentication %s is enabled" auth_type ; - (* 1. first attempts to authenticate against the local superuser *) - try login_as_local_superuser auth_type - with Failure msg -> ( + (* 2. then against the external auth service *) + (* 2.1. we first check the external auth service status *) + let rec waiting_event_hook_auth_on_xapi_initialize_succeeded + seconds = + if not !Xapi_globs.event_hook_auth_on_xapi_initialize_succeeded + then ( + if seconds <= 0 then ( + let msg = + Printf.sprintf + "External authentication %s service still initializing" + auth_type + in + error "%s" msg ; + thread_delay_and_raise_error uname msg + ~error:Api_errors.internal_error + ) else + debug "External authentication %s service initializing..." + auth_type ; + Thread.delay 1.0 ; + waiting_event_hook_auth_on_xapi_initialize_succeeded + (seconds - 1) + ) + in + waiting_event_hook_auth_on_xapi_initialize_succeeded 120 ; + (* 2.2. we then authenticate the usee using the external authentication plugin *) + (* so that we know that he/she exists there *) + let subject_identifier = try - debug "Failed to locally authenticate user %s from %s: %s" + let _subject_identifier = do_external_auth uname pwd in + debug + "Successful external authentication user %s \ + (subject_identifier, %s from %s)" + uname _subject_identifier + (Context.get_origin __context) ; + _subject_identifier + with Auth_signature.Auth_failure msg -> + info "Failed to externally authenticate user %s from %s: %s" uname (Context.get_origin __context) msg ; - (* 2. then against the external auth service *) - (* 2.1. we first check the external auth service status *) - let rec waiting_event_hook_auth_on_xapi_initialize_succeeded - seconds = - if - not - !Xapi_globs.event_hook_auth_on_xapi_initialize_succeeded - then ( - if seconds <= 0 then ( - let msg = - Printf.sprintf - "External authentication %s service still \ - initializing" - auth_type - in - error "%s" msg ; - thread_delay_and_raise_error uname msg - ~error:Api_errors.internal_error - ) else - debug - "External authentication %s service initializing..." - auth_type ; - Thread.delay 1.0 ; - waiting_event_hook_auth_on_xapi_initialize_succeeded - (seconds - 1) - ) - in - waiting_event_hook_auth_on_xapi_initialize_succeeded 120 ; - (* 2.2. we then authenticate the usee using the external authentication plugin *) - (* so that we know that he/she exists there *) - let subject_identifier = - try - let _subject_identifier = do_external_auth uname pwd in - debug - "Successful external authentication user %s \ - (subject_identifier, %s from %s)" - uname _subject_identifier - (Context.get_origin __context) ; - _subject_identifier - with Auth_signature.Auth_failure msg -> - info - "Failed to externally authenticate user %s from %s: %s" - uname - (Context.get_origin __context) - msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authentication_failed uname - msg + thread_delay_and_raise_error + ~error:Api_errors.session_authentication_failed uname msg + in + (* as per tests in CP-827, there should be no need to call is_subject_suspended function here, *) + (* because the authentication server in 2.1 will already reflect if account/password expired, *) + (* disabled, locked-out etc, but since likewise doesn't timely reflect this information *) + (* at the same time for both authentication and subject info queries (modification in the AD *) + (* reflects immediately for AD authentication, but can take 1 hour to reflect on subject info), *) + (* we need to call it here in order to be consistent with the session revalidation function. *) + (* Otherwise, there might be cases where the initial authentication/login succeeds, but *) + (* then a few minutes later the revalidation finds that the user is 'suspended' (due to *) + (* subject info caching problems in likewise) and closes the user's session *) + let subject_suspended, subject_name = + try + let suspended, name = + is_subject_suspended ~__context ~cache:true + subject_identifier in - (* as per tests in CP-827, there should be no need to call is_subject_suspended function here, *) - (* because the authentication server in 2.1 will already reflect if account/password expired, *) - (* disabled, locked-out etc, but since likewise doesn't timely reflect this information *) - (* at the same time for both authentication and subject info queries (modification in the AD *) - (* reflects immediately for AD authentication, but can take 1 hour to reflect on subject info), *) - (* we need to call it here in order to be consistent with the session revalidation function. *) - (* Otherwise, there might be cases where the initial authentication/login succeeds, but *) - (* then a few minutes later the revalidation finds that the user is 'suspended' (due to *) - (* subject info caching problems in likewise) and closes the user's session *) - let subject_suspended, subject_name = - try - let suspended, name = - is_subject_suspended ~__context ~cache:true + if suspended then + is_subject_suspended ~__context ~cache:false + subject_identifier + else + (suspended, name) + with Auth_signature.Auth_service_error (_, msg) -> + debug + "Failed to find if user %s (subject_id %s, from %s) is \ + suspended: %s" + uname subject_identifier + (Context.get_origin __context) + msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authorization_failed uname msg + in + if subject_suspended then ( + let msg = + Printf.sprintf + "User %s (subject_id %s, from %s) suspended in external \ + directory" + uname subject_identifier + (Context.get_origin __context) + in + debug "%s" msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authorization_failed uname msg + ) else + (* 2.2. then, we verify if any elements of the the membership closure of the externally *) + (* authenticated subject_id is inside our local allowed-to-login subjects list *) + (* finds all the groups a user belongs to (non-reflexive closure of member-of relation) *) + let group_membership_closure = + try + (Ext_auth.d ()).query_group_membership subject_identifier + with + | Not_found | Auth_signature.Subject_cannot_be_resolved -> + let msg = + Printf.sprintf + "Failed to obtain the group membership closure for \ + user %s (subject_id %s, from %s): user not found in \ + external directory" + uname + (Context.get_origin __context) subject_identifier in - if suspended then - is_subject_suspended ~__context ~cache:false - subject_identifier - else - (suspended, name) - with Auth_signature.Auth_service_error (_, msg) -> + debug "%s" msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authorization_failed uname msg + | Auth_signature.Auth_service_error (_, msg) -> debug - "Failed to find if user %s (subject_id %s, from %s) is \ - suspended: %s" + "Failed to obtain the group membership closure for \ + user %s (subject_id %s, from %s): %s" uname subject_identifier (Context.get_origin __context) msg ; thread_delay_and_raise_error ~error:Api_errors.session_authorization_failed uname msg + in + (* finds the intersection between group_membership_closure and pool's table of subject_ids *) + let subjects_in_db = Db.Subject.get_all ~__context in + let subject_ids_in_db = + List.map + (fun subj -> + ( subj + , Db.Subject.get_subject_identifier ~__context ~self:subj + ) + ) + subjects_in_db + in + let reflexive_membership_closure = + subject_identifier :: group_membership_closure + in + (* returns all elements of reflexive_membership_closure that are inside subject_ids_in_db *) + let intersect ext_sids db_sids = + List.filter + (fun (_, db_sid) -> List.mem db_sid ext_sids) + db_sids + in + let intersection = + intersect reflexive_membership_closure subject_ids_in_db + in + (* 2.3. finally, we create the session for the authenticated subject if any membership intersection was found *) + let in_intersection = intersection <> [] in + if not in_intersection then ( + (* empty intersection: externally-authenticated subject has no login rights in the pool *) + let msg = + Printf.sprintf + "Subject %s (identifier %s, from %s) has no access \ + rights in this pool" + uname subject_identifier + (Context.get_origin __context) + in + info "%s" msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authorization_failed uname msg + ) else (* compute RBAC structures for the session *) + let subject_membership = List.map fst intersection in + debug "subject membership intersection with subject-list=[%s]" + (List.fold_left + (fun i (subj_ref, sid) -> + let subj_ref = + try + (* attempt to resolve subject_ref -> subject_name *) + List.assoc + Auth_signature + .subject_information_field_subject_name + (Db.Subject.get_other_config ~__context + ~self:subj_ref + ) + with _ -> Ref.string_of subj_ref + in + if i = "" then + subj_ref ^ " (" ^ sid ^ ")" + else + i ^ "," ^ subj_ref ^ " (" ^ sid ^ ")" + ) + "" intersection + ) ; + let rbac_permissions = + get_permissions ~__context ~subject_membership in - if subject_suspended then ( + (* CP-1260: If a subject has no roles assigned, then authentication will fail with an error such as PERMISSION_DENIED.*) + if rbac_permissions = [] then ( let msg = Printf.sprintf - "User %s (subject_id %s, from %s) suspended in \ - external directory" + "Subject %s (identifier %s) has no roles in this pool" uname subject_identifier - (Context.get_origin __context) in - debug "%s" msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authorization_failed uname msg + info "%s" msg ; + thread_delay_and_raise_error uname msg + ~error:Api_errors.rbac_permission_denied ) else - (* 2.2. then, we verify if any elements of the the membership closure of the externally *) - (* authenticated subject_id is inside our local allowed-to-login subjects list *) - (* finds all the groups a user belongs to (non-reflexive closure of member-of relation) *) - let group_membership_closure = + (* non-empty intersection: externally-authenticated subject has login rights in the pool *) + let subject = + (* return reference for the subject obj in the db *) + (* obs: this obj ref can point to either a user or a group contained in the local subject db list *) try - (Ext_auth.d ()).query_group_membership - subject_identifier - with - | Not_found | Auth_signature.Subject_cannot_be_resolved -> - let msg = - Printf.sprintf - "Failed to obtain the group membership closure \ - for user %s (subject_id %s, from %s): user not \ - found in external directory" - uname - (Context.get_origin __context) - subject_identifier - in - debug "%s" msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authorization_failed uname - msg - | Auth_signature.Auth_service_error (_, msg) -> - debug - "Failed to obtain the group membership closure for \ - user %s (subject_id %s, from %s): %s" - uname subject_identifier - (Context.get_origin __context) - msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authorization_failed uname - msg - in - (* finds the intersection between group_membership_closure and pool's table of subject_ids *) - let subjects_in_db = Db.Subject.get_all ~__context in - let subject_ids_in_db = - List.map - (fun subj -> - ( subj - , Db.Subject.get_subject_identifier ~__context - ~self:subj + List.find + (fun subj -> + (* is this the subject ref that returned the non-empty intersection?*) + List.hd intersection + = ( subj + , Db.Subject.get_subject_identifier ~__context + ~self:subj + ) ) - ) - subjects_in_db - in - let reflexive_membership_closure = - subject_identifier :: group_membership_closure - in - (* returns all elements of reflexive_membership_closure that are inside subject_ids_in_db *) - let intersect ext_sids db_sids = - List.filter - (fun (_, db_sid) -> List.mem db_sid ext_sids) - db_sids - in - let intersection = - intersect reflexive_membership_closure subject_ids_in_db - in - (* 2.3. finally, we create the session for the authenticated subject if any membership intersection was found *) - let in_intersection = intersection <> [] in - if not in_intersection then ( - (* empty intersection: externally-authenticated subject has no login rights in the pool *) - let msg = - Printf.sprintf - "Subject %s (identifier %s, from %s) has no access \ - rights in this pool" - uname subject_identifier - (Context.get_origin __context) - in - info "%s" msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authorization_failed uname msg - ) else (* compute RBAC structures for the session *) - let subject_membership = List.map fst intersection in - debug - "subject membership intersection with subject-list=[%s]" - (List.fold_left - (fun i (subj_ref, sid) -> - let subj_ref = - try - (* attempt to resolve subject_ref -> subject_name *) - List.assoc - Auth_signature - .subject_information_field_subject_name - (Db.Subject.get_other_config ~__context - ~self:subj_ref - ) - with _ -> Ref.string_of subj_ref - in - if i = "" then - subj_ref ^ " (" ^ sid ^ ")" - else - i ^ "," ^ subj_ref ^ " (" ^ sid ^ ")" - ) - "" intersection - ) ; - let rbac_permissions = - get_permissions ~__context ~subject_membership - in - (* CP-1260: If a subject has no roles assigned, then authentication will fail with an error such as PERMISSION_DENIED.*) - if rbac_permissions = [] then ( + subjects_in_db + (* goes through exactly the same subject list that we went when computing the intersection, *) + (* so that no one is able to undetectably remove/add another subject with the same subject_identifier *) + (* between that time 2.2 and now 2.3 *) + with Not_found -> + (* this should never happen, it shows an inconsistency in the db between 2.2 and 2.3 *) let msg = Printf.sprintf - "Subject %s (identifier %s) has no roles in this \ - pool" + "Subject %s (identifier %s, from %s) is not \ + present in this pool" uname subject_identifier + (Context.get_origin __context) in - info "%s" msg ; - thread_delay_and_raise_error uname msg - ~error:Api_errors.rbac_permission_denied - ) else - (* non-empty intersection: externally-authenticated subject has login rights in the pool *) - let subject = - (* return reference for the subject obj in the db *) - (* obs: this obj ref can point to either a user or a group contained in the local subject db list *) - try - List.find - (fun subj -> - (* is this the subject ref that returned the non-empty intersection?*) - List.hd intersection - = ( subj - , Db.Subject.get_subject_identifier ~__context - ~self:subj - ) - ) - subjects_in_db - (* goes through exactly the same subject list that we went when computing the intersection, *) - (* so that no one is able to undetectably remove/add another subject with the same subject_identifier *) - (* between that time 2.2 and now 2.3 *) - with Not_found -> - (* this should never happen, it shows an inconsistency in the db between 2.2 and 2.3 *) - let msg = - Printf.sprintf - "Subject %s (identifier %s, from %s) is not \ - present in this pool" - uname subject_identifier - (Context.get_origin __context) - in - debug "%s" msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authorization_failed - uname msg - in - login_no_password_common ~__context ~uname:(Some uname) - ~originator - ~host:(Helpers.get_localhost ~__context) - ~pool:false ~is_local_superuser:false ~subject - ~auth_user_sid:subject_identifier - ~auth_user_name:subject_name ~rbac_permissions - ~db_ref:None ~client_certificate:false - (* we only reach this point if for some reason a function above forgot to catch a possible exception in the Auth_signature module*) - with - | Not_found | Auth_signature.Subject_cannot_be_resolved -> - let msg = - Printf.sprintf - "user %s from %s not found in external directory" uname - (Context.get_origin __context) + debug "%s" msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authorization_failed uname + msg in - debug - "A function failed to catch this exception for user %s \ - during external authentication: %s" - uname msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authorization_failed uname msg - | Auth_signature.Auth_failure msg -> - debug - "A function failed to catch this exception for user %s. \ - Auth_failure: %s" - uname msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authentication_failed uname msg - | Auth_signature.Auth_service_error (_, msg) -> - debug - "A function failed to catch this exception for user %s \ - from %s during external authentication: %s" - uname - (Context.get_origin __context) - msg ; - thread_delay_and_raise_error - ~error:Api_errors.session_authorization_failed uname msg - | Api_errors.Server_error _ as e -> - (* bubble up any api_error already generated *) - raise e - | e -> - (* generic catch-all for unexpected exceptions during external authentication *) - let msg = ExnHelper.string_of_exn e in - debug - "(generic) A function failed to catch this exception for \ - user %s from %s during external authentication: %s" - uname - (Context.get_origin __context) - msg ; - thread_delay_and_raise_error - ~error:Api_errors.internal_error uname msg - ) - ) + login_no_password_common ~__context ~uname:(Some uname) + ~originator + ~host:(Helpers.get_localhost ~__context) + ~pool:false ~is_local_superuser:false ~subject + ~auth_user_sid:subject_identifier + ~auth_user_name:subject_name ~rbac_permissions + ~db_ref:None ~client_certificate:false + (* we only reach this point if for some reason a function above forgot to catch a possible exception in the Auth_signature module*) + with + | Not_found | Auth_signature.Subject_cannot_be_resolved -> + let msg = + Printf.sprintf + "user %s from %s not found in external directory" uname + (Context.get_origin __context) + in + debug + "A function failed to catch this exception for user %s \ + during external authentication: %s" + uname msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authorization_failed uname msg + | Auth_signature.Auth_failure msg -> + debug + "A function failed to catch this exception for user %s. \ + Auth_failure: %s" + uname msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authentication_failed uname msg + | Auth_signature.Auth_service_error (_, msg) -> + debug + "A function failed to catch this exception for user %s from \ + %s during external authentication: %s" + uname + (Context.get_origin __context) + msg ; + thread_delay_and_raise_error + ~error:Api_errors.session_authorization_failed uname msg + | Api_errors.Server_error _ as e -> + (* bubble up any api_error already generated *) + raise e + | e -> + (* generic catch-all for unexpected exceptions during external authentication *) + let msg = ExnHelper.string_of_exn e in + debug + "(generic) A function failed to catch this exception for \ + user %s from %s during external authentication: %s" + uname + (Context.get_origin __context) + msg ; + thread_delay_and_raise_error ~error:Api_errors.internal_error + uname msg + ) ) - ) + ) let change_password ~__context ~old_pwd ~new_pwd = + ignore old_pwd ; Context.with_tracing ~__context __FUNCTION__ @@ fun __context -> - let old_pwd = Bytes.of_string old_pwd in - let new_pwd = Bytes.of_string new_pwd in - wipe_params_after_fn [old_pwd; new_pwd] (fun () -> - let session_id = Context.get_session_id __context in - (*let user = Db.Session.get_this_user ~__context ~self:session_id in - let uname = Db.User.get_short_name ~__context ~self:user in*) - let uname = local_superuser in - (* user class has been deprecated *) - if Db.Session.get_is_local_superuser ~__context ~self:session_id then ( - try - (* CP-696: only change password if session has is_local_superuser bit set *) - (* + let session_id = Context.get_session_id __context in + (*let user = Db.Session.get_this_user ~__context ~self:session_id in + let uname = Db.User.get_short_name ~__context ~self:user in*) + let uname = local_superuser in + (* user class has been deprecated *) + if Db.Session.get_is_local_superuser ~__context ~self:session_id then ( + try + (* CP-696: only change password if session has is_local_superuser bit set *) + (* CA-13567: If you have root privileges then we do not authenticate old_pwd; right now, since we only ever have root privileges we just comment this out. @@ -1177,47 +1140,39 @@ let change_password ~__context ~old_pwd ~new_pwd = raise (Api_errors.Server_error (Api_errors.session_authentication_failed,[uname;msg])) end; *) - do_local_change_password uname new_pwd ; - info "Password changed successfully for user %s" uname ; - info "Syncing password change across hosts in pool" ; - (* tell all hosts (except me to sync new passwd file) *) - let hash = Helpers.compute_hash () in - let hosts = Db.Host.get_all ~__context in - let hosts = - List.filter - (fun hostref -> hostref <> !Xapi_globs.localhost_ref) - hosts - in - Helpers.call_api_functions ~__context (fun rpc session_id -> - List.iter - (fun host -> - try - Client.Host.request_config_file_sync ~rpc ~session_id ~host - ~hash - with e -> - error "Failed to sync password to host %s: %s" - (Db.Host.get_name_label ~__context ~self:host) - (Printexc.to_string e) - ) - hosts - ) ; - info "Finished syncing password across pool" - with Failure msg -> - error "Failed to change password for user %s: %s" uname msg ; - raise - (Api_errors.Server_error (Api_errors.change_password_rejected, [msg]) + do_local_change_password uname new_pwd ; + info "Password changed successfully for user %s" uname ; + info "Syncing password change across hosts in pool" ; + (* tell all hosts (except me to sync new passwd file) *) + let hash = Helpers.compute_hash () in + let hosts = Db.Host.get_all ~__context in + let hosts = + List.filter (fun hostref -> hostref <> !Xapi_globs.localhost_ref) hosts + in + Helpers.call_api_functions ~__context (fun rpc session_id -> + List.iter + (fun host -> + try + Client.Host.request_config_file_sync ~rpc ~session_id ~host + ~hash + with e -> + error "Failed to sync password to host %s: %s" + (Db.Host.get_name_label ~__context ~self:host) + (Printexc.to_string e) ) - ) else - (* CP-696: session does not have is_local_superuser bit set, so we must fail *) - let msg = - Printf.sprintf "Failed to change password for user %s" uname - in - debug "User %s is not local superuser: %s" uname msg ; - raise - (Api_errors.Server_error - (Api_errors.user_is_not_local_superuser, [msg]) - ) - ) + hosts + ) ; + info "Finished syncing password across pool" + with Failure msg -> + error "Failed to change password for user %s: %s" uname msg ; + raise + (Api_errors.Server_error (Api_errors.change_password_rejected, [msg])) + ) else + (* CP-696: session does not have is_local_superuser bit set, so we must fail *) + let msg = Printf.sprintf "Failed to change password for user %s" uname in + debug "User %s is not local superuser: %s" uname msg ; + raise + (Api_errors.Server_error (Api_errors.user_is_not_local_superuser, [msg])) let logout ~__context = Context.with_tracing ~__context __FUNCTION__ @@ fun __context ->