Code modularity

Zhanna Tsitkova tsitkova at MIT.EDU
Tue Dec 8 12:00:39 EST 2009


On Dec 7, 2009, at 6:18 PM, Ezra Peisach wrote:

> I would think that code that logically follows from one function -
> should share the same file as the generator.
>
> One such example:
>
> lib/krb5/os/def_realm.c
>
> 1.       krb5_set_default_realm

>
> 2.       krb5_get_default_realm
>
> 3.       krb5_free_default_realm
>
> 4.       krb5int_get_domain_realm_mapping
>
>
> I would think that the krb5_get_default_realm should be paired with
> krb5_free_default_realm.  If you are not using the latter - you have a
> memory leak.
Agree. For the sake of the  accuracy it should be noted that #2 is  
referred in few additional APIs when compared to #3. They are:
	kadm5_get_admin_service_name,
	kadm5_get_config_params.
	kadm5_get_principal,
	krb5_get_fallback_host_realm,
	krb5_parse_name_flags
	krb5_read_realm_params
This resulted into their "independence"

> Yes you can use free on your own - but I've heard there are
> issues with malloc pools on some platforms - and need to have the same
> shared lib/dll do the allocation and free....
>
> I know you are trying to break down equivalences - I think some logic
> makes sense...
>
> Also - I hope whenever you do this - private library specific header
> files are used instead of dumping alot of prototypes in k5-int.h.
>
> Ezra
>
>
> Zhanna Tsitkova wrote:
>> Hello,
>>
>> The approach that was explained in the parent message was applied to
>> the src/lib files with the exclusion of the subdirectories asn1, rpc,
>> crypto_tests, openssl,old,raw, unit-test. It suggests the file
>> partitions as it is detailed at the end of this message. The file
>> names there are followed by numbered groups of functions. Each group
>> represents a candidate for a new file.
>>
>> Lets consider the first file as an example. File lib/krb5/krb/
>> rd_req_dec.c  is recommended to be divided into files to hold
>> functions from group 1 and 2
>>
>> 1. decrypt_authenticator , krb5_rd_req_decrypt_tkt_part,
>> krb5_rd_req_decoded, decode_etype_list, negotiate_etype,
>> krb5_rd_req_decoded_opt krb5_rd_req_decoded_anyflag
>>
>> 2. krb5int_check_clockskew
>>
>> Apparently, group one is referred in APIs krb5_verify_init_creds,
>> krb5_rd_req, krb5_recvauth, krb5_recvauth_version while group 2 -  in
>> krb5_get_init_creds_password, kadm5_init, krb5_rd_cred,
>> krb5_change_password, kadm5_init_with_creds, krb5_rd_priv,
>> krb5_set_password_using_ccache, krb5_verify_init_creds,
>> krb5_set_password, krb5_rd_safe, krb5_recvauth,  
>> krb5_recvauth_version,
>> kadm5_init_with_password, krb5_rd_req, kadm5_init_with_skey
>>
>> Even though asn1 was dropped off from the analysis in the  
>> anticipation
>> of the major design reconstruction there, one can suggest the  
>> dividing
>> the existing files to recognize somewhat independent parts such as
>> sam, fast, srv etc.
>>
>> =============
>>
>> lib/kr           lib/krb5/krb/rd_req_dec.c
>>
>> 1.       decrypt_authenticator , krb5_rd_req_decrypt_tkt_part,
>> krb5_rd_req_decoded, decode_etype_list, negotiate_etype,
>> krb5_rd_req_decoded_opt krb5_rd_req_decoded_anyflag
>> 2.       krb5int_check_clockskew
>>
>> lib/krb5/krb/preauth2.c
>>
>> 1.       krb5_init_preauth_context, krb5_free_preauth_context
>> 2.       krb5_preauth_supply_preauth_data
>> 3.       krb5_preauth_prepare_request, krb5_do_preauth_tryagain,
>> krb5_preauth_request_context_init, krb5_run_preauth_plugins,
>> krb5_do_preauth, pa_sam, grow_ktypes, client_data_proc, grow_pa_list
>> 4.       krb5_clear_preauth_context_use_counts,
>> krb5_preauth_request_context_fini
>> 5.       pa_salt, padata2data
>> 6.       pa_pkinit_gen_req
>> 7.       pa_pkinit_parse_rep, local_kdc_cert_match
>> 8.       pa_enc_timestamp
>> 9.       pa_sam_2
>> 10.   pa_sam
>> 11.   sam_challenge_banner
>> 12.   pa_fx_cookie
>> 13.   pa_s4u_x509_user
>> 14.   pa_types
>>
>> lib/krb5/krb/get_in_tkt.c
>>
>> 1.       krb5_libdefault_boolean, _krb5_conf_boolean,
>> krb5_libdefault_string
>> 2.       krb5_get_init_creds, make_preauth_list,
>> sort_krb5_padata_sequence, send_as_request, decrypt_as_reply,
>> stash_as_reply, verify_as_reply, build_in_tkt_name
>> 3.       krb5_get_in_tkt, rewrite_server_realm
>>
>> lib/krb5/krb/copy_auth.c
>>
>> 1.       krb5_merge_authdata, krb5_copy_authdata, krb5_copy_authdatum
>> 2.       krb5_decode_authdata_container, find_authdata_1,
>> grow_find_authdata, krb5int_find_authdata,
>> krb5_verify_authdata_kdc_issued
>> 3.       krb5_encode_authdata_container
>> 4.       krb5_make_authdata_kdc_issued
>>
>> lib/krb5/krb/mk_req_ext.c
>>
>> 1.       krb5int_generate_and_save_subkey
>> 2.       krb5_mk_req_extended, krb5_generate_authenticator,
>> make_etype_list
>>
>> lib/krb5/krb/init_ctx.c
>>
>> 1.       krb5_init_context, krb5_init_secure_context,
>> krb5int_init_context_kdc, krb5_free_context, init_common,
>> krb5_set_default_in_tkt_ktypes, krb5_set_default_tgs_ktypes,
>> krb5_set_default_tgs_enctypes, set_default_etype_var
>> 2.       copy_enctypes
>> 3.       krb5_get_permitted_enctypes, krb5_get_default_in_tkt_ktypes,
>> mod_list, krb5int_parse_enctype_list, get_profile_etype_list,
>> krb5_get_tgs_ktypes, krb5_is_permitted_enctype,
>> krb5_is_permitted_enctype_ext, krb5_free_ktypes,
>> 4.       krb5_copy_context
>>
>> lib/krb5/krb/gic_pwd.c
>>
>> 1.       krb5_get_init_creds_password, krb5_get_as_key_password,
>> krb5_init_creds_set_password, krb5_get_in_tkt_with_password
>> 2.       krb5int_populate_gic_opt
>>
>> lib/krb5/krb/gic_opt.c
>>
>> 1.       krb5_get_init_creds_opt_init krb5_get_init_creds_opt_alloc
>> init_common krb5_get_init_creds_opt_set_tkt_life
>> krb5_get_init_creds_opt_set_xxx etc. free_gic_opt_ext_preauth_data
>> krb5int_gic_opte_private_free krb5_get_init_creds_opt_free
>> krb5int_gic_opte_alloc krb5int_gic_opte_private_alloc
>> 2.       krb5int_gic_opt_to_opte krb5int_gic_opte_copy
>> 3.       krb5_get_init_creds_opt_set_pa add_gic_opt_ext_preauth_data
>> 4.       krb5_get_init_creds_opt_get_pa  
>> krb5_get_init_creds_opt_free_pa
>> 5.       krb5_get_init_creds_opt_set_fast_ccache_name
>>
>> lib/krb5/os/init_os_ctx.c
>>
>> 1.       krb5_free_config_files, free_filespecs,
>> 2.       krb5_os_init_context, krb5_os_free_context,
>> krb5_secure_config_files, add_kdc_config_file, os_init_paths
>> 3.       krb5_get_default_config_files, os_get_default_config_files,
>> get_from_windows_dir, get_from_module_dir, get_from_registry,
>> 4.       krb5_get_profile, krb5_set_config_files
>>
>> lib/krb5/os/hst_realm.c
>>
>> 1.       krb5int_clean_hostname
>> 2.       krb5_get_fallback_host_realm, domain_heuristic
>> 3.       krb5_try_realm_txt_rr
>> 4.       krb5int_translate_gai_error. krb5int_get_fq_local_hostname,
>> krb5int_get_fq_hostname
>> 5.       krb5_get_host_realm
>>
>> lib/krb5/os/sendto_kdc.c
>>
>> 1.       service_tcp_fd setup_connection getcurtime service_udp_fd
>> service_fds krb5int_sendto krb5int_cm_call_select
>> set_conn_state_msg_length start_connection kill_conn get_so_error
>> maybe_send krb5int_print_addrlist
>> 2.       krb5_sendto_kdc check_for_svc_unavailable in_addrlist
>> merge_addrlists
>>
>> lib/krb5/os/def_realm.c
>>
>> 1.       krb5_set_default_realm
>> 2.       krb5_get_default_realm
>> 3.       krb5_free_default_realm
>> 4.       krb5int_get_domain_realm_mapping
>>
>> lib/crypto/krb/dk/checksum.c
>>
>> 1.       krb5int_dk_make_checksum
>> 2.       krb5int_dk_make_checksum_iov
>>
>> lib/crypto/krb/keyhash_provider/hmac_md5.c
>>
>> 1.       k5_hmac_md5_hash
>> 2.       k5_hmac_md5_hash_iov
>>
>> lib/crypto/krb/prng.c
>>
>> 1.       krb5_c_random_make_octets
>> 2.       krb5_c_random_add_entropy, krb5_c_random_seed,  
>> entropy_estimate
>> 3.       krb5_c_random_os_entropy, read_entropy_from_device
>> 4.       krb5int_prng_init, krb5int_prng_cleanup
>>
>> lib/crypto/builtin/hmac.c
>>
>> 1.       krb5int_hmac_iov, krb5int_hmac_iov_keyblock
>> 2.       krb5int_hmac, krb5int_hmac_keyblock
>>
>> lib/gssapi/krb5/krb5_gss_glue.c
>>
>> 1.       gss_krb5_ccache_name,
>> 2.       krb5_gss_use_kdc_context
>> 3.       gss_krb5_get_tkt_flags
>> 4.       gss_krb5_copy_ccache, gss_krb5_set_allowable_enctypes,
>> gss_krb5_set_cred_rcache
>> 5.       gss_krb5_export_lucid_sec_context
>> 6.       gss_krb5_ccache_name
>> 7.       gss_krb5_free_lucid_sec_context
>> 8.       krb5_gss_register_acceptor_identity
>> 9.       gsskrb5_extract_authz_data_from_sec_context
>> 10.   gsskrb5_extract_authtime_from_sec_context
>>
>> lib/kadm5/clnt/client_principal.c
>>
>> 1.       kadm5_setkey_principal kadm5_setkey_principal_3
>> 2.       kadm5_chpass_principal_3 kadm5_chpass_principal
>> kadm5_get_principal
>> 3.       kadm5_create_principal_3 kadm5_create_principal
>> 4.       kadm5_delete_principal
>> 5.       kadm5_modify_principal
>> 6.       kadm5_get_principal
>> 7.       kadm5_get_principals
>> 8.       kadm5_rename_principal
>> 9.       kadm5_setv4key_principal
>> 10.   kadm5_randkey_principal kadm5_randkey_principal_3
>>
>> lib/kadm5/srv/svr_policy.c
>>
>> 1.       kadm5_create_policy, kadm5_create_policy_internal
>> 2.       kadm5_modify_policy, kadm5_modify_policy_internal
>> 3.       kadm5_delete_policy
>> 4.       kadm5_get_policy
>>
>> lib/kadm5/srv/server_kdb.c
>>
>> 1.       kdb_iter_entry. kdb_iter_func
>> 2.       kdb_delete_entry
>> 3.       kdb_init_master, kdb_init_hist
>> 4.       kdb_get_entry, kdb_free_entry
>> 5.       kdb_put_entry
>>
>> lib/kadm5/srv/svr_principal.c
>>
>> 1.       kadm5_copy_principal
>> 2.       check_pw_reuse
>> 3.       kadm5_chpass_principal_3, kadm5_chpass_principal,
>> create_history_entry, free_history_entry, add_to_history,
>> kadm5_use_password_server, kadm5_set_use_password_server,
>> kadm5_launch_task
>> 4.       cleanup_key_data <<<== This is in lib/kdb/kdb_cpw.c, but is
>> static – Make it krb5int???
>> 5.       kadm5_setv4key_principal /* kadmind4 */
>> 6.       kadm5_create_principal, kadm5_create_principal_3,
>> 7.       kadm5_delete_principal,
>> 8.       kadm5_modify_principal
>> 9.       kadm5_get_principal, krb5_copy_key_data_contents ,  
>> dup_tl_data
>> 10.   kadm5_rename_principal, kadm5_free_principal
>> 11.   kadm5_randkey_principal, kadm5_randkey_principal_3
>> 12.   kadm5_setkey_principal, kadm5_setkey_principal_3
>> 13.   kadm5_get_principal_keys
>> 14.   decrypt_key_data
>> 15.   kadm5_decrypt_key
>>
>> lib/kdb/kdb_cpw.c
>>
>> 1.       krb5_dbe_crk, krb5_dbe_ark, add_key_rnd
>> 2.       krb5_dbe_def_cpw, krb5_dbe_apw, add_key_pwd
>> 3.       cleanup_key_data <<<== see ./lib/kadm5/srv/svr_principal.c
>> #185 Make it krb5int???
>> 4.       krb5_db_get_key_data_kvno
>>
>> lib/kadm5/alt_prof.c
>>
>> 1.       kadm5_get_admin_service_name, kadm5_get_config_params
>> krb5_aprof_finish krb5_aprof_init string_to_boolean  
>> krb5_aprof_getvals
>> krb5_aprof_get_boolean krb5_aprof_get_string krb5_aprof_get_deltat
>> krb5_aprof_get_int32 kadm5_free_config_params, get_port_param
>> get_string_param copy_key_salt_tuple get_deltat_param
>> 2.       krb5_read_realm_params krb5_free_realm_params
>> krb5_aprof_get_string_all krb5_match_config_pattern
>>
>> lib/kadm5/misc_free.c - depends on kfree status
>>
>> 1.       kadm5_free_policy_ent, kadm5_free_name_list
>> 2.       krb5_free_key_data_contents , kadm5_free_key_data
>> 3.       kadm5_free_principal_ent
>>
>> lib/krb5/krb/enc_helper.c
>>
>> 1.       krb5_encrypt_keyhelper
>> 2.       krb5_encrypt_helper
>>
>> lib/krb5/krb/gic_keytab.c
>>
>> 1.       krb5_get_init_creds_keytab
>> 2.       krb5_get_in_tkt_with_keytab
>> 3.       get_as_key_keytab
>>
>> lib/krb5/krb/authdata.c
>> 1.       krb5_authdata_context_init, krb5int_authdata_verify,
>> krb5_authdata_context_free, krb5_authdata_export_authdata (diff in
>> gss_krb5_export_lucid_sec_context) k5_get_kdc_issued_authdata,
>> k5_ad_module_count, k5_ad_init_modules
>> 2.       krb5_authdata_export_attributes,
>> 3.       krb5_authdata_export_internal
>> 4.       krb5_authdata_free_internal
>> 5.       krb5_authdata_context_copy, k5_copy_ad_module_data
>> 6.       krb5_authdata_context_size, k5_ad_size
>> 7.       krb5_authdata_context_internalize,
>> 8.       krb5_authdata_context_externalize
>> 9.       krb5_ser_authdata_context_init
>> 10.   k5_ad_find_module
>> 11.   k5_ad_externalize,
>> 12.   krb5_authdata_import_attributes, k5_ad_internalize
>> 13.   krb5_authdata_get_attribute_types, k5_merge_data_list
>> 14.   krb5_authdata_get_attribute
>> 15.   krb5_authdata_set_attribute
>> 16.   krb5_authdata_delete_attribute
>>
>> lib/krb5/krb/pac.c
>>
>> 1.       krb5_pac_verify, k5_pac_validate_client ,
>> k5_pac_verify_server_checksum, k5_pac_zero_signature,
>> k5_pac_verify_kdc_checksum, k5_time_to_seconds_since_1970
>> 2.       krb5int_pac_sign, k5_insert_client_info
>> 3.       krb5_pac_add_buffer, k5_pac_add_buffer
>> 4.       krb5_pac_free, krb5_pac_init
>> 5.       krb5_pac_get_buffer, k5_pac_locate_buffer
>> 6.       krb5_pac_get_types
>> 7.       krb5_pac_parse
>> 8.       mspac_xxx - PAC auth data attribute backend, k5_pac_copy
>>
>> lib/krb5/krb/get_creds.c
>>
>> 1.       krb5_validate_or_renew_creds, krb5_get_validated_creds,
>> krb5_get_renewed_creds
>> 2.       krb5int_construct_matching_creds, krb5_get_credentials
>> 3.       krb5_get_credentials_val_renew_core,
>> krb5_get_credentials_validate, krb5_get_credentials_renew
>>
>> lib/crypto/krb/verify_checksum.c
>>
>> 1.       krb5_c_verify_checksum
>> 2.       krb5_k_verify_checksum
>>
>> lib/crypto/krb/decrypt.c
>>
>> 1.       krb5_c_decrypt
>> 2.       krb5_k_decrypt
>>
>> lib/crypto/krb/encrypt.c
>>
>> 1.       krb5_k_encrypt
>> 2.       krb5_c_encrypt
>>
>> lib/krb5/krb/kerrs.c
>>
>> 1.       krb5_clear_error_message
>> 2.       krb5_free_error_message, krb5_get_error_message
>> 3.       krb5_set_error_message
>> 4.       krb5_copy_error_message
>> 5.       krb5_set_error_message_fl
>>
>> lib/crypto/krb/make_checksum.c
>>
>> 1.       krb5_k_make_checksum
>> 2.       krb5_c_make_checksum
>>
>> lib/gssapi/mechglue/g_glue.c
>>
>> 1.       gssint_export_internal_name, gssint_import_internal_name,
>> gssint_display_internal_name, gssint_release_internal_name,
>> gssint_delete_internal_sec_context
>> 2.       gssint_convert_name_to_union_name
>> 3.       gssint_create_copy_buffer
>> 4.       gssint_get_mechanism_cred
>> 5.       gssint_get_mech_type, gssint_get_mech_type_oid
>> 6.       gssint_get_der_length
>> 7.       gssint_put_der_length gssint_der_length_size
>>
>> lib/gssapi/mechglue/g_seal.c
>>
>> 1.       gss_wrap, gss_seal, val_wrap_args
>> 2.       gssint_wrap_size_limit_iov_shim, gss_wrap_size_limit
>>
>> lib/krb5/krb/kfree.c - ?
>>
>> lib/krb5/krb/str_conv.c
>>
>> 1.       krb5_string_to_timestamp, krb5_string_to_salttype,
>> 2.       krb5_timestamp_to_string
>> 3.       krb5_salttype_to_string
>> 4.       krb5_timestamp_to_sfstring
>> 5.       krb5_deltat_to_string
>>
>> lib/krb5/ccache/ccbase.c
>>
>> 1.       krb5int_cc_initialize, krb5int_cc_finalize,
>> krb5int_cc_getops, krb5_cc_register, krb5_cc_resolve
>> 2.       krb5int_cc_typecursor_new, krb5int_cc_typecursor_next
>> krb5int_cc_typecursor_free
>> 3.       krb5_cc_new_unique
>> 4.       krb5_cc_move
>> 5.       krb5_cccol_lock krb5_cccol_unlock k5_cccol_force_unlock
>> 6.       k5_cc_mutex_unlock k5_cc_mutex_lock k5_cc_mutex_init
>> k5_cc_mutex_finish_init k5_cc_mutex_assert_unlocked
>> k5_cc_mutex_force_unlock
>>
>> lib/krb5/os/locate_kdc.c
>>
>> 1.       krb5_locate_kdc krb5_locate_srv_dns_1 module_callback
>> krb5_locate_srv_conf_1 krb5int_locate_server dns_locate_server
>> module_locate_server prof_locate_server
>> 2.       krb5int_grow_addrlist krb5int_free_addrlist
>> krb5int_add_host_to_list call_freeaddrinfo add_addrinfo_to_list
>> 3.       _krb5_use_dns_kdc maybe_use_dns _krb5_use_dns_realm
>>
>> lib/kdb/kdb_convert.c
>>
>> 1.       ulog_conv_2dbentry, set_from_utf8str, conv_princ_2db
>> 2.       find_changed_attrs, data_to_utf8str, conv_princ_2ulog,
>> ulog_conv_2logentry
>> 3.       ulog_free_entries
>>
>> lib/crypto/krb/dk/derive.c
>>
>> 1.       add_cached_dkey, find_cached_dkey, krb5int_derive_key
>> 2.       krb5int_derive_keyblock
>> 3.       krb5int_derive_random (test vectors.c only)
>>
>> lib/kadm5/srv/server_init.c
>>
>> 1.       kadm5_init, kadm5_init_with_creds, kadm5_init_with_password,
>> kadm5_init_with_skey, kadm5_destroy, dup_db_args
>> 2.       kadm5_init_iprop
>> 3.       kadm5_init_krb5_context
>> 4.       kadm5_flush
>> 5.       kadm5_unlock, kadm5_lock
>> 6.       free_db_args
>>
>> lib/kadm5/clnt/client_init.c
>>
>> 1.       kadm5_init_any, kadm5_setup_gss, kadm5_gic_iter,
>> kadm5_rpc_auth, kadm5_get_init_creds, kadm5_init,
>> kadm5_init_with_creds, kadm5_init_with_password, kadm5_init_with_skey
>> 2.       kadm5_init_krb5_context
>> 3.       kadm5_destroy
>> 4.       kadm5_lock, kadm5_unlock,
>> kadm5_flush,_kadm5_check_handle,kadm5_init_iprop
>>
>>
>>
>> Thanks,
>>
>> Zhanna
>>
>>  On Oct 28, 2009, at 11:33 AM, Zhanna Tsitkova wrote:
>>
>>
>>
>>
>>> Hello,
>>> This is the initial write-up for the Code Modularity proj. It's goal
>>> is to reorganize the code to simplify the construction of the code
>>> subsets (clients, servers, u2u etc for mobile devices, embedded
>>> systems etc) and, potentially, improve the quality of the code.
>>>
>>> After analyzing various approaches in the constructing of the  
>>> subsets,
>>> we agreed that the best one is to have related functions in the
>>> separate files so that building these files would produce the  
>>> minimal
>>> lib with the required functionality. It is somewhat one-function- 
>>> per-
>>> file approach without going into extremes of literal "one function  
>>> in
>>> one file", rather "file is a holder of the equivalent functions".
>>> Equivalence relation is defined in terms of reflexivity, symmetry  
>>> and
>>> transitivity.
>>>
>>> We define two functions to be equivalent if they have the same  
>>> parent.
>>>
>>> Let X1, X2, X3, ... Xn denote kerb API's and lets call them  
>>> "parents".
>>>
>>> Example 1.
>>> Suppose that x-reference analyzer shows the following function call
>>> stack:
>>> X1 -> C1 -> B -> (A1, A2)   ( i.e X1 calls C1 which calls B, which
>>> calls two functions A1 and A2)
>>> X2 -> C2 -> B -> (A1, A2)
>>> Then the parents are:
>>> X1 -----> X1
>>> C1 -----> X1
>>> X2-----> X2
>>> C2 -----> X2
>>> B  ----->   X1, X2   ( i.e. X1 and X2 are parents of B)
>>> A1-----> X1, X2
>>> A2-----> X1, X2
>>> This brings us to the conclusion that the following functions are
>>> equivalent and may live in three separate files: (X1,C1), (X2, C2),
>>> (B, A1, A2).
>>>
>>> Example 2.
>>> Let x-ref for X1 and X2 be the same as in example 1 and add a new  
>>> API
>>> X3 which calls only A2. Now the parenthood is:
>>> X1 -----> X1
>>> C1 -----> X1
>>> X2-----> X2
>>> C2 -----> X2
>>> X3-----> X3
>>> B  ----->   X1, X2
>>> A1-----> X1, X2
>>> A2-----> X1, X2, X3
>>> resulting into five separate function holders (X1,C1), (X2, C2),  
>>> (X3),
>>> (B, A1), (A2)
>>>
>>> We might consider the case when X2 and X3 are serving similar  
>>> purpose.
>>> For example, they are client-only code. Then, we can define group,  
>>> say
>>> G23:
>>> X1 -----> X1
>>> C1 -----> X1
>>> X2-----> X2
>>> C2 -----> X2
>>> X3-----> X3
>>> B  ----->   X1, G23
>>> A1-----> X1, G23
>>> A2-----> X1, G23
>>> so one needs four files to hold equivalent functions  (X1,C1), (X2,
>>> C2), (X3), (B, A1, A2)
>>>
>>> Thanks,
>>> Zhanna
>>>
>>>
>>>
>>>
>>>
>>>
>>
>> Zhanna Tsitkova
>> tsitkova at mit.edu
>>
>>
>>
>>
>> _______________________________________________
>> krbdev mailing list             krbdev at mit.edu
>> https://mailman.mit.edu/mailman/listinfo/krbdev
>>
>

Zhanna Tsitkova
tsitkova at mit.edu








More information about the krbdev mailing list