kim_ui_environment kim_os_library_get_ui_environment (void) { #ifdef KIM_BUILTIN_UI kim_boolean has_gui_access = 0; SessionAttributeBits sattrs = 0L; has_gui_access = ((SessionGetInfo (callerSecuritySession, NULL, &sattrs) == noErr) && (sattrs & sessionHasGraphicAccess)); if (has_gui_access && kim_os_library_caller_uses_gui ()) { return KIM_UI_ENVIRONMENT_GUI; } { int fd_stdin = fileno (stdin); int fd_stdout = fileno (stdout); char *fd_stdin_name = ttyname (fd_stdin); /* Session info isn't reliable for remote sessions. * Check manually for terminal access with file descriptors */ if (isatty (fd_stdin) && isatty (fd_stdout) && fd_stdin_name) { return KIM_UI_ENVIRONMENT_CLI; } } /* If we don't have a CLI but can talk to the GUI, use that */ if (has_gui_access) { return KIM_UI_ENVIRONMENT_GUI; } kim_debug_printf ("kim_os_library_get_ui_environment(): no way to talk to the user."); #endif return KIM_UI_ENVIRONMENT_NONE; }
static kim_error kim_os_selection_hints_get_dictionary_identity (CFDictionaryRef in_dictionary, kim_identity *out_identity) { kim_error err = KIM_NO_ERROR; CFStringRef identity_cfstr = NULL; kim_string identity_string = NULL; identity_cfstr = CFDictionaryGetValue (in_dictionary, KIM_IDENTITY_HINT); if (!identity_cfstr || CFGetTypeID (identity_cfstr) != CFStringGetTypeID ()) { kim_debug_printf ("%s: Malformed hints dictionary (invalid identity).", __FUNCTION__); err = check_error (KIM_PREFERENCES_READ_ERR); } if (!err) { err = kim_os_string_create_from_cfstring (&identity_string, identity_cfstr); } if (!err) { err = kim_identity_create_from_string (out_identity, identity_string); } kim_string_free (&identity_string); return check_error (err); }
static kim_boolean kim_os_selection_hints_compare_hint (kim_string in_string, CFStringRef in_value) { kim_boolean equal = 0; if (!in_string && !in_value) { equal = 1; } else if (in_string && in_value) { if (CFGetTypeID (in_value) == CFStringGetTypeID ()) { kim_comparison comparison; kim_error err = kim_os_string_compare_to_cfstring (in_string, in_value, &comparison); if (!err && kim_comparison_is_equal_to (comparison)) { equal = 1; } } else { kim_debug_printf ("%s: Malformed string in hints dictionary.", __FUNCTION__); } } return equal; }
static kim_error kim_ui_cli_read_string (kim_string *out_string, kim_boolean in_hide_reply, const char *in_format, ...) { kim_error err = KIM_NO_ERROR; krb5_context k5context = NULL; krb5_prompt prompts[1]; char prompt_string [BUFSIZ]; krb5_data reply_data; char reply_string [BUFSIZ]; if (!err && !out_string) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_format ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { err = krb5_init_context (&k5context); } if (!err) { unsigned int count; va_list args; va_start (args, in_format); count = vsnprintf (prompt_string, sizeof (prompt_string), in_format, args); va_end (args); if (count > sizeof (prompt_string)) { kim_debug_printf ("%s(): WARNING! Prompt should be %d characters\n", __FUNCTION__, count); prompt_string [sizeof (prompt_string) - 1] = '\0'; } } if (!err) { /* Build the prompt structures */ prompts[0].prompt = prompt_string; prompts[0].hidden = in_hide_reply; prompts[0].reply = &reply_data; prompts[0].reply->data = reply_string; prompts[0].reply->length = sizeof (reply_string); err = krb5_prompter_posix (k5context, NULL, NULL, NULL, 1, prompts); if (err == KRB5_LIBOS_PWDINTR || err == KRB5_LIBOS_CANTREADPWD) { err = check_error (KIM_USER_CANCELED_ERR); } } if (!err) { err = kim_string_create_from_buffer (out_string, prompts[0].reply->data, prompts[0].reply->length); } if (k5context) { krb5_free_context (k5context); } return check_error (err); }
kim_error kim_os_selection_hints_forget_identity (kim_selection_hints in_selection_hints) { kim_error err = KIM_NO_ERROR; CFArrayRef old_hints_array = NULL; CFMutableArrayRef new_hints_array = NULL; CFIndex count = 0; CFIndex i = 0; if (!err && !in_selection_hints) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { err = kim_os_selection_hints_get_selection_hints_array (&old_hints_array); } if (!err) { new_hints_array = CFArrayCreateMutableCopy (kCFAllocatorDefault, 0, old_hints_array); if (!new_hints_array) { err = KIM_OUT_OF_MEMORY_ERR; } } if (!err) { count = CFArrayGetCount (new_hints_array); } for (i = 0; !err && i < count; i++) { CFDictionaryRef dictionary = NULL; kim_boolean hints_equal = 0; dictionary = CFArrayGetValueAtIndex (new_hints_array, i); if (!dictionary) { err = KIM_OUT_OF_MEMORY_ERR; } if (!err && CFGetTypeID (dictionary) != CFDictionaryGetTypeID ()) { kim_debug_printf ("%s: Malformed entry in hints array.", __FUNCTION__); continue; /* skip entries which aren't dictionaries */ } if (!err) { err = kim_os_selection_hints_compare_to_dictionary (in_selection_hints, dictionary, &hints_equal); } if (!err && hints_equal) { CFArrayRemoveValueAtIndex (new_hints_array, i); i--; /* back up one index so we don't skip */ count = CFArrayGetCount (new_hints_array); /* count changed */ } } if (!err) { err = kim_os_selection_hints_set_selection_hints_array (new_hints_array); } if (new_hints_array) { CFRelease (new_hints_array); } return check_error (err); }
kim_error kim_os_selection_hints_lookup_identity (kim_selection_hints in_selection_hints, kim_identity *out_identity) { kim_error err = KIM_NO_ERROR; CFArrayRef hints_array = NULL; CFIndex i = 0; CFIndex count = 0; kim_boolean found = 0; CFDictionaryRef found_dictionary = NULL; if (!err && !in_selection_hints) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !out_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { err = kim_os_selection_hints_get_selection_hints_array (&hints_array); } if (!err && hints_array) { count = CFArrayGetCount (hints_array); } for (i = 0; !err && !found && i < count; i++) { CFDictionaryRef dictionary = NULL; dictionary = CFArrayGetValueAtIndex (hints_array, i); if (!dictionary) { err = KIM_OUT_OF_MEMORY_ERR; } if (!err && CFGetTypeID (dictionary) != CFDictionaryGetTypeID ()) { kim_debug_printf ("%s: Malformed entry in hints array.", __FUNCTION__); continue; /* skip entries which aren't dictionaries */ } if (!err) { err = kim_os_selection_hints_compare_to_dictionary (in_selection_hints, dictionary, &found); } if (!err && found) { found_dictionary = dictionary; } } if (!err && found) { err = kim_os_selection_hints_get_dictionary_identity (found_dictionary, out_identity); } if (hints_array) { CFRelease (hints_array); } return check_error (err); }
kim_error _check_error (kim_error in_err, kim_string in_function, kim_string in_file, int in_line) { if (in_err) { kim_debug_printf ("%s(): got %d ('%s') at %s: %d", in_function, in_err, kim_error_message (in_err), in_file, in_line); } return in_err; }
krb5_error_code kim_ui_prompter (krb5_context in_krb5_context, void *in_context, const char *in_name, const char *in_banner, int in_num_prompts, krb5_prompt in_prompts[]) { kim_error err = KIM_NO_ERROR; krb5_prompt_type *types = NULL; kim_ui_context *context = (kim_ui_context *) in_context; int i; if (!err && !in_krb5_context) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_context ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_prompts ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { types = krb5_get_prompt_types (in_krb5_context); if (!types) { err = check_error (KIM_NULL_PARAMETER_ERR); } } for (i = 0; !err && i < in_num_prompts; i++) { char *reply = NULL; kim_prompt_type type = kim_ui_ptype2ktype (types[i]); kim_boolean got_saved_password = 0; if (type == kim_prompt_type_password) { /* Check for saved password on OSes that support it */ kim_error terr = KIM_NO_ERROR; terr = kim_os_identity_get_saved_password (context->identity, (kim_string *) &reply); if (!terr && reply) { got_saved_password = 1; } } if (!got_saved_password) { kim_boolean save_reply = FALSE; kim_boolean allow_save_password = kim_os_identity_allow_save_password (); context->prompt_count++; err = kim_ui_init_lazy (in_context); if (!err) { if (context->type == kim_ui_type_gui_plugin) { err = kim_ui_plugin_auth_prompt (context, context->identity, type, allow_save_password, in_prompts[i].hidden, in_name, in_banner, in_prompts[i].prompt, &reply, &save_reply); #ifdef KIM_BUILTIN_UI } else if (context->type == kim_ui_type_gui_builtin) { err = kim_os_ui_gui_auth_prompt (context, context->identity, type, allow_save_password, in_prompts[i].hidden, in_name, in_banner, in_prompts[i].prompt, &reply, &save_reply); } else if (context->type == kim_ui_type_cli) { err = kim_ui_cli_auth_prompt (context, context->identity, type, allow_save_password, in_prompts[i].hidden, in_name, in_banner, in_prompts[i].prompt, &reply, &save_reply); #endif /* KIM_BUILTIN_UI */ } else { err = check_error (KIM_NO_UI_ERR); } } if (!err && type == kim_prompt_type_password) { kim_string_free (&context->password_to_save); if (allow_save_password && save_reply) { err = kim_string_copy (&context->password_to_save, reply); } } } if (!err) { uint32_t reply_len = strlen (reply); if ((reply_len + 1) > in_prompts[i].reply->length) { kim_debug_printf ("%s(): reply %d is too long (is %d, should be %d)\n", __FUNCTION__, i, reply_len, in_prompts[i].reply->length); reply_len = in_prompts[i].reply->length; } memmove (in_prompts[i].reply->data, reply, reply_len + 1); in_prompts[i].reply->length = reply_len; } /* Clean up reply buffer. Saved passwords are allocated by KIM. */ if (reply) { if (got_saved_password) { memset (reply, '\0', strlen (reply)); kim_string_free ((kim_string *) &reply); } else { kim_ui_free_string (context, &reply); } } } return check_error (err); }
kim_error kim_os_selection_hints_remember_identity (kim_selection_hints in_selection_hints, kim_identity in_identity) { kim_error err = KIM_NO_ERROR; CFArrayRef old_hints_array = NULL; CFMutableArrayRef new_hints_array = NULL; CFIndex count = 0; CFIndex i = 0; kim_boolean hint_already_exists = 0; kim_boolean hints_array_changed = 0; if (!err && !in_selection_hints) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err && !in_identity ) { err = check_error (KIM_NULL_PARAMETER_ERR); } if (!err) { err = kim_os_selection_hints_get_selection_hints_array (&old_hints_array); } if (!err) { if (old_hints_array) { new_hints_array = CFArrayCreateMutableCopy (kCFAllocatorDefault, 0, old_hints_array); } else { new_hints_array = CFArrayCreateMutable (kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); } if (!new_hints_array) { err = KIM_OUT_OF_MEMORY_ERR; } } if (!err) { count = CFArrayGetCount (new_hints_array); } for (i = 0; !err && i < count; i++) { CFDictionaryRef dictionary = NULL; kim_identity identity = NULL; kim_boolean hints_equal = 0; dictionary = CFArrayGetValueAtIndex (new_hints_array, i); if (!dictionary) { err = KIM_OUT_OF_MEMORY_ERR; } if (!err && CFGetTypeID (dictionary) != CFDictionaryGetTypeID ()) { kim_debug_printf ("%s: Malformed entry in hints array.", __FUNCTION__); continue; /* skip entries which aren't dictionaries */ } if (!err) { err = kim_os_selection_hints_compare_to_dictionary (in_selection_hints, dictionary, &hints_equal); } if (!err && hints_equal) { kim_comparison comparison; err = kim_os_selection_hints_get_dictionary_identity (dictionary, &identity); if (!err) { err = kim_identity_compare (in_identity, identity, &comparison); } if (!err) { if (kim_comparison_is_equal_to (comparison) && !hint_already_exists) { hint_already_exists = 1; } else { CFArrayRemoveValueAtIndex (new_hints_array, i); i--; /* back up one index so we don't skip */ count = CFArrayGetCount (new_hints_array); /* count changed */ hints_array_changed = 1; } } kim_identity_free (&identity); } } if (!err && !hint_already_exists) { CFDictionaryRef new_hint_dictionary = NULL; err = kim_os_selection_hints_create_dictionary (in_selection_hints, in_identity, &new_hint_dictionary); if (!err) { CFArrayInsertValueAtIndex (new_hints_array, 0, new_hint_dictionary); hints_array_changed = 1; } if (new_hint_dictionary) { CFRelease (new_hint_dictionary); } } if (!err && hints_array_changed) { err = kim_os_selection_hints_set_selection_hints_array (new_hints_array); } if (new_hints_array ) { CFRelease (new_hints_array); } if (old_hints_array ) { CFRelease (old_hints_array); } return check_error (err); }