# # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # include global definitions include ../../../Makefile.master # # Build everything in parallel; use .WAIT for dependencies .PARALLEL: $(SUBDIRS) SUBDIRS= clnt srv all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install _msg : TARGET= _msg .KEEP_STATE: all clean clobber install _msg: $(SUBDIRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Data Types for policy and principal information that * exists in the respective databases. * * $Header$ * * This file was originally created with rpcgen. * It has been hacked up since then. */ #ifndef __ADB_H__ #define __ADB_H__ #include #include /* SUNWresync121 - no need to change to gssrpc/ */ #include "k5-int.h" #include #include #include #include #include typedef long osa_adb_ret_t; #define OSA_ADB_POLICY_DB_MAGIC 0x12345A00 #define OSA_ADB_PRINC_DB_MAGIC 0x12345B00 #define OSA_ADB_SHARED 0x7001 #define OSA_ADB_EXCLUSIVE 0x7002 #define OSA_ADB_PERMANENT 0x7003 #define OSA_ADB_PRINC_VERSION_MASK 0x12345C00 #define OSA_ADB_PRINC_VERSION_1 0x12345C01 #define OSA_ADB_POLICY_VERSION_MASK 0x12345D00 #define OSA_ADB_POLICY_VERSION_1 0x12345D01 typedef struct _osa_adb_db_lock_ent_t { FILE *lockfile; char *filename; int refcnt, lockmode, lockcnt; krb5_context context; } osa_adb_lock_ent, *osa_adb_lock_t; typedef struct _osa_adb_db_ent_t { int magic; DB *db; HASHINFO info; BTREEINFO btinfo; char *filename; osa_adb_lock_t lock; int opencnt; } osa_adb_db_ent, *osa_adb_db_t, *osa_adb_princ_t, *osa_adb_policy_t; /* an osa_pw_hist_ent stores all the key_datas for a single password */ typedef struct _osa_pw_hist_t { int n_key_data; krb5_key_data *key_data; } osa_pw_hist_ent, *osa_pw_hist_t; typedef struct _osa_princ_ent_t { int version; char *policy; long aux_attributes; unsigned int old_key_len; unsigned int old_key_next; krb5_kvno admin_history_kvno; osa_pw_hist_ent *old_keys; } osa_princ_ent_rec, *osa_princ_ent_t; typedef struct _osa_policy_ent_t { int version; char *name; uint32_t pw_min_life; uint32_t pw_max_life; uint32_t pw_min_length; uint32_t pw_min_classes; uint32_t pw_history_num; uint32_t policy_refcnt; } osa_policy_ent_rec, *osa_policy_ent_t; typedef void (*osa_adb_iter_princ_func) (void *, osa_princ_ent_t); typedef void (*osa_adb_iter_policy_func) (void *, osa_policy_ent_t); /* * Return Code (the rest are in adb_err.h) */ #define OSA_ADB_OK 0 /* * xdr functions */ bool_t xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp); bool_t xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp); bool_t xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp); bool_t xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp); /* * Functions */ osa_adb_ret_t osa_adb_create_db(char *filename, char *lockfile, int magic); osa_adb_ret_t osa_adb_destroy_db(char *filename, char *lockfile, int magic); osa_adb_ret_t osa_adb_rename_db(char *filefrom, char *lockfrom, char *fileto, char *lockto, int magic); osa_adb_ret_t osa_adb_rename_policy_db(kadm5_config_params *fromparams, kadm5_config_params *toparams); osa_adb_ret_t osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfile, int magic); osa_adb_ret_t osa_adb_fini_db(osa_adb_db_t db, int magic); osa_adb_ret_t osa_adb_get_lock(osa_adb_db_t db, int mode); osa_adb_ret_t osa_adb_release_lock(osa_adb_db_t db); osa_adb_ret_t osa_adb_open_and_lock(osa_adb_princ_t db, int locktype); osa_adb_ret_t osa_adb_close_and_unlock(osa_adb_princ_t db); osa_adb_ret_t osa_adb_create_policy_db(kadm5_config_params *params); osa_adb_ret_t osa_adb_destroy_policy_db(kadm5_config_params *params); osa_adb_ret_t osa_adb_open_princ(osa_adb_princ_t *db, char *filename); osa_adb_ret_t osa_adb_open_policy(osa_adb_policy_t *db, kadm5_config_params *rparams); osa_adb_ret_t osa_adb_close_princ(osa_adb_princ_t db); osa_adb_ret_t osa_adb_close_policy(osa_adb_policy_t db); osa_adb_ret_t osa_adb_create_princ(osa_adb_princ_t db, osa_princ_ent_t entry); osa_adb_ret_t osa_adb_create_policy(osa_adb_policy_t db, osa_policy_ent_t entry); osa_adb_ret_t osa_adb_destroy_princ(osa_adb_princ_t db, kadm5_princ_t name); osa_adb_ret_t osa_adb_destroy_policy(osa_adb_policy_t db, kadm5_policy_t name); osa_adb_ret_t osa_adb_get_princ(osa_adb_princ_t db, kadm5_princ_t name, osa_princ_ent_t *entry); osa_adb_ret_t osa_adb_get_policy(osa_adb_policy_t db, kadm5_policy_t name, osa_policy_ent_t *entry); osa_adb_ret_t osa_adb_put_princ(osa_adb_princ_t db, osa_princ_ent_t entry); osa_adb_ret_t osa_adb_put_policy(osa_adb_policy_t db, osa_policy_ent_t entry); osa_adb_ret_t osa_adb_iter_policy(osa_adb_policy_t db, osa_adb_iter_policy_func func, void * data); osa_adb_ret_t osa_adb_iter_princ(osa_adb_princ_t db, osa_adb_iter_princ_func func, void *data); void osa_free_policy_ent(osa_policy_ent_t val); void osa_free_princ_ent(osa_princ_ent_t val); #endif /* __ADB_H__ */ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef __KADM5_ADMIN_H__ #define __KADM5_ADMIN_H__ #ifdef __cplusplus extern "C" { #endif /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * lib/kadm5/admin.h * * Copyright 2001 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #include #include #include #include #include #include #include #include #include #define KADM5_ADMIN_SERVICE_P "kadmin@admin" /* * Solaris Kerberos: * The kadmin/admin principal is unused on Solaris. This principal is used * in AUTH_GSSAPI but Solaris doesn't support AUTH_GSSAPI. RPCSEC_GSS can only * be used with host-based principals. * */ /* #define KADM5_ADMIN_SERVICE "kadmin/admin" */ #define KADM5_CHANGEPW_SERVICE_P "kadmin@changepw" #define KADM5_CHANGEPW_SERVICE "kadmin/changepw" #define KADM5_HIST_PRINCIPAL "kadmin/history" #define KADM5_ADMIN_HOST_SERVICE "kadmin" #define KADM5_CHANGEPW_HOST_SERVICE "changepw" #define KADM5_KIPROP_HOST_SERVICE "kiprop" typedef krb5_principal kadm5_princ_t; typedef char *kadm5_policy_t; typedef long kadm5_ret_t; typedef int rpc_int32; typedef unsigned int rpc_u_int32; #define KADM5_PW_FIRST_PROMPT \ (error_message(CHPASS_UTIL_NEW_PASSWORD_PROMPT)) #define KADM5_PW_SECOND_PROMPT \ (error_message(CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT)) /* * Successful return code */ #define KADM5_OK 0 /* * Field masks */ /* kadm5_principal_ent_t */ #define KADM5_PRINCIPAL 0x000001 #define KADM5_PRINC_EXPIRE_TIME 0x000002 #define KADM5_PW_EXPIRATION 0x000004 #define KADM5_LAST_PWD_CHANGE 0x000008 #define KADM5_ATTRIBUTES 0x000010 #define KADM5_MAX_LIFE 0x000020 #define KADM5_MOD_TIME 0x000040 #define KADM5_MOD_NAME 0x000080 #define KADM5_KVNO 0x000100 #define KADM5_MKVNO 0x000200 #define KADM5_AUX_ATTRIBUTES 0x000400 #define KADM5_POLICY 0x000800 #define KADM5_POLICY_CLR 0x001000 /* version 2 masks */ #define KADM5_MAX_RLIFE 0x002000 #define KADM5_LAST_SUCCESS 0x004000 #define KADM5_LAST_FAILED 0x008000 #define KADM5_FAIL_AUTH_COUNT 0x010000 #define KADM5_KEY_DATA 0x020000 #define KADM5_TL_DATA 0x040000 #ifdef notyet /* Novell */ #define KADM5_CPW_FUNCTION 0x080000 #define KADM5_RANDKEY_USED 0x100000 #endif #define KADM5_LOAD 0x200000 /* Solaris Kerberos: adding support for key history in LDAP KDB */ #define KADM5_KEY_HIST 0x400000 /* all but KEY_DATA and TL_DATA */ #define KADM5_PRINCIPAL_NORMAL_MASK 0x01ffff /* kadm5_policy_ent_t */ #define KADM5_PW_MAX_LIFE 0x004000 #define KADM5_PW_MIN_LIFE 0x008000 #define KADM5_PW_MIN_LENGTH 0x010000 #define KADM5_PW_MIN_CLASSES 0x020000 #define KADM5_PW_HISTORY_NUM 0x040000 #define KADM5_REF_COUNT 0x080000 /* kadm5_config_params */ #define KADM5_CONFIG_REALM 0x0000001 #define KADM5_CONFIG_DBNAME 0x0000002 #define KADM5_CONFIG_MKEY_NAME 0x0000004 #define KADM5_CONFIG_MAX_LIFE 0x0000008 #define KADM5_CONFIG_MAX_RLIFE 0x0000010 #define KADM5_CONFIG_EXPIRATION 0x0000020 #define KADM5_CONFIG_FLAGS 0x0000040 #define KADM5_CONFIG_ADMIN_KEYTAB 0x0000080 #define KADM5_CONFIG_STASH_FILE 0x0000100 #define KADM5_CONFIG_ENCTYPE 0x0000200 #define KADM5_CONFIG_ADBNAME 0x0000400 #define KADM5_CONFIG_ADB_LOCKFILE 0x0000800 #define KADM5_CONFIG_PROFILE 0x0001000 #define KADM5_CONFIG_ACL_FILE 0x0002000 #define KADM5_CONFIG_KADMIND_PORT 0x0004000 #define KADM5_CONFIG_ENCTYPES 0x0008000 #define KADM5_CONFIG_ADMIN_SERVER 0x0010000 #define KADM5_CONFIG_DICT_FILE 0x0020000 #define KADM5_CONFIG_MKEY_FROM_KBD 0x0040000 #define KADM5_CONFIG_KPASSWD_PORT 0x0080000 #define KADM5_CONFIG_KPASSWD_SERVER 0x0100000 #define KADM5_CONFIG_KPASSWD_PROTOCOL 0x0200000 #define KADM5_CONFIG_IPROP_ENABLED 0x0400000 #define KADM5_CONFIG_ULOG_SIZE 0x0800000 #define KADM5_CONFIG_POLL_TIME 0x1000000 /* password change constants */ #define KRB5_KPASSWD_SUCCESS 0 #define KRB5_KPASSWD_MALFORMED 1 #define KRB5_KPASSWD_HARDERROR 2 #define KRB5_KPASSWD_AUTHERROR 3 #define KRB5_KPASSWD_SOFTERROR 4 #define KRB5_KPASSWD_ACCESSDENIED 5 #define KRB5_KPASSWD_BAD_VERSION 6 #define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7 #define KRB5_KPASSWD_POLICY_REJECT 8 #define KRB5_KPASSWD_BAD_PRINCIPAL 9 #define KRB5_KPASSWD_ETYPE_NOSUPP 10 /* * permission bits */ #define KADM5_PRIV_GET 0x01 #define KADM5_PRIV_ADD 0x02 #define KADM5_PRIV_MODIFY 0x04 #define KADM5_PRIV_DELETE 0x08 /* * API versioning constants */ #define KADM5_MASK_BITS 0xffffff00 #define KADM5_STRUCT_VERSION_MASK 0x12345600 #define KADM5_STRUCT_VERSION_1 (KADM5_STRUCT_VERSION_MASK|0x01) #define KADM5_STRUCT_VERSION KADM5_STRUCT_VERSION_1 #define KADM5_API_VERSION_MASK 0x12345700 #define KADM5_API_VERSION_1 (KADM5_API_VERSION_MASK|0x01) #define KADM5_API_VERSION_2 (KADM5_API_VERSION_MASK|0x02) #ifdef KRB5_DNS_LOOKUP /* * Name length constants for DNS lookups */ #define MAX_HOST_NAMELEN 256 #define MAX_DNS_NAMELEN (15*(MAX_HOST_NAMELEN + 1)+1) #endif /* KRB5_DNS_LOOKUP */ typedef struct _kadm5_principal_ent_t_v2 { krb5_principal principal; krb5_timestamp princ_expire_time; krb5_timestamp last_pwd_change; krb5_timestamp pw_expiration; krb5_deltat max_life; krb5_principal mod_name; krb5_timestamp mod_date; krb5_flags attributes; krb5_kvno kvno; krb5_kvno mkvno; char *policy; long aux_attributes; /* version 2 fields */ krb5_deltat max_renewable_life; krb5_timestamp last_success; krb5_timestamp last_failed; krb5_kvno fail_auth_count; krb5_int16 n_key_data; krb5_int16 n_tl_data; krb5_tl_data *tl_data; krb5_key_data *key_data; } kadm5_principal_ent_rec_v2, *kadm5_principal_ent_t_v2; typedef struct _kadm5_principal_ent_t_v1 { krb5_principal principal; krb5_timestamp princ_expire_time; krb5_timestamp last_pwd_change; krb5_timestamp pw_expiration; krb5_deltat max_life; krb5_principal mod_name; krb5_timestamp mod_date; krb5_flags attributes; krb5_kvno kvno; krb5_kvno mkvno; char *policy; long aux_attributes; } kadm5_principal_ent_rec_v1, *kadm5_principal_ent_t_v1; #if USE_KADM5_API_VERSION == 1 typedef struct _kadm5_principal_ent_t_v1 kadm5_principal_ent_rec, *kadm5_principal_ent_t; #else typedef struct _kadm5_principal_ent_t_v2 kadm5_principal_ent_rec, *kadm5_principal_ent_t; #endif typedef struct _kadm5_policy_ent_t { char *policy; long pw_min_life; long pw_max_life; long pw_min_length; long pw_min_classes; long pw_history_num; long policy_refcnt; } kadm5_policy_ent_rec, *kadm5_policy_ent_t; /* * New types to indicate which protocol to use when sending * password change requests */ typedef enum { KRB5_CHGPWD_RPCSEC, KRB5_CHGPWD_CHANGEPW_V2 } krb5_chgpwd_prot; /* * Data structure returned by kadm5_get_config_params() */ typedef struct _kadm5_config_params { long mask; char * realm; int kadmind_port; int kpasswd_port; char * admin_server; #ifdef notyet /* Novell */ /* ABI change? */ char * kpasswd_server; #endif char * dbname; char * admin_dbname; char * admin_lockfile; char * admin_keytab; char * acl_file; char * dict_file; int mkey_from_kbd; char * stash_file; char * mkey_name; krb5_enctype enctype; krb5_deltat max_life; krb5_deltat max_rlife; krb5_timestamp expiration; krb5_flags flags; krb5_key_salt_tuple *keysalts; krb5_int32 num_keysalts; char *kpasswd_server; krb5_chgpwd_prot kpasswd_protocol; bool_t iprop_enabled; int iprop_ulogsize; char *iprop_polltime; } kadm5_config_params; /*********************************************************************** * This is the old krb5_realm_read_params, which I mutated into * kadm5_get_config_params but which old code (kdb5_* and krb5kdc) * still uses. ***********************************************************************/ /* * Data structure returned by krb5_read_realm_params() */ typedef struct __krb5_realm_params { char * realm_profile; char * realm_dbname; char * realm_mkey_name; char * realm_stash_file; char * realm_kdc_ports; char * realm_kdc_tcp_ports; char * realm_acl_file; krb5_int32 realm_kadmind_port; krb5_enctype realm_enctype; krb5_deltat realm_max_life; krb5_deltat realm_max_rlife; krb5_timestamp realm_expiration; krb5_flags realm_flags; krb5_key_salt_tuple *realm_keysalts; unsigned int realm_reject_bad_transit:1; unsigned int realm_kadmind_port_valid:1; unsigned int realm_enctype_valid:1; unsigned int realm_max_life_valid:1; unsigned int realm_max_rlife_valid:1; unsigned int realm_expiration_valid:1; unsigned int realm_flags_valid:1; unsigned int realm_reject_bad_transit_valid:1; krb5_int32 realm_num_keysalts; } krb5_realm_params; /* * functions */ kadm5_ret_t kadm5_get_adm_host_srv_name(krb5_context context, const char *realm, char **host_service_name); kadm5_ret_t kadm5_get_cpw_host_srv_name(krb5_context context, const char *realm, char **host_service_name); #if USE_KADM5_API_VERSION > 1 krb5_error_code kadm5_get_config_params(krb5_context context, int use_kdc_config, kadm5_config_params *params_in, kadm5_config_params *params_out); krb5_error_code kadm5_free_config_params(krb5_context context, kadm5_config_params *params); krb5_error_code kadm5_free_realm_params(krb5_context kcontext, kadm5_config_params *params); krb5_error_code kadm5_get_admin_service_name(krb5_context, char *, char *, size_t); #endif kadm5_ret_t kadm5_init(char *client_name, char *pass, char *service_name, #if USE_KADM5_API_VERSION == 1 char *realm, #else kadm5_config_params *params, #endif krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle); kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, char *service_name, #if USE_KADM5_API_VERSION == 1 char *realm, #else kadm5_config_params *params, #endif krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle); kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, char *service_name, #if USE_KADM5_API_VERSION == 1 char *realm, #else kadm5_config_params *params, #endif krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle); #if USE_KADM5_API_VERSION > 1 kadm5_ret_t kadm5_init_with_creds(char *client_name, krb5_ccache cc, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle); #endif kadm5_ret_t kadm5_lock(void *server_handle); kadm5_ret_t kadm5_unlock(void *server_handle); kadm5_ret_t kadm5_flush(void *server_handle); kadm5_ret_t kadm5_destroy(void *server_handle); kadm5_ret_t kadm5_check_min_life(void *server_handle, /* Solaris Kerberos */ krb5_principal principal, char *msg_ret, unsigned int msg_len); kadm5_ret_t kadm5_create_principal(void *server_handle, kadm5_principal_ent_t ent, long mask, char *pass); kadm5_ret_t kadm5_create_principal_3(void *server_handle, kadm5_principal_ent_t ent, long mask, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *pass); kadm5_ret_t kadm5_delete_principal(void *server_handle, krb5_principal principal); kadm5_ret_t kadm5_modify_principal(void *server_handle, kadm5_principal_ent_t ent, long mask); kadm5_ret_t kadm5_rename_principal(void *server_handle, krb5_principal,krb5_principal); #if USE_KADM5_API_VERSION == 1 kadm5_ret_t kadm5_get_principal(void *server_handle, krb5_principal principal, kadm5_principal_ent_t *ent); #else kadm5_ret_t kadm5_get_principal(void *server_handle, krb5_principal principal, kadm5_principal_ent_t ent, long mask); #endif kadm5_ret_t kadm5_chpass_principal(void *server_handle, krb5_principal principal, char *pass); kadm5_ret_t kadm5_chpass_principal_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *pass); #if USE_KADM5_API_VERSION == 1 kadm5_ret_t kadm5_randkey_principal(void *server_handle, krb5_principal principal, krb5_keyblock **keyblock); #else /* * Solaris Kerberos: * this routine is only implemented in the client library. */ kadm5_ret_t kadm5_randkey_principal_old(void *server_handle, krb5_principal principal, krb5_keyblock **keyblocks, int *n_keys); kadm5_ret_t kadm5_randkey_principal(void *server_handle, krb5_principal principal, krb5_keyblock **keyblocks, int *n_keys); kadm5_ret_t kadm5_randkey_principal_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock **keyblocks, int *n_keys); #endif kadm5_ret_t kadm5_setv4key_principal(void *server_handle, krb5_principal principal, krb5_keyblock *keyblock); kadm5_ret_t kadm5_setkey_principal(void *server_handle, krb5_principal principal, krb5_keyblock *keyblocks, int n_keys); kadm5_ret_t kadm5_setkey_principal_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock *keyblocks, int n_keys); kadm5_ret_t kadm5_decrypt_key(void *server_handle, kadm5_principal_ent_t entry, krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno, krb5_keyblock *keyblock, krb5_keysalt *keysalt, int *kvnop); kadm5_ret_t kadm5_create_policy(void *server_handle, kadm5_policy_ent_t ent, long mask); /* * kadm5_create_policy_internal is not part of the supported, * exposed API. It is available only in the server library, and you * shouldn't use it unless you know why it's there and how it's * different from kadm5_create_policy. */ kadm5_ret_t kadm5_create_policy_internal(void *server_handle, kadm5_policy_ent_t entry, long mask); kadm5_ret_t kadm5_delete_policy(void *server_handle, kadm5_policy_t policy); kadm5_ret_t kadm5_modify_policy(void *server_handle, kadm5_policy_ent_t ent, long mask); /* * kadm5_modify_policy_internal is not part of the supported, * exposed API. It is available only in the server library, and you * shouldn't use it unless you know why it's there and how it's * different from kadm5_modify_policy. */ kadm5_ret_t kadm5_modify_policy_internal(void *server_handle, kadm5_policy_ent_t entry, long mask); #if USE_KADM5_API_VERSION == 1 kadm5_ret_t kadm5_get_policy(void *server_handle, kadm5_policy_t policy, kadm5_policy_ent_t *ent); #else kadm5_ret_t kadm5_get_policy(void *server_handle, kadm5_policy_t policy, kadm5_policy_ent_t ent); #endif kadm5_ret_t kadm5_get_privs(void *server_handle, long *privs); kadm5_ret_t kadm5_chpass_principal_util(void *server_handle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len); kadm5_ret_t kadm5_free_principal_ent(void *server_handle, kadm5_principal_ent_t ent); kadm5_ret_t kadm5_free_policy_ent(void *server_handle, kadm5_policy_ent_t ent); kadm5_ret_t kadm5_get_principals(void *server_handle, char *exp, char ***princs, int *count); kadm5_ret_t kadm5_get_policies(void *server_handle, char *exp, char ***pols, int *count); #if USE_KADM5_API_VERSION > 1 kadm5_ret_t kadm5_free_key_data(void *server_handle, krb5_int16 *n_key_data, krb5_key_data *key_data); #endif kadm5_ret_t kadm5_free_name_list(void *server_handle, char **names, int count); krb5_error_code kadm5_init_krb5_context (krb5_context *); #if USE_KADM5_API_VERSION == 1 /* * OVSEC_KADM_API_VERSION_1 should be, if possible, compile-time * compatible with KADM5_API_VERSION_2. Basically, this means we have * to continue to provide all the old ovsec_kadm function and symbol * names. */ #define OVSEC_KADM_ACLFILE "/krb5/ovsec_adm.acl" #define OVSEC_KADM_WORDFILE "/krb5/ovsec_adm.dict" #define OVSEC_KADM_ADMIN_SERVICE "ovsec_adm/admin" #define OVSEC_KADM_CHANGEPW_SERVICE "ovsec_adm/changepw" #define OVSEC_KADM_HIST_PRINCIPAL "ovsec_adm/history" typedef krb5_principal ovsec_kadm_princ_t; typedef krb5_keyblock ovsec_kadm_keyblock; typedef char *ovsec_kadm_policy_t; typedef long ovsec_kadm_ret_t; enum ovsec_kadm_salttype { OVSEC_KADM_SALT_V4, OVSEC_KADM_SALT_NORMAL }; enum ovsec_kadm_saltmod { OVSEC_KADM_MOD_KEEP, OVSEC_KADM_MOD_V4, OVSEC_KADM_MOD_NORMAL }; #define OVSEC_KADM_PW_FIRST_PROMPT \ ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_PROMPT)) #define OVSEC_KADM_PW_SECOND_PROMPT \ ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT)) /* * Successful return code */ #define OVSEC_KADM_OK 0 /* * Create/Modify masks */ /* principal */ #define OVSEC_KADM_PRINCIPAL 0x000001 #define OVSEC_KADM_PRINC_EXPIRE_TIME 0x000002 #define OVSEC_KADM_PW_EXPIRATION 0x000004 #define OVSEC_KADM_LAST_PWD_CHANGE 0x000008 #define OVSEC_KADM_ATTRIBUTES 0x000010 #define OVSEC_KADM_MAX_LIFE 0x000020 #define OVSEC_KADM_MOD_TIME 0x000040 #define OVSEC_KADM_MOD_NAME 0x000080 #define OVSEC_KADM_KVNO 0x000100 #define OVSEC_KADM_MKVNO 0x000200 #define OVSEC_KADM_AUX_ATTRIBUTES 0x000400 #define OVSEC_KADM_POLICY 0x000800 #define OVSEC_KADM_POLICY_CLR 0x001000 /* policy */ #define OVSEC_KADM_PW_MAX_LIFE 0x004000 #define OVSEC_KADM_PW_MIN_LIFE 0x008000 #define OVSEC_KADM_PW_MIN_LENGTH 0x010000 #define OVSEC_KADM_PW_MIN_CLASSES 0x020000 #define OVSEC_KADM_PW_HISTORY_NUM 0x040000 #define OVSEC_KADM_REF_COUNT 0x080000 /* * permission bits */ #define OVSEC_KADM_PRIV_GET 0x01 #define OVSEC_KADM_PRIV_ADD 0x02 #define OVSEC_KADM_PRIV_MODIFY 0x04 #define OVSEC_KADM_PRIV_DELETE 0x08 /* * API versioning constants */ #define OVSEC_KADM_MASK_BITS 0xffffff00 #define OVSEC_KADM_STRUCT_VERSION_MASK 0x12345600 #define OVSEC_KADM_STRUCT_VERSION_1 (OVSEC_KADM_STRUCT_VERSION_MASK|0x01) #define OVSEC_KADM_STRUCT_VERSION OVSEC_KADM_STRUCT_VERSION_1 #define OVSEC_KADM_API_VERSION_MASK 0x12345700 #define OVSEC_KADM_API_VERSION_1 (OVSEC_KADM_API_VERSION_MASK|0x01) typedef struct _ovsec_kadm_principal_ent_t { krb5_principal principal; krb5_timestamp princ_expire_time; krb5_timestamp last_pwd_change; krb5_timestamp pw_expiration; krb5_deltat max_life; krb5_principal mod_name; krb5_timestamp mod_date; krb5_flags attributes; krb5_kvno kvno; krb5_kvno mkvno; char *policy; long aux_attributes; } ovsec_kadm_principal_ent_rec, *ovsec_kadm_principal_ent_t; typedef struct _ovsec_kadm_policy_ent_t { char *policy; long pw_min_life; long pw_max_life; long pw_min_length; long pw_min_classes; long pw_history_num; long policy_refcnt; } ovsec_kadm_policy_ent_rec, *ovsec_kadm_policy_ent_t; /* * functions */ ovsec_kadm_ret_t ovsec_kadm_init(char *client_name, char *pass, char *service_name, char *realm, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle); ovsec_kadm_ret_t ovsec_kadm_init_with_password(char *client_name, char *pass, char *service_name, char *realm, krb5_ui_4 struct_version, krb5_ui_4 api_version, char ** db_args, void **server_handle); ovsec_kadm_ret_t ovsec_kadm_init_with_skey(char *client_name, char *keytab, char *service_name, char *realm, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle); ovsec_kadm_ret_t ovsec_kadm_flush(void *server_handle); ovsec_kadm_ret_t ovsec_kadm_destroy(void *server_handle); ovsec_kadm_ret_t ovsec_kadm_create_principal(void *server_handle, ovsec_kadm_principal_ent_t ent, long mask, char *pass); ovsec_kadm_ret_t ovsec_kadm_delete_principal(void *server_handle, krb5_principal principal); ovsec_kadm_ret_t ovsec_kadm_modify_principal(void *server_handle, ovsec_kadm_principal_ent_t ent, long mask); ovsec_kadm_ret_t ovsec_kadm_rename_principal(void *server_handle, krb5_principal,krb5_principal); ovsec_kadm_ret_t ovsec_kadm_get_principal(void *server_handle, krb5_principal principal, ovsec_kadm_principal_ent_t *ent); ovsec_kadm_ret_t ovsec_kadm_chpass_principal(void *server_handle, krb5_principal principal, char *pass); ovsec_kadm_ret_t ovsec_kadm_randkey_principal(void *server_handle, krb5_principal principal, krb5_keyblock **keyblock); ovsec_kadm_ret_t ovsec_kadm_create_policy(void *server_handle, ovsec_kadm_policy_ent_t ent, long mask); /* * ovsec_kadm_create_policy_internal is not part of the supported, * exposed API. It is available only in the server library, and you * shouldn't use it unless you know why it's there and how it's * different from ovsec_kadm_create_policy. */ ovsec_kadm_ret_t ovsec_kadm_create_policy_internal(void *server_handle, ovsec_kadm_policy_ent_t entry, long mask); ovsec_kadm_ret_t ovsec_kadm_delete_policy(void *server_handle, ovsec_kadm_policy_t policy); ovsec_kadm_ret_t ovsec_kadm_modify_policy(void *server_handle, ovsec_kadm_policy_ent_t ent, long mask); /* * ovsec_kadm_modify_policy_internal is not part of the supported, * exposed API. It is available only in the server library, and you * shouldn't use it unless you know why it's there and how it's * different from ovsec_kadm_modify_policy. */ ovsec_kadm_ret_t ovsec_kadm_modify_policy_internal(void *server_handle, ovsec_kadm_policy_ent_t entry, long mask); ovsec_kadm_ret_t ovsec_kadm_get_policy(void *server_handle, ovsec_kadm_policy_t policy, ovsec_kadm_policy_ent_t *ent); ovsec_kadm_ret_t ovsec_kadm_get_privs(void *server_handle, long *privs); ovsec_kadm_ret_t ovsec_kadm_chpass_principal_util(void *server_handle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret); ovsec_kadm_ret_t ovsec_kadm_free_principal_ent(void *server_handle, ovsec_kadm_principal_ent_t ent); ovsec_kadm_ret_t ovsec_kadm_free_policy_ent(void *server_handle, ovsec_kadm_policy_ent_t ent); ovsec_kadm_ret_t ovsec_kadm_free_name_list(void *server_handle, char **names, int count); ovsec_kadm_ret_t ovsec_kadm_get_principals(void *server_handle, char *exp, char ***princs, int *count); ovsec_kadm_ret_t ovsec_kadm_get_policies(void *server_handle, char *exp, char ***pols, int *count); #define OVSEC_KADM_FAILURE KADM5_FAILURE #define OVSEC_KADM_AUTH_GET KADM5_AUTH_GET #define OVSEC_KADM_AUTH_ADD KADM5_AUTH_ADD #define OVSEC_KADM_AUTH_MODIFY KADM5_AUTH_MODIFY #define OVSEC_KADM_AUTH_DELETE KADM5_AUTH_DELETE #define OVSEC_KADM_AUTH_INSUFFICIENT KADM5_AUTH_INSUFFICIENT #define OVSEC_KADM_BAD_DB KADM5_BAD_DB #define OVSEC_KADM_DUP KADM5_DUP #define OVSEC_KADM_RPC_ERROR KADM5_RPC_ERROR #define OVSEC_KADM_NO_SRV KADM5_NO_SRV #define OVSEC_KADM_BAD_HIST_KEY KADM5_BAD_HIST_KEY #define OVSEC_KADM_NOT_INIT KADM5_NOT_INIT #define OVSEC_KADM_UNK_PRINC KADM5_UNK_PRINC #define OVSEC_KADM_UNK_POLICY KADM5_UNK_POLICY #define OVSEC_KADM_BAD_MASK KADM5_BAD_MASK #define OVSEC_KADM_BAD_CLASS KADM5_BAD_CLASS #define OVSEC_KADM_BAD_LENGTH KADM5_BAD_LENGTH #define OVSEC_KADM_BAD_POLICY KADM5_BAD_POLICY #define OVSEC_KADM_BAD_PRINCIPAL KADM5_BAD_PRINCIPAL #define OVSEC_KADM_BAD_AUX_ATTR KADM5_BAD_AUX_ATTR #define OVSEC_KADM_BAD_HISTORY KADM5_BAD_HISTORY #define OVSEC_KADM_BAD_MIN_PASS_LIFE KADM5_BAD_MIN_PASS_LIFE #define OVSEC_KADM_PASS_Q_TOOSHORT KADM5_PASS_Q_TOOSHORT #define OVSEC_KADM_PASS_Q_CLASS KADM5_PASS_Q_CLASS #define OVSEC_KADM_PASS_Q_DICT KADM5_PASS_Q_DICT #define OVSEC_KADM_PASS_REUSE KADM5_PASS_REUSE #define OVSEC_KADM_PASS_TOOSOON KADM5_PASS_TOOSOON #define OVSEC_KADM_POLICY_REF KADM5_POLICY_REF #define OVSEC_KADM_INIT KADM5_INIT #define OVSEC_KADM_BAD_PASSWORD KADM5_BAD_PASSWORD #define OVSEC_KADM_PROTECT_PRINCIPAL KADM5_PROTECT_PRINCIPAL #define OVSEC_KADM_BAD_SERVER_HANDLE KADM5_BAD_SERVER_HANDLE #define OVSEC_KADM_BAD_STRUCT_VERSION KADM5_BAD_STRUCT_VERSION #define OVSEC_KADM_OLD_STRUCT_VERSION KADM5_OLD_STRUCT_VERSION #define OVSEC_KADM_NEW_STRUCT_VERSION KADM5_NEW_STRUCT_VERSION #define OVSEC_KADM_BAD_API_VERSION KADM5_BAD_API_VERSION #define OVSEC_KADM_OLD_LIB_API_VERSION KADM5_OLD_LIB_API_VERSION #define OVSEC_KADM_OLD_SERVER_API_VERSION KADM5_OLD_SERVER_API_VERSION #define OVSEC_KADM_NEW_LIB_API_VERSION KADM5_NEW_LIB_API_VERSION #define OVSEC_KADM_NEW_SERVER_API_VERSION KADM5_NEW_SERVER_API_VERSION #define OVSEC_KADM_SECURE_PRINC_MISSING KADM5_SECURE_PRINC_MISSING #define OVSEC_KADM_NO_RENAME_SALT KADM5_NO_RENAME_SALT #endif /* USE_KADM5_API_VERSION == 1 */ #define MAXPRINCLEN 125 void trunc_name(size_t *len, char **dots); krb5_chgpwd_prot _kadm5_get_kpasswd_protocol(void *server_handle); kadm5_ret_t kadm5_chpass_principal_v2(void *server_handle, krb5_principal princ, char *new_password, kadm5_ret_t *srvr_rsp_code, krb5_data *srvr_msg); void handle_chpw(krb5_context context, int s, void *serverhandle, kadm5_config_params *params); #ifdef __cplusplus } #endif #endif /* __KADM5_ADMIN_H__ */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * */ #ifndef __KADM5_ADMIN_INTERNAL_H__ #define __KADM5_ADMIN_INTERNAL_H__ #include #ifdef DEBUG #define ADMIN_LOG(a, b, c) syslog(a, b, c); #define ADMIN_LOGO(a, b) syslog(a, b); #else #define ADMIN_LOG(a, b, c) #define ADMIN_LOGO(a, b) #endif #define KADM5_SERVER_HANDLE_MAGIC 0x12345800 #define GENERIC_CHECK_HANDLE(handle, old_api_version, new_api_version) \ { \ kadm5_server_handle_t srvr = \ (kadm5_server_handle_t) handle; \ \ if (! srvr) \ return KADM5_BAD_SERVER_HANDLE; \ if (srvr->magic_number != KADM5_SERVER_HANDLE_MAGIC) \ return KADM5_BAD_SERVER_HANDLE; \ if ((srvr->struct_version & KADM5_MASK_BITS) != \ KADM5_STRUCT_VERSION_MASK) \ return KADM5_BAD_STRUCT_VERSION; \ if (srvr->struct_version < KADM5_STRUCT_VERSION_1) \ return KADM5_OLD_STRUCT_VERSION; \ if (srvr->struct_version > KADM5_STRUCT_VERSION_1) \ return KADM5_NEW_STRUCT_VERSION; \ if ((srvr->api_version & KADM5_MASK_BITS) != \ KADM5_API_VERSION_MASK) \ return KADM5_BAD_API_VERSION; \ if (srvr->api_version < KADM5_API_VERSION_1) \ return old_api_version; \ if (srvr->api_version > KADM5_API_VERSION_2) \ return new_api_version; \ } /* * _KADM5_CHECK_HANDLE calls the function _kadm5_check_handle and * returns any non-zero error code that function returns. * _kadm5_check_handle, in client_handle.c and server_handle.c, exists * in both the server- and client- side libraries. In each library, * it calls CHECK_HANDLE, which is defined by the appropriate * _internal.h header file to call GENERIC_CHECK_HANDLE as well as * CLIENT_CHECK_HANDLE and SERVER_CHECK_HANDLE. * * _KADM5_CHECK_HANDLE should be used by a function that needs to * check the handle but wants to be the same code in both the client * and server library; it makes a function call to the right handle * checker. Code that only exists in one library can call the * CHECK_HANDLE macro, which inlines the test instead of making * another function call. * * Got that? */ #define _KADM5_CHECK_HANDLE(handle) \ { int ecode; if ((ecode = _kadm5_check_handle((void *)handle))) return ecode;} int _kadm5_check_handle(void *handle); kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle, void *lhandle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len); /* this is needed by the alt_prof code I stole. The functions maybe shouldn't be named krb5_*, but they are. */ krb5_error_code krb5_string_to_keysalts(char *string, const char *tupleseps, const char *ksaltseps, krb5_boolean dups, krb5_key_salt_tuple **ksaltp, krb5_int32 *nksaltp); krb5_error_code krb5_string_to_flags(char* string, const char* positive, const char* negative, krb5_flags *flagsp); #endif /* __KADM5_ADMIN_INTERNAL_H__ */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ * */ #include #include "kadm_rpc.h" #include "server_internal.h" bool_t xdr_ui_4(XDR *xdrs, krb5_ui_4 *objp); bool_t xdr_nullstring(XDR *xdrs, char **objp); bool_t xdr_nulltype(XDR *xdrs, void **objp, xdrproc_t proc); bool_t xdr_krb5_timestamp(XDR *xdrs, krb5_timestamp *objp); bool_t xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp); bool_t xdr_krb5_deltat(XDR *xdrs, krb5_deltat *objp); bool_t xdr_krb5_flags(XDR *xdrs, krb5_flags *objp); bool_t xdr_krb5_ui_4(XDR *xdrs, krb5_ui_4 *objp); bool_t xdr_krb5_int16(XDR *xdrs, krb5_int16 *objp); bool_t xdr_krb5_ui_2(XDR *xdrs, krb5_ui_2 *objp); bool_t xdr_krb5_key_data_nocontents(XDR *xdrs, krb5_key_data *objp); bool_t xdr_krb5_key_salt_tuple(XDR *xdrs, krb5_key_salt_tuple *objp); bool_t xdr_krb5_tl_data(XDR *xdrs, krb5_tl_data **tl_data_head); bool_t xdr_kadm5_ret_t(XDR *xdrs, kadm5_ret_t *objp); bool_t xdr_kadm5_principal_ent_rec_v1(XDR *xdrs, kadm5_principal_ent_rec *objp); bool_t xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp); bool_t xdr_kadm5_policy_ent_rec(XDR *xdrs, kadm5_policy_ent_rec *objp); bool_t xdr_kadm5_policy_ent_t(XDR *xdrs, kadm5_policy_ent_t *objp); bool_t xdr_kadm5_principal_ent_t(XDR *xdrs, kadm5_principal_ent_t *objp); bool_t xdr_cprinc_arg(XDR *xdrs, cprinc_arg *objp); bool_t xdr_cprinc3_arg(XDR *xdrs, cprinc3_arg *objp); bool_t xdr_generic_ret(XDR *xdrs, generic_ret *objp); bool_t xdr_dprinc_arg(XDR *xdrs, dprinc_arg *objp); bool_t xdr_mprinc_arg(XDR *xdrs, mprinc_arg *objp); bool_t xdr_rprinc_arg(XDR *xdrs, rprinc_arg *objp); bool_t xdr_chpass_arg(XDR *xdrs, chpass_arg *objp); bool_t xdr_chpass3_arg(XDR *xdrs, chpass3_arg *objp); bool_t xdr_setv4key_arg(XDR *xdrs, setv4key_arg *objp); bool_t xdr_setkey_arg(XDR *xdrs, setkey_arg *objp); bool_t xdr_setkey3_arg(XDR *xdrs, setkey3_arg *objp); bool_t xdr_chrand_arg(XDR *xdrs, chrand_arg *objp); bool_t xdr_chrand3_arg(XDR *xdrs, chrand3_arg *objp); bool_t xdr_chrand_ret(XDR *xdrs, chrand_ret *objp); bool_t xdr_gprinc_arg(XDR *xdrs, gprinc_arg *objp); bool_t xdr_gprinc_ret(XDR *xdrs, gprinc_ret *objp); bool_t xdr_gprincs_arg(XDR *xdrs, gprincs_arg *objp); bool_t xdr_gprincs_ret(XDR *xdrs, gprincs_ret *objp); bool_t xdr_cpol_arg(XDR *xdrs, cpol_arg *objp); bool_t xdr_dpol_arg(XDR *xdrs, dpol_arg *objp); bool_t xdr_mpol_arg(XDR *xdrs, mpol_arg *objp); bool_t xdr_gpol_arg(XDR *xdrs, gpol_arg *objp); bool_t xdr_gpol_ret(XDR *xdrs, gpol_ret *objp); bool_t xdr_gpols_arg(XDR *xdrs, gpols_arg *objp); bool_t xdr_gpols_ret(XDR *xdrs, gpols_ret *objp); bool_t xdr_getprivs_ret(XDR *xdrs, getprivs_ret *objp); bool_t xdr_krb5_principal(XDR *xdrs, krb5_principal *objp); bool_t xdr_krb5_octet(XDR *xdrs, krb5_octet *objp); bool_t xdr_krb5_int32(XDR *xdrs, krb5_int32 *objp); bool_t xdr_krb5_enctype(XDR *xdrs, krb5_enctype *objp); bool_t xdr_krb5_salttype(XDR *xdrs, krb5_int32 *objp); bool_t xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp); bool_t xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp); bool_t xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp); /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * lib/kadm/alt_prof.c * * Copyright 1995,2001 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * alt_prof.c - Implement alternate profile file handling. */ #include "k5-int.h" #include #include "adm_proto.h" #include #include #include #include krb5_error_code kadm5_free_config_params(); #define DEFAULT_ENCTYPE_LIST \ "aes256-cts-hmac-sha1-96:normal " \ "aes128-cts-hmac-sha1-96:normal " \ "des3-cbc-hmac-sha1-kd:normal " \ "arcfour-hmac-md5:normal " \ "arcfour-hmac-md5-exp:normal " \ "des-cbc-md5:normal " \ "des-cbc-crc:normal" static krb5_key_salt_tuple *copy_key_salt_tuple(ksalt, len) krb5_key_salt_tuple *ksalt; krb5_int32 len; { krb5_key_salt_tuple *knew; if((knew = (krb5_key_salt_tuple *) malloc((len ) * sizeof(krb5_key_salt_tuple)))) { memcpy(knew, ksalt, len * sizeof(krb5_key_salt_tuple)); return knew; } return 0; } /* * krb5_aprof_init() - Initialize alternate profile context. * * Parameters: * fname - default file name of the profile. * envname - environment variable name which can override fname. * acontextp - Pointer to opaque context for alternate profile. * * Returns: * error codes from profile_init() */ krb5_error_code krb5_aprof_init(fname, envname, acontextp) char *fname; char *envname; krb5_pointer *acontextp; { krb5_error_code kret; profile_t profile; const char *kdc_config; size_t krb5_config_len, kdc_config_len; char *profile_path; char **filenames; int i; kret = krb5_get_default_config_files (&filenames); if (kret) return kret; krb5_config_len = 0; for (i = 0; filenames[i] != NULL; i++) krb5_config_len += strlen(filenames[i]) + 1; if (i > 0) krb5_config_len--; if (envname == NULL || (kdc_config = getenv(envname)) == NULL) kdc_config = fname; if (kdc_config == NULL) kdc_config_len = 0; else kdc_config_len = strlen(kdc_config); profile_path = malloc(2 + krb5_config_len + kdc_config_len); if (profile_path == NULL) { krb5_free_config_files(filenames); return errno; } if (kdc_config_len) strcpy(profile_path, kdc_config); else profile_path[0] = 0; if (krb5_config_len) for (i = 0; filenames[i] != NULL; i++) { if (kdc_config_len || i) strcat(profile_path, ":"); strcat(profile_path, filenames[i]); } krb5_free_config_files(filenames); profile = (profile_t) NULL; kret = profile_init_path(profile_path, &profile); free(profile_path); if (kret) return kret; *acontextp = profile; return 0; } /* * krb5_aprof_getvals() - Get values from alternate profile. * * Parameters: * acontext - opaque context for alternate profile. * hierarchy - hierarchy of value to retrieve. * retdata - Returned data values. * * Returns: * error codes from profile_get_values() */ krb5_error_code krb5_aprof_getvals(acontext, hierarchy, retdata) krb5_pointer acontext; const char **hierarchy; char ***retdata; { return(profile_get_values((profile_t) acontext, hierarchy, retdata)); } /* * krb5_aprof_get_boolean() * * Parameters: * acontext - opaque context for alternate profile * hierarchy - hierarchy of value to retrieve * retdata - Returned data value * Returns: * error codes */ static krb5_error_code string_to_boolean (const char *string, krb5_boolean *out) { static const char *const yes[] = { "y", "yes", "true", "t", "1", "on" }; static const char *const no[] = { "n", "no", "false", "f", "nil", "0", "off" }; int i; for (i = 0; i < sizeof(yes)/sizeof(yes[0]); i++) if (!strcasecmp(string, yes[i])) { *out = 1; return 0; } for (i = 0; i < sizeof(no)/sizeof(no[0]); i++) if (!strcasecmp(string, no[i])) { *out = 0; return 0; } return PROF_BAD_BOOLEAN; } krb5_error_code krb5_aprof_get_boolean(krb5_pointer acontext, const char **hierarchy, int uselast, krb5_boolean *retdata) { krb5_error_code kret; char **values; char *valp; int idx; krb5_boolean val; kret = krb5_aprof_getvals (acontext, hierarchy, &values); if (kret) return kret; idx = 0; if (uselast) { while (values[idx]) idx++; idx--; } valp = values[idx]; kret = string_to_boolean (valp, &val); if (kret) return kret; *retdata = val; return 0; } /* * krb5_aprof_get_deltat() - Get a delta time value from the alternate * profile. * * Parameters: * acontext - opaque context for alternate profile. * hierarchy - hierarchy of value to retrieve. * uselast - if true, use last value, otherwise use * first value found. * deltatp - returned delta time value. * * Returns: * error codes from profile_get_values() * error codes from krb5_string_to_deltat() */ krb5_error_code krb5_aprof_get_deltat(acontext, hierarchy, uselast, deltatp) krb5_pointer acontext; const char **hierarchy; krb5_boolean uselast; krb5_deltat *deltatp; { krb5_error_code kret; char **values; char *valp; int idx; if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) { idx = 0; if (uselast) { for (idx=0; values[idx]; idx++); idx--; } valp = values[idx]; kret = krb5_string_to_deltat(valp, deltatp); /* Free the string storage */ for (idx=0; values[idx]; idx++) krb5_xfree(values[idx]); krb5_xfree(values); } return(kret); } /* * krb5_aprof_get_string() - Get a string value from the alternate * profile. * * Parameters: * acontext - opaque context for alternate profile. * hierarchy - hierarchy of value to retrieve. * uselast - if true, use last value, otherwise use * first value found. * stringp - returned string value. * * Returns: * error codes from profile_get_values() */ krb5_error_code krb5_aprof_get_string(acontext, hierarchy, uselast, stringp) krb5_pointer acontext; const char **hierarchy; krb5_boolean uselast; char **stringp; { krb5_error_code kret; char **values; int idx, i; if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) { idx = 0; if (uselast) { for (idx=0; values[idx]; idx++); idx--; } *stringp = values[idx]; /* Free the string storage */ for (i=0; values[i]; i++) if (i != idx) krb5_xfree(values[i]); krb5_xfree(values); } return(kret); } /* * krb5_aprof_get_int32() - Get a 32-bit integer value from the alternate * profile. * * Parameters: * acontext - opaque context for alternate profile. * hierarchy - hierarchy of value to retrieve. * uselast - if true, use last value, otherwise use * first value found. * intp - returned 32-bit integer value. * * Returns: * error codes from profile_get_values() * EINVAL - value is not an integer */ krb5_error_code krb5_aprof_get_int32(acontext, hierarchy, uselast, intp) krb5_pointer acontext; const char **hierarchy; krb5_boolean uselast; krb5_int32 *intp; { krb5_error_code kret; char **values; int idx; if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) { idx = 0; if (uselast) { for (idx=0; values[idx]; idx++); idx--; } if (sscanf(values[idx], "%d", intp) != 1) kret = EINVAL; /* Free the string storage */ for (idx=0; values[idx]; idx++) krb5_xfree(values[idx]); krb5_xfree(values); } return(kret); } /* * krb5_aprof_finish() - Finish alternate profile context. * * Parameter: * acontext - opaque context for alternate profile. * * Returns: * 0 on success, something else on failure. */ krb5_error_code krb5_aprof_finish(acontext) krb5_pointer acontext; { profile_release(acontext); return(0); } /* * Function: kadm5_get_config_params * * Purpose: Merge configuration parameters provided by the caller with * values specified in configuration files and with default values. * * Arguments: * * context (r) krb5_context to use * profile (r) profile file to use * envname (r) envname that contains a profile name to * override profile * params_in (r) params structure containing user-supplied * values, or NULL * params_out (w) params structure to be filled in * * Effects: * * The fields and mask of params_out are filled in with values * obtained from params_in, the specified profile, and default * values. Only and all fields specified in params_out->mask are * set. The context of params_out must be freed with * kadm5_free_config_params. * * params_in and params_out may be the same pointer. However, all pointers * in params_in for which the mask is set will be re-assigned to newly copied * versions, overwriting the old pointer value. */ krb5_error_code kadm5_get_config_params(context, use_kdc_config, params_in, params_out) krb5_context context; int use_kdc_config; kadm5_config_params *params_in, *params_out; { char *filename; char *envname; char *lrealm; krb5_pointer aprofile = 0; const char *hierarchy[4]; char *svalue; krb5_int32 ivalue; kadm5_config_params params, empty_params; krb5_error_code kret = 0; krb5_error_code dnsret = 1; #ifdef KRB5_DNS_LOOKUP char dns_host[MAX_DNS_NAMELEN]; unsigned short dns_portno; krb5_data dns_realm; memset((char *)&dns_realm, 0, sizeof (dns_realm)); #endif /* KRB5_DNS_LOOKUP */ memset((char *) ¶ms, 0, sizeof(params)); memset((char *) &empty_params, 0, sizeof(empty_params)); if (params_in == NULL) params_in = &empty_params; if (params_in->mask & KADM5_CONFIG_REALM) { lrealm = params.realm = strdup(params_in->realm); if (params.realm) params.mask |= KADM5_CONFIG_REALM; } else { kret = krb5_get_default_realm(context, &lrealm); if (kret) goto cleanup; params.realm = lrealm; params.mask |= KADM5_CONFIG_REALM; } /* * XXX These defaults should to work on both client and * server. kadm5_get_config_params can be implemented as a * wrapper function in each library that provides correct * defaults for NULL values. */ if (use_kdc_config) { filename = DEFAULT_KDC_PROFILE; envname = KDC_PROFILE_ENV; } else { filename = DEFAULT_PROFILE_PATH; envname = "KRB5_CONFIG"; } if (context->profile_secure == TRUE) envname = 0; kret = krb5_aprof_init(filename, envname, &aprofile); if (kret) goto cleanup; /* Initialize realm parameters */ hierarchy[0] = "realms"; hierarchy[1] = lrealm; hierarchy[3] = (char *) NULL; #ifdef KRB5_DNS_LOOKUP /* * Initialize realm info for (possible) DNS lookups. */ dns_realm.data = strdup(lrealm); dns_realm.length = strlen(lrealm); dns_realm.magic = 0; #endif /* KRB5_DNS_LOOKUP */ /* Get the value for the admin server */ hierarchy[2] = "admin_server"; if (params_in->mask & KADM5_CONFIG_ADMIN_SERVER) { params.admin_server = strdup(params_in->admin_server); if (params.admin_server) params.mask |= KADM5_CONFIG_ADMIN_SERVER; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { params.admin_server = svalue; params.mask |= KADM5_CONFIG_ADMIN_SERVER; } #ifdef KRB5_DNS_LOOKUP else if (strcmp(envname, "KRB5_CONFIG") == 0) { /* * Solaris Kerberos: only do DNS lookup for admin_server if this * is a krb5.conf type of config file. Note, the filename may * not be /etc/krb5/krb5.conf so we assume that the KRB5_CONFIG * envname string will consistently indicate the type of config * file. */ dnsret = krb5_get_servername(context, &dns_realm, "_kerberos-adm", "_udp", dns_host, &dns_portno); if (dnsret == 0) { params.admin_server = strdup(dns_host); if (params.admin_server) params.mask |= KADM5_CONFIG_ADMIN_SERVER; params.kadmind_port = dns_portno; params.mask |= KADM5_CONFIG_KADMIND_PORT; } } #endif /* KRB5_DNS_LOOKUP */ if ((params.mask & KADM5_CONFIG_ADMIN_SERVER) && dnsret) { char *p; p = strchr(params.admin_server, ':'); if (p) { params.kadmind_port = atoi(p+1); params.mask |= KADM5_CONFIG_KADMIND_PORT; *p = '\0'; } } /* Get the value for the database */ hierarchy[2] = "database_name"; if (params_in->mask & KADM5_CONFIG_DBNAME) { params.dbname = strdup(params_in->dbname); if (params.dbname) params.mask |= KADM5_CONFIG_DBNAME; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { params.dbname = svalue; params.mask |= KADM5_CONFIG_DBNAME; } else { params.dbname = strdup(DEFAULT_KDB_FILE); if (params.dbname) params.mask |= KADM5_CONFIG_DBNAME; } /* * admin database name and lockfile are now always derived from dbname */ if (params.mask & KADM5_CONFIG_DBNAME) { params.admin_dbname = (char *) malloc(strlen(params.dbname) + 7); if (params.admin_dbname) { sprintf(params.admin_dbname, "%s.kadm5", params.dbname); params.mask |= KADM5_CONFIG_ADBNAME; } } if (params.mask & KADM5_CONFIG_ADBNAME) { params.admin_lockfile = (char *) malloc(strlen(params.admin_dbname) + 6); if (params.admin_lockfile) { sprintf(params.admin_lockfile, "%s.lock", params.admin_dbname); params.mask |= KADM5_CONFIG_ADB_LOCKFILE; } } /* Get the value for the admin (policy) database lock file*/ hierarchy[2] = "admin_keytab"; if (params_in->mask & KADM5_CONFIG_ADMIN_KEYTAB) { params.admin_keytab = strdup(params_in->admin_keytab); if (params.admin_keytab) params.mask |= KADM5_CONFIG_ADMIN_KEYTAB; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { params.mask |= KADM5_CONFIG_ADMIN_KEYTAB; params.admin_keytab = svalue; } else if ((params.admin_keytab = (char *) getenv("KRB5_KTNAME"))) { params.admin_keytab = strdup(params.admin_keytab); if (params.admin_keytab) params.mask |= KADM5_CONFIG_ADMIN_KEYTAB; } else { params.admin_keytab = strdup(DEFAULT_KADM5_KEYTAB); if (params.admin_keytab) params.mask |= KADM5_CONFIG_ADMIN_KEYTAB; } /* Get the name of the acl file */ hierarchy[2] = "acl_file"; if (params_in->mask & KADM5_CONFIG_ACL_FILE) { params.acl_file = strdup(params_in->acl_file); if (params.acl_file) params.mask |= KADM5_CONFIG_ACL_FILE; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { params.mask |= KADM5_CONFIG_ACL_FILE; params.acl_file = svalue; } else { params.acl_file = strdup(DEFAULT_KADM5_ACL_FILE); if (params.acl_file) params.mask |= KADM5_CONFIG_ACL_FILE; } /* Get the name of the dict file */ hierarchy[2] = "dict_file"; if (params_in->mask & KADM5_CONFIG_DICT_FILE) { params.dict_file = strdup(params_in->dict_file); if (params.dict_file) params.mask |= KADM5_CONFIG_DICT_FILE; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { params.mask |= KADM5_CONFIG_DICT_FILE; params.dict_file = svalue; } /* Get the value for the kadmind port */ if (! (params.mask & KADM5_CONFIG_KADMIND_PORT)) { hierarchy[2] = "kadmind_port"; if (params_in->mask & KADM5_CONFIG_KADMIND_PORT) { params.mask |= KADM5_CONFIG_KADMIND_PORT; params.kadmind_port = params_in->kadmind_port; } else if (aprofile && !krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) { params.kadmind_port = ivalue; params.mask |= KADM5_CONFIG_KADMIND_PORT; } else { params.kadmind_port = DEFAULT_KADM5_PORT; params.mask |= KADM5_CONFIG_KADMIND_PORT; } } /* Get the value for the kpasswd port */ if (! (params.mask & KADM5_CONFIG_KPASSWD_PORT)) { hierarchy[2] = "kpasswd_port"; if (params_in->mask & KADM5_CONFIG_KPASSWD_PORT) { params.mask |= KADM5_CONFIG_KPASSWD_PORT; params.kpasswd_port = params_in->kpasswd_port; } else if (aprofile && !krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) { params.kpasswd_port = ivalue; params.mask |= KADM5_CONFIG_KPASSWD_PORT; } else { params.kpasswd_port = DEFAULT_KPASSWD_PORT; params.mask |= KADM5_CONFIG_KPASSWD_PORT; } } /* Get the value for the master key name */ hierarchy[2] = "master_key_name"; if (params_in->mask & KADM5_CONFIG_MKEY_NAME) { params.mkey_name = strdup(params_in->mkey_name); if (params.mkey_name) params.mask |= KADM5_CONFIG_MKEY_NAME; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { params.mask |= KADM5_CONFIG_MKEY_NAME; params.mkey_name = svalue; } /* Get the value for the master key type */ hierarchy[2] = "master_key_type"; if (params_in->mask & KADM5_CONFIG_ENCTYPE) { params.mask |= KADM5_CONFIG_ENCTYPE; params.enctype = params_in->enctype; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { if (!krb5_string_to_enctype(svalue, ¶ms.enctype)) { params.mask |= KADM5_CONFIG_ENCTYPE; krb5_xfree(svalue); } } else { params.mask |= KADM5_CONFIG_ENCTYPE; params.enctype = DEFAULT_KDC_ENCTYPE; } /* Get the value for mkey_from_kbd */ if (params_in->mask & KADM5_CONFIG_MKEY_FROM_KBD) { params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; params.mkey_from_kbd = params_in->mkey_from_kbd; } /* Get the value for the stashfile */ hierarchy[2] = "key_stash_file"; if (params_in->mask & KADM5_CONFIG_STASH_FILE) { params.stash_file = strdup(params_in->stash_file); if (params.stash_file) params.mask |= KADM5_CONFIG_STASH_FILE; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { params.mask |= KADM5_CONFIG_STASH_FILE; params.stash_file = svalue; } /* * Solaris Kerberos * Get the value for maximum ticket lifetime. * See SEAM documentation or the Bug ID 4184504 * We have changed the logic so that the entries are * created in the database with the maximum duration * for life and renew life KRB5_INT32_MAX * However this wil get negotiated down when * as or tgs request is processed by KDC. */ hierarchy[2] = "max_life"; if (params_in->mask & KADM5_CONFIG_MAX_LIFE) { params.mask |= KADM5_CONFIG_MAX_LIFE; params.max_life = params_in->max_life; } else { params.max_life = KRB5_INT32_MAX; params.mask |= KADM5_CONFIG_MAX_LIFE; } /* Get the value for maximum renewable ticket lifetime. */ hierarchy[2] = "max_renewable_life"; if (params_in->mask & KADM5_CONFIG_MAX_RLIFE) { params.mask |= KADM5_CONFIG_MAX_RLIFE; params.max_rlife = params_in->max_rlife; } else { params.max_rlife = KRB5_INT32_MAX; params.mask |= KADM5_CONFIG_MAX_RLIFE; } /* Get the value for the default principal expiration */ hierarchy[2] = "default_principal_expiration"; if (params_in->mask & KADM5_CONFIG_EXPIRATION) { params.mask |= KADM5_CONFIG_EXPIRATION; params.expiration = params_in->expiration; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { if (!krb5_string_to_timestamp(svalue, ¶ms.expiration)) { params.mask |= KADM5_CONFIG_EXPIRATION; krb5_xfree(svalue); } } else { params.mask |= KADM5_CONFIG_EXPIRATION; params.expiration = 0; } /* Get the value for the default principal flags */ hierarchy[2] = "default_principal_flags"; if (params_in->mask & KADM5_CONFIG_FLAGS) { params.mask |= KADM5_CONFIG_FLAGS; params.flags = params_in->flags; } else if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { char *sp, *ep, *tp; sp = svalue; params.flags = 0; while (sp) { if ((ep = strchr(sp, (int) ',')) || (ep = strchr(sp, (int) ' ')) || (ep = strchr(sp, (int) '\t'))) { /* Fill in trailing whitespace of sp */ tp = ep - 1; while (isspace((int) *tp) && (tp > sp)) { *tp = '\0'; tp--; } *ep = '\0'; ep++; /* Skip over trailing whitespace of ep */ while (isspace((int) *ep) && (*ep)) ep++; } /* Convert this flag */ if (krb5_string_to_flags(sp, "+", "-", ¶ms.flags)) break; sp = ep; } if (!sp) params.mask |= KADM5_CONFIG_FLAGS; krb5_xfree(svalue); } else { params.mask |= KADM5_CONFIG_FLAGS; params.flags = KRB5_KDB_DEF_FLAGS; } /* Get the value for the supported enctype/salttype matrix */ hierarchy[2] = "supported_enctypes"; if (params_in->mask & KADM5_CONFIG_ENCTYPES) { params.mask |= KADM5_CONFIG_ENCTYPES; if (params_in->num_keysalts > 0) { params.keysalts = malloc(params_in->num_keysalts * sizeof (*params.keysalts)); if (params.keysalts == NULL) { kret = ENOMEM; goto cleanup; } (void) memcpy(params.keysalts, params_in->keysalts, (params_in->num_keysalts * sizeof (*params.keysalts))); params.num_keysalts = params_in->num_keysalts; } } else { svalue = NULL; if (aprofile) krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue); if (svalue == NULL) svalue = strdup(DEFAULT_ENCTYPE_LIST); params.keysalts = NULL; params.num_keysalts = 0; krb5_string_to_keysalts(svalue, ", \t",/* Tuple separators */ ":.-", /* Key/salt separators */ 0, /* No duplicates */ ¶ms.keysalts, ¶ms.num_keysalts); if (params.num_keysalts) params.mask |= KADM5_CONFIG_ENCTYPES; if (svalue) krb5_xfree(svalue); } hierarchy[2] = "kpasswd_server"; if (params_in->mask & KADM5_CONFIG_KPASSWD_SERVER) { params.mask |= KADM5_CONFIG_KPASSWD_SERVER; params.kpasswd_server = strdup(params_in->kpasswd_server); } else { svalue = NULL; if (aprofile) krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue); if (svalue == NULL) { #ifdef KRB5_DNS_LOOKUP if (strcmp(envname, "KRB5_CONFIG") == 0) { /* * Solaris Kerberos: only do DNS lookup for * kpasswd_server if this is a krb5.conf type of * config file. Note, the filename may not be * /etc/krb5/krb5.conf so we assume that the * KRB5_CONFIG envname string will consistently * indicate the type of config file. */ dnsret = krb5_get_servername(context, &dns_realm, "_kpasswd", "_udp", dns_host, &dns_portno); if (dnsret == 0) { params.kpasswd_server = strdup(dns_host); if (params.kpasswd_server) { params.mask |= KADM5_CONFIG_KPASSWD_SERVER; } params.kpasswd_port = dns_portno; params.mask |= KADM5_CONFIG_KPASSWD_PORT; } } #endif /* KRB5_DNS_LOOKUP */ /* * If a unique 'kpasswd_server' is not specified, * use the normal 'admin_server'. */ if ((params.mask & KADM5_CONFIG_ADMIN_SERVER) && dnsret) { params.kpasswd_server = strdup(params.admin_server); params.mask |= KADM5_CONFIG_KPASSWD_SERVER; } } else { char *p; params.kpasswd_server = svalue; params.mask |= KADM5_CONFIG_KPASSWD_SERVER; if ((p = strchr(params.kpasswd_server, ':'))) { params.kpasswd_port = atoi(p+1); params.mask |= KADM5_CONFIG_KPASSWD_PORT; *p = '\0'; } } } hierarchy[2] = "kpasswd_protocol"; /* default to current RPCSEC_GSS protocol */ params.kpasswd_protocol = KRB5_CHGPWD_RPCSEC; params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL; if (params_in->mask & KADM5_CONFIG_KPASSWD_PROTOCOL) { params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL; params.kpasswd_protocol = params_in->kpasswd_protocol; } else { svalue = NULL; if (aprofile) krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue); if (svalue != NULL) { if (strcasecmp(svalue, "RPCSEC_GSS") == 0) { params.kpasswd_protocol = KRB5_CHGPWD_RPCSEC; params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL; } else if (strcasecmp(svalue, "SET_CHANGE") == 0) { params.kpasswd_protocol = KRB5_CHGPWD_CHANGEPW_V2; params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL; } } if (svalue) krb5_xfree(svalue); } /* * If the kpasswd_port is not yet defined, define it now. */ if (! (params.mask & KADM5_CONFIG_KPASSWD_PORT)) { if (params_in->mask & KADM5_CONFIG_KPASSWD_PORT) params.kpasswd_port = params_in->kpasswd_port; /* * If kpasswd_port is not explicitly defined, * determine the port to use based on the protocol. * The alternative protocol uses a different port * than the standard admind port. */ else if (params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC) { params.kpasswd_port = DEFAULT_KADM5_PORT; } else { /* * When using the Horowitz/IETF protocol for * password changing, the default port is 464 * (officially recognized by IANA). */ params.kpasswd_port = DEFAULT_KPASSWD_PORT; } params.mask |= KADM5_CONFIG_KPASSWD_PORT; } hierarchy[2] = "sunw_dbprop_enable"; params.iprop_enabled = FALSE; params.mask |= KADM5_CONFIG_IPROP_ENABLED; if (params_in->mask & KADM5_CONFIG_IPROP_ENABLED) { params.mask |= KADM5_CONFIG_IPROP_ENABLED; params.iprop_enabled = params_in->iprop_enabled; } else { if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { if (strncasecmp(svalue, "Y", 1) == 0) params.iprop_enabled = TRUE; if (strncasecmp(svalue, "true", 4) == 0) params.iprop_enabled = TRUE; params.mask |= KADM5_CONFIG_IPROP_ENABLED; krb5_xfree(svalue); } } hierarchy[2] = "sunw_dbprop_master_ulogsize"; params.iprop_ulogsize = DEF_ULOGENTRIES; params.mask |= KADM5_CONFIG_ULOG_SIZE; if (params_in->mask & KADM5_CONFIG_ULOG_SIZE) { params.mask |= KADM5_CONFIG_ULOG_SIZE; params.iprop_ulogsize = params_in->iprop_ulogsize; } else { if (aprofile && !krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) { if (ivalue > MAX_ULOGENTRIES) params.iprop_ulogsize = MAX_ULOGENTRIES; else if (ivalue <= 0) params.iprop_ulogsize = DEF_ULOGENTRIES; else params.iprop_ulogsize = ivalue; params.mask |= KADM5_CONFIG_ULOG_SIZE; } } hierarchy[2] = "sunw_dbprop_slave_poll"; params.iprop_polltime = strdup("2m"); if (params.iprop_polltime) params.mask |= KADM5_CONFIG_POLL_TIME; if (params_in->mask & KADM5_CONFIG_POLL_TIME) { if (params.iprop_polltime) free(params.iprop_polltime); params.iprop_polltime = strdup(params_in->iprop_polltime); if (params.iprop_polltime) params.mask |= KADM5_CONFIG_POLL_TIME; } else { if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { if (params.iprop_polltime) free(params.iprop_polltime); params.iprop_polltime = strdup(svalue); params.mask |= KADM5_CONFIG_POLL_TIME; krb5_xfree(svalue); } } *params_out = params; cleanup: if (aprofile) krb5_aprof_finish(aprofile); if (kret) { kadm5_free_config_params(context, ¶ms); params_out->mask = 0; } #ifdef KRB5_DNS_LOOKUP if (dns_realm.data) free(dns_realm.data); #endif /* KRB5_DNS_LOOKUP */ return(kret); } /* * kadm5_free_config_params() - Free data allocated by above. */ /*ARGSUSED*/ krb5_error_code kadm5_free_config_params(context, params) krb5_context context; kadm5_config_params *params; { if (params) { if (params->dbname) { krb5_xfree(params->dbname); params->dbname = NULL; } if (params->mkey_name) { krb5_xfree(params->mkey_name); params->mkey_name = NULL; } if (params->stash_file) { krb5_xfree(params->stash_file); params->stash_file = NULL; } if (params->keysalts) { krb5_xfree(params->keysalts); params->keysalts = NULL; params->num_keysalts = 0; } if (params->admin_keytab) { free(params->admin_keytab); params->admin_keytab = NULL; } if (params->dict_file) { free(params->dict_file); params->dict_file = NULL; } if (params->acl_file) { free(params->acl_file); params->acl_file = NULL; } if (params->realm) { free(params->realm); params->realm = NULL; } if (params->admin_dbname) { free(params->admin_dbname); params->admin_dbname = NULL; } if (params->admin_lockfile) { free(params->admin_lockfile); params->admin_lockfile = NULL; } if (params->admin_server) { free(params->admin_server); params->admin_server = NULL; } if (params->kpasswd_server) { free(params->kpasswd_server); params->kpasswd_server = NULL; } if (params->iprop_polltime) { free(params->iprop_polltime); params->iprop_polltime = NULL; } } return (0); } krb5_error_code kadm5_get_admin_service_name(krb5_context ctx, char *realm_in, char *admin_name, size_t maxlen) { krb5_error_code ret; kadm5_config_params params_in, params_out; struct hostent *hp; memset(¶ms_in, 0, sizeof(params_in)); memset(¶ms_out, 0, sizeof(params_out)); params_in.mask |= KADM5_CONFIG_REALM; params_in.realm = realm_in; ret = kadm5_get_config_params(ctx, 0, ¶ms_in, ¶ms_out); if (ret) return ret; if (!(params_out.mask & KADM5_CONFIG_ADMIN_SERVER)) { ret = KADM5_MISSING_KRB5_CONF_PARAMS; goto err_params; } hp = gethostbyname(params_out.admin_server); if (hp == NULL) { ret = errno; goto err_params; } if (strlen(hp->h_name) + sizeof("kadmin/") > maxlen) { ret = ENOMEM; goto err_params; } sprintf(admin_name, "kadmin/%s", hp->h_name); err_params: kadm5_free_config_params(ctx, ¶ms_out); return ret; } /*********************************************************************** * This is the old krb5_realm_read_params, which I mutated into * kadm5_get_config_params but which old code (kdb5_* and krb5kdc) * still uses. ***********************************************************************/ /* * krb5_read_realm_params() - Read per-realm parameters from KDC * alternate profile. */ krb5_error_code krb5_read_realm_params(kcontext, realm, rparamp) krb5_context kcontext; char *realm; krb5_realm_params **rparamp; { char *filename; char *envname; char *lrealm; krb5_pointer aprofile = 0; krb5_realm_params *rparams; const char *hierarchy[4]; char *svalue; krb5_int32 ivalue; krb5_boolean bvalue; krb5_deltat dtvalue; char *kdcprofile = 0; char *kdcenv = 0; krb5_error_code kret; filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE; envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV; if (kcontext->profile_secure == TRUE) envname = 0; rparams = (krb5_realm_params *) NULL; if (realm) lrealm = strdup(realm); else { kret = krb5_get_default_realm(kcontext, &lrealm); if (kret) goto cleanup; } kret = krb5_aprof_init(filename, envname, &aprofile); if (kret) goto cleanup; rparams = (krb5_realm_params *) malloc(sizeof(krb5_realm_params)); if (rparams == 0) { kret = ENOMEM; goto cleanup; } /* Initialize realm parameters */ memset((char *) rparams, 0, sizeof(krb5_realm_params)); /* Get the value for the database */ hierarchy[0] = "realms"; hierarchy[1] = lrealm; hierarchy[2] = "database_name"; hierarchy[3] = (char *) NULL; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) rparams->realm_dbname = svalue; /* Get the value for the KDC port list */ hierarchy[2] = "kdc_ports"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) rparams->realm_kdc_ports = svalue; hierarchy[2] = "kdc_tcp_ports"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) rparams->realm_kdc_tcp_ports = svalue; /* Get the name of the acl file */ hierarchy[2] = "acl_file"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) rparams->realm_acl_file = svalue; /* Get the value for the kadmind port */ hierarchy[2] = "kadmind_port"; if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) { rparams->realm_kadmind_port = ivalue; rparams->realm_kadmind_port_valid = 1; } /* Get the value for the master key name */ hierarchy[2] = "master_key_name"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) rparams->realm_mkey_name = svalue; /* Get the value for the master key type */ hierarchy[2] = "master_key_type"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { if (!krb5_string_to_enctype(svalue, &rparams->realm_enctype)) rparams->realm_enctype_valid = 1; krb5_xfree(svalue); } /* Get the value for the stashfile */ hierarchy[2] = "key_stash_file"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) rparams->realm_stash_file = svalue; /* Get the value for maximum ticket lifetime. */ hierarchy[2] = "max_life"; if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) { rparams->realm_max_life = dtvalue; rparams->realm_max_life_valid = 1; } /* Get the value for maximum renewable ticket lifetime. */ hierarchy[2] = "max_renewable_life"; if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) { rparams->realm_max_rlife = dtvalue; rparams->realm_max_rlife_valid = 1; } /* Get the value for the default principal expiration */ hierarchy[2] = "default_principal_expiration"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { if (!krb5_string_to_timestamp(svalue, &rparams->realm_expiration)) rparams->realm_expiration_valid = 1; krb5_xfree(svalue); } hierarchy[2] = "reject_bad_transit"; if (!krb5_aprof_get_boolean(aprofile, hierarchy, TRUE, &bvalue)) { rparams->realm_reject_bad_transit = bvalue; rparams->realm_reject_bad_transit_valid = 1; } /* Get the value for the default principal flags */ hierarchy[2] = "default_principal_flags"; if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { char *sp, *ep, *tp; sp = svalue; rparams->realm_flags = 0; while (sp) { if ((ep = strchr(sp, (int) ',')) || (ep = strchr(sp, (int) ' ')) || (ep = strchr(sp, (int) '\t'))) { /* Fill in trailing whitespace of sp */ tp = ep - 1; while (isspace((int) *tp) && (tp < sp)) { *tp = '\0'; tp--; } *ep = '\0'; ep++; /* Skip over trailing whitespace of ep */ while (isspace((int) *ep) && (*ep)) ep++; } /* Convert this flag */ if (krb5_string_to_flags(sp, "+", "-", &rparams->realm_flags)) break; sp = ep; } if (!sp) rparams->realm_flags_valid = 1; krb5_xfree(svalue); } /* Get the value for the supported enctype/salttype matrix */ /* * SUNWresync121 * Solaris kerberos: updated this code to support default values for * the supported_enctypes. */ hierarchy[2] = "supported_enctypes"; svalue = NULL; krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue); /* * Set the default value if supported_enctypes was not explicitly * set in the kdc.conf. */ if (svalue == NULL) { svalue = strdup(DEFAULT_ENCTYPE_LIST); } if (svalue != NULL) { krb5_string_to_keysalts(svalue, ", \t", /* Tuple separators */ ":.-", /* Key/salt separators */ 0, /* No duplicates */ &rparams->realm_keysalts, &rparams->realm_num_keysalts); krb5_xfree(svalue); svalue = NULL; } cleanup: if (aprofile) krb5_aprof_finish(aprofile); if (lrealm) free(lrealm); if (kret) { if (rparams) krb5_free_realm_params(kcontext, rparams); rparams = 0; } *rparamp = rparams; return(kret); } /* * krb5_free_realm_params() - Free data allocated by above. */ krb5_error_code krb5_free_realm_params(kcontext, rparams) krb5_context kcontext; krb5_realm_params *rparams; { if (rparams) { if (rparams->realm_profile) krb5_xfree(rparams->realm_profile); if (rparams->realm_dbname) krb5_xfree(rparams->realm_dbname); if (rparams->realm_mkey_name) krb5_xfree(rparams->realm_mkey_name); if (rparams->realm_stash_file) krb5_xfree(rparams->realm_stash_file); if (rparams->realm_keysalts) krb5_xfree(rparams->realm_keysalts); if (rparams->realm_kdc_ports) krb5_xfree(rparams->realm_kdc_ports); if (rparams->realm_kdc_tcp_ports) krb5_xfree(rparams->realm_kdc_tcp_ports); if (rparams->realm_acl_file) krb5_xfree(rparams->realm_acl_file); krb5_xfree(rparams); } return(0); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. */ #include #ifdef HAVE_MEMORY_H #include #endif #include #include #include #include "admin_internal.h" #include #include #define string_text error_message const char *chpw_error_message(kadm5_ret_t code); /* * Function: kadm5_chpass_principal_util * * Purpose: Wrapper around chpass_principal. We can read new pw, change pw and return useful messages * * Arguments: * * princ (input) a krb5b_principal structure for the * principal whose password we should change. * * new_password (input) NULL or a null terminated string with the * the principal's desired new password. If new_password * is NULL then this routine will read a new password. * * pw_ret (output) if non-NULL, points to a static buffer * containing the new password (if password is prompted * internally), or to the new_password argument (if * that is non-NULL). If the former, then the buffer * is only valid until the next call to the function, * and the caller should be sure to zero it when * it is no longer needed. * * msg_ret (output) a useful message is copied here. * * exit status of 0 for success, else the com err code * for the last significant routine called. * * Requires: * * A msg_ret should point to a buffer large enough for the messasge. * * Effects: * * Modifies: * * */ kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle, void *lhandle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len) { int code, code2; unsigned int pwsize; static char buffer[255]; char *new_password; kadm5_principal_ent_rec princ_ent; kadm5_policy_ent_rec policy_ent; krb5_chgpwd_prot passwd_protocol; _KADM5_CHECK_HANDLE(server_handle); if (ret_pw) *ret_pw = NULL; if (new_pw != NULL) { new_password = new_pw; } else { /* read the password */ krb5_context context; if ((code = (int) kadm5_init_krb5_context(&context)) == 0) { pwsize = sizeof(buffer); code = krb5_read_password(context, KADM5_PW_FIRST_PROMPT, KADM5_PW_SECOND_PROMPT, buffer, &pwsize); krb5_free_context(context); } if (code == 0) new_password = buffer; else { #ifdef ZEROPASSWD memset(buffer, 0, sizeof(buffer)); #endif if (code == KRB5_LIBOS_BADPWDMATCH) { (void) strncpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(code); } else { (void) strncpy(msg_ret, error_message(code), msg_len - 1); (void) strncat(msg_ret, " ", msg_len - 1); (void) strncat(msg_ret, string_text(CHPASS_UTIL_WHILE_READING_PASSWORD), msg_len - 1); (void) strncat(msg_ret, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(code); } } if (pwsize == 0) { #ifdef ZEROPASSWD memset(buffer, 0, sizeof(buffer)); #endif strncpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(KRB5_LIBOS_CANTREADPWD); /* could do better */ } } if (ret_pw) *ret_pw = new_password; passwd_protocol = _kadm5_get_kpasswd_protocol(server_handle); if (passwd_protocol == KRB5_CHGPWD_CHANGEPW_V2) { kadm5_ret_t srvr_rsp_code; krb5_data srvr_msg; srvr_msg.length = 0; srvr_msg.data = NULL; code = kadm5_chpass_principal_v2(server_handle, princ, new_password, &srvr_rsp_code, &srvr_msg); if (srvr_rsp_code) { sprintf(msg_ret, "%s%s%.*s\n", chpw_error_message(srvr_rsp_code), srvr_msg.length? ": " : "", srvr_msg.length, srvr_msg.data ? srvr_msg.data : ""); return (srvr_rsp_code); } return (code); } else if (passwd_protocol == KRB5_CHGPWD_RPCSEC) { code = kadm5_chpass_principal(server_handle, princ, new_password); #ifdef ZEROPASSWD if (!ret_pw) memset(buffer, 0, sizeof(buffer)); /* in case we read a new password */ #endif if (code == KADM5_OK) { strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_CHANGED), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(0); } if ((code != KADM5_PASS_Q_TOOSHORT) && (code != KADM5_PASS_REUSE) &&(code != KADM5_PASS_Q_CLASS) && (code != KADM5_PASS_Q_DICT) && (code != KADM5_PASS_TOOSOON)) { /* Can't get more info for other errors */ sprintf(buffer, "%s %s", error_message(code), string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE)); sprintf(msg_ret, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), buffer); return(code); } /* Ok, we have a password quality error. Return a good message */ if (code == KADM5_PASS_REUSE) { strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_REUSE), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(code); } if (code == KADM5_PASS_Q_DICT) { strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY), msg_len - 1); msg_ret[msg_len - 1] = '\0'; return(code); } /* Look up policy for the remaining messages */ code2 = kadm5_get_principal (lhandle, princ, &princ_ent, KADM5_PRINCIPAL_NORMAL_MASK); if (code2 != 0) { strncpy(msg_ret, error_message(code2), msg_len - 1); strncat(msg_ret, " ", msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, string_text(CHPASS_UTIL_GET_PRINC_INFO), msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, "\n", msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, error_message(code), msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, " ", msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE), msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, "\n\n", msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, "\n", msg_len - 1 - strlen(msg_ret)); msg_ret[msg_len - 1] = '\0'; return(code); } if ((princ_ent.aux_attributes & KADM5_POLICY) == 0) { strncpy(msg_ret, error_message(code), msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, " ", msg_len - 1 - strlen(msg_ret)); strncpy(msg_ret, string_text(CHPASS_UTIL_NO_POLICY_YET_Q_ERROR), msg_len - 1 - strlen(msg_ret)); strncat(msg_ret, "\n\n", msg_len - 1 - strlen(msg_ret)); strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), msg_len - 1 - strlen(msg_ret)); msg_ret[msg_len - 1] = '\0'; (void) kadm5_free_principal_ent(lhandle, &princ_ent); return(code); } code2 = kadm5_get_policy(lhandle, princ_ent.policy, &policy_ent); if (code2 != 0) { sprintf(msg_ret, "%s %s\n%s %s\n\n%s\n ", error_message(code2), string_text(CHPASS_UTIL_GET_POLICY_INFO), error_message(code), string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE), string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); (void) kadm5_free_principal_ent(lhandle, &princ_ent); return(code); } if (code == KADM5_PASS_Q_TOOSHORT) { sprintf(msg_ret, string_text(CHPASS_UTIL_PASSWORD_TOO_SHORT), policy_ent.pw_min_length); (void) kadm5_free_principal_ent(lhandle, &princ_ent); (void) kadm5_free_policy_ent(lhandle, &policy_ent); return(code); } if (code == KADM5_PASS_Q_CLASS) { sprintf(msg_ret, string_text(CHPASS_UTIL_TOO_FEW_CLASSES), policy_ent.pw_min_classes); (void) kadm5_free_principal_ent(lhandle, &princ_ent); (void) kadm5_free_policy_ent(lhandle, &policy_ent); return(code); } if (code == KADM5_PASS_TOOSOON) { time_t until; char *time_string, *ptr; until = princ_ent.last_pwd_change + policy_ent.pw_min_life; time_string = ctime(&until); if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') *ptr = '\0'; sprintf(msg_ret, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON), time_string); (void) kadm5_free_principal_ent(lhandle, &princ_ent); (void) kadm5_free_policy_ent(lhandle, &policy_ent); return(code); } else { /* We should never get here, but just in case ... */ sprintf(buffer, "%s %s", error_message(code), string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE)); sprintf(msg_ret, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), buffer); (void) kadm5_free_principal_ent(lhandle, &princ_ent); (void) kadm5_free_policy_ent(lhandle, &policy_ent); return(code); } } else { sprintf(msg_ret, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), "Password protocol in krb5.conf is not supported\n"); return (-1); } } /* * krb5_chpw_result_code_string * * convert the return code received from the password server * to a human-readable string. */ const char * chpw_error_message(kadm5_ret_t result_code) { switch (result_code) { case KRB5_KPASSWD_MALFORMED: return (dgettext(TEXT_DOMAIN, "Malformed request error")); case KRB5_KPASSWD_HARDERROR: return (dgettext(TEXT_DOMAIN, "Server error")); case KRB5_KPASSWD_AUTHERROR: return (dgettext(TEXT_DOMAIN, "Authentication error")); case KRB5_KPASSWD_SOFTERROR: return (dgettext(TEXT_DOMAIN, "Password change rejected")); case KRB5_KPASSWD_ACCESSDENIED: return (dgettext(TEXT_DOMAIN, "Not authorized to change password")); case KRB5_KPASSWD_BAD_VERSION: return (dgettext(TEXT_DOMAIN, "Protocol version unsupported")); case KRB5_KPASSWD_INITIAL_FLAG_NEEDED: return (dgettext(TEXT_DOMAIN, "initial flag required in changepw request")); case KRB5_KPASSWD_POLICY_REJECT: return (dgettext(TEXT_DOMAIN, "new password fails policy")); case KRB5_KPASSWD_BAD_PRINCIPAL: return (dgettext(TEXT_DOMAIN, "target principal does not exist for " "changepw request")); case KRB5_KPASSWD_ETYPE_NOSUPP: return (dgettext(TEXT_DOMAIN, "changepw request key sequence has an " "unsupported Etype")); default: return (dgettext(TEXT_DOMAIN, "Password change failed")); } } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * chpass_util_strings.h: * This file is automatically generated; please do not edit it. */ #define CHPASS_UTIL_GET_POLICY_INFO (-1492553984L) #define CHPASS_UTIL_GET_PRINC_INFO (-1492553983L) #define CHPASS_UTIL_NEW_PASSWORD_MISMATCH (-1492553982L) #define CHPASS_UTIL_NEW_PASSWORD_PROMPT (-1492553981L) #define CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT (-1492553980L) #define CHPASS_UTIL_NO_PASSWORD_READ (-1492553979L) #define CHPASS_UTIL_NO_POLICY_YET_Q_ERROR (-1492553978L) #define CHPASS_UTIL_PASSWORD_CHANGED (-1492553977L) #define CHPASS_UTIL_PASSWORD_IN_DICTIONARY (-1492553976L) #define CHPASS_UTIL_PASSWORD_NOT_CHANGED (-1492553975L) #define CHPASS_UTIL_PASSWORD_TOO_SHORT (-1492553974L) #define CHPASS_UTIL_TOO_FEW_CLASSES (-1492553973L) #define CHPASS_UTIL_PASSWORD_TOO_SOON (-1492553972L) #define CHPASS_UTIL_PASSWORD_REUSE (-1492553971L) #define CHPASS_UTIL_WHILE_TRYING_TO_CHANGE (-1492553970L) #define CHPASS_UTIL_WHILE_READING_PASSWORD (-1492553969L) #define ERROR_TABLE_BASE_ovku (-1492553984L) extern const struct error_table et_ovku_error_table; #if !defined(_WIN32) /* for compatibility with older versions... */ extern void initialize_ovku_error_table (void) /*@modifies internalState@*/; #else #define initialize_ovku_error_table() #endif #if !defined(_WIN32) #define init_ovku_err_tbl initialize_ovku_error_table #define ovku_err_base ERROR_TABLE_BASE_ovku #endif # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib # Hammerhead: amd64-only SUBDIRS = $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install LIBRARY= libkadm5clnt.a POFILE= $(LIBRARY:%.a=%.po) POFILES= generic.po .KEEP_STATE: all clean install: $(SUBDIRS) clobber: $(SUBDIRS) $(RM) $(CLOBBERFILES) _msg: $(MSGDOMAIN) .WAIT $(POFILE) $(RM) $(MSGDOMAIN)/$(POFILE) $(CP) $(POFILE) $(MSGDOMAIN) $(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ generic.po: FRC $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../*.[ch] *.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: $(MSGDOMAIN): $(INS.dir) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. LIBRARY= libkadm5clnt.a VERS= .1 CLNT_OBJS = clnt_policy.o \ client_rpc.o \ client_principal.o \ client_init.o \ clnt_privs.o \ clnt_chpass_util.o \ logger.o \ changepw.o \ chpw.o SHARED_OBJS = \ alt_prof.o \ chpass_util.o \ kadm_rpc_xdr.o \ misc_free.o \ kadm_host_srv_names.o \ str_conv.o OBJECTS= $(CLNT_OBJS) $(SHARED_OBJS) ISRCHDR= ../iprop.h KRB5IPROPDIR= $(SRC)/cmd/krb5/iprop # include library definitions include ../../../Makefile.lib SRCS= $(CLNT_OBJS:%.o=../%.c) \ $(SHARED_OBJS:%.o=../../%.c) LIBS= $(DYNLIB) include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE = $(LIBRARY:%.a=%.po) POFILES = generic.po #override liblink INS.liblink= -$(RM) $@; $(SYMLINK) $(LIBLINKS)$(VERS) $@ CPPFLAGS += -I.. -I../.. -I../../.. -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(SRC)/lib/krb5 \ -I$(SRC)/lib/gss_mechs/mech_krb5/include/krb5 \ -I$(SRC)/uts/common/gssapi/ \ -I$(SRC)/uts/common/gssapi/include/ \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include \ -I$(SRC)/lib/gss_mechs/mech_krb5/krb5/os \ -I$(KRB5IPROPDIR) \ -DHAVE_STDLIB_H -DUSE_SOLARIS_SHARED_LIBRARIES \ -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DSETRPCENT_TYPE=void \ -DENDRPCENT_TYPE=void -DHAVE_SYS_ERRLIST=1 -DNEED_SYS_ERRLIST=1 \ -DHAVE_SYSLOG_H=1 -DHAVE_OPENLOG=1 -DHAVE_SYSLOG=1 -DHAVE_CLOSELOG=1 \ -DHAVE_STRFTIME=1 -DHAVE_VSPRINTF=1 -DUSE_KADM5_API_VERSION=2 # Hammerhead: -I.. already in CPPFLAGS above; removed from CFLAGS (lost in Makefile.master.64 reset) CFLAGS += $(CCVERBOSE) CERRWARN += -Wno-unused-function CERRWARN += -Wno-unused-variable CERRWARN += -Wno-parentheses CERRWARN += $(CNOWARN_UNINIT) SMOFF += all_func_returns,indenting,no_if_block LDLIBS += -lc .KEEP_STATE: all: $(LIBS) # Hammerhead: pre-generated (rpcgen + GNU cpp truncation bug) # iprop.h is now a committed source file. # Hammerhead: GNU Make parallel builds need PICS to depend on generated files. # $(LIBS): $(ISRCHDR) only ensures iprop.h before link, not before .o compilation. $(PICS): $(ISRCHDR) # Hammerhead: pre-generated files are permanent source, do not delete # CLEANFILES += $(ISRCHDR) # include library targets include ../../../Makefile.targ pics/%.o: ../../%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) FRC: generic.po: FRC $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../*.[ch] ../../*.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # include ../Makefile.com include ../../../../Makefile.lib.64 DYNFLAGS += $(KRUNPATH64) $(KMECHLIB64) LDLIBS += -L $(ROOTLIBDIR) -lgss -lnsl -lsocket -lc install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * lib/krb5/os/changepw.c * * Copyright 1990,1999 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ #define NEED_SOCKETS #include #include #include #include #include #include #include /* #include "adm_err.h" */ #include #include extern krb5_error_code krb5int_mk_chpw_req(krb5_context context, krb5_auth_context auth_context, krb5_data *ap_req, char *passwd, krb5_data *packet); extern krb5_error_code krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data); /* * _kadm5_get_kpasswd_protocol * * returns the password change protocol value to the caller. * Since the 'handle' is an opaque value to higher up callers, * this method is needed to provide a way for them to get a peek * at the protocol being used without having to expose the entire * handle structure. */ krb5_chgpwd_prot _kadm5_get_kpasswd_protocol(void *handle) { kadm5_server_handle_t srvrhdl = (kadm5_server_handle_t)handle; return (srvrhdl->params.kpasswd_protocol); } /* * krb5_change_password * * Prepare and send a CHANGEPW request to a password server * using UDP datagrams. This is only used for sending to * non-SEAM servers which support the Marc Horowitz defined * protocol (1998) for password changing. * * SUNW14resync - added _local as it conflicts with one in krb5.h */ static krb5_error_code krb5_change_password_local(context, params, creds, newpw, srvr_rsp_code, srvr_msg) krb5_context context; kadm5_config_params *params; krb5_creds *creds; char *newpw; kadm5_ret_t *srvr_rsp_code; krb5_data *srvr_msg; { krb5_auth_context auth_context; krb5_data ap_req, chpw_req, chpw_rep; krb5_address local_kaddr, remote_kaddr; krb5_error_code code = 0; int i, addrlen; struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr; struct sockaddr_in *sin_p; struct hostent *hp; int naddr_p; int cc, local_result_code, tmp_len; SOCKET s1 = INVALID_SOCKET; SOCKET s2 = INVALID_SOCKET; /* Initialize values so that cleanup call can safely check for NULL */ auth_context = NULL; addr_p = NULL; memset(&chpw_req, 0, sizeof (krb5_data)); memset(&chpw_rep, 0, sizeof (krb5_data)); memset(&ap_req, 0, sizeof (krb5_data)); /* initialize auth_context so that we know we have to free it */ if ((code = krb5_auth_con_init(context, &auth_context))) goto cleanup; if (code = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY, NULL, creds, &ap_req)) goto cleanup; /* * find the address of the kpasswd_server. */ addr_p = (struct sockaddr *)malloc(sizeof (struct sockaddr)); if (!addr_p) goto cleanup; memset(addr_p, 0, sizeof (struct sockaddr)); if ((hp = gethostbyname(params->kpasswd_server)) == NULL) { code = KRB5_REALM_CANT_RESOLVE; goto cleanup; } sin_p = (struct sockaddr_in *)addr_p; memset((char *)sin_p, 0, sizeof (struct sockaddr)); sin_p->sin_family = hp->h_addrtype; sin_p->sin_port = htons(params->kpasswd_port); memcpy((char *)&sin_p->sin_addr, (char *)hp->h_addr, hp->h_length); naddr_p = 1; /* * this is really obscure. s1 is used for all communications. it * is left unconnected in case the server is multihomed and routes * are asymmetric. s2 is connected to resolve routes and get * addresses. this is the *only* way to get proper addresses for * multihomed hosts if routing is asymmetric. * * A related problem in the server, but not the client, is that * many os's have no way to disconnect a connected udp socket, so * the s2 socket needs to be closed and recreated for each * request. The s1 socket must not be closed, or else queued * requests will be lost. * * A "naive" client implementation (one socket, no connect, * hostname resolution to get the local ip addr) will work and * interoperate if the client is single-homed. */ if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { code = errno; goto cleanup; } if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) { code = errno; goto cleanup; } for (i = 0; i < naddr_p; i++) { fd_set fdset; struct timeval timeout; if (connect(s2, &addr_p[i], sizeof (addr_p[i])) == SOCKET_ERROR) { if ((errno == ECONNREFUSED) || (errno == EHOSTUNREACH)) continue; /* try the next addr */ code = errno; goto cleanup; } addrlen = sizeof (local_addr); if (getsockname(s2, &local_addr, &addrlen) < 0) { if ((errno == ECONNREFUSED) || (errno == EHOSTUNREACH)) continue; /* try the next addr */ code = errno; goto cleanup; } /* * some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof (((struct sockaddr_in *) &local_addr)->sin_addr); local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *) &local_addr)->sin_addr); } else { krb5_address **addrs; krb5_os_localaddr(context, &addrs); local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; local_kaddr.contents = malloc(addrs[0]->length); memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); krb5_free_addresses(context, addrs); } addrlen = sizeof (remote_addr); if (getpeername(s2, &remote_addr, &addrlen) < 0) { if ((errno == ECONNREFUSED) || (errno == EHOSTUNREACH)) continue; /* try the next addr */ code = errno; goto cleanup; } remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof (((struct sockaddr_in *) &remote_addr)->sin_addr); remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&remote_addr)->sin_addr); /* * mk_priv requires that the local address be set. * getsockname is used for this. rd_priv requires that the * remote address be set. recvfrom is used for this. If * rd_priv is given a local address, and the message has the * recipient addr in it, this will be checked. However, there * is simply no way to know ahead of time what address the * message will be delivered *to*. Therefore, it is important * that either no recipient address is in the messages when * mk_priv is called, or that no local address is passed to * rd_priv. Both is a better idea, and I have done that. In * summary, when mk_priv is called, *only* a local address is * specified. when rd_priv is called, *only* a remote address * is specified. Are we having fun yet? */ if (code = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL)) { code = errno; goto cleanup; } if (code = krb5int_mk_chpw_req(context, auth_context, &ap_req, newpw, &chpw_req)) { code = errno; goto cleanup; } if ((cc = sendto(s1, chpw_req.data, chpw_req.length, 0, (struct sockaddr *)&addr_p[i], sizeof (addr_p[i]))) != chpw_req.length) { if ((cc < 0) && ((errno == ECONNREFUSED) || (errno == EHOSTUNREACH))) continue; /* try the next addr */ code = (cc < 0) ? errno : ECONNABORTED; goto cleanup; } chpw_rep.length = 1500; chpw_rep.data = (char *)malloc(chpw_rep.length); /* XXX need a timeout/retry loop here */ FD_ZERO(&fdset); FD_SET(s1, &fdset); timeout.tv_sec = 120; timeout.tv_usec = 0; switch (select(s1 + 1, &fdset, 0, 0, &timeout)) { case -1: code = errno; goto cleanup; case 0: code = ETIMEDOUT; goto cleanup; default: /* fall through */ ; } tmp_len = sizeof (tmp_addr); if ((cc = recvfrom(s1, chpw_rep.data, chpw_rep.length, 0, &tmp_addr, &tmp_len)) < 0) { code = errno; goto cleanup; } closesocket(s1); s1 = INVALID_SOCKET; closesocket(s2); s2 = INVALID_SOCKET; chpw_rep.length = cc; if (code = krb5_auth_con_setaddrs(context, auth_context, NULL, &remote_kaddr)) goto cleanup; if (code = krb5int_rd_chpw_rep(context, auth_context, &chpw_rep, &local_result_code, srvr_msg)) goto cleanup; if (srvr_rsp_code) *srvr_rsp_code = local_result_code; code = 0; goto cleanup; } code = errno; cleanup: if (auth_context != NULL) krb5_auth_con_free(context, auth_context); if (addr_p != NULL) krb5_xfree(addr_p); if (s1 != INVALID_SOCKET) closesocket(s1); if (s2 != INVALID_SOCKET) closesocket(s2); krb5_xfree(chpw_req.data); krb5_xfree(chpw_rep.data); krb5_xfree(ap_req.data); return (code); } /* * kadm5_chpass_principal_v2 * * New function used to prepare to make the change password request to a * non-SEAM admin server. The protocol used in this case is not based on * RPCSEC_GSS, it simply makes the request to port 464 (udp and tcp). * This is the same way that MIT KRB5 1.2.1 changes passwords. */ kadm5_ret_t kadm5_chpass_principal_v2(void *server_handle, krb5_principal princ, char *newpw, kadm5_ret_t *srvr_rsp_code, krb5_data *srvr_msg) { kadm5_ret_t code; kadm5_server_handle_t handle = (kadm5_server_handle_t)server_handle; krb5_error_code result; krb5_creds mcreds; krb5_creds ncreds; krb5_ccache ccache; int cpwlen; char *cpw_service = NULL; /* * The credentials have already been stored in the cache in the * initialization step earlier, but we dont have direct access to it * at this level. Derive the cache and fetch the credentials to use for * sending the request. */ memset(&mcreds, 0, sizeof (krb5_creds)); if ((code = krb5_cc_resolve(handle->context, handle->cache_name, &ccache))) return (code); /* set the client principal in the credential match structure */ mcreds.client = princ; /* * set the server principal (kadmin/changepw@REALM) in the credential * match struct */ cpwlen = strlen(KADM5_CHANGEPW_SERVICE) + strlen(handle->params.realm) + 2; cpw_service = malloc(cpwlen); if (cpw_service == NULL) { return (ENOMEM); } snprintf(cpw_service, cpwlen, "%s@%s", KADM5_CHANGEPW_SERVICE, handle->params.realm); /* generate the server principal from the name string we generated */ if ((code = krb5_parse_name(handle->context, cpw_service, &mcreds.server))) { free(cpw_service); return (code); } /* Find the credentials in the cache */ if ((code = krb5_cc_retrieve_cred(handle->context, ccache, 0, &mcreds, &ncreds))) { free(cpw_service); return (code); } /* Now we have all we need to make the change request. */ result = krb5_change_password_local(handle->context, &handle->params, &ncreds, newpw, srvr_rsp_code, srvr_msg); free(cpw_service); return (result); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "k5-int.h" #include #include #include "auth_con.h" #include krb5_error_code krb5int_mk_chpw_req( krb5_context context, krb5_auth_context auth_context, krb5_data *ap_req, char *passwd, krb5_data *packet) { krb5_error_code ret = 0; krb5_data clearpw; krb5_data cipherpw; krb5_replay_data replay; char *ptr; cipherpw.data = NULL; if ((ret = krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE))) goto cleanup; clearpw.length = strlen(passwd); clearpw.data = passwd; if ((ret = krb5_mk_priv(context, auth_context, &clearpw, &cipherpw, &replay))) goto cleanup; packet->length = 6 + ap_req->length + cipherpw.length; packet->data = (char *) malloc(packet->length); if (packet->data == NULL) { ret = ENOMEM; goto cleanup; } ptr = packet->data; /* length */ *ptr++ = (packet->length>> 8) & 0xff; *ptr++ = packet->length & 0xff; /* version == 0x0001 big-endian * NOTE: when MS and MIT start supporting the latest * version of the passwd change protocol (v2), * this value will change to 2. */ *ptr++ = 0; *ptr++ = 1; /* ap_req length, big-endian */ *ptr++ = (ap_req->length>>8) & 0xff; *ptr++ = ap_req->length & 0xff; /* ap-req data */ memcpy(ptr, ap_req->data, ap_req->length); ptr += ap_req->length; /* krb-priv of password */ memcpy(ptr, cipherpw.data, cipherpw.length); cleanup: if(cipherpw.data != NULL) /* allocated by krb5_mk_priv */ free(cipherpw.data); return(ret); } krb5_error_code krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data) { char *ptr; int plen, vno; krb5_data ap_rep; krb5_ap_rep_enc_part *ap_rep_enc; krb5_error_code ret; krb5_data cipherresult; krb5_data clearresult; krb5_error *krberror; krb5_replay_data replay; krb5_keyblock *tmp; int local_result_code; if (packet->length < 4) /* either this, or the server is printing bad messages, or the caller passed in garbage */ return(KRB5KRB_AP_ERR_MODIFIED); ptr = packet->data; /* verify length */ plen = (*ptr++ & 0xff); plen = (plen<<8) | (*ptr++ & 0xff); if (plen != packet->length) { /* * MS KDCs *may* send back a KRB_ERROR. Although * not 100% correct via RFC3244, it's something * we can workaround here. */ if (krb5_is_krb_error(packet)) { if ((ret = krb5_rd_error(context, packet, &krberror))) return(ret); if (krberror->e_data.data == NULL) { ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error; krb5_free_error(context, krberror); return (ret); } } else { return(KRB5KRB_AP_ERR_MODIFIED); } } /* verify version number */ vno = (*ptr++ & 0xff); vno = (vno<<8) | (*ptr++ & 0xff); /* * when the servers update to v2 of the protocol, * "2" will be a valid version number here */ if (vno != 1 && vno != 2) return (KRB5KDC_ERR_BAD_PVNO); /* read, check ap-rep length */ ap_rep.length = (*ptr++ & 0xff); ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff); if (ptr + ap_rep.length >= packet->data + packet->length) return(KRB5KRB_AP_ERR_MODIFIED); if (ap_rep.length) { /* verify ap_rep */ ap_rep.data = ptr; ptr += ap_rep.length; /* * Save send_subkey to later smash recv_subkey. */ ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp); if (ret) return ret; ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc); if (ret) { krb5_free_keyblock(context, tmp); return(ret); } krb5_free_ap_rep_enc_part(context, ap_rep_enc); /* extract and decrypt the result */ cipherresult.data = ptr; cipherresult.length = (packet->data + packet->length) - ptr; /* * Smash recv_subkey to be send_subkey, per spec. */ ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmp); krb5_free_keyblock(context, tmp); if (ret) return ret; ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult, &replay); if (ret) return(ret); } else { cipherresult.data = ptr; cipherresult.length = (packet->data + packet->length) - ptr; if ((ret = krb5_rd_error(context, &cipherresult, &krberror))) return(ret); clearresult = krberror->e_data; } if (clearresult.length < 2) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } ptr = clearresult.data; local_result_code = (*ptr++ & 0xff); local_result_code = (local_result_code<<8) | (*ptr++ & 0xff); if (result_code) *result_code = local_result_code; /* * Make sure the result code is in range for this * protocol. */ if ((local_result_code < KRB5_KPASSWD_SUCCESS) || (local_result_code > KRB5_KPASSWD_ETYPE_NOSUPP)) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } /* all success replies should be authenticated/encrypted */ if ((ap_rep.length == 0) && (local_result_code == KRB5_KPASSWD_SUCCESS)) { ret = KRB5KRB_AP_ERR_MODIFIED; goto cleanup; } result_data->length = (clearresult.data + clearresult.length) - ptr; if (result_data->length) { result_data->data = (char *) malloc(result_data->length); if (result_data->data == NULL) { ret = ENOMEM; goto cleanup; } memcpy(result_data->data, ptr, result_data->length); } else { result_data->data = NULL; } ret = 0; cleanup: if (ap_rep.length) { krb5_xfree(clearresult.data); } else { krb5_free_error(context, krberror); } return(ret); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include #include #include "client_internal.h" int _kadm5_check_handle(void *handle) { CHECK_HANDLE(handle); return 0; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved */ /* * Copyright (C) 1998 by the FundsXpress, INC. * * All rights reserved. * * Export of this software from the United States of America may require * a specific license from the United States Government. It is the * responsibility of any person or organization contemplating export to * obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of FundsXpress. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. FundsXpress makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include "autoconf.h" #ifdef HAVE_MEMORY_H #include #endif #include #include #include #include #include #include /* for KRB5_ADM_DEFAULT_PORT */ #include #ifdef __STDC__ #include #endif #include #include #include #include "client_internal.h" #include #include #include #include #include #include #include "iprop.h" #define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX" static int old_auth_gssapi = 0; /* connection timeout to kadmind in seconds */ #define KADMIND_CONNECT_TIMEOUT 25 int _kadm5_check_handle(); enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS }; static kadm5_ret_t _kadm5_init_any(char *client_name, enum init_type init_type, char *pass, krb5_ccache ccache_in, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle); kadm5_ret_t kadm5_init_with_creds(char *client_name, krb5_ccache ccache, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache, service_name, params, struct_version, api_version, db_args, server_handle); } kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { return _kadm5_init_any(client_name, INIT_PASS, pass, NULL, service_name, params, struct_version, api_version, db_args, server_handle); } kadm5_ret_t kadm5_init(char *client_name, char *pass, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { return _kadm5_init_any(client_name, INIT_PASS, pass, NULL, service_name, params, struct_version, api_version, db_args, server_handle); } kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL, service_name, params, struct_version, api_version, db_args, server_handle); } krb5_error_code kadm5_free_config_params(); static void display_status_1(m, code, type, mech) char *m; OM_uint32 code; int type; const gss_OID mech; { OM_uint32 maj_stat, min_stat; gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; OM_uint32 msg_ctx; msg_ctx = 0; ADMIN_LOG(LOG_ERR, "%s\n", m); /* LINTED */ while (1) { maj_stat = gss_display_status(&min_stat, code, type, mech, &msg_ctx, &msg); if (maj_stat != GSS_S_COMPLETE) { syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "error in gss_display_status" " called from <%s>\n"), m); break; } else syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "GSS-API error : %s\n"), m); syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "GSS-API error : %s\n"), (char *)msg.value); if (msg.length != 0) (void) gss_release_buffer(&min_stat, &msg); if (!msg_ctx) break; } } /* * Function: display_status * * Purpose: displays GSS-API messages * * Arguments: * * msg a string to be displayed with the message * maj_stat the GSS-API major status code * min_stat the GSS-API minor status code * mech kerberos mech * Effects: * * The GSS-API messages associated with maj_stat and min_stat are * displayed on stderr, each preceeded by "GSS-API error : " and * followed by a newline. */ void display_status(msg, maj_stat, min_stat, mech) char *msg; OM_uint32 maj_stat; OM_uint32 min_stat; char *mech; { gss_OID mech_oid; if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) { ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "Invalid mechanism oid <%s>"), mech); return; } display_status_1(msg, maj_stat, GSS_C_GSS_CODE, mech_oid); display_status_1(msg, min_stat, GSS_C_MECH_CODE, mech_oid); } /* * Open an fd for the given address and connect asynchronously. Wait * KADMIND_CONNECT_TIMEOUT seconds or till it succeeds. If it succeeds * change fd to blocking and return it, else return -1. */ static int get_connection(struct netconfig *nconf, struct netbuf netaddr) { struct t_info tinfo; struct t_call sndcall; struct t_call *rcvcall = NULL; int connect_time; int flags; int fd; (void) memset(&tinfo, 0, sizeof (tinfo)); /* we'l open with O_NONBLOCK and avoid an fcntl */ fd = t_open(nconf->nc_device, O_RDWR | O_NONBLOCK, &tinfo); if (fd == -1) { return (-1); } if (t_bind(fd, (struct t_bind *)NULL, (struct t_bind *)NULL) == -1) { (void) close(fd); return (-1); } /* we can't connect unless fd is in IDLE state */ if (t_getstate(fd) != T_IDLE) { (void) close(fd); return (-1); } /* setup connect parameters */ netaddr.len = netaddr.maxlen = __rpc_get_a_size(tinfo.addr); sndcall.addr = netaddr; sndcall.opt.len = sndcall.udata.len = 0; /* we wait for KADMIND_CONNECT_TIMEOUT seconds from now */ connect_time = time(NULL) + KADMIND_CONNECT_TIMEOUT; if (t_connect(fd, &sndcall, rcvcall) != 0) { if (t_errno != TNODATA) { (void) close(fd); return (-1); } } /* loop till success or timeout */ for (;;) { if (t_rcvconnect(fd, rcvcall) == 0) break; if (t_errno != TNODATA || time(NULL) > connect_time) { /* we have either timed out or caught an error */ (void) close(fd); if (rcvcall != NULL) t_free((char *)rcvcall, T_CALL); return (-1); } sleep(1); } /* make the fd blocking (synchronous) */ flags = fcntl(fd, F_GETFL, 0); (void) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); if (rcvcall != NULL) t_free((char *)rcvcall, T_CALL); return (fd); } /* * Open an RPCSEC_GSS connection and * get a client handle to use for future RPCSEC calls. * * This function is only used when changing passwords and * the kpasswd_protocol is RPCSEC_GSS */ static int _kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle, char *client_name, char *service_name) { struct netbuf netaddr; struct hostent *hp; int fd; struct sockaddr_in addr; struct sockaddr_in *sin; struct netconfig *nconf; int code = 0; generic_ret *r; char *ccname_orig; char *iprop_svc; boolean_t iprop_enable = B_FALSE; char mech[] = "kerberos_v5"; gss_OID mech_oid; gss_OID_set_desc oid_set; gss_name_t gss_client; gss_buffer_desc input_name; gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL; rpc_gss_options_req_t options_req; rpc_gss_options_ret_t options_ret; rpc_gss_service_t service = rpc_gss_svc_privacy; OM_uint32 gssstat, minor_stat; void *handlep; enum clnt_stat rpc_err_code; char *server = handle->params.admin_server; /* * Try to find the kpasswd_server first if this is for the changepw * service. If defined then it should be resolvable else return error. */ if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE, strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0) { if (handle->params.kpasswd_server != NULL) server = handle->params.kpasswd_server; } hp = gethostbyname(server); if (hp == (struct hostent *)NULL) { code = KADM5_BAD_SERVER_NAME; ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "bad server name\n")); goto cleanup; } memset(&addr, 0, sizeof (addr)); addr.sin_family = hp->h_addrtype; (void) memcpy((char *)&addr.sin_addr, (char *)hp->h_addr, sizeof (addr.sin_addr)); addr.sin_port = htons((ushort_t)handle->params.kadmind_port); sin = &addr; #ifdef DEBUG printf("kadmin_port %d\n", handle->params.kadmind_port); printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n", addr.sin_port, addr.sin_family, addr.sin_zero); printf("sin_addr %d:%d\n", addr.sin_addr.S_un.S_un_w.s_w1, addr.sin_addr.S_un.S_un_w.s_w2); #endif if ((handlep = setnetconfig()) == (void *) NULL) { (void) syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "cannot get any transport information")); goto error; } while (nconf = getnetconfig(handlep)) { if ((nconf->nc_semantics == NC_TPI_COTS_ORD) && (strcmp(nconf->nc_protofmly, NC_INET) == 0) && (strcmp(nconf->nc_proto, NC_TCP) == 0)) break; } if (nconf == (struct netconfig *)NULL) goto error; /* Transform addr to netbuf */ (void) memset(&netaddr, 0, sizeof (netaddr)); netaddr.buf = (char *)sin; /* get an fd connected to the given address */ fd = get_connection(nconf, netaddr); if (fd == -1) { syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "unable to open connection to ADMIN server " "(t_error %i)"), t_errno); code = KADM5_RPC_ERROR; goto error; } #ifdef DEBUG printf("fd: %d, KADM: %d, KADMVERS %d\n", fd, KADM, KADMVERS); printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, " "nc_protofmly: %s\n", nconf->nc_netid, nconf->nc_semantics, nconf->nc_flag, nconf->nc_protofmly); printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n", nconf->nc_proto, nconf->nc_device, nconf->nc_nlookups, nconf->nc_unused); printf("netaddr: maxlen %d, buf: %s, len: %d\n", netaddr.maxlen, netaddr.buf, netaddr.len); #endif /* * Tell clnt_tli_create that given fd is already connected * * If the service_name and client_name are iprop-centric, * we need to clnt_tli_create to the appropriate RPC prog */ iprop_svc = strdup(KIPROP_SVC_NAME); if (iprop_svc == NULL) return (ENOMEM); if ((strstr(service_name, iprop_svc) != NULL) && (strstr(client_name, iprop_svc) != NULL)) { iprop_enable = B_TRUE; handle->clnt = clnt_tli_create(fd, nconf, NULL, KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0); } else handle->clnt = clnt_tli_create(fd, nconf, NULL, KADM, KADMVERS, 0, 0); if (iprop_svc) free(iprop_svc); if (handle->clnt == NULL) { syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "clnt_tli_create failed\n")); code = KADM5_RPC_ERROR; (void) close(fd); goto error; } /* * The rpc-handle was created on an fd opened and connected * by us, so we have to explicitly tell rpc to close it. */ if (clnt_control(handle->clnt, CLSET_FD_CLOSE, NULL) != TRUE) { clnt_pcreateerror("ERROR:"); syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "clnt_control failed to set CLSET_FD_CLOSE")); code = KADM5_RPC_ERROR; (void) close(fd); goto error; } handle->lhandle->clnt = handle->clnt; /* now that handle->clnt is set, we can check the handle */ if (code = _kadm5_check_handle((void *) handle)) goto error; /* * The RPC connection is open; establish the GSS-API * authentication context. */ ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "have an rpc connection open\n")); /* use the kadm5 cache */ ccname_orig = getenv("KRB5CCNAME"); if (ccname_orig) ccname_orig = strdup(ccname_orig); (void) krb5_setenv("KRB5CCNAME", handle->cache_name, 1); ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "current credential cache: %s"), handle->cache_name); input_name.value = client_name; input_name.length = strlen((char *)input_name.value) + 1; gssstat = gss_import_name(&minor_stat, &input_name, (gss_OID)gss_nt_krb5_name, &gss_client); if (gssstat != GSS_S_COMPLETE) { code = KADM5_GSS_ERROR; ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "gss_import_name failed for client name\n")); goto error; } if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) { ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "Invalid mechanism oid <%s>"), mech); goto error; } oid_set.count = 1; oid_set.elements = mech_oid; gssstat = gss_acquire_cred(&minor_stat, gss_client, 0, &oid_set, GSS_C_INITIATE, &gss_client_creds, NULL, NULL); (void) gss_release_name(&minor_stat, &gss_client); if (gssstat != GSS_S_COMPLETE) { code = KADM5_GSS_ERROR; ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "could not acquire credentials, " "major error code: %d\n"), gssstat); goto error; } handle->my_cred = gss_client_creds; options_req.my_cred = gss_client_creds; options_req.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; options_req.time_req = 0; options_req.input_channel_bindings = NULL; #ifndef INIT_TEST handle->clnt->cl_auth = rpc_gss_seccreate(handle->clnt, service_name, mech, service, NULL, &options_req, &options_ret); #endif /* ! INIT_TEST */ if (ccname_orig) { (void) krb5_setenv("KRB5CCNAME", ccname_orig, 1); free(ccname_orig); } else (void) krb5_unsetenv("KRB5CCNAME"); if (handle->clnt->cl_auth == NULL) { code = KADM5_GSS_ERROR; display_status(dgettext(TEXT_DOMAIN, "rpc_gss_seccreate failed\n"), options_ret.major_status, options_ret.minor_status, mech); goto error; } /* * Bypass the remainder of the code and return straightaway * if the gss service requested is kiprop */ if (iprop_enable == B_TRUE) { code = 0; goto cleanup; } r = init_2(&handle->api_version, handle->clnt); /* Solaris Kerberos: 163 resync */ if (r == NULL) { ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "error during admin api initialization\n")); code = KADM5_RPC_ERROR; goto error; } if (r->code) { code = r->code; ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "error during admin api initialization: %d\n"), r->code); goto error; } error: cleanup: if (handlep != (void *) NULL) (void) endnetconfig(handlep); /* * gss_client_creds is freed only when there is an error condition, * given that rpc_gss_seccreate() will assign the cred pointer to the * my_cred member in the auth handle's private data structure. */ if (code && (gss_client_creds != GSS_C_NO_CREDENTIAL)) (void) gss_release_cred(&minor_stat, &gss_client_creds); return (code); } static kadm5_ret_t _kadm5_init_any(char *client_name, enum init_type init_type, char *pass, krb5_ccache ccache_in, char *service_name, kadm5_config_params *params_in, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { int i; krb5_creds creds; krb5_ccache ccache = NULL; krb5_timestamp now; OM_uint32 gssstat, minor_stat; kadm5_server_handle_t handle; kadm5_config_params params_local; int code = 0; krb5_get_init_creds_opt opt; gss_buffer_desc input_name; krb5_error_code kret; krb5_int32 starttime; char *server = NULL; krb5_principal serverp = NULL, clientp = NULL; krb5_principal saved_server = NULL; bool_t cpw = FALSE; ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "entering kadm5_init_any\n")); if (! server_handle) { return EINVAL; } if (! (handle = malloc(sizeof(*handle)))) { return ENOMEM; } if (! (handle->lhandle = malloc(sizeof(*handle)))) { free(handle); return ENOMEM; } handle->magic_number = KADM5_SERVER_HANDLE_MAGIC; handle->struct_version = struct_version; handle->api_version = api_version; handle->clnt = 0; handle->cache_name = 0; handle->destroy_cache = 0; *handle->lhandle = *handle; handle->lhandle->api_version = KADM5_API_VERSION_2; handle->lhandle->struct_version = KADM5_STRUCT_VERSION; handle->lhandle->lhandle = handle->lhandle; kret = krb5_init_context(&handle->context); if (kret) { free(handle->lhandle); free(handle); return (kret); } if(service_name == NULL || client_name == NULL) { krb5_free_context(handle->context); free(handle->lhandle); free(handle); return EINVAL; } memset((char *) &creds, 0, sizeof(creds)); /* * Verify the version numbers before proceeding; we can't use * CHECK_HANDLE because not all fields are set yet. */ GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION, KADM5_NEW_LIB_API_VERSION); /* * Acquire relevant profile entries. In version 2, merge values * in params_in with values from profile, based on * params_in->mask. * * In version 1, we've given a realm (which may be NULL) instead * of params_in. So use that realm, make params_in contain an * empty mask, and behave like version 2. */ memset((char *) ¶ms_local, 0, sizeof(params_local)); if (api_version == KADM5_API_VERSION_1) { if (params_in) params_local.mask = KADM5_CONFIG_REALM; params_in = ¶ms_local; } #define ILLEGAL_PARAMS ( \ KADM5_CONFIG_ACL_FILE | KADM5_CONFIG_ADB_LOCKFILE | \ KADM5_CONFIG_DBNAME | KADM5_CONFIG_ADBNAME | \ KADM5_CONFIG_DICT_FILE | KADM5_CONFIG_ADMIN_KEYTAB | \ KADM5_CONFIG_STASH_FILE | KADM5_CONFIG_MKEY_NAME | \ KADM5_CONFIG_ENCTYPE | KADM5_CONFIG_MAX_LIFE | \ KADM5_CONFIG_MAX_RLIFE | KADM5_CONFIG_EXPIRATION | \ KADM5_CONFIG_FLAGS | KADM5_CONFIG_ENCTYPES | \ KADM5_CONFIG_MKEY_FROM_KBD) if (params_in && params_in->mask & ILLEGAL_PARAMS) { krb5_free_context(handle->context); free(handle->lhandle); free(handle); ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "bad client parameters, returning %d"), KADM5_BAD_CLIENT_PARAMS); return KADM5_BAD_CLIENT_PARAMS; } if ((code = kadm5_get_config_params(handle->context, 0, params_in, &handle->params))) { krb5_free_context(handle->context); free(handle->lhandle); free(handle); ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "failed to get config_params, return: %d\n"), code); return(code); } #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \ KADM5_CONFIG_ADMIN_SERVER | \ KADM5_CONFIG_KADMIND_PORT) #define KPW_REQUIRED_PARAMS (KADM5_CONFIG_REALM | \ KADM5_CONFIG_KPASSWD_SERVER | \ KADM5_CONFIG_KPASSWD_PORT) if (((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) && ((handle->params.mask & KPW_REQUIRED_PARAMS) != KPW_REQUIRED_PARAMS)) { (void) kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free(handle->lhandle); free(handle); ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "missing config parameters\n")); return KADM5_MISSING_KRB5_CONF_PARAMS; } /* * Acquire a service ticket for service_name@realm in the name of * client_name, using password pass (which could be NULL), and * create a ccache to store them in. If INIT_CREDS, use the * ccache we were provided instead. */ if ((code = krb5_parse_name(handle->context, client_name, &creds.client))) { ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "could not parse client name\n")); goto error; } clientp = creds.client; if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE, strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0) cpw = TRUE; if (init_type == INIT_PASS && handle->params.kpasswd_protocol == KRB5_CHGPWD_CHANGEPW_V2 && cpw == TRUE) { /* * The 'service_name' is constructed by the caller * but its done before the parameter which determines * the kpasswd_protocol is found. The servers that * support the SET/CHANGE password protocol expect * a slightly different service principal than * the normal SEAM kadmind so construct the correct * name here and then forget it. */ char *newsvcname = NULL; newsvcname = malloc(strlen(KADM5_CHANGEPW_SERVICE) + strlen(handle->params.realm) + 2); if (newsvcname == NULL) { ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "could not malloc\n")); code = ENOMEM; goto error; } sprintf(newsvcname, "%s@%s", KADM5_CHANGEPW_SERVICE, handle->params.realm); if ((code = krb5_parse_name(handle->context, newsvcname, &creds.server))) { ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "could not parse server " "name\n")); free(newsvcname); goto error; } free(newsvcname); } else { input_name.value = service_name; input_name.length = strlen((char *)input_name.value) + 1; gssstat = krb5_gss_import_name(&minor_stat, &input_name, (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, (gss_name_t *)&creds.server); if (gssstat != GSS_S_COMPLETE) { code = KADM5_GSS_ERROR; ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "gss_import_name failed for client name\n")); goto error; } } serverp = creds.server; /* XXX temporarily fix a bug in krb5_cc_get_type */ #undef krb5_cc_get_type #define krb5_cc_get_type(context, cache) ((cache)->ops->prefix) if (init_type == INIT_CREDS) { ccache = ccache_in; handle->cache_name = (char *) malloc(strlen(krb5_cc_get_type(handle->context, ccache)) + strlen(krb5_cc_get_name(handle->context, ccache)) + 2); if (handle->cache_name == NULL) { code = ENOMEM; goto error; } sprintf(handle->cache_name, "%s:%s", krb5_cc_get_type(handle->context, ccache), krb5_cc_get_name(handle->context, ccache)); } else { #if 0 handle->cache_name = (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1); if (handle->cache_name == NULL) { code = ENOMEM; goto error; } sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE); mktemp(handle->cache_name + strlen("FILE:")); #endif { static int counter = 0; handle->cache_name = malloc(sizeof("MEMORY:kadm5_") + 3*sizeof(counter)); sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++); } if ((code = krb5_cc_resolve(handle->context, handle->cache_name, &ccache))) goto error; if ((code = krb5_cc_initialize (handle->context, ccache, creds.client))) goto error; handle->destroy_cache = 1; } handle->lhandle->cache_name = handle->cache_name; ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN, "cache created: %s\n"), handle->cache_name); if ((code = krb5_timeofday(handle->context, &now))) goto error; /* * Get a ticket, use the method specified in init_type. */ creds.times.starttime = 0; /* start timer at KDC */ creds.times.endtime = 0; /* endtime will be limited by service */ memset(&opt, 0, sizeof (opt)); krb5_get_init_creds_opt_init(&opt); if (creds.times.endtime) { if (creds.times.starttime) starttime = creds.times.starttime; else starttime = now; krb5_get_init_creds_opt_set_tkt_life(&opt, creds.times.endtime - starttime); } code = krb5_unparse_name(handle->context, creds.server, &server); if (code) goto error; /* * Solaris Kerberos: * Save the original creds.server as krb5_get_init_creds*() always * sets the realm of the server to the client realm. */ code = krb5_copy_principal(handle->context, creds.server, &saved_server); if (code) goto error; if (init_type == INIT_PASS) { code = krb5_get_init_creds_password(handle->context, &creds, creds.client, pass, NULL, NULL, creds.times.starttime, server, &opt); } else if (init_type == INIT_SKEY) { krb5_keytab kt = NULL; if (!(pass && (code = krb5_kt_resolve(handle->context, pass, &kt)))) { code = krb5_get_init_creds_keytab( handle->context, &creds, creds.client, kt, creds.times.starttime, server, &opt); if (pass) krb5_kt_close(handle->context, kt); } } /* Improved error messages */ if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD; if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) code = KADM5_SECURE_PRINC_MISSING; if (code != 0) { ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "failed to obtain credentials cache\n")); krb5_free_principal(handle->context, saved_server); goto error; } /* * Solaris Kerberos: * If the server principal had an empty realm then store that in * the cred cache and not the server realm as returned by * krb5_get_init_creds_{keytab|password}(). This ensures that rpcsec_gss * will find the credential in the cred cache even if a "fallback" * method is being used to determine the realm. */ if (init_type != INIT_CREDS) { krb5_free_principal(handle->context, creds.server); } creds.server = saved_server; /* * If we got this far, save the creds in the cache. */ if (ccache) { code = krb5_cc_store_cred(handle->context, ccache, &creds); } ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "obtained credentials cache\n")); #ifdef ZEROPASSWD if (pass != NULL) memset(pass, 0, strlen(pass)); #endif if (init_type != INIT_PASS || handle->params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC || cpw == FALSE) { code = _kadm5_initialize_rpcsec_gss_handle(handle, client_name, service_name); /* * Solaris Kerberos: * If _kadm5_initialize_rpcsec_gss_handle() fails it will have * called krb5_gss_release_cred(). If the credential cache is a * MEMORY cred cache krb5_gss_release_cred() destroys the * cred cache data. Make sure that the cred-cache is closed * to prevent a double free in the "error" code. */ if (code != 0) { if (init_type != INIT_CREDS) { krb5_cc_close(handle->context, ccache); ccache = NULL; } goto error; } } *server_handle = (void *) handle; if (init_type != INIT_CREDS) krb5_cc_close(handle->context, ccache); goto cleanup; error: /* * Note that it is illegal for this code to execute if "handle" * has not been allocated and initialized. I.e., don't use "goto * error" before the block of code at the top of the function * that allocates and initializes "handle". */ if (handle->cache_name) free(handle->cache_name); if (handle->destroy_cache && ccache) krb5_cc_destroy(handle->context, ccache); if(handle->clnt && handle->clnt->cl_auth) AUTH_DESTROY(handle->clnt->cl_auth); if(handle->clnt) clnt_destroy(handle->clnt); (void) kadm5_free_config_params(handle->context, &handle->params); cleanup: if (server) free(server); /* * cred's server and client pointers could have been overwritten * by the krb5_get_init_* functions. If the addresses are different * before and after the calls then we must free the memory that * was allocated before the call. */ if (clientp && clientp != creds.client) krb5_free_principal(handle->context, clientp); if (serverp && serverp != creds.server) krb5_free_principal(handle->context, serverp); krb5_free_cred_contents(handle->context, &creds); /* * Dont clean up the handle if the code is OK (code==0) * because it is returned to the caller in the 'server_handle' * ptr. */ if (code) { krb5_free_context(handle->context); free(handle->lhandle); free(handle); } return code; } kadm5_ret_t kadm5_destroy(void *server_handle) { krb5_ccache ccache = NULL; int code = KADM5_OK; kadm5_server_handle_t handle = (kadm5_server_handle_t) server_handle; OM_uint32 min_stat; CHECK_HANDLE(server_handle); /* SUNW14resync: * krb5_cc_resolve() will resolve a ccache with the same data that * handle->my_cred points to. If the ccache is a MEMORY ccache then * gss_release_cred() will free that data (it doesn't do this when ccache * is a FILE ccache). * if'ed out to avoid the double free. */ #if 0 if (handle->destroy_cache && handle->cache_name) { if ((code = krb5_cc_resolve(handle->context, handle->cache_name, &ccache)) == 0) code = krb5_cc_destroy (handle->context, ccache); } #endif if (handle->cache_name) free(handle->cache_name); if (handle->clnt && handle->clnt->cl_auth) { /* * Since kadm5 doesn't use the default credentials we * must clean this up manually. */ if (handle->my_cred != GSS_C_NO_CREDENTIAL) (void) gss_release_cred(&min_stat, &handle->my_cred); AUTH_DESTROY(handle->clnt->cl_auth); } if (handle->clnt) clnt_destroy(handle->clnt); if (handle->lhandle) free (handle->lhandle); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); handle->magic_number = 0; free(handle); return code; } /* not supported on client */ kadm5_ret_t kadm5_lock(void *server_handle) { return EINVAL; } /* not supported on client */ kadm5_ret_t kadm5_unlock(void *server_handle) { return EINVAL; } kadm5_ret_t kadm5_flush(void *server_handle) { return KADM5_OK; } int _kadm5_check_handle(void *handle) { CHECK_HANDLE(handle); return 0; } krb5_error_code kadm5_init_krb5_context (krb5_context *ctx) { return krb5_init_context(ctx); } /* * Stub function for kadmin. It was created to eliminate the dependency on * libkdb's ulog functions. The srv equivalent makes the actual calls. */ krb5_error_code kadm5_init_iprop(void *handle) { return (0); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef __KADM5_CLIENT_INTERNAL_H__ #define __KADM5_CLIENT_INTERNAL_H__ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ * * $Log$ * Revision 1.1 1996/07/24 22:22:43 tlyu * * Makefile.in, configure.in: break out client lib into a * subdirectory * * Revision 1.11 1996/07/22 20:35:46 marc * this commit includes all the changes on the OV_9510_INTEGRATION and * OV_MERGE branches. This includes, but is not limited to, the new openvision * admin system, and major changes to gssapi to add functionality, and bring * the implementation in line with rfc1964. before committing, the * code was built and tested for netbsd and solaris. * * Revision 1.10.4.1 1996/07/18 03:08:37 marc * merged in changes from OV_9510_BP to OV_9510_FINAL1 * * Revision 1.10.2.1 1996/06/20 02:16:46 marc * File added to the repository on a branch * * Revision 1.10 1996/06/06 20:09:16 bjaspan * add destroy_cache, for kadm5_init_with_creds * * Revision 1.9 1996/05/30 21:04:42 bjaspan * add lhandle to handle * * Revision 1.8 1996/05/28 20:33:49 bjaspan * rework kadm5_config * * Revision 1.7 1996/05/17 21:36:59 bjaspan * rename to kadm5, begin implementing version 2 * * Revision 1.6 1996/05/16 21:45:07 bjaspan * add context * * Revision 1.5 1996/05/08 21:10:23 bjaspan * marc's changes * * Revision 1.4 1996/01/16 20:54:30 grier * secure/3570 use krb5_ui_4 not unsigned int * * Revision 1.3 1995/11/14 17:48:57 grier * long to int * * Revision 1.2 1994/08/16 18:53:47 jik * Versioning stuff. * * Revision 1.1 1994/08/09 21:14:38 jik * Initial revision * */ /* * This header file is used internally by the Admin API client * libraries. IF YOU THINK YOU NEED TO USE THIS FILE FOR ANYTHING, * YOU'RE ALMOST CERTAINLY WRONG. */ #ifdef __cplusplus extern "C" { #endif #include "admin_internal.h" typedef struct _kadm5_server_handle_t { krb5_ui_4 magic_number; krb5_ui_4 struct_version; krb5_ui_4 api_version; char * cache_name; int destroy_cache; CLIENT * clnt; krb5_context context; /* Solaris Kerberos */ gss_cred_id_t my_cred; kadm5_config_params params; struct _kadm5_server_handle_t *lhandle; } kadm5_server_handle_rec, *kadm5_server_handle_t; #define CLIENT_CHECK_HANDLE(handle) \ { \ kadm5_server_handle_t srvr = \ (kadm5_server_handle_t) handle; \ \ if (srvr->params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC && ! srvr->clnt) \ return KADM5_BAD_SERVER_HANDLE; \ if (! srvr->cache_name) \ return KADM5_BAD_SERVER_HANDLE; \ if (! srvr->lhandle) \ return KADM5_BAD_SERVER_HANDLE; \ } #define CHECK_HANDLE(handle) \ GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION, \ KADM5_NEW_LIB_API_VERSION) \ CLIENT_CHECK_HANDLE(handle) #ifdef __cplusplus } #endif #endif /* __KADM5_CLIENT_INTERNAL_H__ */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include /* SUNWresync121 XXX */ #include #include #ifdef HAVE_MEMORY_H #include #endif #include #include "client_internal.h" #ifdef DEBUG /* SUNWresync14 XXX */ #define eret() {clnt_perror(handle->clnt, "null ret"); return KADM5_RPC_ERROR;} #else #define eret() return KADM5_RPC_ERROR #endif kadm5_ret_t kadm5_create_principal(void *server_handle, kadm5_principal_ent_t princ, long mask, char *pw) { generic_ret *r; cprinc_arg arg; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); memset(&arg, 0, sizeof(arg)); arg.mask = mask; arg.passwd = pw; arg.api_version = handle->api_version; if(princ == NULL) return EINVAL; if (handle->api_version == KADM5_API_VERSION_1) { memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1)); } else { memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); } if (handle->api_version == KADM5_API_VERSION_1) { /* * hack hack cough cough. * krb5_unparse name dumps core if we pass it in garbage * or null. So, since the client is not allowed to set mod_name * anyway, we just fill it in with a dummy principal. The server of * course ignores this. */ /* krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); */ arg.rec.mod_name = NULL; } else arg.rec.mod_name = NULL; if(!(mask & KADM5_POLICY)) arg.rec.policy = NULL; if (! (mask & KADM5_KEY_DATA)) { arg.rec.n_key_data = 0; arg.rec.key_data = NULL; } if (! (mask & KADM5_TL_DATA)) { arg.rec.n_tl_data = 0; arg.rec.tl_data = NULL; } r = create_principal_2(&arg, handle->clnt); if (handle->api_version == KADM5_API_VERSION_1) krb5_free_principal(handle->context, arg.rec.mod_name); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_create_principal_3(void *server_handle, kadm5_principal_ent_t princ, long mask, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *pw) { generic_ret *r; cprinc3_arg arg; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); memset(&arg, 0, sizeof(arg)); arg.mask = mask; arg.passwd = pw; arg.api_version = handle->api_version; arg.n_ks_tuple = n_ks_tuple; arg.ks_tuple = ks_tuple; if(princ == NULL) return EINVAL; if (handle->api_version == KADM5_API_VERSION_1) { memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1)); } else { memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); } if (handle->api_version == KADM5_API_VERSION_1) { /* * hack hack cough cough. * krb5_unparse name dumps core if we pass it in garbage * or null. So, since the client is not allowed to set mod_name * anyway, we just fill it in with a dummy principal. The server of * course ignores this. */ krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); } else arg.rec.mod_name = NULL; if(!(mask & KADM5_POLICY)) arg.rec.policy = NULL; if (! (mask & KADM5_KEY_DATA)) { arg.rec.n_key_data = 0; arg.rec.key_data = NULL; } if (! (mask & KADM5_TL_DATA)) { arg.rec.n_tl_data = 0; arg.rec.tl_data = NULL; } r = create_principal3_2(&arg, handle->clnt); if (handle->api_version == KADM5_API_VERSION_1) krb5_free_principal(handle->context, arg.rec.mod_name); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_delete_principal(void *server_handle, krb5_principal principal) { dprinc_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(principal == NULL) return EINVAL; arg.princ = principal; arg.api_version = handle->api_version; r = delete_principal_2(&arg, handle->clnt); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_modify_principal(void *server_handle, kadm5_principal_ent_t princ, long mask) { mprinc_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); memset(&arg, 0, sizeof(arg)); arg.mask = mask; arg.api_version = handle->api_version; /* * cough cough gag gag * see comment in create_principal. */ if(princ == NULL) return EINVAL; if (handle->api_version == KADM5_API_VERSION_1) { memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1)); } else { memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); } if(!(mask & KADM5_POLICY)) arg.rec.policy = NULL; if (! (mask & KADM5_KEY_DATA)) { arg.rec.n_key_data = 0; arg.rec.key_data = NULL; } if (! (mask & KADM5_TL_DATA)) { arg.rec.n_tl_data = 0; arg.rec.tl_data = NULL; } if (handle->api_version == KADM5_API_VERSION_1) { /* * See comment in create_principal */ krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); } else arg.rec.mod_name = NULL; r = modify_principal_2(&arg, handle->clnt); if (handle->api_version == KADM5_API_VERSION_1) krb5_free_principal(handle->context, arg.rec.mod_name); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_get_principal(void *server_handle, krb5_principal princ, kadm5_principal_ent_t ent, long mask) { gprinc_arg arg; gprinc_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(princ == NULL) return EINVAL; arg.princ = princ; if (handle->api_version == KADM5_API_VERSION_1) arg.mask = KADM5_PRINCIPAL_NORMAL_MASK; else arg.mask = mask; arg.api_version = handle->api_version; r = get_principal_2(&arg, handle->clnt); if(r == NULL) eret(); if (handle->api_version == KADM5_API_VERSION_1) { kadm5_principal_ent_t_v1 *entp; entp = (kadm5_principal_ent_t_v1 *) ent; if (r->code == 0) { if (!(*entp = (kadm5_principal_ent_t_v1) malloc(sizeof(kadm5_principal_ent_rec_v1)))) return ENOMEM; /* this memcpy works because the v1 structure is an initial subset of the v2 struct. C guarantees that this will result in the same layout in memory */ memcpy(*entp, &r->rec, sizeof(**entp)); } else { *entp = NULL; } } else { if (r->code == 0) memcpy(ent, &r->rec, sizeof(r->rec)); } return r->code; } kadm5_ret_t kadm5_get_principals(void *server_handle, char *exp, char ***princs, int *count) { gprincs_arg arg; gprincs_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(princs == NULL || count == NULL) return EINVAL; arg.exp = exp; arg.api_version = handle->api_version; r = get_princs_2(&arg, handle->clnt); if(r == NULL) eret(); if(r->code == 0) { *count = r->count; *princs = r->princs; } else { *count = 0; *princs = NULL; } return r->code; } kadm5_ret_t kadm5_rename_principal(void *server_handle, krb5_principal source, krb5_principal dest) { rprinc_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); arg.src = source; arg.dest = dest; arg.api_version = handle->api_version; if (source == NULL || dest == NULL) return EINVAL; r = rename_principal_2(&arg, handle->clnt); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_chpass_principal(void *server_handle, krb5_principal princ, char *password) { chpass_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); arg.princ = princ; arg.pass = password; arg.api_version = handle->api_version; if(princ == NULL) return EINVAL; r = chpass_principal_2(&arg, handle->clnt); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_chpass_principal_3(void *server_handle, krb5_principal princ, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *password) { chpass3_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); arg.princ = princ; arg.pass = password; arg.api_version = handle->api_version; arg.keepold = keepold; arg.n_ks_tuple = n_ks_tuple; arg.ks_tuple = ks_tuple; if(princ == NULL) return EINVAL; r = chpass_principal3_2(&arg, handle->clnt); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_setv4key_principal(void *server_handle, krb5_principal princ, krb5_keyblock *keyblock) { setv4key_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); arg.princ = princ; arg.keyblock = keyblock; arg.api_version = handle->api_version; if(princ == NULL || keyblock == NULL) return EINVAL; r = setv4key_principal_2(&arg, handle->clnt); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_setkey_principal(void *server_handle, krb5_principal princ, krb5_keyblock *keyblocks, int n_keys) { setkey_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); arg.princ = princ; arg.keyblocks = keyblocks; arg.n_keys = n_keys; arg.api_version = handle->api_version; if(princ == NULL || keyblocks == NULL) return EINVAL; r = setkey_principal_2(&arg, handle->clnt); if(r == NULL) eret(); return r->code; } kadm5_ret_t kadm5_setkey_principal_3(void *server_handle, krb5_principal princ, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock *keyblocks, int n_keys) { setkey3_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); arg.princ = princ; arg.keyblocks = keyblocks; arg.n_keys = n_keys; arg.api_version = handle->api_version; arg.keepold = keepold; arg.n_ks_tuple = n_ks_tuple; arg.ks_tuple = ks_tuple; if(princ == NULL || keyblocks == NULL) return EINVAL; r = setkey_principal3_2(&arg, handle->clnt); if(r == NULL) eret(); return r->code; } /* * Solaris Kerberos: * This routine implements just the "old" randkey_principal code. * The code in the kadmin client sometimes needs to call this * directly when the kadm5_randkey_principal_3 call fails. * * The kadmin client utility uses a specific set of key/salt tuples, * so the standard fallback in kadm5_randkey_principal (see below) * will not work because it would result in kadm5_randkey_principal_3 * being called twice - once with the specific key/salts specified by * kadmin and once with the NULL set (used to indicate that the server * should use the full set of supported enctypes). Making this * routine separate makes the code simpler and avoids making the * kadm5_randkey_principal_3 twice from kadmin. */ kadm5_ret_t kadm5_randkey_principal_old(void *server_handle, krb5_principal princ, krb5_keyblock **key, int *n_keys) { chrand_arg arg; chrand_ret *r; kadm5_server_handle_t handle = server_handle; int i, ret; /* For safety */ if (n_keys) *n_keys = 0; if (key) *key = NULL; CHECK_HANDLE(server_handle); arg.princ = princ; arg.api_version = handle->api_version; if(princ == NULL) return EINVAL; r = chrand_principal_2(&arg, handle->clnt); if (r == NULL) return KADM5_RPC_ERROR; if (handle->api_version == KADM5_API_VERSION_1) { if (key) krb5_copy_keyblock(handle->context, &r->key, key); } else if (key && (r->n_keys > 0)) { *key = (krb5_keyblock *) malloc( r->n_keys*sizeof(krb5_keyblock)); if (*key == NULL) return ENOMEM; for (i = 0; i < r->n_keys; i++) { ret = krb5_copy_keyblock_contents( handle->context, &r->keys[i], &(*key)[i]); if (ret) { free(*key); *key = NULL; return ENOMEM; } } if (n_keys) *n_keys = r->n_keys; } return (r->code); } kadm5_ret_t kadm5_randkey_principal_3(void *server_handle, krb5_principal princ, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock **key, int *n_keys) { chrand3_arg arg; chrand_ret *r; kadm5_server_handle_t handle = server_handle; int i, ret; /* Solaris Kerberos - For safety */ if (n_keys) *n_keys = 0; if (key) *key = NULL; CHECK_HANDLE(server_handle); arg.princ = princ; arg.api_version = handle->api_version; arg.keepold = keepold; arg.n_ks_tuple = n_ks_tuple; arg.ks_tuple = ks_tuple; if(princ == NULL) return EINVAL; r = chrand_principal3_2(&arg, handle->clnt); if(r == NULL) eret(); if (handle->api_version == KADM5_API_VERSION_1) { if (key) krb5_copy_keyblock(handle->context, &r->key, key); } else { if (n_keys) *n_keys = r->n_keys; if (key) { if(r->n_keys) { *key = (krb5_keyblock *) malloc(r->n_keys*sizeof(krb5_keyblock)); if (*key == NULL) return ENOMEM; for (i = 0; i < r->n_keys; i++) { ret = krb5_copy_keyblock_contents(handle->context, &r->keys[i], &(*key)[i]); if (ret) { free(*key); return ENOMEM; } } } else *key = NULL; } } return r->code; } kadm5_ret_t kadm5_randkey_principal(void *server_handle, krb5_principal princ, krb5_keyblock **key, int *n_keys) { /* Solaris Kerberos */ kadm5_ret_t kret; /* * Default to trying the newest API to insure that the full * set of enctypes is created. */ kret = kadm5_randkey_principal_3(server_handle, princ, FALSE, 0, NULL, key, n_keys); /* * We will get an RPC error if the RPC call failed which * will normally indicate that the remote procedure did not * exist on the server, so try the older API. */ if (kret == KADM5_RPC_ERROR) { kret = kadm5_randkey_principal_old(server_handle, princ, key, n_keys); } return (kret); } /* not supported on client side */ kadm5_ret_t kadm5_decrypt_key(void *server_handle, kadm5_principal_ent_t entry, krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno, krb5_keyblock *keyblock, krb5_keysalt *keysalt, int *kvnop) { return EINVAL; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include /* SUNWresync121 XXX */ #include #include #include #ifdef HAVE_MEMORY_H #include #endif /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 25, 0 }; generic_ret * create_principal_2(cprinc_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, CREATE_PRINCIPAL, (xdrproc_t) xdr_cprinc_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * create_principal3_2(cprinc3_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, CREATE_PRINCIPAL3, (xdrproc_t) xdr_cprinc3_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * delete_principal_2(dprinc_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, DELETE_PRINCIPAL, (xdrproc_t) xdr_dprinc_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * modify_principal_2(mprinc_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, MODIFY_PRINCIPAL, (xdrproc_t) xdr_mprinc_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * rename_principal_2(rprinc_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, RENAME_PRINCIPAL, (xdrproc_t) xdr_rprinc_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } gprinc_ret * get_principal_2(gprinc_arg *argp, CLIENT *clnt) { static gprinc_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, GET_PRINCIPAL, (xdrproc_t) xdr_gprinc_arg, (caddr_t) argp, (xdrproc_t) xdr_gprinc_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } gprincs_ret * get_princs_2(gprincs_arg *argp, CLIENT *clnt) { static gprincs_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, GET_PRINCS, (xdrproc_t) xdr_gprincs_arg, (caddr_t) argp, (xdrproc_t) xdr_gprincs_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * chpass_principal_2(chpass_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, CHPASS_PRINCIPAL, (xdrproc_t) xdr_chpass_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * chpass_principal3_2(chpass3_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, CHPASS_PRINCIPAL3, (xdrproc_t) xdr_chpass3_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * setv4key_principal_2(setv4key_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, SETV4KEY_PRINCIPAL, (xdrproc_t) xdr_setv4key_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * setkey_principal_2(setkey_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, SETKEY_PRINCIPAL, (xdrproc_t) xdr_setkey_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * setkey_principal3_2(setkey3_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, SETKEY_PRINCIPAL3, (xdrproc_t) xdr_setkey3_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } chrand_ret * chrand_principal_2(chrand_arg *argp, CLIENT *clnt) { static chrand_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, CHRAND_PRINCIPAL, (xdrproc_t) xdr_chrand_arg, (caddr_t) argp, (xdrproc_t) xdr_chrand_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } chrand_ret * chrand_principal3_2(chrand3_arg *argp, CLIENT *clnt) { static chrand_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, CHRAND_PRINCIPAL3, (xdrproc_t) xdr_chrand3_arg, (caddr_t) argp, (xdrproc_t) xdr_chrand_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * create_policy_2(cpol_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, CREATE_POLICY, (xdrproc_t) xdr_cpol_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * delete_policy_2(dpol_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, DELETE_POLICY, (xdrproc_t) xdr_dpol_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * modify_policy_2(mpol_arg *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, MODIFY_POLICY, (xdrproc_t) xdr_mpol_arg, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } gpol_ret * get_policy_2(gpol_arg *argp, CLIENT *clnt) { static gpol_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, GET_POLICY, (xdrproc_t) xdr_gpol_arg, (caddr_t) argp, (xdrproc_t) xdr_gpol_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } gpols_ret * get_pols_2(gpols_arg *argp, CLIENT *clnt) { static gpols_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, GET_POLS, (xdrproc_t) xdr_gpols_arg, (caddr_t) argp, (xdrproc_t) xdr_gpols_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } getprivs_ret * get_privs_2(void *argp, CLIENT *clnt) { static getprivs_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, GET_PRIVS, (xdrproc_t) xdr_u_int, (caddr_t) argp, (xdrproc_t) xdr_getprivs_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } generic_ret * init_2(void *argp, CLIENT *clnt) { static generic_ret clnt_res; /* Solaris Kerberos */ if (clnt == NULL) return (NULL); memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, INIT, (xdrproc_t) xdr_u_int, (caddr_t) argp, (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include #include "client_internal.h" kadm5_ret_t kadm5_chpass_principal_util(void *server_handle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len) { kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); return _kadm5_chpass_principal_util(handle, handle->lhandle, princ, new_pw, ret_pw, msg_ret, msg_len); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include /* SUNWresync121 XXX */ #include #include #include "client_internal.h" #include #include #include kadm5_ret_t kadm5_create_policy(void *server_handle, kadm5_policy_ent_t policy, long mask) { cpol_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(policy == (kadm5_policy_ent_t) NULL) return EINVAL; arg.mask = mask; arg.api_version = handle->api_version; memcpy(&arg.rec, policy, sizeof(kadm5_policy_ent_rec)); r = create_policy_2(&arg, handle->clnt); if(r == NULL) return KADM5_RPC_ERROR; return r->code; } kadm5_ret_t kadm5_delete_policy(void *server_handle, char *name) { dpol_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(name == NULL) return EINVAL; arg.name = name; arg.api_version = handle->api_version; r = delete_policy_2(&arg, handle->clnt); if(r == NULL) return KADM5_RPC_ERROR; return r->code; } kadm5_ret_t kadm5_modify_policy(void *server_handle, kadm5_policy_ent_t policy, long mask) { mpol_arg arg; generic_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(policy == (kadm5_policy_ent_t) NULL) return EINVAL; arg.mask = mask; arg.api_version = handle->api_version; memcpy(&arg.rec, policy, sizeof(kadm5_policy_ent_rec)); r = modify_policy_2(&arg, handle->clnt); if(r == NULL) return KADM5_RPC_ERROR; return r->code; } kadm5_ret_t kadm5_get_policy(void *server_handle, char *name, kadm5_policy_ent_t ent) { gpol_arg arg; gpol_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); arg.name = name; arg.api_version = handle->api_version; if(name == NULL) return EINVAL; r = get_policy_2(&arg, handle->clnt); if(r == NULL) return KADM5_RPC_ERROR; if (handle->api_version == KADM5_API_VERSION_1) { kadm5_policy_ent_t *entp; entp = (kadm5_policy_ent_t *) ent; if(r->code == 0) { if (!(*entp = (kadm5_policy_ent_t) malloc(sizeof(kadm5_policy_ent_rec)))) return ENOMEM; memcpy(*entp, &r->rec, sizeof(**entp)); } else { *entp = NULL; } } else { if (r->code == 0) memcpy(ent, &r->rec, sizeof(r->rec)); } return r->code; } kadm5_ret_t kadm5_get_policies(void *server_handle, char *exp, char ***pols, int *count) { gpols_arg arg; gpols_ret *r; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(pols == NULL || count == NULL) return EINVAL; arg.exp = exp; arg.api_version = handle->api_version; r = get_pols_2(&arg, handle->clnt); if(r == NULL) return KADM5_RPC_ERROR; if(r->code == 0) { *count = r->count; *pols = r->pols; } else { *count = 0; *pols = NULL; } return r->code; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * * $Id: clnt_privs.c 18130 2006-06-14 21:42:02Z raeburn $ * $Source$ * */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include /* SUNWresync121 XXX */ #include #include #include "client_internal.h" kadm5_ret_t kadm5_get_privs(void *server_handle, long *privs) { getprivs_ret *r; kadm5_server_handle_t handle = server_handle; r = get_privs_2(&handle->api_version, handle->clnt); if (r == NULL) return KADM5_RPC_ERROR; else if (r->code == KADM5_OK) *privs = r->privs; return r->code; } /* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _IPROP_H_RPCGEN #define _IPROP_H_RPCGEN #include typedef struct { u_int utf8str_t_len; char *utf8str_t_val; } utf8str_t; typedef uint32_t kdb_sno_t; struct kdbe_time_t { uint32_t seconds; uint32_t useconds; }; typedef struct kdbe_time_t kdbe_time_t; struct kdbe_key_t { int32_t k_ver; int32_t k_kvno; struct { u_int k_enctype_len; int32_t *k_enctype_val; } k_enctype; struct { u_int k_contents_len; utf8str_t *k_contents_val; } k_contents; }; typedef struct kdbe_key_t kdbe_key_t; struct kdbe_data_t { int32_t k_magic; utf8str_t k_data; }; typedef struct kdbe_data_t kdbe_data_t; struct kdbe_princ_t { utf8str_t k_realm; struct { u_int k_components_len; kdbe_data_t *k_components_val; } k_components; int32_t k_nametype; }; typedef struct kdbe_princ_t kdbe_princ_t; struct kdbe_tl_t { int16_t tl_type; struct { u_int tl_data_len; char *tl_data_val; } tl_data; }; typedef struct kdbe_tl_t kdbe_tl_t; typedef struct { u_int kdbe_pw_hist_t_len; kdbe_key_t *kdbe_pw_hist_t_val; } kdbe_pw_hist_t; enum kdbe_attr_type_t { AT_ATTRFLAGS = 0, AT_MAX_LIFE = 1, AT_MAX_RENEW_LIFE = 2, AT_EXP = 3, AT_PW_EXP = 4, AT_LAST_SUCCESS = 5, AT_LAST_FAILED = 6, AT_FAIL_AUTH_COUNT = 7, AT_PRINC = 8, AT_KEYDATA = 9, AT_TL_DATA = 10, AT_LEN = 11, AT_MOD_PRINC = 12, AT_MOD_TIME = 13, AT_MOD_WHERE = 14, AT_PW_LAST_CHANGE = 15, AT_PW_POLICY = 16, AT_PW_POLICY_SWITCH = 17, AT_PW_HIST_KVNO = 18, AT_PW_HIST = 19 }; typedef enum kdbe_attr_type_t kdbe_attr_type_t; struct kdbe_val_t { kdbe_attr_type_t av_type; union { uint32_t av_attrflags; uint32_t av_max_life; uint32_t av_max_renew_life; uint32_t av_exp; uint32_t av_pw_exp; uint32_t av_last_success; uint32_t av_last_failed; uint32_t av_fail_auth_count; kdbe_princ_t av_princ; struct { u_int av_keydata_len; kdbe_key_t *av_keydata_val; } av_keydata; struct { u_int av_tldata_len; kdbe_tl_t *av_tldata_val; } av_tldata; int16_t av_len; uint32_t av_pw_last_change; kdbe_princ_t av_mod_princ; uint32_t av_mod_time; utf8str_t av_mod_where; utf8str_t av_pw_policy; bool_t av_pw_policy_switch; uint32_t av_pw_hist_kvno; struct { u_int av_pw_hist_len; kdbe_pw_hist_t *av_pw_hist_val; } av_pw_hist; struct { u_int av_extension_len; char *av_extension_val; } av_extension; } kdbe_val_t_u; }; typedef struct kdbe_val_t kdbe_val_t; typedef struct { u_int kdbe_t_len; kdbe_val_t *kdbe_t_val; } kdbe_t; struct kdb_incr_update_t { utf8str_t kdb_princ_name; kdb_sno_t kdb_entry_sno; kdbe_time_t kdb_time; kdbe_t kdb_update; bool_t kdb_deleted; bool_t kdb_commit; struct { u_int kdb_kdcs_seen_by_len; utf8str_t *kdb_kdcs_seen_by_val; } kdb_kdcs_seen_by; struct { u_int kdb_futures_len; char *kdb_futures_val; } kdb_futures; }; typedef struct kdb_incr_update_t kdb_incr_update_t; typedef struct { u_int kdb_ulog_t_len; kdb_incr_update_t *kdb_ulog_t_val; } kdb_ulog_t; enum update_status_t { UPDATE_OK = 0, UPDATE_ERROR = 1, UPDATE_FULL_RESYNC_NEEDED = 2, UPDATE_BUSY = 3, UPDATE_NIL = 4, UPDATE_PERM_DENIED = 5 }; typedef enum update_status_t update_status_t; struct kdb_last_t { kdb_sno_t last_sno; kdbe_time_t last_time; }; typedef struct kdb_last_t kdb_last_t; struct kdb_incr_result_t { kdb_last_t lastentry; kdb_ulog_t updates; update_status_t ret; }; typedef struct kdb_incr_result_t kdb_incr_result_t; struct kdb_fullresync_result_t { kdb_last_t lastentry; update_status_t ret; }; typedef struct kdb_fullresync_result_t kdb_fullresync_result_t; #define KRB5_IPROP_PROG 100423 #define KRB5_IPROP_VERS 1 #define IPROP_NULL 0 extern void * iprop_null_1(); #define IPROP_GET_UPDATES 1 extern kdb_incr_result_t * iprop_get_updates_1(); #define IPROP_FULL_RESYNC 2 extern kdb_fullresync_result_t * iprop_full_resync_1(); extern int krb5_iprop_prog_1_freeresult(); /* the xdr functions */ extern bool_t xdr_utf8str_t(); extern bool_t xdr_kdb_sno_t(); extern bool_t xdr_kdbe_time_t(); extern bool_t xdr_kdbe_key_t(); extern bool_t xdr_kdbe_data_t(); extern bool_t xdr_kdbe_princ_t(); extern bool_t xdr_kdbe_tl_t(); extern bool_t xdr_kdbe_pw_hist_t(); extern bool_t xdr_kdbe_attr_type_t(); extern bool_t xdr_kdbe_val_t(); extern bool_t xdr_kdbe_t(); extern bool_t xdr_kdb_incr_update_t(); extern bool_t xdr_kdb_ulog_t(); extern bool_t xdr_update_status_t(); extern bool_t xdr_kdb_last_t(); extern bool_t xdr_kdb_incr_result_t(); extern bool_t xdr_kdb_fullresync_result_t(); #endif /* !_IPROP_H_RPCGEN */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * lib/kadm/logger.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* KADM5 wants non-syslog log files to contain syslog-like entries */ #define VERBOSE_LOGS /* * logger.c - Handle logging functions for those who want it. */ #include "k5-int.h" #include "adm_proto.h" #include "com_err.h" #include #include #include #ifdef HAVE_SYSLOG_H #include #endif /* HAVE_SYSLOG_H */ #ifdef HAVE_STDARG_H #include #else /* HAVE_STDARG_H */ #include #endif /* HAVE_STDARG_H */ #include #include #include #define KRB5_KLOG_MAX_ERRMSG_SIZE 2048 #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif /* MAXHOSTNAMELEN */ #define LSPEC_PARSE_ERR_1 1 #define LSPEC_PARSE_ERR_2 2 #define LOG_FILE_ERR 3 #define LOG_DEVICE_ERR 4 #define LOG_UFO_STRING 5 #define LOG_EMERG_STRING 6 #define LOG_ALERT_STRING 7 #define LOG_CRIT_STRING 8 #define LOG_ERR_STRING 9 #define LOG_WARNING_STRING 10 #define LOG_NOTICE_STRING 11 #define LOG_INFO_STRING 12 #define LOG_DEBUG_STRING 13 /* This is to assure that we have at least one match in the syslog stuff */ /* static const char LSPEC_PARSE_ERR_1[] = "%s: cannot parse <%s>\n"; static const char LSPEC_PARSE_ERR_2[] = "%s: warning - logging entry syntax error\n"; static const char LOG_FILE_ERR[] = "%s: error writing to %s\n"; static const char LOG_DEVICE_ERR[] = "%s: error writing to %s device\n"; static const char LOG_UFO_STRING[] = "???"; static const char LOG_EMERG_STRING[] = "EMERGENCY"; static const char LOG_ALERT_STRING[] = "ALERT"; static const char LOG_CRIT_STRING[] = "CRITICAL"; static const char LOG_ERR_STRING[] = "Error"; static const char LOG_WARNING_STRING[] = "Warning"; static const char LOG_NOTICE_STRING[] = "Notice"; static const char LOG_INFO_STRING[] = "info"; static const char LOG_DEBUG_STRING[] = "debug"; */ const char * krb5_log_error_table(long errorno) { switch (errorno) { case LSPEC_PARSE_ERR_1: return(gettext("%s: cannot parse <%s>\n")); case LSPEC_PARSE_ERR_2: return(gettext("%s: warning - logging entry syntax error\n")); case LOG_FILE_ERR: return(gettext("%s: error writing to %s\n")); case LOG_DEVICE_ERR: return(gettext("%s: error writing to %s device\n")); case LOG_UFO_STRING: return(gettext("???")); case LOG_EMERG_STRING: return(gettext("EMERGENCY")); case LOG_ALERT_STRING: return(gettext("ALERT")); case LOG_CRIT_STRING: return(gettext("CRITICAL")); case LOG_ERR_STRING: return(gettext("Error")); case LOG_WARNING_STRING: return(gettext("Warning")); case LOG_NOTICE_STRING: return(gettext("Notice")); case LOG_INFO_STRING: case LOG_DEBUG_STRING: default: return(gettext("info")); } } /* * Output logging. * * Output logging is now controlled by the configuration file. We can specify * the following syntaxes under the [logging]->entity specification. * FILE * SYSLOG[=[:]] * STDERR * CONSOLE * DEVICE= * * Where: * is ":" for open/append, "=" for open/create. * is a valid path name. * is one of: (default = ERR) * EMERG * ALERT * CRIT * ERR * WARNING * NOTICE * INFO * DEBUG * is one of: (default = AUTH) * KERN * USER * MAIL * DAEMON * AUTH * LPR * NEWS * UUCP * AUDIT * CRON * LOCAL0..LOCAL7 * is a valid device specification. */ struct log_entry { enum log_type { K_LOG_FILE, K_LOG_SYSLOG, K_LOG_STDERR, K_LOG_CONSOLE, K_LOG_DEVICE, K_LOG_NONE } log_type; krb5_pointer log_2free; union log_union { struct log_file { FILE *lf_filep; char *lf_fname; char *lf_fopen_mode; /* "a+" or "w" */ #define K_LOG_DEF_FILE_ROTATE_PERIOD -1 /* never */ #define K_LOG_DEF_FILE_ROTATE_VERSIONS 0 /* no versions */ time_t lf_rotate_period; time_t lf_last_rotated; int lf_rotate_versions; } log_file; struct log_syslog { int ls_facility; int ls_severity; } log_syslog; struct log_device { FILE *ld_filep; char *ld_devname; } log_device; } log_union; }; #define lfu_filep log_union.log_file.lf_filep #define lfu_fname log_union.log_file.lf_fname #define lfu_fopen_mode log_union.log_file.lf_fopen_mode #define lfu_rotate_period log_union.log_file.lf_rotate_period #define lfu_last_rotated log_union.log_file.lf_last_rotated #define lfu_rotate_versions log_union.log_file.lf_rotate_versions #define lsu_facility log_union.log_syslog.ls_facility #define lsu_severity log_union.log_syslog.ls_severity #define ldu_filep log_union.log_device.ld_filep #define ldu_devname log_union.log_device.ld_devname struct log_control { struct log_entry *log_entries; int log_nentries; char *log_whoami; char *log_hostname; krb5_boolean log_opened; }; static struct log_control log_control = { (struct log_entry *) NULL, 0, (char *) NULL, (char *) NULL, 0 }; static struct log_entry def_log_entry; /* * These macros define any special processing that needs to happen for * devices. For unix, of course, this is hardly anything. */ #define DEVICE_OPEN(d, m) fopen(d, m) #define CONSOLE_OPEN(m) fopen("/dev/console", m) #define DEVICE_PRINT(f, m) ((fprintf(f, "%s\r\n", m) >= 0) ? \ (fflush(f), 0) : \ -1) #define DEVICE_CLOSE(d) fclose(d) /* * klog_rotate() - roate a log file if we have specified rotation * parameters in krb5.conf. */ static void klog_rotate(struct log_entry *le) { time_t t; int i; char *name_buf1; char *name_buf2; char *old_name; char *new_name; char *tmp; FILE *fp; int num_vers; mode_t old_umask; /* * By default we don't rotate. */ if (le->lfu_rotate_period == K_LOG_DEF_FILE_ROTATE_PERIOD) return; t = time(0); if (t >= le->lfu_last_rotated + le->lfu_rotate_period) { /* * The N log file versions will be renamed X.N-1 X.N-2, ... X.0. * So the allocate file name buffers that can the version * number extensions. * 32 extra bytes is plenty. */ name_buf1 = malloc(strlen(le->lfu_fname) + 32); if (name_buf1 == NULL) return; name_buf2 = malloc(strlen(le->lfu_fname) + 32); if (name_buf2 == NULL) { free(name_buf1); return; } old_name = name_buf1; new_name = name_buf2; /* * If there N versions, then the first one has file extension * of N-1. */ (void) sprintf(new_name, "%s.%d", le->lfu_fname, le->lfu_rotate_versions - 1); /* * Rename file.N-2 to file.N-1, file.N-3 to file.N-2, ... * file.0 to file.1 */ for (i = le->lfu_rotate_versions - 1; i > 0; i--) { (void) sprintf(old_name, "%s.%d", le->lfu_fname, i - 1); (void) rename(old_name, new_name); /* * swap old name and new name. This way, * on the next iteration, new_name.X * becomes new_name.X-1. */ tmp = old_name; old_name = new_name; new_name = tmp; } old_name = le->lfu_fname; (void) rename(old_name, new_name); /* * Even though we don't know yet if the fopen() * of the log file will succeed, we mark the log * as rotated. This is so we don't repeatably * rotate file.N-2 to file.N-1 ... etc without * waiting for the rotate period to elapse. */ le->lfu_last_rotated = t; /* * Default log file creation mode should be read-only * by owner(root), but the admin can override with * chmod(1) if desired. */ old_umask = umask(077); fp = fopen(old_name, le->lfu_fopen_mode); umask(old_umask); if (fp != NULL) { (void) fclose(le->lfu_filep); le->lfu_filep = fp; /* * If the version parameter in krb5.conf was * 0, then we take this to mean that rotating the * log file will cause us to dispose of the * old one, and created a new one. We have just * renamed the old one to file.-1, so remove it. */ if (le->lfu_rotate_versions <= 0) (void) unlink(new_name); } else { fprintf(stderr, gettext("During rotate, couldn't open log file %s: %s\n"), old_name, error_message(errno)); /* * Put it back. */ (void) rename(new_name, old_name); } free(name_buf1); free(name_buf2); } } /* * klog_com_err_proc() - Handle com_err(3) messages as specified by the * profile. */ static krb5_context err_context; static void klog_com_err_proc(const char *whoami, long code, const char *format, va_list ap) { char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; int lindex; const char *actual_format; #ifdef HAVE_SYSLOG int log_pri = -1; #endif /* HAVE_SYSLOG */ char *cp; char *syslogp; /* Make the header */ sprintf(outbuf, "%s: ", whoami); /* * Squirrel away address after header for syslog since syslog makes * a header */ syslogp = &outbuf[strlen(outbuf)]; /* If reporting an error message, separate it. */ if (code) { const char *emsg; outbuf[sizeof(outbuf) - 1] = '\0'; emsg = krb5_get_error_message (err_context, code); strncat(outbuf, emsg, sizeof(outbuf) - 1 - strlen(outbuf)); strncat(outbuf, " - ", sizeof(outbuf) - 1 - strlen(outbuf)); krb5_free_error_message(err_context, emsg); } cp = &outbuf[strlen(outbuf)]; actual_format = format; #ifdef HAVE_SYSLOG /* * This is an unpleasant hack. If the first character is less than * 8, then we assume that it is a priority. * * Since it is not guaranteed that there is a direct mapping between * syslog priorities (e.g. Ultrix and old BSD), we resort to this * intermediate representation. */ if ((((unsigned char) *format) > 0) && (((unsigned char) *format) <= 8)) { actual_format = (format + 1); switch ((unsigned char) *format) { #ifdef LOG_EMERG case 1: log_pri = LOG_EMERG; break; #endif /* LOG_EMERG */ #ifdef LOG_ALERT case 2: log_pri = LOG_ALERT; break; #endif /* LOG_ALERT */ #ifdef LOG_CRIT case 3: log_pri = LOG_CRIT; break; #endif /* LOG_CRIT */ default: case 4: log_pri = LOG_ERR; break; #ifdef LOG_WARNING case 5: log_pri = LOG_WARNING; break; #endif /* LOG_WARNING */ #ifdef LOG_NOTICE case 6: log_pri = LOG_NOTICE; break; #endif /* LOG_NOTICE */ #ifdef LOG_INFO case 7: log_pri = LOG_INFO; break; #endif /* LOG_INFO */ #ifdef LOG_DEBUG case 8: log_pri = LOG_DEBUG; break; #endif /* LOG_DEBUG */ } } #endif /* HAVE_SYSLOG */ /* Now format the actual message */ #if HAVE_VSNPRINTF vsnprintf(cp, sizeof(outbuf) - (cp - outbuf), actual_format, ap); #elif HAVE_VSPRINTF vsprintf(cp, actual_format, ap); #else /* HAVE_VSPRINTF */ sprintf(cp, actual_format, ((int *) ap)[0], ((int *) ap)[1], ((int *) ap)[2], ((int *) ap)[3], ((int *) ap)[4], ((int *) ap)[5]); #endif /* HAVE_VSPRINTF */ /* * Now that we have the message formatted, perform the output to each * logging specification. */ for (lindex = 0; lindex < log_control.log_nentries; lindex++) { switch (log_control.log_entries[lindex].log_type) { case K_LOG_FILE: klog_rotate(&log_control.log_entries[lindex]); /*FALLTHRU*/ case K_LOG_STDERR: /* * Files/standard error. */ if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n", outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR), whoami, log_control.log_entries[lindex].lfu_fname); } else { fflush(log_control.log_entries[lindex].lfu_filep); } break; case K_LOG_CONSOLE: case K_LOG_DEVICE: /* * Devices (may need special handling) */ if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR), whoami, log_control.log_entries[lindex].ldu_devname); } break; #ifdef HAVE_SYSLOG case K_LOG_SYSLOG: /* * System log. */ /* * If we have specified a priority through our hackery, then * use it, otherwise use the default. */ if (log_pri >= 0) log_pri |= log_control.log_entries[lindex].lsu_facility; else log_pri = log_control.log_entries[lindex].lsu_facility | log_control.log_entries[lindex].lsu_severity; /* Log the message with our header trimmed off */ syslog(log_pri, syslogp); break; #endif /* HAVE_SYSLOG */ default: break; } } } /* * krb5_klog_init() - Initialize logging. * * This routine parses the syntax described above to specify destinations for * com_err(3) or krb5_klog_syslog() messages generated by the caller. * * Parameters: * kcontext - Kerberos context. * ename - Entity name as it is to appear in the profile. * whoami - Entity name as it is to appear in error output. * do_com_err - Take over com_err(3) processing. * * Implicit inputs: * stderr - This is where STDERR output goes. * * Implicit outputs: * log_nentries - Number of log entries, both valid and invalid. * log_control - List of entries (log_nentries long) which contains * data for klog_com_err_proc() to use to determine * where/how to send output. */ krb5_error_code krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do_com_err) { const char *logging_profent[3]; const char *logging_defent[3]; char **logging_specs; int i, ngood; char *cp, *cp2; char savec = '\0'; int error; int do_openlog, log_facility; FILE *f; mode_t old_umask; /* Initialize */ do_openlog = 0; log_facility = 0; err_context = kcontext; /* * Look up [logging]-> in the profile. If that doesn't * succeed, then look for [logging]->default. */ logging_profent[0] = "logging"; logging_profent[1] = ename; logging_profent[2] = (char *) NULL; logging_defent[0] = "logging"; logging_defent[1] = "default"; logging_defent[2] = (char *) NULL; logging_specs = (char **) NULL; ngood = 0; log_control.log_nentries = 0; if (!profile_get_values(kcontext->profile, logging_profent, &logging_specs) || !profile_get_values(kcontext->profile, logging_defent, &logging_specs)) { /* * We have a match, so we first count the number of elements */ for (log_control.log_nentries = 0; logging_specs[log_control.log_nentries]; log_control.log_nentries++); /* * Now allocate our structure. */ log_control.log_entries = (struct log_entry *) malloc(log_control.log_nentries * sizeof(struct log_entry)); if (log_control.log_entries) { /* * Scan through the list. */ for (i=0; i * so, trim off the leading and trailing whitespace here. */ for (cp = logging_specs[i]; isspace((int) *cp); cp++); for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1]; isspace((int) *cp2); cp2--); cp2++; *cp2 = '\0'; /* * Is this a file? */ if (!strncasecmp(cp, "FILE", 4)) { /* * Check for append/overwrite, then open the file. */ if (cp[4] == ':' || cp[4] == '=') { log_control.log_entries[i].lfu_fopen_mode = (cp[4] == ':') ? "a+F" : "wF"; old_umask = umask(077); f = fopen(&cp[5], log_control.log_entries[i].lfu_fopen_mode); umask(old_umask); if (f) { char rotate_kw[128]; log_control.log_entries[i].lfu_filep = f; log_control.log_entries[i].log_type = K_LOG_FILE; log_control.log_entries[i].lfu_fname = &cp[5]; log_control.log_entries[i].lfu_rotate_period = K_LOG_DEF_FILE_ROTATE_PERIOD; log_control.log_entries[i].lfu_rotate_versions = K_LOG_DEF_FILE_ROTATE_VERSIONS; log_control.log_entries[i].lfu_last_rotated = time(0); /* * Now parse for ename_"rotate" = { * period = XXX * versions = 10 * } */ if (strlen(ename) + strlen("_rotate") < sizeof (rotate_kw)) { char *time; krb5_deltat dt; int vers; strcpy(rotate_kw, ename); strcat(rotate_kw, "_rotate"); if (!profile_get_string(kcontext->profile, "logging", rotate_kw, "period", NULL, &time)) { if (time != NULL) { if (!krb5_string_to_deltat(time, &dt)) { log_control.log_entries[i].lfu_rotate_period = (time_t) dt; } free(time); } } if (!profile_get_integer( kcontext->profile, "logging", rotate_kw, "versions", K_LOG_DEF_FILE_ROTATE_VERSIONS, &vers)) { log_control.log_entries[i].lfu_rotate_versions = vers; } } } else { fprintf(stderr, gettext("Couldn't open log file %s: %s\n"), &cp[5], error_message(errno)); continue; } } } #ifdef HAVE_SYSLOG /* * Is this a syslog? */ else if (!strncasecmp(cp, "SYSLOG", 6)) { error = 0; log_control.log_entries[i].lsu_facility = LOG_AUTH; log_control.log_entries[i].lsu_severity = LOG_ERR; /* * Is there a severify specified? */ if (cp[6] == ':') { /* * Find the end of the severity. */ cp2 = strchr(&cp[7], ':'); if (cp2) { savec = *cp2; *cp2 = '\0'; cp2++; } /* * Match a severity. */ if (!strcasecmp(&cp[7], "ERR")) { log_control.log_entries[i].lsu_severity = LOG_ERR; } #ifdef LOG_EMERG else if (!strcasecmp(&cp[7], "EMERG")) { log_control.log_entries[i].lsu_severity = LOG_EMERG; } #endif /* LOG_EMERG */ #ifdef LOG_ALERT else if (!strcasecmp(&cp[7], "ALERT")) { log_control.log_entries[i].lsu_severity = LOG_ALERT; } #endif /* LOG_ALERT */ #ifdef LOG_CRIT else if (!strcasecmp(&cp[7], "CRIT")) { log_control.log_entries[i].lsu_severity = LOG_CRIT; } #endif /* LOG_CRIT */ #ifdef LOG_WARNING else if (!strcasecmp(&cp[7], "WARNING")) { log_control.log_entries[i].lsu_severity = LOG_WARNING; } #endif /* LOG_WARNING */ #ifdef LOG_NOTICE else if (!strcasecmp(&cp[7], "NOTICE")) { log_control.log_entries[i].lsu_severity = LOG_NOTICE; } #endif /* LOG_NOTICE */ #ifdef LOG_INFO else if (!strcasecmp(&cp[7], "INFO")) { log_control.log_entries[i].lsu_severity = LOG_INFO; } #endif /* LOG_INFO */ #ifdef LOG_DEBUG else if (!strcasecmp(&cp[7], "DEBUG")) { log_control.log_entries[i].lsu_severity = LOG_DEBUG; } #endif /* LOG_DEBUG */ else error = 1; /* * If there is a facility present, then parse that. */ if (cp2) { if (!strcasecmp(cp2, "AUTH")) { log_control.log_entries[i].lsu_facility = LOG_AUTH; } else if (!strcasecmp(cp2, "KERN")) { log_control.log_entries[i].lsu_facility = LOG_KERN; } else if (!strcasecmp(cp2, "USER")) { log_control.log_entries[i].lsu_facility = LOG_USER; } else if (!strcasecmp(cp2, "MAIL")) { log_control.log_entries[i].lsu_facility = LOG_MAIL; } else if (!strcasecmp(cp2, "DAEMON")) { log_control.log_entries[i].lsu_facility = LOG_DAEMON; } else if (!strcasecmp(cp2, "LPR")) { log_control.log_entries[i].lsu_facility = LOG_LPR; } else if (!strcasecmp(cp2, "NEWS")) { log_control.log_entries[i].lsu_facility = LOG_NEWS; } else if (!strcasecmp(cp2, "UUCP")) { log_control.log_entries[i].lsu_facility = LOG_UUCP; } else if (!strcasecmp(cp2, "CRON")) { log_control.log_entries[i].lsu_facility = LOG_CRON; } else if (!strcasecmp(cp2, "AUDIT")) { log_control.log_entries[i].lsu_facility = LOG_AUDIT; } else if (!strcasecmp(cp2, "LOCAL0")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL0; } else if (!strcasecmp(cp2, "LOCAL1")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL1; } else if (!strcasecmp(cp2, "LOCAL2")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL2; } else if (!strcasecmp(cp2, "LOCAL3")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL3; } else if (!strcasecmp(cp2, "LOCAL4")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL4; } else if (!strcasecmp(cp2, "LOCAL5")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL5; } else if (!strcasecmp(cp2, "LOCAL6")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL6; } else if (!strcasecmp(cp2, "LOCAL7")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL7; } cp2--; *cp2 = savec; } } if (!error) { log_control.log_entries[i].log_type = K_LOG_SYSLOG; do_openlog = 1; log_facility = log_control.log_entries[i].lsu_facility; } } #endif /* HAVE_SYSLOG */ /* * Is this a standard error specification? */ else if (!strcasecmp(cp, "STDERR")) { log_control.log_entries[i].lfu_filep = fdopen(fileno(stderr), "a+F"); if (log_control.log_entries[i].lfu_filep) { log_control.log_entries[i].log_type = K_LOG_STDERR; log_control.log_entries[i].lfu_fname = "standard error"; } } /* * Is this a specification of the console? */ else if (!strcasecmp(cp, "CONSOLE")) { log_control.log_entries[i].ldu_filep = CONSOLE_OPEN("a+F"); if (log_control.log_entries[i].ldu_filep) { log_control.log_entries[i].log_type = K_LOG_CONSOLE; log_control.log_entries[i].ldu_devname = "console"; } } /* * Is this a specification of a device? */ else if (!strncasecmp(cp, "DEVICE", 6)) { /* * We handle devices very similarly to files. */ if (cp[6] == '=') { log_control.log_entries[i].ldu_filep = DEVICE_OPEN(&cp[7], "wF"); if (log_control.log_entries[i].ldu_filep) { log_control.log_entries[i].log_type = K_LOG_DEVICE; log_control.log_entries[i].ldu_devname = &cp[7]; } } } /* * See if we successfully parsed this specification. */ if (log_control.log_entries[i].log_type == K_LOG_NONE) { fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_1), whoami, cp); fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_2), whoami); } else ngood++; } } /* * If we didn't find anything, then free our lists. */ if (ngood == 0) { for (i=0; ilog_type = K_LOG_SYSLOG; log_control.log_entries->log_2free = (krb5_pointer) NULL; log_facility = log_control.log_entries->lsu_facility = LOG_AUTH; log_control.log_entries->lsu_severity = LOG_ERR; do_openlog = 1; log_control.log_nentries = 1; } if (log_control.log_nentries) { log_control.log_whoami = (char *) malloc(strlen(whoami)+1); if (log_control.log_whoami) strcpy(log_control.log_whoami, whoami); log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN + 1); if (log_control.log_hostname) { gethostname(log_control.log_hostname, MAXHOSTNAMELEN); log_control.log_hostname[MAXHOSTNAMELEN] = '\0'; } #ifdef HAVE_OPENLOG if (do_openlog) { openlog(whoami, LOG_NDELAY|LOG_PID, log_facility); log_control.log_opened = 1; } #endif /* HAVE_OPENLOG */ if (do_com_err) (void) set_com_err_hook(klog_com_err_proc); } return((log_control.log_nentries) ? 0 : ENOENT); } /* * krb5_klog_close() - Close the logging context and free all data. */ void krb5_klog_close(krb5_context kcontext) { int lindex; (void) reset_com_err_hook(); for (lindex = 0; lindex < log_control.log_nentries; lindex++) { switch (log_control.log_entries[lindex].log_type) { case K_LOG_FILE: case K_LOG_STDERR: /* * Files/standard error. */ fclose(log_control.log_entries[lindex].lfu_filep); break; case K_LOG_CONSOLE: case K_LOG_DEVICE: /* * Devices (may need special handling) */ DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep); break; #ifdef HAVE_SYSLOG case K_LOG_SYSLOG: /* * System log. */ break; #endif /* HAVE_SYSLOG */ default: break; } if (log_control.log_entries[lindex].log_2free) free(log_control.log_entries[lindex].log_2free); } if (log_control.log_entries != &def_log_entry) free(log_control.log_entries); log_control.log_entries = (struct log_entry *) NULL; log_control.log_nentries = 0; if (log_control.log_whoami) free(log_control.log_whoami); log_control.log_whoami = (char *) NULL; if (log_control.log_hostname) free(log_control.log_hostname); log_control.log_hostname = (char *) NULL; #ifdef HAVE_CLOSELOG if (log_control.log_opened) closelog(); #endif /* HAVE_CLOSELOG */ } /* * severity2string() - Convert a severity to a string. */ static const char * severity2string(int severity) { int s; const char *ss; s = severity & LOG_PRIMASK; ss = krb5_log_error_table(LOG_UFO_STRING); switch (s) { #ifdef LOG_EMERG case LOG_EMERG: ss = krb5_log_error_table(LOG_EMERG_STRING); break; #endif /* LOG_EMERG */ #ifdef LOG_ALERT case LOG_ALERT: ss = krb5_log_error_table(LOG_ALERT_STRING); break; #endif /* LOG_ALERT */ #ifdef LOG_CRIT case LOG_CRIT: ss = krb5_log_error_table(LOG_CRIT_STRING); break; #endif /* LOG_CRIT */ case LOG_ERR: ss = krb5_log_error_table(LOG_ERR_STRING); break; #ifdef LOG_WARNING case LOG_WARNING: ss = krb5_log_error_table(LOG_WARNING_STRING); break; #endif /* LOG_WARNING */ #ifdef LOG_NOTICE case LOG_NOTICE: ss = krb5_log_error_table(LOG_NOTICE_STRING); break; #endif /* LOG_NOTICE */ #ifdef LOG_INFO case LOG_INFO: ss = krb5_log_error_table(LOG_INFO_STRING); break; #endif /* LOG_INFO */ #ifdef LOG_DEBUG case LOG_DEBUG: ss = krb5_log_error_table(LOG_DEBUG_STRING); break; #endif /* LOG_DEBUG */ } return((char *) ss); } /* * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while * also performing the logging redirection as specified * by krb5_klog_init(). */ static int klog_vsyslog(int priority, const char *format, va_list arglist) { char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; int lindex; char *syslogp; char *cp; time_t now; #ifdef HAVE_STRFTIME size_t soff; #endif /* HAVE_STRFTIME */ /* * Format a syslog-esque message of the format: * * (verbose form) * [](): * * (short form) * */ cp = outbuf; (void) time(&now); #ifdef HAVE_STRFTIME /* * Format the date: mon dd hh:mm:ss */ soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", localtime(&now)); if (soff > 0) cp += soff; else return(-1); #else /* HAVE_STRFTIME */ /* * Format the date: * We ASSUME here that the output of ctime is of the format: * dow mon dd hh:mm:ss tzs yyyy\n * 012345678901234567890123456789 */ strncpy(outbuf, ctime(&now) + 4, 15); cp += 15; #endif /* HAVE_STRFTIME */ #ifdef VERBOSE_LOGS sprintf(cp, " %s %s[%ld](%s): ", log_control.log_hostname, log_control.log_whoami, (long) getpid(), severity2string(priority)); #else sprintf(cp, " "); #endif syslogp = &outbuf[strlen(outbuf)]; /* Now format the actual message */ #ifdef HAVE_VSNPRINTF vsnprintf(syslogp, sizeof(outbuf) - (syslogp - outbuf), format, arglist); #elif HAVE_VSPRINTF vsprintf(syslogp, format, arglist); #else /* HAVE_VSPRINTF */ sprintf(syslogp, format, ((int *) arglist)[0], ((int *) arglist)[1], ((int *) arglist)[2], ((int *) arglist)[3], ((int *) arglist)[4], ((int *) arglist)[5]); #endif /* HAVE_VSPRINTF */ /* * If the user did not use krb5_klog_init() instead of dropping * the request on the floor, syslog it - if it exists */ #ifdef HAVE_SYSLOG if (log_control.log_nentries == 0) { /* Log the message with our header trimmed off */ syslog(priority, "%s", syslogp); } #endif /* * Now that we have the message formatted, perform the output to each * logging specification. */ for (lindex = 0; lindex < log_control.log_nentries; lindex++) { switch (log_control.log_entries[lindex].log_type) { case K_LOG_FILE: klog_rotate(&log_control.log_entries[lindex]); /*FALLTHRU*/ case K_LOG_STDERR: /* * Files/standard error. */ if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n", outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR), log_control.log_whoami, log_control.log_entries[lindex].lfu_fname); } else { fflush(log_control.log_entries[lindex].lfu_filep); } break; case K_LOG_CONSOLE: case K_LOG_DEVICE: /* * Devices (may need special handling) */ if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR), log_control.log_whoami, log_control.log_entries[lindex].ldu_devname); } break; #ifdef HAVE_SYSLOG case K_LOG_SYSLOG: /* * System log. */ /* Log the message with our header trimmed off */ syslog(priority, "%s", syslogp); break; #endif /* HAVE_SYSLOG */ default: break; } } return(0); } int krb5_klog_syslog(int priority, const char *format, ...) { int retval; va_list pvar; va_start(pvar, format); retval = klog_vsyslog(priority, format, pvar); va_end(pvar); return(retval); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNWprivate_1.1 { global: _kadm5_get_kpasswd_protocol; chpass_principal3_2; chpass_principal_2; chpw_error_message; chrand_principal3_2; chrand_principal_2; create_policy_2; create_principal3_2; create_principal_2; delete_policy_2; delete_principal_2; display_status; get_policy_2; get_pols_2; get_principal_2; get_princs_2; get_privs_2; init_2; kadm5_chpass_principal; kadm5_chpass_principal_3; kadm5_chpass_principal_util; kadm5_chpass_principal_v2; kadm5_create_policy; kadm5_create_principal; kadm5_create_principal_3; kadm5_decrypt_key; kadm5_delete_policy; kadm5_delete_principal; kadm5_destroy; kadm5_flush; kadm5_free_config_params; kadm5_free_name_list; kadm5_free_policy_ent; kadm5_free_principal_ent; kadm5_get_adm_host_srv_name; kadm5_get_admin_service_name; kadm5_get_config_params; kadm5_get_cpw_host_srv_name; kadm5_get_kiprop_host_srv_name; kadm5_get_master; kadm5_get_policies; kadm5_get_policy; kadm5_get_principal; kadm5_get_principals; kadm5_get_privs; kadm5_init; kadm5_init_iprop; kadm5_init_krb5_context; kadm5_init_with_creds; kadm5_init_with_password; kadm5_init_with_skey; kadm5_is_master; kadm5_lock; kadm5_modify_policy; kadm5_modify_principal; kadm5_randkey_principal; kadm5_randkey_principal_3; kadm5_randkey_principal_old; kadm5_rename_principal; kadm5_setkey_principal; kadm5_setkey_principal_3; kadm5_unlock; krb5_aprof_finish; krb5_aprof_get_boolean; krb5_aprof_get_deltat; krb5_aprof_get_int32; krb5_aprof_get_string; krb5_aprof_getvals; krb5_aprof_init; krb5_flags_to_string; krb5_free_key_data_contents; krb5_free_realm_params; krb5_input_flag_to_string; krb5_keysalt_is_present; krb5_keysalt_iterate; krb5_klog_close; krb5_klog_init; krb5_klog_syslog; krb5_log_error_table; krb5int_mk_chpw_req; krb5int_rd_chpw_rep; krb5_read_realm_params; krb5_string_to_flags; krb5_string_to_keysalts; modify_policy_2; modify_principal_2; rename_principal_2; setkey_principal3_2; setkey_principal_2; xdr_chpass3_arg; xdr_chpass_arg; xdr_chrand3_arg; xdr_chrand_arg; xdr_chrand_ret; xdr_cpol_arg; xdr_cprinc3_arg; xdr_cprinc_arg; xdr_dpol_arg; xdr_dprinc_arg; xdr_generic_ret; xdr_getprivs_ret; xdr_gpol_arg; xdr_gpol_ret; xdr_gpols_arg; xdr_gpols_ret; xdr_gprinc_arg; xdr_gprinc_ret; xdr_gprincs_arg; xdr_gprincs_ret; xdr_kadm5_policy_ent_rec; xdr_kadm5_principal_ent_rec; xdr_kadm5_principal_ent_rec_v1; xdr_kadm5_ret_t; xdr_krb5_deltat; xdr_krb5_enctype; xdr_krb5_flags; xdr_krb5_int16; xdr_krb5_key_data_nocontents; xdr_krb5_key_salt_tuple; xdr_krb5_keyblock; xdr_krb5_kvno; xdr_krb5_octet; xdr_krb5_principal; xdr_krb5_salttype; xdr_krb5_timestamp; xdr_krb5_tl_data; xdr_krb5_ui_2; xdr_krb5_ui_4; xdr_mpol_arg; xdr_mprinc_arg; xdr_nullstring; xdr_nulltype; xdr_rprinc_arg; xdr_setkey3_arg; xdr_setkey_arg; xdr_ui_4; local: *; }; /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * kadm_err.h: * This file is automatically generated; please do not edit it. */ #define KADM5_FAILURE (43787520L) #define KADM5_AUTH_GET (43787521L) #define KADM5_AUTH_ADD (43787522L) #define KADM5_AUTH_MODIFY (43787523L) #define KADM5_AUTH_DELETE (43787524L) #define KADM5_AUTH_INSUFFICIENT (43787525L) #define KADM5_BAD_DB (43787526L) #define KADM5_DUP (43787527L) #define KADM5_RPC_ERROR (43787528L) #define KADM5_NO_SRV (43787529L) #define KADM5_BAD_HIST_KEY (43787530L) #define KADM5_NOT_INIT (43787531L) #define KADM5_UNK_PRINC (43787532L) #define KADM5_UNK_POLICY (43787533L) #define KADM5_BAD_MASK (43787534L) #define KADM5_BAD_CLASS (43787535L) #define KADM5_BAD_LENGTH (43787536L) #define KADM5_BAD_POLICY (43787537L) #define KADM5_BAD_PRINCIPAL (43787538L) #define KADM5_BAD_AUX_ATTR (43787539L) #define KADM5_BAD_HISTORY (43787540L) #define KADM5_BAD_MIN_PASS_LIFE (43787541L) #define KADM5_PASS_Q_TOOSHORT (43787542L) #define KADM5_PASS_Q_CLASS (43787543L) #define KADM5_PASS_Q_DICT (43787544L) #define KADM5_PASS_REUSE (43787545L) #define KADM5_PASS_TOOSOON (43787546L) #define KADM5_POLICY_REF (43787547L) #define KADM5_INIT (43787548L) #define KADM5_BAD_PASSWORD (43787549L) #define KADM5_PROTECT_PRINCIPAL (43787550L) #define KADM5_BAD_SERVER_HANDLE (43787551L) #define KADM5_BAD_STRUCT_VERSION (43787552L) #define KADM5_OLD_STRUCT_VERSION (43787553L) #define KADM5_NEW_STRUCT_VERSION (43787554L) #define KADM5_BAD_API_VERSION (43787555L) #define KADM5_OLD_LIB_API_VERSION (43787556L) #define KADM5_OLD_SERVER_API_VERSION (43787557L) #define KADM5_NEW_LIB_API_VERSION (43787558L) #define KADM5_NEW_SERVER_API_VERSION (43787559L) #define KADM5_SECURE_PRINC_MISSING (43787560L) #define KADM5_NO_RENAME_SALT (43787561L) #define KADM5_BAD_CLIENT_PARAMS (43787562L) #define KADM5_BAD_SERVER_PARAMS (43787563L) #define KADM5_AUTH_LIST (43787564L) #define KADM5_AUTH_CHANGEPW (43787565L) #define KADM5_GSS_ERROR (43787566L) #define KADM5_BAD_TL_TYPE (43787567L) #define KADM5_MISSING_CONF_PARAMS (43787568L) #define KADM5_BAD_SERVER_NAME (43787569L) #define KADM5_AUTH_SETKEY (43787570L) #define KADM5_SETKEY_DUP_ENCTYPES (43787571L) #define KADM5_SETV4KEY_INVAL_ENCTYPE (43787572L) #define KADM5_SETKEY3_ETYPE_MISMATCH (43787573L) #define KADM5_MISSING_KRB5_CONF_PARAMS (43787574L) #define KADM5_RPC_ERROR_CANTENCODEARGS (43787575L) #define KADM5_RPC_ERROR_CANTDECODEARGS (43787576L) #define KADM5_XDR_FAILURE (43787577L) #define ERROR_TABLE_BASE_ovk (43787520L) extern const struct error_table et_ovk_error_table; #if !defined(_WIN32) /* for compatibility with older versions... */ extern void initialize_ovk_error_table (void) /*@modifies internalState@*/; #else #define initialize_ovk_error_table() #endif #if !defined(_WIN32) #define init_ovk_err_tbl initialize_ovk_error_table #define ovk_err_base ERROR_TABLE_BASE_ovk #endif /* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * lib/kad5/kadm_host_srv_names.c */ #include #include "admin.h" #include #include #define KADM5_MASTER "admin_server" #define KADM5_KPASSWD "kpasswd_server" /* * Find the admin server for the given realm. If the realm is null or * the empty string, find the admin server for the default realm. * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to * free the storage allocated to the admin server, master. */ kadm5_ret_t kadm5_get_master(krb5_context context, const char *realm, char **master) { /* Solaris Kerberos */ char *def_realm = NULL; char *delim; #ifdef KRB5_DNS_LOOKUP struct sockaddr *addrs; int naddrs; unsigned short dns_portno; char dns_host[MAX_DNS_NAMELEN]; krb5_data dns_realm; krb5_error_code dns_ret = 1; #endif /* KRB5_DNS_LOOKUP */ if (realm == 0 || *realm == '\0') krb5_get_default_realm(context, &def_realm); (void) profile_get_string(context->profile, "realms", realm ? realm : def_realm, KADM5_MASTER, 0, master); if ((*master != NULL) && ((delim = strchr(*master, ':')) != NULL)) *delim = '\0'; #ifdef KRB5_DNS_LOOKUP if (*master == NULL) { /* * Initialize realm info for (possible) DNS lookups. */ dns_realm.data = strdup(realm ? realm : def_realm); dns_realm.length = strlen(realm ? realm : def_realm); dns_realm.magic = 0; dns_ret = krb5_get_servername(context, &dns_realm, "_kerberos-adm", "_udp", dns_host, &dns_portno); if (dns_ret == 0) *master = strdup(dns_host); if (dns_realm.data) free(dns_realm.data); } #endif /* KRB5_DNS_LOOKUP */ /* Solaris Kerberos */ if (def_realm != NULL) krb5_free_default_realm(context, def_realm); return (*master ? KADM5_OK : KADM5_NO_SRV); } /* * Find the kpasswd server for the given realm. If the realm is null or * the empty string, find the admin server for the default realm. * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to * free the storage allocated to the admin server, master. */ kadm5_ret_t kadm5_get_kpasswd(krb5_context context, const char *realm, char **kpasswd) { char *def_realm = NULL; char *delim; #ifdef KRB5_DNS_LOOKUP struct sockaddr *addrs; int naddrs; unsigned short dns_portno; char dns_host[MAX_DNS_NAMELEN]; krb5_data dns_realm; krb5_error_code dns_ret = 1, ret; #endif /* KRB5_DNS_LOOKUP */ if (realm == 0 || *realm == '\0') { ret = krb5_get_default_realm(context, &def_realm); if (ret != 0) return (ret); } (void) profile_get_string(context->profile, "realms", realm ? realm : def_realm, KADM5_KPASSWD, 0, kpasswd); if ((*kpasswd != NULL) && ((delim = strchr(*kpasswd, ':')) != NULL)) *delim = '\0'; #ifdef KRB5_DNS_LOOKUP if (*kpasswd == NULL) { /* * Initialize realm info for (possible) DNS lookups. */ dns_realm.data = strdup(realm ? realm : def_realm); if (dns_realm.data == NULL) { if (def_realm != NULL) free(def_realm); return (ENOMEM); } dns_realm.length = strlen(realm ? realm : def_realm); dns_realm.magic = 0; dns_ret = krb5_get_servername(context, &dns_realm, "_kpasswd", "_tcp", dns_host, &dns_portno); if (dns_ret == 0) { *kpasswd = strdup(dns_host); if (*kpasswd == NULL) { free(dns_realm.data); if (def_realm != NULL) free(def_realm); return (ENOMEM); } } free(dns_realm.data); } #endif /* KRB5_DNS_LOOKUP */ if (def_realm != NULL) free(def_realm); return (*kpasswd ? KADM5_OK : KADM5_NO_SRV); } /* * Get the host base service name for the admin principal. Returns * KADM5_OK on success. Caller must free the storage allocated for * host_service_name. */ kadm5_ret_t kadm5_get_adm_host_srv_name(krb5_context context, const char *realm, char **host_service_name) { kadm5_ret_t ret; char *name; char *host; if (ret = kadm5_get_master(context, realm, &host)) return (ret); name = malloc(strlen(KADM5_ADMIN_HOST_SERVICE)+ strlen(host) + 2); if (name == NULL) { free(host); return (ENOMEM); } sprintf(name, "%s@%s", KADM5_ADMIN_HOST_SERVICE, host); free(host); *host_service_name = name; return (KADM5_OK); } /* * Get the host base service name for the changepw principal. Returns * KADM5_OK on success. Caller must free the storage allocated for * host_service_name. */ kadm5_ret_t kadm5_get_cpw_host_srv_name(krb5_context context, const char *realm, char **host_service_name) { kadm5_ret_t ret; char *name; char *host; /* * First try to find the kpasswd server, after all we are about to * try to change our password. If this fails then try admin_server. */ if (ret = kadm5_get_kpasswd(context, realm, &host)) { if (ret = kadm5_get_master(context, realm, &host)) return (ret); } name = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) + strlen(host) + 2); if (name == NULL) { free(host); return (ENOMEM); } sprintf(name, "%s@%s", KADM5_CHANGEPW_HOST_SERVICE, host); free(host); *host_service_name = name; return (KADM5_OK); } /* * Get the host base service name for the kiprop principal. Returns * KADM5_OK on success. Caller must free the storage allocated * for host_service_name. */ kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context, const char *realm, char **host_service_name) { kadm5_ret_t ret; char *name; char *host; if (ret = kadm5_get_master(context, realm, &host)) return (ret); name = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) + strlen(host) + 2); if (name == NULL) { free(host); return (ENOMEM); } sprintf(name, "%s@%s", KADM5_KIPROP_HOST_SERVICE, host); free(host); *host_service_name = name; return (KADM5_OK); } /* * Solaris Kerberos: * Try to determine if this is the master KDC for a given realm */ kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm, krb5_boolean *is_master) { kadm5_ret_t ret; char *admin_host = NULL; krb5_address **tmp_addr, **master_addr = NULL; krb5_address **local_addr = NULL; if (is_master) *is_master = FALSE; else return (KADM5_FAILURE); /* Locate the master KDC */ if (ret = kadm5_get_master(context, realm, &admin_host)) return (ret); if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) { free(admin_host); return (ret); } /* Get the local addresses */ if (ret = krb5_os_localaddr(context, &local_addr)) { krb5_free_addresses(context, master_addr); free(admin_host); return (ret); } /* Compare them */ for (tmp_addr = master_addr; *tmp_addr; tmp_addr++) { if (krb5_address_search(context, *tmp_addr, local_addr)) { *is_master = TRUE; break; } } krb5_free_addresses(context, local_addr); krb5_free_addresses(context, master_addr); free(admin_host); return (KADM5_OK); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #ifndef __KADM_RPC_H__ #define __KADM_RPC_H__ #include #include #include struct cprinc_arg { krb5_ui_4 api_version; kadm5_principal_ent_rec rec; long mask; char *passwd; }; typedef struct cprinc_arg cprinc_arg; struct cprinc3_arg { krb5_ui_4 api_version; kadm5_principal_ent_rec rec; long mask; int n_ks_tuple; krb5_key_salt_tuple *ks_tuple; char *passwd; }; typedef struct cprinc3_arg cprinc3_arg; struct generic_ret { krb5_ui_4 api_version; kadm5_ret_t code; }; typedef struct generic_ret generic_ret; struct dprinc_arg { krb5_ui_4 api_version; krb5_principal princ; }; typedef struct dprinc_arg dprinc_arg; struct mprinc_arg { krb5_ui_4 api_version; kadm5_principal_ent_rec rec; long mask; }; typedef struct mprinc_arg mprinc_arg; struct rprinc_arg { krb5_ui_4 api_version; krb5_principal src; krb5_principal dest; }; typedef struct rprinc_arg rprinc_arg; struct gprincs_arg { krb5_ui_4 api_version; char *exp; }; typedef struct gprincs_arg gprincs_arg; struct gprincs_ret { krb5_ui_4 api_version; kadm5_ret_t code; char **princs; int count; }; typedef struct gprincs_ret gprincs_ret; struct chpass_arg { krb5_ui_4 api_version; krb5_principal princ; char *pass; }; typedef struct chpass_arg chpass_arg; struct chpass3_arg { krb5_ui_4 api_version; krb5_principal princ; krb5_boolean keepold; int n_ks_tuple; krb5_key_salt_tuple *ks_tuple; char *pass; }; typedef struct chpass3_arg chpass3_arg; struct setv4key_arg { krb5_ui_4 api_version; krb5_principal princ; krb5_keyblock *keyblock; }; typedef struct setv4key_arg setv4key_arg; struct setkey_arg { krb5_ui_4 api_version; krb5_principal princ; krb5_keyblock *keyblocks; int n_keys; }; typedef struct setkey_arg setkey_arg; struct setkey3_arg { krb5_ui_4 api_version; krb5_principal princ; krb5_boolean keepold; int n_ks_tuple; krb5_key_salt_tuple *ks_tuple; krb5_keyblock *keyblocks; int n_keys; }; typedef struct setkey3_arg setkey3_arg; struct chrand_arg { krb5_ui_4 api_version; krb5_principal princ; }; typedef struct chrand_arg chrand_arg; struct chrand3_arg { krb5_ui_4 api_version; krb5_principal princ; krb5_boolean keepold; int n_ks_tuple; krb5_key_salt_tuple *ks_tuple; }; typedef struct chrand3_arg chrand3_arg; struct chrand_ret { krb5_ui_4 api_version; kadm5_ret_t code; krb5_keyblock key; krb5_keyblock *keys; int n_keys; }; typedef struct chrand_ret chrand_ret; struct gprinc_arg { krb5_ui_4 api_version; krb5_principal princ; long mask; }; typedef struct gprinc_arg gprinc_arg; struct gprinc_ret { krb5_ui_4 api_version; kadm5_ret_t code; kadm5_principal_ent_rec rec; }; typedef struct gprinc_ret gprinc_ret; struct cpol_arg { krb5_ui_4 api_version; kadm5_policy_ent_rec rec; long mask; }; typedef struct cpol_arg cpol_arg; struct dpol_arg { krb5_ui_4 api_version; char *name; }; typedef struct dpol_arg dpol_arg; struct mpol_arg { krb5_ui_4 api_version; kadm5_policy_ent_rec rec; long mask; }; typedef struct mpol_arg mpol_arg; struct gpol_arg { krb5_ui_4 api_version; char *name; }; typedef struct gpol_arg gpol_arg; struct gpol_ret { krb5_ui_4 api_version; kadm5_ret_t code; kadm5_policy_ent_rec rec; }; typedef struct gpol_ret gpol_ret; struct gpols_arg { krb5_ui_4 api_version; char *exp; }; typedef struct gpols_arg gpols_arg; struct gpols_ret { krb5_ui_4 api_version; kadm5_ret_t code; char **pols; int count; }; typedef struct gpols_ret gpols_ret; struct getprivs_ret { krb5_ui_4 api_version; kadm5_ret_t code; long privs; }; typedef struct getprivs_ret getprivs_ret; #define KADM 2112 #define KADMVERS 2 #define CREATE_PRINCIPAL 1 extern generic_ret * create_principal_2(cprinc_arg *, CLIENT *); extern generic_ret * create_principal_2_svc(cprinc_arg *, struct svc_req *); #define DELETE_PRINCIPAL 2 extern generic_ret * delete_principal_2(dprinc_arg *, CLIENT *); extern generic_ret * delete_principal_2_svc(dprinc_arg *, struct svc_req *); #define MODIFY_PRINCIPAL 3 extern generic_ret * modify_principal_2(mprinc_arg *, CLIENT *); extern generic_ret * modify_principal_2_svc(mprinc_arg *, struct svc_req *); #define RENAME_PRINCIPAL 4 extern generic_ret * rename_principal_2(rprinc_arg *, CLIENT *); extern generic_ret * rename_principal_2_svc(rprinc_arg *, struct svc_req *); #define GET_PRINCIPAL 5 extern gprinc_ret * get_principal_2(gprinc_arg *, CLIENT *); extern gprinc_ret * get_principal_2_svc(gprinc_arg *, struct svc_req *); #define CHPASS_PRINCIPAL 6 extern generic_ret * chpass_principal_2(chpass_arg *, CLIENT *); extern generic_ret * chpass_principal_2_svc(chpass_arg *, struct svc_req *); #define CHRAND_PRINCIPAL 7 extern chrand_ret * chrand_principal_2(chrand_arg *, CLIENT *); extern chrand_ret * chrand_principal_2_svc(chrand_arg *, struct svc_req *); #define CREATE_POLICY 8 extern generic_ret * create_policy_2(cpol_arg *, CLIENT *); extern generic_ret * create_policy_2_svc(cpol_arg *, struct svc_req *); #define DELETE_POLICY 9 extern generic_ret * delete_policy_2(dpol_arg *, CLIENT *); extern generic_ret * delete_policy_2_svc(dpol_arg *, struct svc_req *); #define MODIFY_POLICY 10 extern generic_ret * modify_policy_2(mpol_arg *, CLIENT *); extern generic_ret * modify_policy_2_svc(mpol_arg *, struct svc_req *); #define GET_POLICY 11 extern gpol_ret * get_policy_2(gpol_arg *, CLIENT *); extern gpol_ret * get_policy_2_svc(gpol_arg *, struct svc_req *); #define GET_PRIVS 12 extern getprivs_ret * get_privs_2(void *, CLIENT *); extern getprivs_ret * get_privs_2_svc(krb5_ui_4 *, struct svc_req *); #define INIT 13 extern generic_ret * init_2(void *, CLIENT *); extern generic_ret * init_2_svc(krb5_ui_4 *, struct svc_req *); #define GET_PRINCS 14 extern gprincs_ret * get_princs_2(gprincs_arg *, CLIENT *); extern gprincs_ret * get_princs_2_svc(gprincs_arg *, struct svc_req *); #define GET_POLS 15 extern gpols_ret * get_pols_2(gpols_arg *, CLIENT *); extern gpols_ret * get_pols_2_svc(gpols_arg *, struct svc_req *); #define SETKEY_PRINCIPAL 16 extern generic_ret * setkey_principal_2(setkey_arg *, CLIENT *); extern generic_ret * setkey_principal_2_svc(setkey_arg *, struct svc_req *); #define SETV4KEY_PRINCIPAL 17 extern generic_ret * setv4key_principal_2(setv4key_arg *, CLIENT *); extern generic_ret * setv4key_principal_2_svc(setv4key_arg *, struct svc_req *); #define CREATE_PRINCIPAL3 18 extern generic_ret * create_principal3_2(cprinc3_arg *, CLIENT *); extern generic_ret * create_principal3_2_svc(cprinc3_arg *, struct svc_req *); #define CHPASS_PRINCIPAL3 19 extern generic_ret * chpass_principal3_2(chpass3_arg *, CLIENT *); extern generic_ret * chpass_principal3_2_svc(chpass3_arg *, struct svc_req *); #define CHRAND_PRINCIPAL3 20 extern chrand_ret * chrand_principal3_2(chrand3_arg *, CLIENT *); extern chrand_ret * chrand_principal3_2_svc(chrand3_arg *, struct svc_req *); #define SETKEY_PRINCIPAL3 21 extern generic_ret * setkey_principal3_2(setkey3_arg *, CLIENT *); extern generic_ret * setkey_principal3_2_svc(setkey3_arg *, struct svc_req *); extern bool_t xdr_cprinc_arg (); extern bool_t xdr_cprinc3_arg (); extern bool_t xdr_generic_ret (); extern bool_t xdr_dprinc_arg (); extern bool_t xdr_mprinc_arg (); extern bool_t xdr_rprinc_arg (); extern bool_t xdr_gprincs_arg (); extern bool_t xdr_gprincs_ret (); extern bool_t xdr_chpass_arg (); extern bool_t xdr_chpass3_arg (); extern bool_t xdr_setv4key_arg (); extern bool_t xdr_setkey_arg (); extern bool_t xdr_setkey3_arg (); extern bool_t xdr_chrand_arg (); extern bool_t xdr_chrand3_arg (); extern bool_t xdr_chrand_ret (); extern bool_t xdr_gprinc_arg (); extern bool_t xdr_gprinc_ret (); extern bool_t xdr_kadm5_ret_t (); extern bool_t xdr_kadm5_principal_ent_rec (); extern bool_t xdr_kadm5_policy_ent_rec (); extern bool_t xdr_krb5_keyblock (); extern bool_t xdr_krb5_principal (); extern bool_t xdr_krb5_enctype (); extern bool_t xdr_krb5_octet (); extern bool_t xdr_krb5_int32 (); extern bool_t xdr_u_int32 (); extern bool_t xdr_cpol_arg (); extern bool_t xdr_dpol_arg (); extern bool_t xdr_mpol_arg (); extern bool_t xdr_gpol_arg (); extern bool_t xdr_gpol_ret (); extern bool_t xdr_gpols_arg (); extern bool_t xdr_gpols_ret (); extern bool_t xdr_getprivs_ret (); #endif /* __KADM_RPC_H__ */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved */ #include #include #include #include #include #include #include static bool_t _xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp, int v); bool_t xdr_krb5_salttype(XDR *xdrs, krb5_int32 *objp); /* SUNWresync121 XXX */ /* * Function: xdr_ui_4 * * Purpose: XDR function which serves as a wrapper for xdr_u_int, * to prevent compiler warnings about type clashes between u_int32 * and krb5_ui_4. */ bool_t xdr_ui_4(XDR *xdrs, krb5_ui_4 *objp) { /* Assumes that krb5_ui_4 and u_int32 are both four bytes long. This should not be a harmful assumption. */ return xdr_u_int(xdrs, (uint32_t *) objp); } /* * Function: xdr_nullstring * * Purpose: XDR function for "strings" that are either NULL-terminated * or NULL. */ bool_t xdr_nullstring(XDR *xdrs, char **objp) { u_int size; if (xdrs->x_op == XDR_ENCODE) { if (*objp == NULL) size = 0; else size = strlen(*objp) + 1; } if (! xdr_u_int(xdrs, &size)) { return FALSE; } switch (xdrs->x_op) { case XDR_DECODE: if (size == 0) { *objp = NULL; return TRUE; } else if (*objp == NULL) { *objp = (char *) mem_alloc(size); if (*objp == NULL) { errno = ENOMEM; return FALSE; } } return (xdr_opaque(xdrs, *objp, size)); case XDR_ENCODE: if (size != 0) return (xdr_opaque(xdrs, *objp, size)); return TRUE; case XDR_FREE: if (*objp != NULL) mem_free(*objp, size); *objp = NULL; return TRUE; } return FALSE; } /* * Function: xdr_nulltype * * Purpose: XDR function for arbitrary pointer types that are either * NULL or contain data. */ bool_t xdr_nulltype(XDR *xdrs, void **objp, xdrproc_t proc) { bool_t null; switch (xdrs->x_op) { case XDR_DECODE: if (!xdr_bool(xdrs, &null)) return FALSE; if (null) { *objp = NULL; return TRUE; } return (*proc)(xdrs, objp); case XDR_ENCODE: if (*objp == NULL) null = TRUE; else null = FALSE; if (!xdr_bool(xdrs, &null)) return FALSE; if (null == FALSE) return (*proc)(xdrs, objp); return TRUE; case XDR_FREE: if (*objp) return (*proc)(xdrs, objp); return TRUE; } return FALSE; } bool_t xdr_krb5_timestamp(XDR *xdrs, krb5_timestamp *objp) { /* This assumes that int32 and krb5_timestamp are the same size. This shouldn't be a problem, since we've got a unit test which checks for this. */ if (!xdr_int(xdrs, (int32_t *) objp)) { return (FALSE); } return (TRUE); } bool_t xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp) { unsigned char tmp; tmp = '\0'; /* for purify, else xdr_u_char performs a umr */ if (xdrs->x_op == XDR_ENCODE) tmp = (unsigned char) *objp; if (!xdr_u_char(xdrs, &tmp)) return (FALSE); if (xdrs->x_op == XDR_DECODE) *objp = (krb5_kvno) tmp; return (TRUE); } bool_t xdr_krb5_deltat(XDR *xdrs, krb5_deltat *objp) { /* This assumes that int32 and krb5_deltat are the same size. This shouldn't be a problem, since we've got a unit test which checks for this. */ if (!xdr_int(xdrs, (int32_t *) objp)) { return (FALSE); } return (TRUE); } bool_t xdr_krb5_flags(XDR *xdrs, krb5_flags *objp) { /* This assumes that int32 and krb5_flags are the same size. This shouldn't be a problem, since we've got a unit test which checks for this. */ if (!xdr_int(xdrs, (int32_t *) objp)) { return (FALSE); } return (TRUE); } bool_t xdr_krb5_ui_4(XDR *xdrs, krb5_ui_4 *objp) { if (!xdr_u_int(xdrs, (uint32_t *) objp)) { return (FALSE); } return (TRUE); } bool_t xdr_krb5_int16(XDR *xdrs, krb5_int16 *objp) { int tmp; tmp = (int) *objp; if (!xdr_int(xdrs, &tmp)) return(FALSE); *objp = (krb5_int16) tmp; return(TRUE); } /* * Function: xdr_krb5_ui_2 * * Purpose: XDR function which serves as a wrapper for xdr_u_int, * to prevent compiler warnings about type clashes between u_int * and krb5_ui_2. */ bool_t xdr_krb5_ui_2(XDR *xdrs, krb5_ui_2 *objp) { unsigned int tmp; tmp = (unsigned int) *objp; if (!xdr_u_int(xdrs, &tmp)) return(FALSE); *objp = (krb5_ui_2) tmp; return(TRUE); } bool_t xdr_krb5_key_data_nocontents(XDR *xdrs, krb5_key_data *objp) { /* * Note that this function intentionally DOES NOT tranfer key * length or contents! xdr_krb5_key_data in adb_xdr.c does, but * that is only for use within the server-side library. */ unsigned int tmp; if (xdrs->x_op == XDR_DECODE) memset((char *) objp, 0, sizeof(krb5_key_data)); if (!xdr_krb5_int16(xdrs, &objp->key_data_ver)) { return (FALSE); } if (!xdr_krb5_int16(xdrs, &objp->key_data_kvno)) { return (FALSE); } if (!xdr_krb5_int16(xdrs, &objp->key_data_type[0])) { return (FALSE); } if (objp->key_data_ver > 1) { if (!xdr_krb5_int16(xdrs, &objp->key_data_type[1])) { return (FALSE); } } /* * kadm5_get_principal on the server side allocates and returns * key contents when asked. Even though this function refuses to * transmit that data, it still has to *free* the data at the * appropriate time to avoid a memory leak. */ if (xdrs->x_op == XDR_FREE) { tmp = (unsigned int) objp->key_data_length[0]; if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[0], &tmp, ~0)) return FALSE; tmp = (unsigned int) objp->key_data_length[1]; if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[1], &tmp, ~0)) return FALSE; } return (TRUE); } bool_t xdr_krb5_key_salt_tuple(XDR *xdrs, krb5_key_salt_tuple *objp) { if (!xdr_krb5_enctype(xdrs, &objp->ks_enctype)) return FALSE; if (!xdr_krb5_salttype(xdrs, &objp->ks_salttype)) return FALSE; return TRUE; } bool_t xdr_krb5_tl_data(XDR *xdrs, krb5_tl_data **tl_data_head) { krb5_tl_data *tl, *tl2; bool_t more; unsigned int len; switch (xdrs->x_op) { case XDR_FREE: tl = tl2 = *tl_data_head; while (tl) { tl2 = tl->tl_data_next; free(tl->tl_data_contents); free(tl); tl = tl2; } break; case XDR_ENCODE: tl = *tl_data_head; while (1) { more = (tl != NULL); if (!xdr_bool(xdrs, &more)) return FALSE; if (tl == NULL) break; if (!xdr_krb5_int16(xdrs, &tl->tl_data_type)) return FALSE; len = tl->tl_data_length; if (!xdr_bytes(xdrs, (char **) &tl->tl_data_contents, &len, ~0)) return FALSE; tl = tl->tl_data_next; } break; case XDR_DECODE: tl = NULL; while (1) { if (!xdr_bool(xdrs, &more)) return FALSE; if (more == FALSE) break; tl2 = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); if (tl2 == NULL) return FALSE; memset((char *) tl2, 0, sizeof(krb5_tl_data)); if (!xdr_krb5_int16(xdrs, &tl2->tl_data_type)) return FALSE; if (!xdr_bytes(xdrs, (char **)&tl2->tl_data_contents, &len, ~0)) return FALSE; tl2->tl_data_length = len; tl2->tl_data_next = tl; tl = tl2; } *tl_data_head = tl; break; } return TRUE; } bool_t xdr_kadm5_ret_t(XDR *xdrs, kadm5_ret_t *objp) { uint32_t tmp; if (xdrs->x_op == XDR_ENCODE) tmp = (uint32_t) *objp; if (!xdr_u_int(xdrs, &tmp)) return (FALSE); if (xdrs->x_op == XDR_DECODE) *objp = (kadm5_ret_t) tmp; return (TRUE); } bool_t xdr_kadm5_principal_ent_rec_v1(XDR *xdrs, kadm5_principal_ent_rec *objp) { return _xdr_kadm5_principal_ent_rec(xdrs, objp, KADM5_API_VERSION_1); } bool_t xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp) { return _xdr_kadm5_principal_ent_rec(xdrs, objp, KADM5_API_VERSION_2); } static bool_t _xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp, int v) { unsigned int n; if (!xdr_krb5_principal(xdrs, &objp->principal)) { return (FALSE); } if (!xdr_krb5_timestamp(xdrs, &objp->princ_expire_time)) { return (FALSE); } if (!xdr_krb5_timestamp(xdrs, &objp->last_pwd_change)) { return (FALSE); } if (!xdr_krb5_timestamp(xdrs, &objp->pw_expiration)) { return (FALSE); } if (!xdr_krb5_deltat(xdrs, &objp->max_life)) { return (FALSE); } if (v == KADM5_API_VERSION_1) { if (!xdr_krb5_principal(xdrs, &objp->mod_name)) { return (FALSE); } } else { if (!xdr_nulltype(xdrs, (void **) &objp->mod_name, xdr_krb5_principal)) { return (FALSE); } } if (!xdr_krb5_timestamp(xdrs, &objp->mod_date)) { return (FALSE); } if (!xdr_krb5_flags(xdrs, &objp->attributes)) { return (FALSE); } if (!xdr_krb5_kvno(xdrs, &objp->kvno)) { return (FALSE); } if (!xdr_krb5_kvno(xdrs, &objp->mkvno)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->policy)) { return (FALSE); } if (!xdr_long(xdrs, &objp->aux_attributes)) { return (FALSE); } if (v != KADM5_API_VERSION_1) { if (!xdr_krb5_deltat(xdrs, &objp->max_renewable_life)) { return (FALSE); } if (!xdr_krb5_timestamp(xdrs, &objp->last_success)) { return (FALSE); } if (!xdr_krb5_timestamp(xdrs, &objp->last_failed)) { return (FALSE); } if (!xdr_krb5_kvno(xdrs, &objp->fail_auth_count)) { return (FALSE); } if (!xdr_krb5_int16(xdrs, &objp->n_key_data)) { return (FALSE); } if (!xdr_krb5_int16(xdrs, &objp->n_tl_data)) { return (FALSE); } if (!xdr_nulltype(xdrs, (void **) &objp->tl_data, xdr_krb5_tl_data)) { return FALSE; } n = objp->n_key_data; if (!xdr_array(xdrs, (caddr_t *) &objp->key_data, &n, ~0, sizeof(krb5_key_data), xdr_krb5_key_data_nocontents)) { return (FALSE); } } return (TRUE); } bool_t xdr_kadm5_policy_ent_rec(XDR *xdrs, kadm5_policy_ent_rec *objp) { if (!xdr_nullstring(xdrs, &objp->policy)) { return (FALSE); } /* these all used to be u_int32, but it's stupid for sized types to be exposed at the api, and they're the same as longs on the wire. */ if (!xdr_long(xdrs, &objp->pw_min_life)) { return (FALSE); } if (!xdr_long(xdrs, &objp->pw_max_life)) { return (FALSE); } if (!xdr_long(xdrs, &objp->pw_min_length)) { return (FALSE); } if (!xdr_long(xdrs, &objp->pw_min_classes)) { return (FALSE); } if (!xdr_long(xdrs, &objp->pw_history_num)) { return (FALSE); } if (!xdr_long(xdrs, &objp->policy_refcnt)) { return (FALSE); } return (TRUE); } bool_t xdr_cprinc_arg(XDR *xdrs, cprinc_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (objp->api_version == KADM5_API_VERSION_1) { if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) { return (FALSE); } } else { if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) { return (FALSE); } } if (!xdr_long(xdrs, &objp->mask)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->passwd)) { return (FALSE); } return (TRUE); } bool_t xdr_cprinc3_arg(XDR *xdrs, cprinc3_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (objp->api_version == KADM5_API_VERSION_1) { if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) { return (FALSE); } } else { if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) { return (FALSE); } } if (!xdr_long(xdrs, &objp->mask)) { return (FALSE); } if (!xdr_array(xdrs, (caddr_t *)&objp->ks_tuple, (unsigned int *)&objp->n_ks_tuple, ~0, sizeof(krb5_key_salt_tuple), xdr_krb5_key_salt_tuple)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->passwd)) { return (FALSE); } return (TRUE); } bool_t xdr_generic_ret(XDR *xdrs, generic_ret *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { return (FALSE); } return(TRUE); } bool_t xdr_dprinc_arg(XDR *xdrs, dprinc_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } return (TRUE); } bool_t xdr_mprinc_arg(XDR *xdrs, mprinc_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (objp->api_version == KADM5_API_VERSION_1) { if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) { return (FALSE); } } else { if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) { return (FALSE); } } if (!xdr_long(xdrs, &objp->mask)) { return (FALSE); } return (TRUE); } bool_t xdr_rprinc_arg(XDR *xdrs, rprinc_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->src)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->dest)) { return (FALSE); } return (TRUE); } bool_t xdr_gprincs_arg(XDR *xdrs, gprincs_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->exp)) { return (FALSE); } return (TRUE); } bool_t xdr_gprincs_ret(XDR *xdrs, gprincs_ret *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { return (FALSE); } if (objp->code == KADM5_OK) { if (!xdr_int(xdrs, &objp->count)) { return (FALSE); } if (!xdr_array(xdrs, (caddr_t *) &objp->princs, (unsigned int *) &objp->count, ~0, sizeof(char *), xdr_nullstring)) { return (FALSE); } } return (TRUE); } bool_t xdr_chpass_arg(XDR *xdrs, chpass_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->pass)) { return (FALSE); } return (TRUE); } bool_t xdr_chpass3_arg(XDR *xdrs, chpass3_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } if (!xdr_bool(xdrs, (bool_t *) &objp->keepold)) { /* SUNWresync121 XXX */ return (FALSE); } if (!xdr_array(xdrs, (caddr_t *)&objp->ks_tuple, (unsigned int*)&objp->n_ks_tuple, ~0, sizeof(krb5_key_salt_tuple), xdr_krb5_key_salt_tuple)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->pass)) { return (FALSE); } return (TRUE); } bool_t xdr_setv4key_arg(XDR *xdrs, setv4key_arg *objp) { unsigned int n_keys = 1; if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } if (!xdr_array(xdrs, (caddr_t *) &objp->keyblock, &n_keys, ~0, sizeof(krb5_keyblock), xdr_krb5_keyblock)) { return (FALSE); } return (TRUE); } bool_t xdr_setkey_arg(XDR *xdrs, setkey_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } if (!xdr_array(xdrs, (caddr_t *) &objp->keyblocks, (unsigned int *) &objp->n_keys, ~0, sizeof(krb5_keyblock), xdr_krb5_keyblock)) { return (FALSE); } return (TRUE); } bool_t xdr_setkey3_arg(XDR *xdrs, setkey3_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } if (!xdr_bool(xdrs, (bool_t *) &objp->keepold)) { /* SUNWresync121 XXX */ return (FALSE); } if (!xdr_array(xdrs, (caddr_t *) &objp->ks_tuple, (unsigned int *) &objp->n_ks_tuple, ~0, sizeof(krb5_key_salt_tuple), xdr_krb5_key_salt_tuple)) { return (FALSE); } if (!xdr_array(xdrs, (caddr_t *) &objp->keyblocks, (unsigned int *) &objp->n_keys, ~0, sizeof(krb5_keyblock), xdr_krb5_keyblock)) { return (FALSE); } return (TRUE); } bool_t xdr_chrand_arg(XDR *xdrs, chrand_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } return (TRUE); } bool_t xdr_chrand3_arg(XDR *xdrs, chrand3_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } if (!xdr_bool(xdrs, (bool_t *) &objp->keepold)) { /* SUNWresync121 XXX */ return (FALSE); } if (!xdr_array(xdrs, (caddr_t *)&objp->ks_tuple, (unsigned int*)&objp->n_ks_tuple, ~0, sizeof(krb5_key_salt_tuple), xdr_krb5_key_salt_tuple)) { return (FALSE); } return (TRUE); } bool_t xdr_chrand_ret(XDR *xdrs, chrand_ret *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { return (FALSE); } if (objp->api_version == KADM5_API_VERSION_1) { if(objp->code == KADM5_OK) { if (!xdr_krb5_keyblock(xdrs, &objp->key)) { return (FALSE); } } } else { if (objp->code == KADM5_OK) { if (!xdr_array(xdrs, (char **)&objp->keys, (unsigned int *)&objp->n_keys, ~0, sizeof(krb5_keyblock), xdr_krb5_keyblock)) return FALSE; } } return (TRUE); } bool_t xdr_gprinc_arg(XDR *xdrs, gprinc_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_krb5_principal(xdrs, &objp->princ)) { return (FALSE); } if ((objp->api_version > KADM5_API_VERSION_1) && !xdr_long(xdrs, &objp->mask)) { return FALSE; } return (TRUE); } bool_t xdr_gprinc_ret(XDR *xdrs, gprinc_ret *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { return (FALSE); } if(objp->code == KADM5_OK) { if (objp->api_version == KADM5_API_VERSION_1) { if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) { return (FALSE); } } else { if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) { return (FALSE); } } } return (TRUE); } bool_t xdr_cpol_arg(XDR *xdrs, cpol_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) { return (FALSE); } if (!xdr_long(xdrs, &objp->mask)) { return (FALSE); } return (TRUE); } bool_t xdr_dpol_arg(XDR *xdrs, dpol_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->name)) { return (FALSE); } return (TRUE); } bool_t xdr_mpol_arg(XDR *xdrs, mpol_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) { return (FALSE); } if (!xdr_long(xdrs, &objp->mask)) { return (FALSE); } return (TRUE); } bool_t xdr_gpol_arg(XDR *xdrs, gpol_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->name)) { return (FALSE); } return (TRUE); } bool_t xdr_gpol_ret(XDR *xdrs, gpol_ret *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { return (FALSE); } if(objp->code == KADM5_OK) { if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) return (FALSE); } return (TRUE); } bool_t xdr_gpols_arg(XDR *xdrs, gpols_arg *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_nullstring(xdrs, &objp->exp)) { return (FALSE); } return (TRUE); } bool_t xdr_gpols_ret(XDR *xdrs, gpols_ret *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { return (FALSE); } if (objp->code == KADM5_OK) { if (!xdr_int(xdrs, &objp->count)) { return (FALSE); } if (!xdr_array(xdrs, (caddr_t *) &objp->pols, (unsigned int *) &objp->count, ~0, sizeof(char *), xdr_nullstring)) { return (FALSE); } } return (TRUE); } bool_t xdr_getprivs_ret(XDR *xdrs, getprivs_ret *objp) { if (!xdr_ui_4(xdrs, &objp->api_version)) { return (FALSE); } if (! xdr_kadm5_ret_t(xdrs, &objp->code) || ! xdr_long(xdrs, &objp->privs)) return FALSE; return TRUE; } bool_t xdr_krb5_principal(XDR *xdrs, krb5_principal *objp) { int ret; char *p = NULL; krb5_principal pr = NULL; static krb5_context context = NULL; /* using a static context here is ugly, but should work ok, and the other solutions are even uglier */ if (!context && kadm5_init_krb5_context(&context)) return(FALSE); switch(xdrs->x_op) { case XDR_ENCODE: if (*objp) { if((ret = krb5_unparse_name(context, *objp, &p)) != 0) return FALSE; } if(!xdr_nullstring(xdrs, &p)) return FALSE; if (p) free(p); break; case XDR_DECODE: if(!xdr_nullstring(xdrs, &p)) return FALSE; if (p) { ret = krb5_parse_name(context, p, &pr); if(ret != 0) return FALSE; *objp = pr; free(p); } else *objp = NULL; break; case XDR_FREE: if(*objp != NULL) krb5_free_principal(context, *objp); break; } return TRUE; } bool_t xdr_krb5_octet(XDR *xdrs, krb5_octet *objp) { if (!xdr_u_char(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_krb5_enctype(XDR *xdrs, krb5_enctype *objp) { /* * This used to be xdr_krb5_keytype, but keytypes and enctypes have * been merged into only enctypes. However, randkey_principal * already ensures that only a key of ENCTYPE_DES_CBC_CRC will be * returned to v1 clients, and ENCTYPE_DES_CBC_CRC has the same * value as KEYTYPE_DES used too, which is what all v1 clients * expect. Therefore, IMHO, just encoding whatever enctype we get * is safe. */ if (!xdr_u_int(xdrs, (unsigned int *) objp)) return (FALSE); return (TRUE); } bool_t xdr_krb5_salttype(XDR *xdrs, krb5_int32 *objp) { if (!xdr_int(xdrs, (int32_t *) objp)) return FALSE; return TRUE; } bool_t xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp) { /* XXX This only works because free_keyblock assumes ->contents is allocated by malloc() */ if(!xdr_krb5_enctype(xdrs, &objp->enctype)) return FALSE; if(!xdr_bytes(xdrs, (char **) &objp->contents, (unsigned int *) &objp->length, ~0)) return FALSE; return TRUE; } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include "server_internal.h" #include #include kadm5_ret_t kadm5_free_policy_ent(void *server_handle, kadm5_policy_ent_t val) { kadm5_server_handle_t handle = server_handle; _KADM5_CHECK_HANDLE(server_handle); if(val) { if (val->policy) free(val->policy); if (handle->api_version == KADM5_API_VERSION_1) free(val); } return KADM5_OK; } kadm5_ret_t kadm5_free_name_list(void *server_handle, char **names, int count) { _KADM5_CHECK_HANDLE(server_handle); while (count--) free(names[count]); free(names); return KADM5_OK; } /* XXX this ought to be in libkrb5.a, but isn't */ kadm5_ret_t krb5_free_key_data_contents(context, key) krb5_context context; krb5_key_data *key; { int i, idx; idx = (key->key_data_ver == 1 ? 1 : 2); for (i = 0; i < idx; i++) { if (key->key_data_contents[i]) { memset(key->key_data_contents[i], 0, key->key_data_length[i]); free(key->key_data_contents[i]); } } return KADM5_OK; } kadm5_ret_t kadm5_free_key_data(void *server_handle, krb5_int16 *n_key_data, krb5_key_data *key_data) { kadm5_server_handle_t handle = server_handle; int i, nkeys = (int) *n_key_data; _KADM5_CHECK_HANDLE(server_handle); if (key_data == NULL) return KADM5_OK; for (i = 0; i < nkeys; i++) krb5_free_key_data_contents(handle->context, &key_data[i]); free(key_data); return KADM5_OK; } kadm5_ret_t kadm5_free_principal_ent(void *server_handle, kadm5_principal_ent_t val) { kadm5_server_handle_t handle = server_handle; int i; _KADM5_CHECK_HANDLE(server_handle); if(val) { if(val->principal) krb5_free_principal(handle->context, val->principal); if(val->mod_name) krb5_free_principal(handle->context, val->mod_name); if(val->policy) free(val->policy); if (handle->api_version > KADM5_API_VERSION_1) { if (val->n_key_data) { for (i = 0; i < val->n_key_data; i++) krb5_free_key_data_contents(handle->context, &val->key_data[i]); free(val->key_data); } if (val->tl_data) { krb5_tl_data *tl; while (val->tl_data) { tl = val->tl_data->tl_data_next; free(val->tl_data->tl_data_contents); free(val->tl_data); val->tl_data = tl; } } } if (handle->api_version == KADM5_API_VERSION_1) free(val); } return KADM5_OK; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ /* * This header file is used internally by the Admin API server * libraries and Admin server. IF YOU THINK YOU NEED TO USE THIS FILE * FOR ANYTHING, YOU'RE ALMOST CERTAINLY WRONG. */ #ifndef __KADM5_SERVER_INTERNAL_H__ #define __KADM5_SERVER_INTERNAL_H__ #ifdef HAVE_MEMORY_H #include #endif #include #include #include "k5-int.h" #include #include #include #include "admin_internal.h" typedef struct _kadm5_server_handle_t { krb5_ui_4 magic_number; krb5_ui_4 struct_version; krb5_ui_4 api_version; krb5_context context; krb5_principal current_caller; kadm5_config_params params; struct _kadm5_server_handle_t *lhandle; char **db_args; krb5_keyblock master_keyblock; } kadm5_server_handle_rec, *kadm5_server_handle_t; #define OSA_ADB_PRINC_VERSION_1 0x12345C01 typedef struct _osa_pw_hist_t { int n_key_data; krb5_key_data *key_data; } osa_pw_hist_ent, *osa_pw_hist_t; typedef struct _osa_princ_ent_t { int version; char *policy; long aux_attributes; unsigned int old_key_len; unsigned int old_key_next; krb5_kvno admin_history_kvno; osa_pw_hist_ent *old_keys; } osa_princ_ent_rec, *osa_princ_ent_t; kadm5_ret_t adb_policy_init(kadm5_server_handle_t handle); kadm5_ret_t adb_policy_close(kadm5_server_handle_t handle); kadm5_ret_t passwd_check(kadm5_server_handle_t handle, char *pass, int use_policy, kadm5_policy_ent_t policy, krb5_principal principal); kadm5_ret_t principal_exists(krb5_principal principal); krb5_error_code kdb_init_master(kadm5_server_handle_t handle, char *r, int from_keyboard); krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r); krb5_error_code kdb_get_entry(kadm5_server_handle_t handle, krb5_principal principal, krb5_db_entry *kdb, osa_princ_ent_rec *adb); krb5_error_code kdb_free_entry(kadm5_server_handle_t handle, krb5_db_entry *kdb, osa_princ_ent_rec *adb); krb5_error_code kdb_put_entry(kadm5_server_handle_t handle, krb5_db_entry *kdb, osa_princ_ent_rec *adb); krb5_error_code kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name); krb5_error_code kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry, void (*iter_fct)(void *, krb5_principal), void *data); int init_dict(kadm5_config_params *); int find_word(const char *word); void destroy_dict(void); /* XXX this ought to be in libkrb5.a, but isn't */ kadm5_ret_t krb5_copy_key_data_contents(krb5_context context, krb5_key_data *from, krb5_key_data *to); kadm5_ret_t krb5_free_key_data_contents(krb5_context context, krb5_key_data *key); /* * *Warning* * *Warning* This is going to break if we * *Warning* ever go multi-threaded * *Warning* */ extern krb5_principal current_caller; /* * Why is this (or something similar) not defined *anywhere* in krb5? */ #define KSUCCESS 0 #define WORD_NOT_FOUND 1 /* * all the various mask bits or'd together */ #define ALL_PRINC_MASK \ (KADM5_PRINCIPAL | KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION | \ KADM5_LAST_PWD_CHANGE | KADM5_ATTRIBUTES | KADM5_MAX_LIFE | \ KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_KVNO | KADM5_MKVNO | \ KADM5_AUX_ATTRIBUTES | KADM5_POLICY_CLR | KADM5_POLICY | \ KADM5_MAX_RLIFE | KADM5_TL_DATA | KADM5_KEY_DATA) #define ALL_POLICY_MASK \ (KADM5_POLICY | KADM5_PW_MAX_LIFE | KADM5_PW_MIN_LIFE | \ KADM5_PW_MIN_LENGTH | KADM5_PW_MIN_CLASSES | KADM5_PW_HISTORY_NUM | \ KADM5_REF_COUNT) #define SERVER_CHECK_HANDLE(handle) \ { \ kadm5_server_handle_t srvr = \ (kadm5_server_handle_t) handle; \ \ if (! srvr->current_caller) \ return KADM5_BAD_SERVER_HANDLE; \ if (! srvr->lhandle) \ return KADM5_BAD_SERVER_HANDLE; \ } #define CHECK_HANDLE(handle) \ GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION, \ KADM5_NEW_SERVER_API_VERSION) \ SERVER_CHECK_HANDLE(handle) bool_t xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp); void osa_free_princ_ent(osa_princ_ent_t val); #endif /* __KADM5_SERVER_INTERNAL_H__ */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../../Makefile.lib # Hammerhead: amd64-only SUBDIRS= $(MACH64) all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber install : TARGET= install _msg : TARGET= _msg .KEEP_STATE: all clean clobber install _msg: $(SUBDIRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. LIBRARY= libkadm5srv.a VERS= .1 SRV_OBJS = svr_policy.o \ svr_principal.o \ server_acl.o \ server_kdb.o \ server_misc.o \ server_init.o \ server_dict.o \ svr_iters.o \ svr_chpass_util.o \ adb_xdr.o \ xdr_alloc.o \ logger.o \ chgpwd.o SHARED_OBJS = \ misc_free.o \ kadm_rpc_xdr.o \ chpass_util.o \ alt_prof.o \ kadm_host_srv_names.o \ str_conv.o OBJECTS= $(SHARED_OBJS) $(SRV_OBJS) # include library definitions include ../../../Makefile.lib SRCS= $(SRV_OBJS:%.o=../%.c) \ $(SHARED_OBJS:%.o=../../%.c) KRB5LIB= $(ROOT)/usr/lib/krb5 LIBS= $(DYNLIB) include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE = $(LIBRARY:%.a=%.po) POFILES = generic.po #override liblink INS.liblink= -$(RM) $@; $(SYMLINK) $(LIBLINKS)$(VERS) $@ CPPFLAGS += -I.. -I../.. -I../../.. \ -I$(SRC)/lib/krb5/kdb \ -I$(SRC)/cmd/krb5/iprop \ -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(SRC)/lib/gss_mechs/mech_krb5/include/krb5 \ -I$(SRC)/uts/common/gssapi/ \ -I$(SRC)/uts/common/gssapi/include/ \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include \ -I$(SRC)/lib/gss_mechs/mech_krb5/krb5/os \ -DHAVE_STDLIB_H -DUSE_SOLARIS_SHARED_LIBRARIES \ -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DSETRPCENT_TYPE=void \ -DENDRPCENT_TYPE=void -DHAVE_SYS_ERRLIST=1 -DNEED_SYS_ERRLIST=1 \ -DHAVE_SYSLOG_H=1 -DHAVE_OPENLOG=1 -DHAVE_SYSLOG=1 -DHAVE_CLOSELOG=1 \ -DHAVE_STEP=1 -DHAVE_RE_COMP=1 -DHAVE_RE_EXEC=1 -DHAVE_REGCOMP=1 \ -DHAVE_REGEXEC=1 -DHAVE_STRFTIME=1 -DHAVE_VSPRINTF=1 \ -DUSE_KADM5_API_VERSION=2 # Hammerhead: -I.. already in CPPFLAGS above; removed from CFLAGS (lost in Makefile.master.64 reset) CFLAGS += $(CCVERBOSE) # Hammerhead: GNU ld with -zdefs requires all symbols resolved at link time. # Link against mech_krb5 for krb5_* symbols, plus standard system libs. # libkdb provides krb5_db_*, ulog_* symbols; libdyn provides Dyn* symbols. # Both live in $(ROOT)/usr/lib/krb5, so use full proto-area paths. LDLIBS += $(KMECHLIB) $(KRB5LIB)/libkdb.so $(KRB5LIB)/libdyn.so \ -lnsl -lsocket -lc CERRWARN += -Wno-unused-function CERRWARN += -Wno-unused-variable CERRWARN += -Wno-parentheses CERRWARN += -Wno-type-limits CERRWARN += $(CNOWARN_UNINIT) SMOFF += all_func_returns,indenting .KEEP_STATE: all: $(LIBS) # include library targets include ../../../Makefile.targ pics/%.o: ../../%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) FRC: generic.po: FRC $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../*.[ch] ../../*.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include #include "server_internal.h" #include #include /* SUNWresync121 XXX */ #include "admin_xdr.h" #ifdef HAVE_MEMORY_H #include #endif bool_t xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp) { unsigned int tmp; if (!xdr_krb5_int16(xdrs, &objp->key_data_ver)) return(FALSE); if (!xdr_krb5_int16(xdrs, &objp->key_data_kvno)) return(FALSE); if (!xdr_krb5_int16(xdrs, &objp->key_data_type[0])) return(FALSE); if (!xdr_krb5_int16(xdrs, &objp->key_data_type[1])) return(FALSE); /* SUNW14resync */ if (!xdr_krb5_ui_2(xdrs, (krb5_ui_2 *)&objp->key_data_length[0])) return(FALSE); if (!xdr_krb5_ui_2(xdrs, (krb5_ui_2 *)&objp->key_data_length[1])) return(FALSE); tmp = (unsigned int) objp->key_data_length[0]; if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[0], &tmp, ~0)) return FALSE; tmp = (unsigned int) objp->key_data_length[1]; if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[1], &tmp, ~0)) return FALSE; /* don't need to copy tmp out, since key_data_length will be set by the above encoding. */ return(TRUE); } bool_t xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp) { if (!xdr_array(xdrs, (caddr_t *) &objp->key_data, (u_int *) &objp->n_key_data, ~0, sizeof(krb5_key_data), xdr_krb5_key_data)) return (FALSE); return (TRUE); } bool_t xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp) { switch (xdrs->x_op) { case XDR_ENCODE: objp->version = OSA_ADB_PRINC_VERSION_1; /* fall through */ case XDR_FREE: if (!xdr_int(xdrs, &objp->version)) return FALSE; break; case XDR_DECODE: if (!xdr_int(xdrs, &objp->version)) return FALSE; if (objp->version != OSA_ADB_PRINC_VERSION_1) return FALSE; break; } if (!xdr_nullstring(xdrs, &objp->policy)) return (FALSE); if (!xdr_long(xdrs, &objp->aux_attributes)) return (FALSE); if (!xdr_u_int(xdrs, &objp->old_key_next)) return (FALSE); if (!xdr_krb5_kvno(xdrs, &objp->admin_history_kvno)) return (FALSE); if (!xdr_array(xdrs, (caddr_t *) &objp->old_keys, (unsigned int *) &objp->old_key_len, ~0, sizeof(osa_pw_hist_ent), xdr_osa_pw_hist_ent)) return (FALSE); return (TRUE); } void osa_free_princ_ent(osa_princ_ent_t val) { XDR xdrs; xdrmem_create(&xdrs, NULL, 0, XDR_FREE); xdr_osa_princ_ent_rec(&xdrs, val); free(val); } # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2025 Hammerhead Project # include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 install: all $(ROOTLIBS64) $(ROOTLINKS64) /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * lib/krb5/kadm5/srv/chgpwd.c * * Copyright 1998 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * chgpwd.c - Handles changepw requests issued from non-Solaris krb5 clients. */ #include #include #include #include #include #define MAXAPREQ 1500 static krb5_error_code process_chpw_request(krb5_context context, void *server_handle, char *realm, int s, krb5_keytab keytab, struct sockaddr_in *sin, krb5_data *req, krb5_data *rep) { krb5_error_code ret; char *ptr; int plen, vno; krb5_address local_kaddr, remote_kaddr; int allocated_mem = 0; krb5_data ap_req, ap_rep; krb5_auth_context auth_context; krb5_principal changepw; krb5_ticket *ticket; krb5_data cipher, clear; struct sockaddr local_addr, remote_addr; int addrlen; krb5_replay_data replay; krb5_error krberror; int numresult; char strresult[1024]; char *clientstr; size_t clen; char *cdots; ret = 0; rep->length = 0; auth_context = NULL; changepw = NULL; ap_rep.length = 0; ap_rep.data = NULL; ticket = NULL; clear.length = 0; clear.data = NULL; cipher.length = 0; cipher.data = NULL; if (req->length < 4) { /* * either this, or the server is printing bad messages, * or the caller passed in garbage */ ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; (void) strlcpy(strresult, "Request was truncated", sizeof (strresult)); goto chpwfail; } ptr = req->data; /* * Verify length */ plen = (*ptr++ & 0xff); plen = (plen<<8) | (*ptr++ & 0xff); if (plen != req->length) return (KRB5KRB_AP_ERR_MODIFIED); /* * Verify version number */ vno = (*ptr++ & 0xff); vno = (vno<<8) | (*ptr++ & 0xff); if (vno != 1) { ret = KRB5KDC_ERR_BAD_PVNO; numresult = KRB5_KPASSWD_MALFORMED; (void) snprintf(strresult, sizeof (strresult), "Request contained unknown protocol version number %d", vno); goto chpwfail; } /* * Read, check ap-req length */ ap_req.length = (*ptr++ & 0xff); ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff); if (ptr + ap_req.length >= req->data + req->length) { ret = KRB5KRB_AP_ERR_MODIFIED; numresult = KRB5_KPASSWD_MALFORMED; (void) strlcpy(strresult, "Request was truncated in AP-REQ", sizeof (strresult)); goto chpwfail; } /* * Verify ap_req */ ap_req.data = ptr; ptr += ap_req.length; if (ret = krb5_auth_con_init(context, &auth_context)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed initializing auth context: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed initializing auth context", sizeof (strresult)); goto chpwfail; } if (ret = krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed setting auth " "context flags: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed initializing auth context", sizeof (strresult)); goto chpwfail; } if (ret = krb5_build_principal(context, &changepw, strlen(realm), realm, "kadmin", "changepw", NULL)) { krb5_klog_syslog(LOG_ERR, gettext("Change password request failed " "Failed to build kadmin/changepw " "principal: %s"), error_message(ret)); numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed building kadmin/changepw principal", sizeof (strresult)); goto chpwfail; } ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab, NULL, &ticket); if (ret) { char kt_name[MAX_KEYTAB_NAME_LEN]; if (krb5_kt_get_name(context, keytab, kt_name, sizeof (kt_name))) strncpy(kt_name, "default keytab", sizeof (kt_name)); switch (ret) { case KRB5_KT_NOTFOUND: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed because " "keytab entry \"kadmin/changepw\" " "is missing from \"%s\""), kt_name); break; case ENOENT: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed because " "keytab file \"%s\" does not exist"), kt_name); break; default: krb5_klog_syslog(LOG_ERR, gettext("Change password request failed. " "Failed to parse Kerberos AP_REQ message: %s"), error_message(ret)); } numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Failed reading application request", sizeof (strresult)); goto chpwfail; } /* * Set up address info */ addrlen = sizeof (local_addr); if (getsockname(s, &local_addr, &addrlen) < 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed getting server internet address", sizeof (strresult)); goto chpwfail; } /* * Some brain-dead OS's don't return useful information from * the getsockname call. Namely, windows and solaris. */ if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) { local_kaddr.addrtype = ADDRTYPE_INET; local_kaddr.length = sizeof (((struct sockaddr_in *) &local_addr)->sin_addr); /* CSTYLED */ local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&local_addr)->sin_addr); } else { krb5_address **addrs; krb5_os_localaddr(context, &addrs); local_kaddr.magic = addrs[0]->magic; local_kaddr.addrtype = addrs[0]->addrtype; local_kaddr.length = addrs[0]->length; if ((local_kaddr.contents = malloc(addrs[0]->length)) == 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for local_kaddr", sizeof (strresult)); goto chpwfail; } (void) memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length); allocated_mem++; krb5_free_addresses(context, addrs); } addrlen = sizeof (remote_addr); if (getpeername(s, &remote_addr, &addrlen) < 0) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed getting client internet address", sizeof (strresult)); goto chpwfail; } remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof (((struct sockaddr_in *) &remote_addr)->sin_addr); /* CSTYLED */ remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&remote_addr)->sin_addr); remote_kaddr.addrtype = ADDRTYPE_INET; remote_kaddr.length = sizeof (sin->sin_addr); remote_kaddr.contents = (krb5_octet *) &sin->sin_addr; /* * mk_priv requires that the local address be set. * getsockname is used for this. rd_priv requires that the * remote address be set. recvfrom is used for this. If * rd_priv is given a local address, and the message has the * recipient addr in it, this will be checked. However, there * is simply no way to know ahead of time what address the * message will be delivered *to*. Therefore, it is important * that either no recipient address is in the messages when * mk_priv is called, or that no local address is passed to * rd_priv. Both is a better idea, and I have done that. In * summary, when mk_priv is called, *only* a local address is * specified. when rd_priv is called, *only* a remote address * is specified. Are we having fun yet? */ if (ret = krb5_auth_con_setaddrs(context, auth_context, NULL, &remote_kaddr)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed storing client internet address", sizeof (strresult)); goto chpwfail; } /* * Verify that this is an AS_REQ ticket */ if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) { numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Ticket must be derived from a password", sizeof (strresult)); goto chpwfail; } /* * Construct the ap-rep */ if (ret = krb5_mk_rep(context, auth_context, &ap_rep)) { numresult = KRB5_KPASSWD_AUTHERROR; (void) strlcpy(strresult, "Failed replying to application request", sizeof (strresult)); goto chpwfail; } /* * Decrypt the new password */ cipher.length = (req->data + req->length) - ptr; cipher.data = ptr; if (ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed decrypting request", sizeof (strresult)); goto chpwfail; } ret = krb5_unparse_name(context, ticket->enc_part2->client, &clientstr); if (ret) { numresult = KRB5_KPASSWD_HARDERROR; (void) strcpy(strresult, "Failed decrypting request"); goto chpwfail; } /* * Change the password */ if ((ptr = (char *)malloc(clear.length + 1)) == NULL) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for ptr", sizeof (strresult)); krb5_free_unparsed_name(context, clientstr); goto chpwfail; } (void) memcpy(ptr, clear.data, clear.length); ptr[clear.length] = '\0'; ret = (kadm5_ret_t)kadm5_chpass_principal_util(server_handle, ticket->enc_part2->client, ptr, NULL, strresult, sizeof (strresult)); /* * Zap the password */ (void) memset(clear.data, 0, clear.length); (void) memset(ptr, 0, clear.length); if (clear.data != NULL) { krb5_xfree(clear.data); clear.data = NULL; } free(ptr); clear.length = 0; clen = strlen(clientstr); trunc_name(&clen, &cdots); krb5_klog_syslog(LOG_NOTICE, "chpw request from %s for %.*s%s: %s", inet_ntoa(((struct sockaddr_in *)&remote_addr)->sin_addr), clen, clientstr, cdots, ret ? error_message(ret) : "success"); krb5_free_unparsed_name(context, clientstr); if (ret) { if ((ret != KADM5_PASS_Q_TOOSHORT) && (ret != KADM5_PASS_REUSE) && (ret != KADM5_PASS_Q_CLASS) && (ret != KADM5_PASS_Q_DICT) && (ret != KADM5_PASS_TOOSOON)) numresult = KRB5_KPASSWD_HARDERROR; else numresult = KRB5_KPASSWD_SOFTERROR; /* * strresult set by kadb5_chpass_principal_util() */ goto chpwfail; } /* * Success! */ numresult = KRB5_KPASSWD_SUCCESS; (void) strlcpy(strresult, "", sizeof (strresult)); chpwfail: clear.length = 2 + strlen(strresult); if (clear.data != NULL) { krb5_xfree(clear.data); clear.data = NULL; } if ((clear.data = (char *)malloc(clear.length)) == NULL) { ret = errno; numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Malloc failed for clear.data", sizeof (strresult)); } ptr = clear.data; *ptr++ = (numresult>>8) & 0xff; *ptr++ = numresult & 0xff; (void) memcpy(ptr, strresult, strlen(strresult)); cipher.length = 0; if (ap_rep.length) { if (ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed storing client and server internet addresses", sizeof (strresult)); } else { if (ret = krb5_mk_priv(context, auth_context, &clear, &cipher, &replay)) { numresult = KRB5_KPASSWD_HARDERROR; (void) strlcpy(strresult, "Failed encrypting reply", sizeof (strresult)); } } } /* * If no KRB-PRIV was constructed, then we need a KRB-ERROR. * If this fails, just bail. There's nothing else we can do. */ if (cipher.length == 0) { /* * Clear out ap_rep now, so that it won't be inserted * in the reply */ if (ap_rep.length) { if (ap_rep.data != NULL) krb5_xfree(ap_rep.data); ap_rep.data = NULL; ap_rep.length = 0; } krberror.ctime = 0; krberror.cusec = 0; krberror.susec = 0; if (ret = krb5_timeofday(context, &krberror.stime)) goto bailout; /* * This is really icky. but it's what all the other callers * to mk_error do. */ krberror.error = ret; krberror.error -= ERROR_TABLE_BASE_krb5; if (krberror.error < 0 || krberror.error > 128) krberror.error = KRB_ERR_GENERIC; krberror.client = NULL; if (ret = krb5_build_principal(context, &krberror.server, strlen(realm), realm, "kadmin", "changepw", NULL)) { goto bailout; } krberror.text.length = 0; krberror.e_data = clear; ret = krb5_mk_error(context, &krberror, &cipher); krb5_free_principal(context, krberror.server); if (ret) goto bailout; } /* * Construct the reply */ rep->length = 6 + ap_rep.length + cipher.length; if ((rep->data = (char *)malloc(rep->length)) == NULL) { ret = errno; goto bailout; } ptr = rep->data; /* * Length */ *ptr++ = (rep->length>>8) & 0xff; *ptr++ = rep->length & 0xff; /* * Version == 0x0001 big-endian */ *ptr++ = 0; *ptr++ = 1; /* * ap_rep length, big-endian */ *ptr++ = (ap_rep.length>>8) & 0xff; *ptr++ = ap_rep.length & 0xff; /* * ap-rep data */ if (ap_rep.length) { (void) memcpy(ptr, ap_rep.data, ap_rep.length); ptr += ap_rep.length; } /* * krb-priv or krb-error */ (void) memcpy(ptr, cipher.data, cipher.length); bailout: if (auth_context) krb5_auth_con_free(context, auth_context); if (changepw) krb5_free_principal(context, changepw); if (ap_rep.data != NULL) krb5_xfree(ap_rep.data); if (ticket) krb5_free_ticket(context, ticket); if (clear.data != NULL) krb5_xfree(clear.data); if (cipher.data != NULL) krb5_xfree(cipher.data); if (allocated_mem) krb5_xfree(local_kaddr.contents); return (ret); } /* * This routine is used to handle password-change requests received * on kpasswd-port 464 from MIT/M$ clients. */ void handle_chpw(krb5_context context, int s1, void *serverhandle, kadm5_config_params *params) { krb5_error_code ret; char req[MAXAPREQ]; int len; struct sockaddr_in from; int fromlen; krb5_keytab kt; krb5_data reqdata, repdata; int s2 = -1; reqdata.length = 0; reqdata.data = NULL; repdata.length = 0; repdata.data = NULL; fromlen = sizeof (from); if ((len = recvfrom(s1, req, sizeof (req), 0, (struct sockaddr *)&from, &fromlen)) < 0) { krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't receive " "request: %s"), error_message(errno)); return; } /* * Solaris Kerberos: * The only caller is kadmind, which is the master and therefore has the * correct keys in the KDB, rather than obtaining them via the * kadm5.keytab, by default. */ if ((ret = krb5_kt_resolve(context, "KDB:", &kt))) { krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't open " "admin keytab %s"), error_message(ret)); return; } reqdata.length = len; reqdata.data = req; /* * This is really obscure. s1 is used for all communications. it * is left unconnected in case the server is multihomed and routes * are asymmetric. s2 is connected to resolve routes and get * addresses. this is the *only* way to get proper addresses for * multihomed hosts if routing is asymmetric. * * A related problem in the server, but not the client, is that * many os's have no way to disconnect a connected udp socket, so * the s2 socket needs to be closed and recreated for each * request. The s1 socket must not be closed, or else queued * requests will be lost. * * A "naive" client implementation (one socket, no connect, * hostname resolution to get the local ip addr) will work and * interoperate if the client is single-homed. */ if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { krb5_klog_syslog(LOG_ERR, gettext("chpw: Cannot create " "connecting socket: %s"), error_message(errno)); goto cleanup; } if (connect(s2, (struct sockaddr *)&from, sizeof (from)) < 0) { krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't connect " "to client: %s"), error_message(errno)); if (s2 > 0) (void) close(s2); goto cleanup; } if ((ret = process_chpw_request(context, serverhandle, params->realm, s2, kt, &from, &reqdata, &repdata))) { krb5_klog_syslog(LOG_ERR, gettext("chpw: Error processing " "request: %s"), error_message(ret)); } if (s2 > 0) (void) close(s2); if (repdata.length == 0 || repdata.data == NULL) { /* * Just return. This means something really bad happened */ goto cleanup; } len = sendto(s1, repdata.data, repdata.length, 0, (struct sockaddr *)&from, sizeof (from)); if (len < repdata.length) { krb5_xfree(repdata.data); krb5_klog_syslog(LOG_ERR, gettext("chpw: Error sending reply:" " %s"), error_message(errno)); goto cleanup; } if (repdata.data != NULL) krb5_xfree(repdata.data); cleanup: krb5_kt_close(context, kt); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * lib/kadm/logger.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* KADM5 wants non-syslog log files to contain syslog-like entries */ #define VERBOSE_LOGS /* * logger.c - Handle logging functions for those who want it. */ #include "k5-int.h" #include "adm_proto.h" #include "com_err.h" #include #include #include #ifdef HAVE_SYSLOG_H #include #endif /* HAVE_SYSLOG_H */ #ifdef HAVE_STDARG_H #include #else /* HAVE_STDARG_H */ #include #endif /* HAVE_STDARG_H */ #include #include #include #define KRB5_KLOG_MAX_ERRMSG_SIZE 2048 #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif /* MAXHOSTNAMELEN */ #define LSPEC_PARSE_ERR_1 1 #define LSPEC_PARSE_ERR_2 2 #define LOG_FILE_ERR 3 #define LOG_DEVICE_ERR 4 #define LOG_UFO_STRING 5 #define LOG_EMERG_STRING 6 #define LOG_ALERT_STRING 7 #define LOG_CRIT_STRING 8 #define LOG_ERR_STRING 9 #define LOG_WARNING_STRING 10 #define LOG_NOTICE_STRING 11 #define LOG_INFO_STRING 12 #define LOG_DEBUG_STRING 13 /* This is to assure that we have at least one match in the syslog stuff */ /* static const char LSPEC_PARSE_ERR_1[] = "%s: cannot parse <%s>\n"; static const char LSPEC_PARSE_ERR_2[] = "%s: warning - logging entry syntax error\n"; static const char LOG_FILE_ERR[] = "%s: error writing to %s\n"; static const char LOG_DEVICE_ERR[] = "%s: error writing to %s device\n"; static const char LOG_UFO_STRING[] = "???"; static const char LOG_EMERG_STRING[] = "EMERGENCY"; static const char LOG_ALERT_STRING[] = "ALERT"; static const char LOG_CRIT_STRING[] = "CRITICAL"; static const char LOG_ERR_STRING[] = "Error"; static const char LOG_WARNING_STRING[] = "Warning"; static const char LOG_NOTICE_STRING[] = "Notice"; static const char LOG_INFO_STRING[] = "info"; static const char LOG_DEBUG_STRING[] = "debug"; */ const char * krb5_log_error_table(long errorno) { switch (errorno) { case LSPEC_PARSE_ERR_1: return(gettext("%s: cannot parse <%s>\n")); case LSPEC_PARSE_ERR_2: return(gettext("%s: warning - logging entry syntax error\n")); case LOG_FILE_ERR: return(gettext("%s: error writing to %s\n")); case LOG_DEVICE_ERR: return(gettext("%s: error writing to %s device\n")); case LOG_UFO_STRING: default: return(gettext("???")); case LOG_EMERG_STRING: return(gettext("EMERGENCY")); case LOG_ALERT_STRING: return(gettext("ALERT")); case LOG_CRIT_STRING: return(gettext("CRITICAL")); case LOG_ERR_STRING: return(gettext("Error")); case LOG_WARNING_STRING: return(gettext("Warning")); case LOG_NOTICE_STRING: return(gettext("Notice")); case LOG_INFO_STRING: return(gettext("info")); case LOG_DEBUG_STRING: return(gettext("info")); } } /* * Output logging. * * Output logging is now controlled by the configuration file. We can specify * the following syntaxes under the [logging]->entity specification. * FILE * SYSLOG[=[:]] * STDERR * CONSOLE * DEVICE= * * Where: * is ":" for open/append, "=" for open/create. * is a valid path name. * is one of: (default = ERR) * EMERG * ALERT * CRIT * ERR * WARNING * NOTICE * INFO * DEBUG * is one of: (default = AUTH) * KERN * USER * MAIL * DAEMON * AUTH * LPR * NEWS * UUCP * CRON * LOCAL0..LOCAL7 * is a valid device specification. */ struct log_entry { enum log_type { K_LOG_FILE, K_LOG_SYSLOG, K_LOG_STDERR, K_LOG_CONSOLE, K_LOG_DEVICE, K_LOG_NONE } log_type; krb5_pointer log_2free; union log_union { struct log_file { FILE *lf_filep; char *lf_fname; char *lf_fopen_mode; /* "a+" or "w" */ #define K_LOG_DEF_FILE_ROTATE_PERIOD -1 /* never */ #define K_LOG_DEF_FILE_ROTATE_VERSIONS 0 /* no versions */ time_t lf_rotate_period; time_t lf_last_rotated; int lf_rotate_versions; } log_file; struct log_syslog { int ls_facility; int ls_severity; } log_syslog; struct log_device { FILE *ld_filep; char *ld_devname; } log_device; } log_union; }; #define lfu_filep log_union.log_file.lf_filep #define lfu_fname log_union.log_file.lf_fname #define lfu_fopen_mode log_union.log_file.lf_fopen_mode #define lfu_rotate_period log_union.log_file.lf_rotate_period #define lfu_last_rotated log_union.log_file.lf_last_rotated #define lfu_rotate_versions log_union.log_file.lf_rotate_versions #define lsu_facility log_union.log_syslog.ls_facility #define lsu_severity log_union.log_syslog.ls_severity #define ldu_filep log_union.log_device.ld_filep #define ldu_devname log_union.log_device.ld_devname struct log_control { struct log_entry *log_entries; int log_nentries; char *log_whoami; char *log_hostname; krb5_boolean log_opened; }; static struct log_control log_control = { (struct log_entry *) NULL, 0, (char *) NULL, (char *) NULL, 0 }; static struct log_entry def_log_entry; /* * These macros define any special processing that needs to happen for * devices. For unix, of course, this is hardly anything. */ #define DEVICE_OPEN(d, m) fopen(d, m) #define CONSOLE_OPEN(m) fopen("/dev/console", m) #define DEVICE_PRINT(f, m) ((fprintf(f, "%s\r\n", m) >= 0) ? \ (fflush(f), 0) : \ -1) #define DEVICE_CLOSE(d) fclose(d) /* * klog_rotate() - roate a log file if we have specified rotation * parameters in krb5.conf. */ static void klog_rotate(struct log_entry *le) { time_t t; int i; char *name_buf1; char *name_buf2; char *old_name; char *new_name; char *tmp; FILE *fp; int num_vers; mode_t old_umask; /* * By default we don't rotate. */ if (le->lfu_rotate_period == K_LOG_DEF_FILE_ROTATE_PERIOD) return; t = time(0); if (t >= le->lfu_last_rotated + le->lfu_rotate_period) { /* * The N log file versions will be renamed X.N-1 X.N-2, ... X.0. * So the allocate file name buffers that can the version * number extensions. * 32 extra bytes is plenty. */ name_buf1 = malloc(strlen(le->lfu_fname) + 32); if (name_buf1 == NULL) return; name_buf2 = malloc(strlen(le->lfu_fname) + 32); if (name_buf2 == NULL) { free(name_buf1); return; } old_name = name_buf1; new_name = name_buf2; /* * If there N versions, then the first one has file extension * of N-1. */ (void) sprintf(new_name, "%s.%d", le->lfu_fname, le->lfu_rotate_versions - 1); /* * Rename file.N-2 to file.N-1, file.N-3 to file.N-2, ... * file.0 to file.1 */ for (i = le->lfu_rotate_versions - 1; i > 0; i--) { (void) sprintf(old_name, "%s.%d", le->lfu_fname, i - 1); (void) rename(old_name, new_name); /* * swap old name and new name. This way, * on the next iteration, new_name.X * becomes new_name.X-1. */ tmp = old_name; old_name = new_name; new_name = tmp; } old_name = le->lfu_fname; (void) rename(old_name, new_name); /* * Even though we don't know yet if the fopen() * of the log file will succeed, we mark the log * as rotated. This is so we don't repeatably * rotate file.N-2 to file.N-1 ... etc without * waiting for the rotate period to elapse. */ le->lfu_last_rotated = t; /* * Default log file creation mode should be read-only * by owner(root), but the admin can override with * chmod(1) if desired. */ old_umask = umask(077); fp = fopen(old_name, le->lfu_fopen_mode); umask(old_umask); if (fp != NULL) { (void) fclose(le->lfu_filep); le->lfu_filep = fp; /* * If the version parameter in krb5.conf was * 0, then we take this to mean that rotating the * log file will cause us to dispose of the * old one, and created a new one. We have just * renamed the old one to file.-1, so remove it. */ if (le->lfu_rotate_versions <= 0) (void) unlink(new_name); } else { fprintf(stderr, gettext("During rotate, couldn't open log file %s: %s\n"), old_name, error_message(errno)); /* * Put it back. */ (void) rename(new_name, old_name); } free(name_buf1); free(name_buf2); } } /* * klog_com_err_proc() - Handle com_err(3) messages as specified by the * profile. */ static krb5_context err_context; static void klog_com_err_proc(const char *whoami, long code, const char *format, va_list ap) { char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; int lindex; const char *actual_format; #ifdef HAVE_SYSLOG int log_pri = -1; #endif /* HAVE_SYSLOG */ char *cp; char *syslogp; /* Make the header */ sprintf(outbuf, "%s: ", whoami); /* * Squirrel away address after header for syslog since syslog makes * a header */ syslogp = &outbuf[strlen(outbuf)]; /* If reporting an error message, separate it. */ if (code) { /* Solaris Kerberos */ const char *emsg; outbuf[sizeof(outbuf) - 1] = '\0'; emsg = krb5_get_error_message (err_context, code); strncat(outbuf, emsg, sizeof(outbuf) - 1 - strlen(outbuf)); strncat(outbuf, " - ", sizeof(outbuf) - 1 - strlen(outbuf)); krb5_free_error_message(err_context, emsg); } cp = &outbuf[strlen(outbuf)]; actual_format = format; #ifdef HAVE_SYSLOG /* * This is an unpleasant hack. If the first character is less than * 8, then we assume that it is a priority. * * Since it is not guaranteed that there is a direct mapping between * syslog priorities (e.g. Ultrix and old BSD), we resort to this * intermediate representation. */ if ((((unsigned char) *format) > 0) && (((unsigned char) *format) <= 8)) { actual_format = (format + 1); switch ((unsigned char) *format) { #ifdef LOG_EMERG case 1: log_pri = LOG_EMERG; break; #endif /* LOG_EMERG */ #ifdef LOG_ALERT case 2: log_pri = LOG_ALERT; break; #endif /* LOG_ALERT */ #ifdef LOG_CRIT case 3: log_pri = LOG_CRIT; break; #endif /* LOG_CRIT */ default: case 4: log_pri = LOG_ERR; break; #ifdef LOG_WARNING case 5: log_pri = LOG_WARNING; break; #endif /* LOG_WARNING */ #ifdef LOG_NOTICE case 6: log_pri = LOG_NOTICE; break; #endif /* LOG_NOTICE */ #ifdef LOG_INFO case 7: log_pri = LOG_INFO; break; #endif /* LOG_INFO */ #ifdef LOG_DEBUG case 8: log_pri = LOG_DEBUG; break; #endif /* LOG_DEBUG */ } } #endif /* HAVE_SYSLOG */ /* Now format the actual message */ #if HAVE_VSNPRINTF vsnprintf(cp, sizeof(outbuf) - (cp - outbuf), actual_format, ap); #elif HAVE_VSPRINTF vsprintf(cp, actual_format, ap); #else /* HAVE_VSPRINTF */ sprintf(cp, actual_format, ((int *) ap)[0], ((int *) ap)[1], ((int *) ap)[2], ((int *) ap)[3], ((int *) ap)[4], ((int *) ap)[5]); #endif /* HAVE_VSPRINTF */ /* * Now that we have the message formatted, perform the output to each * logging specification. */ for (lindex = 0; lindex < log_control.log_nentries; lindex++) { switch (log_control.log_entries[lindex].log_type) { case K_LOG_FILE: klog_rotate(&log_control.log_entries[lindex]); /*FALLTHRU*/ case K_LOG_STDERR: /* * Files/standard error. */ if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n", outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR), whoami, log_control.log_entries[lindex].lfu_fname); } else { fflush(log_control.log_entries[lindex].lfu_filep); } break; case K_LOG_CONSOLE: case K_LOG_DEVICE: /* * Devices (may need special handling) */ if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR), whoami, log_control.log_entries[lindex].ldu_devname); } break; #ifdef HAVE_SYSLOG case K_LOG_SYSLOG: /* * System log. */ /* * If we have specified a priority through our hackery, then * use it, otherwise use the default. */ if (log_pri >= 0) log_pri |= log_control.log_entries[lindex].lsu_facility; else log_pri = log_control.log_entries[lindex].lsu_facility | log_control.log_entries[lindex].lsu_severity; /* Log the message with our header trimmed off */ syslog(log_pri, "%s", syslogp); break; #endif /* HAVE_SYSLOG */ default: break; } } } /* * krb5_klog_init() - Initialize logging. * * This routine parses the syntax described above to specify destinations for * com_err(3) or krb5_klog_syslog() messages generated by the caller. * * Parameters: * kcontext - Kerberos context. * ename - Entity name as it is to appear in the profile. * whoami - Entity name as it is to appear in error output. * do_com_err - Take over com_err(3) processing. * * Implicit inputs: * stderr - This is where STDERR output goes. * * Implicit outputs: * log_nentries - Number of log entries, both valid and invalid. * log_control - List of entries (log_nentries long) which contains * data for klog_com_err_proc() to use to determine * where/how to send output. */ krb5_error_code krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do_com_err) { const char *logging_profent[3]; const char *logging_defent[3]; char **logging_specs; int i, ngood; char *cp, *cp2; char savec = '\0'; int error; int do_openlog, log_facility; FILE *f; mode_t old_umask; /* Initialize */ do_openlog = 0; log_facility = 0; err_context = kcontext; /* * Look up [logging]-> in the profile. If that doesn't * succeed, then look for [logging]->default. */ logging_profent[0] = "logging"; logging_profent[1] = ename; logging_profent[2] = (char *) NULL; logging_defent[0] = "logging"; logging_defent[1] = "default"; logging_defent[2] = (char *) NULL; logging_specs = (char **) NULL; ngood = 0; log_control.log_nentries = 0; if (!profile_get_values(kcontext->profile, logging_profent, &logging_specs) || !profile_get_values(kcontext->profile, logging_defent, &logging_specs)) { /* * We have a match, so we first count the number of elements */ for (log_control.log_nentries = 0; logging_specs[log_control.log_nentries]; log_control.log_nentries++); /* * Now allocate our structure. */ log_control.log_entries = (struct log_entry *) malloc(log_control.log_nentries * sizeof(struct log_entry)); if (log_control.log_entries) { /* * Scan through the list. */ for (i=0; i * so, trim off the leading and trailing whitespace here. */ for (cp = logging_specs[i]; isspace((int) *cp); cp++); for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1]; isspace((int) *cp2); cp2--); cp2++; *cp2 = '\0'; /* * Is this a file? */ if (!strncasecmp(cp, "FILE", 4)) { /* * Check for append/overwrite, then open the file. */ if (cp[4] == ':' || cp[4] == '=') { log_control.log_entries[i].lfu_fopen_mode = (cp[4] == ':') ? "a+F" : "wF"; old_umask = umask(077); f = fopen(&cp[5], log_control.log_entries[i].lfu_fopen_mode); umask(old_umask); if (f) { char rotate_kw[128]; log_control.log_entries[i].lfu_filep = f; log_control.log_entries[i].log_type = K_LOG_FILE; log_control.log_entries[i].lfu_fname = &cp[5]; log_control.log_entries[i].lfu_rotate_period = K_LOG_DEF_FILE_ROTATE_PERIOD; log_control.log_entries[i].lfu_rotate_versions = K_LOG_DEF_FILE_ROTATE_VERSIONS; log_control.log_entries[i].lfu_last_rotated = time(0); /* * Now parse for ename_"rotate" = { * period = XXX * versions = 10 * } */ if (strlen(ename) + strlen("_rotate") < sizeof (rotate_kw)) { char *time; krb5_deltat dt; int vers; strcpy(rotate_kw, ename); strcat(rotate_kw, "_rotate"); if (!profile_get_string(kcontext->profile, "logging", rotate_kw, "period", NULL, &time)) { if (time != NULL) { if (!krb5_string_to_deltat(time, &dt)) { log_control.log_entries[i].lfu_rotate_period = (time_t) dt; } free(time); } } if (!profile_get_integer( kcontext->profile, "logging", rotate_kw, "versions", K_LOG_DEF_FILE_ROTATE_VERSIONS, &vers)) { log_control.log_entries[i].lfu_rotate_versions = vers; } } } else { fprintf(stderr, gettext("Couldn't open log file %s: %s\n"), &cp[5], error_message(errno)); continue; } } } #ifdef HAVE_SYSLOG /* * Is this a syslog? */ else if (!strncasecmp(cp, "SYSLOG", 6)) { error = 0; log_control.log_entries[i].lsu_facility = LOG_AUTH; log_control.log_entries[i].lsu_severity = LOG_ERR; /* * Is there a severify specified? */ if (cp[6] == ':') { /* * Find the end of the severity. */ cp2 = strchr(&cp[7], ':'); if (cp2) { savec = *cp2; *cp2 = '\0'; cp2++; } /* * Match a severity. */ if (!strcasecmp(&cp[7], "ERR")) { log_control.log_entries[i].lsu_severity = LOG_ERR; } #ifdef LOG_EMERG else if (!strcasecmp(&cp[7], "EMERG")) { log_control.log_entries[i].lsu_severity = LOG_EMERG; } #endif /* LOG_EMERG */ #ifdef LOG_ALERT else if (!strcasecmp(&cp[7], "ALERT")) { log_control.log_entries[i].lsu_severity = LOG_ALERT; } #endif /* LOG_ALERT */ #ifdef LOG_CRIT else if (!strcasecmp(&cp[7], "CRIT")) { log_control.log_entries[i].lsu_severity = LOG_CRIT; } #endif /* LOG_CRIT */ #ifdef LOG_WARNING else if (!strcasecmp(&cp[7], "WARNING")) { log_control.log_entries[i].lsu_severity = LOG_WARNING; } #endif /* LOG_WARNING */ #ifdef LOG_NOTICE else if (!strcasecmp(&cp[7], "NOTICE")) { log_control.log_entries[i].lsu_severity = LOG_NOTICE; } #endif /* LOG_NOTICE */ #ifdef LOG_INFO else if (!strcasecmp(&cp[7], "INFO")) { log_control.log_entries[i].lsu_severity = LOG_INFO; } #endif /* LOG_INFO */ #ifdef LOG_DEBUG else if (!strcasecmp(&cp[7], "DEBUG")) { log_control.log_entries[i].lsu_severity = LOG_DEBUG; } #endif /* LOG_DEBUG */ else error = 1; /* * If there is a facility present, then parse that. */ if (cp2) { if (!strcasecmp(cp2, "AUTH")) { log_control.log_entries[i].lsu_facility = LOG_AUTH; } else if (!strcasecmp(cp2, "KERN")) { log_control.log_entries[i].lsu_facility = LOG_KERN; } else if (!strcasecmp(cp2, "USER")) { log_control.log_entries[i].lsu_facility = LOG_USER; } else if (!strcasecmp(cp2, "MAIL")) { log_control.log_entries[i].lsu_facility = LOG_MAIL; } else if (!strcasecmp(cp2, "DAEMON")) { log_control.log_entries[i].lsu_facility = LOG_DAEMON; } else if (!strcasecmp(cp2, "LPR")) { log_control.log_entries[i].lsu_facility = LOG_LPR; } else if (!strcasecmp(cp2, "NEWS")) { log_control.log_entries[i].lsu_facility = LOG_NEWS; } else if (!strcasecmp(cp2, "UUCP")) { log_control.log_entries[i].lsu_facility = LOG_UUCP; } else if (!strcasecmp(cp2, "CRON")) { log_control.log_entries[i].lsu_facility = LOG_CRON; } else if (!strcasecmp(cp2, "LOCAL0")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL0; } else if (!strcasecmp(cp2, "LOCAL1")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL1; } else if (!strcasecmp(cp2, "LOCAL2")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL2; } else if (!strcasecmp(cp2, "LOCAL3")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL3; } else if (!strcasecmp(cp2, "LOCAL4")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL4; } else if (!strcasecmp(cp2, "LOCAL5")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL5; } else if (!strcasecmp(cp2, "LOCAL6")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL6; } else if (!strcasecmp(cp2, "LOCAL7")) { log_control.log_entries[i].lsu_facility = LOG_LOCAL7; } cp2--; *cp2 = savec; } } if (!error) { log_control.log_entries[i].log_type = K_LOG_SYSLOG; do_openlog = 1; log_facility = log_control.log_entries[i].lsu_facility; } } #endif /* HAVE_SYSLOG */ /* * Is this a standard error specification? */ else if (!strcasecmp(cp, "STDERR")) { log_control.log_entries[i].lfu_filep = fdopen(fileno(stderr), "a+F"); if (log_control.log_entries[i].lfu_filep) { log_control.log_entries[i].log_type = K_LOG_STDERR; log_control.log_entries[i].lfu_fname = "standard error"; } } /* * Is this a specification of the console? */ else if (!strcasecmp(cp, "CONSOLE")) { log_control.log_entries[i].ldu_filep = CONSOLE_OPEN("a+F"); if (log_control.log_entries[i].ldu_filep) { log_control.log_entries[i].log_type = K_LOG_CONSOLE; log_control.log_entries[i].ldu_devname = "console"; } } /* * Is this a specification of a device? */ else if (!strncasecmp(cp, "DEVICE", 6)) { /* * We handle devices very similarly to files. */ if (cp[6] == '=') { log_control.log_entries[i].ldu_filep = DEVICE_OPEN(&cp[7], "wF"); if (log_control.log_entries[i].ldu_filep) { log_control.log_entries[i].log_type = K_LOG_DEVICE; log_control.log_entries[i].ldu_devname = &cp[7]; } } } /* * See if we successfully parsed this specification. */ if (log_control.log_entries[i].log_type == K_LOG_NONE) { fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_1), whoami, cp); fprintf(stderr, krb5_log_error_table(LSPEC_PARSE_ERR_2), whoami); } else ngood++; } } /* * If we didn't find anything, then free our lists. */ if (ngood == 0) { for (i=0; ilog_type = K_LOG_SYSLOG; log_control.log_entries->log_2free = (krb5_pointer) NULL; log_facility = log_control.log_entries->lsu_facility = LOG_AUTH; log_control.log_entries->lsu_severity = LOG_ERR; do_openlog = 1; log_control.log_nentries = 1; } if (log_control.log_nentries) { log_control.log_whoami = (char *) malloc(strlen(whoami)+1); if (log_control.log_whoami) strcpy(log_control.log_whoami, whoami); log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN + 1); if (log_control.log_hostname) { gethostname(log_control.log_hostname, MAXHOSTNAMELEN); log_control.log_hostname[MAXHOSTNAMELEN] = '\0'; } #ifdef HAVE_OPENLOG if (do_openlog) { openlog(whoami, LOG_NDELAY|LOG_PID, log_facility); log_control.log_opened = 1; } #endif /* HAVE_OPENLOG */ if (do_com_err) (void) set_com_err_hook(klog_com_err_proc); } return((log_control.log_nentries) ? 0 : ENOENT); } /* * krb5_klog_close() - Close the logging context and free all data. */ void krb5_klog_close(krb5_context kcontext) { int lindex; (void) reset_com_err_hook(); for (lindex = 0; lindex < log_control.log_nentries; lindex++) { switch (log_control.log_entries[lindex].log_type) { case K_LOG_FILE: case K_LOG_STDERR: /* * Files/standard error. */ fclose(log_control.log_entries[lindex].lfu_filep); break; case K_LOG_CONSOLE: case K_LOG_DEVICE: /* * Devices (may need special handling) */ DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep); break; #ifdef HAVE_SYSLOG case K_LOG_SYSLOG: /* * System log. */ break; #endif /* HAVE_SYSLOG */ default: break; } if (log_control.log_entries[lindex].log_2free) free(log_control.log_entries[lindex].log_2free); } if (log_control.log_entries != &def_log_entry) free(log_control.log_entries); log_control.log_entries = (struct log_entry *) NULL; log_control.log_nentries = 0; if (log_control.log_whoami) free(log_control.log_whoami); log_control.log_whoami = (char *) NULL; if (log_control.log_hostname) free(log_control.log_hostname); log_control.log_hostname = (char *) NULL; #ifdef HAVE_CLOSELOG if (log_control.log_opened) closelog(); #endif /* HAVE_CLOSELOG */ } /* * severity2string() - Convert a severity to a string. */ static const char * severity2string(int severity) { int s; const char *ss; s = severity & LOG_PRIMASK; ss = krb5_log_error_table(LOG_UFO_STRING); switch (s) { #ifdef LOG_EMERG case LOG_EMERG: ss = krb5_log_error_table(LOG_EMERG_STRING); break; #endif /* LOG_EMERG */ #ifdef LOG_ALERT case LOG_ALERT: ss = krb5_log_error_table(LOG_ALERT_STRING); break; #endif /* LOG_ALERT */ #ifdef LOG_CRIT case LOG_CRIT: ss = krb5_log_error_table(LOG_CRIT_STRING); break; #endif /* LOG_CRIT */ case LOG_ERR: ss = krb5_log_error_table(LOG_ERR_STRING); break; #ifdef LOG_WARNING case LOG_WARNING: ss = krb5_log_error_table(LOG_WARNING_STRING); break; #endif /* LOG_WARNING */ #ifdef LOG_NOTICE case LOG_NOTICE: ss = krb5_log_error_table(LOG_NOTICE_STRING); break; #endif /* LOG_NOTICE */ #ifdef LOG_INFO case LOG_INFO: ss = krb5_log_error_table(LOG_INFO_STRING); break; #endif /* LOG_INFO */ #ifdef LOG_DEBUG case LOG_DEBUG: ss = krb5_log_error_table(LOG_DEBUG_STRING); break; #endif /* LOG_DEBUG */ } return((char *) ss); } /* * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while * also performing the logging redirection as specified * by krb5_klog_init(). */ static int klog_vsyslog(int priority, const char *format, va_list arglist) { char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; int lindex; char *syslogp; char *cp; time_t now; #ifdef HAVE_STRFTIME size_t soff; #endif /* HAVE_STRFTIME */ /* * Format a syslog-esque message of the format: * * (verbose form) * [](): * * (short form) * */ cp = outbuf; (void) time(&now); #ifdef HAVE_STRFTIME /* * Format the date: mon dd hh:mm:ss */ soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", localtime(&now)); if (soff > 0) cp += soff; else return(-1); #else /* HAVE_STRFTIME */ /* * Format the date: * We ASSUME here that the output of ctime is of the format: * dow mon dd hh:mm:ss tzs yyyy\n * 012345678901234567890123456789 */ strncpy(outbuf, ctime(&now) + 4, 15); cp += 15; #endif /* HAVE_STRFTIME */ #ifdef VERBOSE_LOGS sprintf(cp, " %s %s[%ld](%s): ", log_control.log_hostname, log_control.log_whoami, (long) getpid(), severity2string(priority)); #else sprintf(cp, " "); #endif syslogp = &outbuf[strlen(outbuf)]; /* Now format the actual message */ #ifdef HAVE_VSNPRINTF vsnprintf(syslogp, sizeof(outbuf) - (syslogp - outbuf), format, arglist); #elif HAVE_VSPRINTF vsprintf(syslogp, format, arglist); #else /* HAVE_VSPRINTF */ sprintf(syslogp, format, ((int *) arglist)[0], ((int *) arglist)[1], ((int *) arglist)[2], ((int *) arglist)[3], ((int *) arglist)[4], ((int *) arglist)[5]); #endif /* HAVE_VSPRINTF */ /* * If the user did not use krb5_klog_init() instead of dropping * the request on the floor, syslog it - if it exists */ #ifdef HAVE_SYSLOG if (log_control.log_nentries == 0) { /* Log the message with our header trimmed off */ syslog(priority, "%s", syslogp); } #endif /* * Now that we have the message formatted, perform the output to each * logging specification. */ for (lindex = 0; lindex < log_control.log_nentries; lindex++) { switch (log_control.log_entries[lindex].log_type) { case K_LOG_FILE: klog_rotate(&log_control.log_entries[lindex]); /*FALLTHRU*/ case K_LOG_STDERR: /* * Files/standard error. */ if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n", outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_FILE_ERR), log_control.log_whoami, log_control.log_entries[lindex].lfu_fname); } else { fflush(log_control.log_entries[lindex].lfu_filep); } break; case K_LOG_CONSOLE: case K_LOG_DEVICE: /* * Devices (may need special handling) */ if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, outbuf) < 0) { /* Attempt to report error */ fprintf(stderr, krb5_log_error_table(LOG_DEVICE_ERR), log_control.log_whoami, log_control.log_entries[lindex].ldu_devname); } break; #ifdef HAVE_SYSLOG case K_LOG_SYSLOG: /* * System log. */ /* Log the message with our header trimmed off */ syslog(priority, "%s", syslogp); break; #endif /* HAVE_SYSLOG */ default: break; } } return(0); } int krb5_klog_syslog(int priority, const char *format, ...) { int retval; va_list pvar; va_start(pvar, format); retval = klog_vsyslog(priority, format, pvar); va_end(pvar); return(retval); } /* * krb5_klog_reopen() - Close and reopen any open (non-syslog) log files. * This function is called when a SIGHUP is received * so that external log-archival utilities may * alert the Kerberos daemons that they should get * a new file descriptor for the give filename. */ void krb5_klog_reopen(krb5_context kcontext) { int lindex; FILE *f; /* * Only logs which are actually files need to be closed * and reopened in response to a SIGHUP */ for (lindex = 0; lindex < log_control.log_nentries; lindex++) { if (log_control.log_entries[lindex].log_type == K_LOG_FILE) { fclose(log_control.log_entries[lindex].lfu_filep); /* * In case the old logfile did not get moved out of the * way, open for append to prevent squashing the old logs. */ f = fopen(log_control.log_entries[lindex].lfu_fname, "a+F"); if (f) { log_control.log_entries[lindex].lfu_filep = f; } else { fprintf(stderr, "Couldn't open log file %s: %s\n", log_control.log_entries[lindex].lfu_fname, error_message(errno)); } } } } /* * Solaris Kerberos: * Switch the current context to the one supplied */ void krb5_klog_set_context(krb5_context context) { err_context = context; } /* * Solaris Kerberos: * Return a string representation of "facility" */ static const char * facility2string(int facility) { switch (facility) { case (LOG_AUTH): return ("AUTH"); case (LOG_KERN): return ("KERN"); case (LOG_USER): return ("USER"); case (LOG_MAIL): return ("MAIL"); case (LOG_DAEMON): return ("DAEMON"); case (LOG_LPR): return ("LPR"); case (LOG_NEWS): return ("NEWS"); case (LOG_UUCP): return ("UUCP"); case (LOG_CRON): return ("CRON"); case (LOG_LOCAL0): return ("LOCAL0"); case (LOG_LOCAL1): return ("LOCAL1"); case (LOG_LOCAL2): return ("LOCAL2"); case (LOG_LOCAL3): return ("LOCAL3"); case (LOG_LOCAL4): return ("LOCAL4"); case (LOG_LOCAL5): return ("LOCAL6"); case (LOG_LOCAL7): return ("LOCAL7"); } return ("UNKNOWN"); } /* * Solaris Kerberos: * Print to stderr where logging is being done */ krb5_error_code krb5_klog_list_logs(const char *whoami) { int lindex; fprintf(stderr, gettext("%s: logging to "), whoami); for (lindex = 0; lindex < log_control.log_nentries; lindex++) { if (lindex != 0 && log_control.log_entries[lindex].log_type != K_LOG_NONE) fprintf(stderr, ", "); switch (log_control.log_entries[lindex].log_type) { case K_LOG_FILE: fprintf(stderr, "FILE=%s", log_control.log_entries[lindex].lfu_fname); break; case K_LOG_STDERR: fprintf(stderr, "STDERR"); break; case K_LOG_CONSOLE: fprintf(stderr, "CONSOLE"); break; case K_LOG_DEVICE: fprintf(stderr, "DEVICE=%s", log_control.log_entries[lindex].ldu_devname); break; case K_LOG_SYSLOG: fprintf(stderr, "SYSLOG=%s:%s", severity2string(log_control.log_entries[lindex].lsu_severity), facility2string(log_control.log_entries[lindex].lsu_facility)); break; case K_LOG_NONE: break; default: /* Should never get here */ return (-1); } } fprintf(stderr, "\n"); return (0); } /* * Solaris Kerberos: * Add logging to stderr. */ krb5_error_code krb5_klog_add_stderr() { struct log_entry *tmp_log_entries = log_control.log_entries; int i; if (log_control.log_entries != &def_log_entry) { log_control.log_entries = realloc(log_control.log_entries, (log_control.log_nentries + 1) * sizeof(struct log_entry)); if (log_control.log_entries == NULL) { log_control.log_entries = tmp_log_entries; return (ENOMEM); } } else { log_control.log_entries = malloc(2 * sizeof(struct log_entry)); if (log_control.log_entries == NULL) { log_control.log_entries = &def_log_entry; return (ENOMEM); } (void) memcpy(&log_control.log_entries[0], &def_log_entry, sizeof(struct log_entry)); } i = log_control.log_nentries; if (log_control.log_entries[i].lfu_filep = fdopen(fileno(stderr), "a+F")) { log_control.log_entries[i].log_type = K_LOG_STDERR; log_control.log_entries[i].log_2free = NULL; log_control.log_entries[i].lfu_fname = "standard error"; log_control.log_nentries++; } else { /* Free the alloc'ed extra entry */ int err = errno; tmp_log_entries = log_control.log_entries; log_control.log_entries = realloc(log_control.log_entries, (log_control.log_nentries) * sizeof(struct log_entry)); if (log_control.log_entries == NULL) log_control.log_entries = tmp_log_entries; return (err); } return (0); } /* * Solaris Kerberos * Remove logging to stderr. */ void krb5_klog_remove_stderr() { struct log_entry *tmp_log_entries = log_control.log_entries; int i; /* Find the entry (if it exists) */ for (i = 0; i < log_control.log_nentries; i++) { if (log_control.log_entries[i].log_type == K_LOG_STDERR) { break; } } if ( i < log_control.log_nentries) { for (; i < log_control.log_nentries - 1; i++) log_control.log_entries[i] = log_control.log_entries[i + 1]; if (log_control.log_nentries > 1) { log_control.log_entries = realloc(log_control.log_entries, (log_control.log_nentries + 1) * sizeof(struct log_entry)); if (log_control.log_entries != NULL) log_control.log_nentries--; else log_control.log_entries = tmp_log_entries; } else { if (log_control.log_entries != NULL) free(log_control.log_entries); } } } /* Solaris Kerberos: Indicate if currently logging to stderr */ krb5_boolean krb5_klog_logging_to_stderr() { int i; /* Find the entry (if it exists) */ for (i = 0; i < log_control.log_nentries; i++) { if (log_control.log_entries[i].log_type == K_LOG_STDERR) { return (TRUE); } } return (FALSE); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # # Due to mistakes made early in the history of this library, there are # no SUNW_1.1 symbols, but the version is now kept as a placeholder. # Don't add any symbols to this version. $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { global: SUNW_1.1; }; SYMBOL_VERSION SUNWprivate_1.1 { global: __kadm5_get_priv; _kadm5_get_kpasswd_protocol; adb_policy_close; adb_policy_init; destroy_dict; find_word; handle_chpw; hist_db { ASSERT = { TYPE = OBJECT; SIZE = 68; }; }; hist_key { ASSERT = { TYPE = OBJECT; SIZE = 28; }; }; hist_kvno { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; hist_princ { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; init_dict; kadm5_check_min_life; kadm5_chpass_principal; kadm5_chpass_principal_3; kadm5_chpass_principal_util; kadm5_create_policy; kadm5_create_policy_internal; kadm5_create_principal; kadm5_create_principal_3; kadm5_decrypt_key; kadm5_delete_policy; kadm5_delete_principal; kadm5_destroy; kadm5_flush; kadm5_free_config_params; kadm5_free_name_list; kadm5_free_policy_ent; kadm5_free_principal_ent; kadm5_get_adm_host_srv_name; kadm5_get_config_params; kadm5_get_cpw_host_srv_name; kadm5_get_kiprop_host_srv_name; kadm5_get_master; kadm5_get_policies; kadm5_get_policy; kadm5_get_principal; kadm5_get_principals; kadm5_get_privs; kadm5_init2; kadm5_init; kadm5_init_iprop; kadm5_init_krb5_context; kadm5_init_with_creds; kadm5_init_with_password; kadm5_is_master; kadm5_lock; kadm5_modify_policy; kadm5_modify_policy_internal; kadm5_modify_principal; kadm5_randkey_principal; kadm5_randkey_principal_3; kadm5_rename_principal; kadm5_setkey_principal; kadm5_setkey_principal_3; kadm5_unlock; kadm5int_acl_check; kadm5int_acl_finish; kadm5int_acl_impose_restrictions; kadm5int_acl_init; kadm5_init_with_skey; kdb_delete_entry; kdb_free_entry; kdb_get_entry; kdb_init_hist; kdb_init_master; kdb_iter_entry; kdb_put_entry; krb5_aprof_finish; krb5_aprof_get_boolean; krb5_aprof_get_deltat; krb5_aprof_get_int32; krb5_aprof_get_string; krb5_aprof_getvals; krb5_aprof_init; krb5_copy_key_data_contents; krb5_flags_to_string; krb5_free_key_data_contents; krb5_free_realm_params; krb5_input_flag_to_string; krb5_keysalt_is_present; krb5_keysalt_iterate; krb5_klog_add_stderr; krb5_klog_close; krb5_klog_init; krb5_klog_list_logs; krb5_klog_logging_to_stderr; krb5_klog_remove_stderr; krb5_klog_reopen; krb5_klog_set_context; krb5_klog_syslog; krb5_read_realm_params; krb5_string_to_flags; krb5_string_to_keysalts; master_db { ASSERT = { TYPE = OBJECT; SIZE = 68; }; }; master_princ { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; osa_free_princ_ent; passwd_check; trunc_name; xdr_chpass3_arg; xdr_chpass_arg; xdr_chrand3_arg; xdr_chrand_arg; xdr_chrand_ret; xdr_cpol_arg; xdr_cprinc3_arg; xdr_cprinc_arg; xdr_dpol_arg; xdr_dprinc_arg; xdr_generic_ret; xdr_getprivs_ret; xdr_gpol_arg; xdr_gpol_ret; xdr_gpols_arg; xdr_gpols_ret; xdr_gprinc_arg; xdr_gprinc_ret; xdr_gprincs_arg; xdr_gprincs_ret; xdr_kadm5_policy_ent_rec; xdr_kadm5_principal_ent_rec; xdr_kadm5_principal_ent_rec_v1; xdr_kadm5_ret_t; xdr_krb5_deltat; xdr_krb5_enctype; xdr_krb5_flags; xdr_krb5_int16; xdr_krb5_key_data; xdr_krb5_key_data_nocontents; xdr_krb5_key_salt_tuple; xdr_krb5_keyblock; xdr_krb5_kvno; xdr_krb5_octet; xdr_krb5_principal; xdr_krb5_salttype; xdr_krb5_timestamp; xdr_krb5_tl_data; xdr_krb5_ui_2; xdr_krb5_ui_4; xdr_mpol_arg; xdr_mprinc_arg; xdr_nullstring; xdr_nulltype; xdr_osa_princ_ent_rec; xdr_osa_pw_hist_ent; xdr_rprinc_arg; xdr_setkey3_arg; xdr_setkey_arg; xdr_ui_4; xdralloc_create; xdralloc_getdata; xdralloc_release; local: *; }; /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * kadmin/v5server/srv_acl.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * srv_acl.c - Handle Kerberos ACL related functions. */ #include #include #include #include "k5-int.h" #include #include #include #include /* SUNWresync121 XXX */ #include "server_acl.h" #include #include /* SUNWresync121 XXX */ typedef struct _acl_op_table { char ao_op; krb5_int32 ao_mask; } aop_t; typedef struct _acl_entry { struct _acl_entry *ae_next; char *ae_name; krb5_boolean ae_name_bad; krb5_principal ae_principal; krb5_int32 ae_op_allowed; char *ae_target; krb5_boolean ae_target_bad; krb5_principal ae_target_princ; char *ae_restriction_string; /* eg: "-maxlife 3h -service +proxiable" */ krb5_boolean ae_restriction_bad; restriction_t *ae_restrictions; } aent_t; static const aop_t acl_op_table[] = { { 'a', ACL_ADD }, { 'd', ACL_DELETE }, { 'm', ACL_MODIFY }, { 'c', ACL_CHANGEPW }, { 'i', ACL_INQUIRE }, { 'l', ACL_LIST }, { 'p', ACL_IPROP }, /* SUNW IProp */ { 's', ACL_SETKEY }, { 'u', ACL_MIGRATE }, /* pam_krb5_migrate */ { 'x', ACL_ALL_MASK }, { '*', ACL_ALL_MASK }, { '\0', 0 } }; typedef struct _wildstate { int nwild; krb5_data *backref[9]; } wildstate_t; static aent_t *acl_list_head = (aent_t *) NULL; static aent_t *acl_list_tail = (aent_t *) NULL; static const char *acl_acl_file = (char *) NULL; static int acl_inited = 0; static int acl_debug_level = 0; /* * This is the catchall entry. If nothing else appropriate is found, or in * the case where the ACL file is not present, this entry controls what can * be done. */ static const char *acl_catchall_entry = NULL; /* Solaris Kerberos */ #define ACL_LINE2LONG_MSG dgettext(TEXT_DOMAIN, \ "%s: line %d too long, truncated\n") #define ACL_OP_BAD_MSG dgettext(TEXT_DOMAIN, \ "Unrecognized ACL operation '%c' in %s\n") #define ACL_SYN_ERR_MSG dgettext(TEXT_DOMAIN, \ "%s: syntax error at line %d <%10s...>\n") #define ACL_CANTOPEN_MSG dgettext(TEXT_DOMAIN, \ "\007cannot open ACL file") /* * kadm5int_acl_get_line() - Get a line from the ACL file. * Lines ending with \ are continued on the next line */ static char * kadm5int_acl_get_line(fp, lnp) FILE *fp; int *lnp; /* caller should set to 1 before first call */ { int i, domore; static int line_incr = 0; static char acl_buf[BUFSIZ]; *lnp += line_incr; line_incr = 0; for (domore = 1; domore && !feof(fp); ) { /* Copy in the line, with continuations */ for (i=0; ((i < sizeof acl_buf) && !feof(fp)); i++ ) { acl_buf[i] = fgetc(fp); if (acl_buf[i] == (char)EOF) { if (i > 0 && acl_buf[i-1] == '\\') i--; break; /* it gets nulled-out below */ } else if (acl_buf[i] == '\n') { if (i == 0 || acl_buf[i-1] != '\\') break; /* empty line or normal end of line */ else { i -= 2; /* back up over "\\\n" and continue */ line_incr++; } } } /* Check if we exceeded our buffer size */ if (i == sizeof acl_buf && (i--, !feof(fp))) { int c1 = acl_buf[i], c2; krb5_klog_syslog(LOG_ERR, ACL_LINE2LONG_MSG, acl_acl_file, *lnp); while ((c2 = fgetc(fp)) != EOF) { if (c2 == '\n') { if (c1 != '\\') break; line_incr++; } c1 = c2; } } acl_buf[i] = '\0'; if (acl_buf[0] == (char) EOF) /* ptooey */ acl_buf[0] = '\0'; else line_incr++; if ((acl_buf[0] != '#') && (acl_buf[0] != '\0')) domore = 0; } if (domore || (strlen(acl_buf) == 0)) return((char *) NULL); else return(acl_buf); } /* * kadm5int_acl_parse_line() - Parse the contents of an ACL line. */ static aent_t * kadm5int_acl_parse_line(lp) const char *lp; { static char acle_principal[BUFSIZ]; static char acle_ops[BUFSIZ]; static char acle_object[BUFSIZ]; static char acle_restrictions[BUFSIZ]; aent_t *acle; char *op; int t, found, opok, nmatch; DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_parse_line(line=%20s)\n", lp)); /* * Format is still simple: * entry ::= [] * [ [ * []]] */ acle = (aent_t *) NULL; acle_object[0] = '\0'; nmatch = sscanf(lp, "%s %s %s %[^\n]", acle_principal, acle_ops, acle_object, acle_restrictions); if (nmatch >= 2) { acle = (aent_t *) malloc(sizeof(aent_t)); if (acle) { acle->ae_next = (aent_t *) NULL; acle->ae_op_allowed = (krb5_int32) 0; acle->ae_target = (nmatch >= 3) ? strdup(acle_object) : (char *) NULL; acle->ae_target_bad = 0; acle->ae_target_princ = (krb5_principal) NULL; opok = 1; for (op=acle_ops; *op; op++) { char rop; rop = (isupper((unsigned char) *op)) ? tolower((unsigned char) *op) : *op; found = 0; for (t=0; acl_op_table[t].ao_op; t++) { if (rop == acl_op_table[t].ao_op) { found = 1; if (rop == *op) acle->ae_op_allowed |= acl_op_table[t].ao_mask; else acle->ae_op_allowed &= ~acl_op_table[t].ao_mask; } } if (!found) { krb5_klog_syslog(LOG_ERR, ACL_OP_BAD_MSG, *op, lp); opok = 0; } } if (opok) { acle->ae_name = (char *) malloc(strlen(acle_principal)+1); if (acle->ae_name) { strcpy(acle->ae_name, acle_principal); acle->ae_principal = (krb5_principal) NULL; acle->ae_name_bad = 0; DPRINT(DEBUG_ACL, acl_debug_level, ("A ACL entry %s -> opmask %x\n", acle->ae_name, acle->ae_op_allowed)); } else { if (acle->ae_target) free(acle->ae_target); free(acle); acle = (aent_t *) NULL; } } else { if (acle->ae_target) free(acle->ae_target); free(acle); acle = (aent_t *) NULL; } if ( nmatch >= 4 ) { char *trailing; trailing = &acle_restrictions[strlen(acle_restrictions)-1]; while ( isspace((int) *trailing) ) trailing--; trailing[1] = '\0'; acle->ae_restriction_string = strdup(acle_restrictions); } else { acle->ae_restriction_string = (char *) NULL; } acle->ae_restriction_bad = 0; acle->ae_restrictions = (restriction_t *) NULL; } } DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_parse_line() = %x\n", (long) acle)); return(acle); } /* * kadm5int_acl_parse_restrictions() - Parse optional restrictions field * * Allowed restrictions are: * [+-]flagname (recognized by krb5_string_to_flags) * flag is forced to indicated value * -clearpolicy policy is forced clear * -policy pol policy is forced to be "pol" * -{expire,pwexpire,maxlife,maxrenewlife} deltat * associated value will be forced to * MIN(deltat, requested value) * * Returns: 0 on success, or system errors */ static krb5_error_code kadm5int_acl_parse_restrictions(s, rpp) char *s; restriction_t **rpp; { char *sp, *tp, *ap; static const char *delims = "\t\n\f\v\r ,"; krb5_deltat dt; krb5_flags flag; krb5_error_code code; DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp)); *rpp = (restriction_t *) NULL; code = 0; if (s) { if (!(sp = strdup(s)) /* Don't munge the original */ || !(*rpp = (restriction_t *) malloc(sizeof(restriction_t)))) { code = ENOMEM; } else { memset(*rpp, 0, sizeof(**rpp)); for (tp=strtok(sp, delims); tp; tp=strtok((char *)NULL, delims)) { flag = 0; if (!krb5_string_to_flags(tp, "+", "-", &flag)) { /* OK, but was it in the positive or negative sense? */ if (flag) { (*rpp)->require_attrs |= flag; } else { flag = ~0; (void) krb5_string_to_flags(tp, "+", "-", &flag); (*rpp)->forbid_attrs |= ~flag; } (*rpp)->mask |= KADM5_ATTRIBUTES; } else if (!strcmp(tp, "-clearpolicy")) { (*rpp)->mask |= KADM5_POLICY_CLR; } else { /* everything else needs an argument ... */ if (!(ap = strtok((char *)NULL, delims))) { code = EINVAL; break; } if (!strcmp(tp, "-policy")) { if (!((*rpp)->policy = strdup(ap))) { code = ENOMEM; break; } (*rpp)->mask |= KADM5_POLICY; } else { /* all other arguments must be a deltat ... */ if (krb5_string_to_deltat(ap, &dt)) { code = EINVAL; break; } if (!strcmp(tp, "-expire")) { (*rpp)->princ_lifetime = dt; (*rpp)->mask |= KADM5_PRINC_EXPIRE_TIME; } else if (!strcmp(tp, "-pwexpire")) { (*rpp)->pw_lifetime = dt; (*rpp)->mask |= KADM5_PW_EXPIRATION; } else if (!strcmp(tp, "-maxlife")) { (*rpp)->max_life = dt; (*rpp)->mask |= KADM5_MAX_LIFE; } else if (!strcmp(tp, "-maxrenewlife")) { (*rpp)->max_renewable_life = dt; (*rpp)->mask |= KADM5_MAX_RLIFE; } else { code = EINVAL; break; } } } } } } if (sp) free(sp); if (*rpp && code) { if ((*rpp)->policy) free((*rpp)->policy); free(*rpp); *rpp = (restriction_t *) NULL; } DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_parse_restrictions() = %d, mask=0x%08x\n", code, (*rpp) ? (*rpp)->mask : 0)); return code; } /* * kadm5int_acl_impose_restrictions() - impose restrictions, modifying *recp, *maskp * * Returns: 0 on success; * malloc or timeofday errors */ krb5_error_code kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp) krb5_context kcontext; kadm5_principal_ent_rec *recp; long *maskp; restriction_t *rp; { krb5_error_code code; krb5_int32 now; DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n", *maskp, (long)rp)); if (!rp) return 0; if (rp->mask & (KADM5_PRINC_EXPIRE_TIME|KADM5_PW_EXPIRATION)) if ((code = krb5_timeofday(kcontext, &now))) return code; if (rp->mask & KADM5_ATTRIBUTES) { recp->attributes |= rp->require_attrs; recp->attributes &= ~(rp->forbid_attrs); *maskp |= KADM5_ATTRIBUTES; } if (rp->mask & KADM5_POLICY_CLR) { *maskp &= ~KADM5_POLICY; *maskp |= KADM5_POLICY_CLR; } else if (rp->mask & KADM5_POLICY) { if (recp->policy && strcmp(recp->policy, rp->policy)) { free(recp->policy); recp->policy = (char *) NULL; } if (!recp->policy) { recp->policy = strdup(rp->policy); /* XDR will free it */ if (!recp->policy) return ENOMEM; } *maskp |= KADM5_POLICY; } if (rp->mask & KADM5_PRINC_EXPIRE_TIME) { if (!(*maskp & KADM5_PRINC_EXPIRE_TIME) || (recp->princ_expire_time > (now + rp->princ_lifetime))) recp->princ_expire_time = now + rp->princ_lifetime; *maskp |= KADM5_PRINC_EXPIRE_TIME; } if (rp->mask & KADM5_PW_EXPIRATION) { if (!(*maskp & KADM5_PW_EXPIRATION) || (recp->pw_expiration > (now + rp->pw_lifetime))) recp->pw_expiration = now + rp->pw_lifetime; *maskp |= KADM5_PW_EXPIRATION; } if (rp->mask & KADM5_MAX_LIFE) { if (!(*maskp & KADM5_MAX_LIFE) || (recp->max_life > rp->max_life)) recp->max_life = rp->max_life; *maskp |= KADM5_MAX_LIFE; } if (rp->mask & KADM5_MAX_RLIFE) { if (!(*maskp & KADM5_MAX_RLIFE) || (recp->max_renewable_life > rp->max_renewable_life)) recp->max_renewable_life = rp->max_renewable_life; *maskp |= KADM5_MAX_RLIFE; } DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp)); return 0; } /* * kadm5int_acl_free_entries() - Free all ACL entries. */ static void kadm5int_acl_free_entries() { aent_t *ap; aent_t *np; DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_free_entries()\n")); for (ap=acl_list_head; ap; ap = np) { if (ap->ae_name) free(ap->ae_name); if (ap->ae_principal) krb5_free_principal((krb5_context) NULL, ap->ae_principal); if (ap->ae_target) free(ap->ae_target); if (ap->ae_target_princ) krb5_free_principal((krb5_context) NULL, ap->ae_target_princ); if (ap->ae_restriction_string) free(ap->ae_restriction_string); if (ap->ae_restrictions) { if (ap->ae_restrictions->policy) free(ap->ae_restrictions->policy); free(ap->ae_restrictions); } np = ap->ae_next; free(ap); } acl_list_head = acl_list_tail = (aent_t *) NULL; acl_inited = 0; DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_free_entries()\n")); } /* * kadm5int_acl_load_acl_file() - Open and parse the ACL file. */ static int kadm5int_acl_load_acl_file() { FILE *afp; char *alinep; aent_t **aentpp; int alineno; int retval = 1; DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_load_acl_file()\n")); /* Open the ACL file for read */ afp = fopen(acl_acl_file, "rF"); /* Solaris Kerberos */ if (afp) { alineno = 1; aentpp = &acl_list_head; /* Get a non-comment line */ while ((alinep = kadm5int_acl_get_line(afp, &alineno))) { /* Parse it */ *aentpp = kadm5int_acl_parse_line(alinep); /* If syntax error, then fall out */ if (!*aentpp) { krb5_klog_syslog(LOG_ERR, ACL_SYN_ERR_MSG, acl_acl_file, alineno, alinep); retval = 0; break; } acl_list_tail = *aentpp; aentpp = &(*aentpp)->ae_next; } fclose(afp); if (acl_catchall_entry) { *aentpp = kadm5int_acl_parse_line(acl_catchall_entry); if (*aentpp) { acl_list_tail = *aentpp; } else { retval = 0; DPRINT(DEBUG_OPERATION, acl_debug_level, ("> catchall acl entry (%s) load failed\n", acl_catchall_entry)); } } } else { krb5_klog_syslog(LOG_ERR, ACL_CANTOPEN_MSG, error_message(errno), acl_acl_file); if (acl_catchall_entry && (acl_list_head = kadm5int_acl_parse_line((char *)acl_catchall_entry))) { acl_list_tail = acl_list_head; } else { retval = 0; DPRINT(DEBUG_OPERATION, acl_debug_level, ("> catchall acl entry (%s) load failed\n", acl_catchall_entry)); } } if (!retval) { kadm5int_acl_free_entries(); } DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_load_acl_file() = %d\n", retval)); return(retval); } /* * kadm5int_acl_match_data() - See if two data entries match. * * Wildcarding is only supported for a whole component. */ static krb5_boolean kadm5int_acl_match_data(e1, e2, targetflag, ws) krb5_data *e1, *e2; int targetflag; wildstate_t *ws; { krb5_boolean retval; DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_match_entry(%s, %s)\n", e1->data, e2->data)); retval = 0; if (!strncmp(e1->data, "*", e1->length)) { retval = 1; if (ws && !targetflag) { if (ws->nwild >= 9) { /* Solaris Kerberos */ DPRINT(DEBUG_ACL, acl_debug_level, ("Too many wildcards in ACL entry %s\n", e1->data)); } else ws->backref[ws->nwild++] = e2; } } else if (ws && targetflag && (e1->length == 2) && (e1->data[0] == '*') && (e1->data[1] >= '1') && (e1->data[1] <= '9')) { int n = e1->data[1] - '1'; if (n >= ws->nwild) { /* Solaris Kerberos */ DPRINT(DEBUG_ACL, acl_debug_level, ("Too many backrefs in ACL entry %s\n", e1->data)); } else if ((ws->backref[n]->length == e2->length) && (!strncmp(ws->backref[n]->data, e2->data, e2->length))) retval = 1; } else { if ((e1->length == e2->length) && (!strncmp(e1->data, e2->data, e1->length))) retval = 1; } DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval)); return(retval); } /* * kadm5int_acl_find_entry() - Find a matching entry. */ static aent_t * kadm5int_acl_find_entry(kcontext, principal, dest_princ) krb5_context kcontext; krb5_principal principal; krb5_principal dest_princ; { aent_t *entry; krb5_error_code kret; int i; int matchgood; wildstate_t state; DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_find_entry()\n")); memset((char *)&state, 0, sizeof state); for (entry=acl_list_head; entry; entry = entry->ae_next) { if (entry->ae_name_bad) continue; if (!strcmp(entry->ae_name, "*")) { DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n")); matchgood = 1; } else { if (!entry->ae_principal && !entry->ae_name_bad) { kret = krb5_parse_name(kcontext, entry->ae_name, &entry->ae_principal); if (kret) entry->ae_name_bad = 1; } if (entry->ae_name_bad) { DPRINT(DEBUG_ACL, acl_debug_level, ("Bad ACL entry %s\n", entry->ae_name)); continue; } matchgood = 0; if (kadm5int_acl_match_data(&entry->ae_principal->realm, &principal->realm, 0, (wildstate_t *)0) && (entry->ae_principal->length == principal->length)) { matchgood = 1; for (i=0; ilength; i++) { if (!kadm5int_acl_match_data(&entry->ae_principal->data[i], &principal->data[i], 0, &state)) { matchgood = 0; break; } } } } if (!matchgood) continue; /* We've matched the principal. If we have a target, then try it */ if (entry->ae_target && strcmp(entry->ae_target, "*")) { if (!entry->ae_target_princ && !entry->ae_target_bad) { kret = krb5_parse_name(kcontext, entry->ae_target, &entry->ae_target_princ); if (kret) entry->ae_target_bad = 1; } if (entry->ae_target_bad) { DPRINT(DEBUG_ACL, acl_debug_level, ("Bad target in ACL entry for %s\n", entry->ae_name)); entry->ae_name_bad = 1; continue; } if (!dest_princ) matchgood = 0; else if (entry->ae_target_princ && dest_princ) { if (kadm5int_acl_match_data(&entry->ae_target_princ->realm, &dest_princ->realm, 1, (wildstate_t *)0) && (entry->ae_target_princ->length == dest_princ->length)) { for (i=0; ilength; i++) { if (!kadm5int_acl_match_data(&entry->ae_target_princ->data[i], &dest_princ->data[i], 1, &state)) { matchgood = 0; break; } } } else matchgood = 0; } } if (!matchgood) continue; if (entry->ae_restriction_string && !entry->ae_restriction_bad && !entry->ae_restrictions && kadm5int_acl_parse_restrictions(entry->ae_restriction_string, &entry->ae_restrictions)) { DPRINT(DEBUG_ACL, acl_debug_level, ("Bad restrictions in ACL entry for %s\n", entry->ae_name)); entry->ae_restriction_bad = 1; } if (entry->ae_restriction_bad) { entry->ae_name_bad = 1; continue; } break; } DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_find_entry()=%x\n",entry)); return(entry); } /* * kadm5int_acl_init() - Initialize ACL context. */ krb5_error_code kadm5int_acl_init(kcontext, debug_level, acl_file) krb5_context kcontext; int debug_level; char *acl_file; { krb5_error_code kret; kret = 0; acl_debug_level = debug_level; DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_init(afile=%s)\n", ((acl_file) ? acl_file : "(null)"))); acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL; acl_inited = kadm5int_acl_load_acl_file(); DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_init() = %d\n", kret)); return(kret); } /* * kadm5int_acl_finish - Terminate ACL context. */ void kadm5int_acl_finish(kcontext, debug_level) krb5_context kcontext; int debug_level; { DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_finish()\n")); kadm5int_acl_free_entries(); DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_finish()\n")); } /* * kadm5int_acl_check() - Is this operation permitted for this principal? * this code used not to be based on gssapi. In order * to minimize porting hassles, I've put all the * gssapi hair in this function. This might not be * the best medium-term solution. (The best long-term * solution is, of course, a real authorization service.) */ krb5_boolean kadm5int_acl_check(kcontext, caller, opmask, principal, restrictions) krb5_context kcontext; gss_name_t caller; krb5_int32 opmask; krb5_principal principal; restriction_t **restrictions; { krb5_boolean retval; aent_t *aentry; gss_buffer_desc caller_buf; gss_OID caller_oid; OM_uint32 emaj, emin; krb5_error_code code; krb5_principal caller_princ; DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n")); /* Solaris Kerberos */ if (restrictions) *restrictions = NULL; if (GSS_ERROR(emaj = gss_display_name(&emin, caller, &caller_buf, &caller_oid))) return(1); code = krb5_parse_name(kcontext, (char *) caller_buf.value, &caller_princ); gss_release_buffer(&emin, &caller_buf); if (code) return(code); retval = 0; aentry = kadm5int_acl_find_entry(kcontext, caller_princ, principal); if (aentry) { if ((aentry->ae_op_allowed & opmask) == opmask) { retval = 1; if (restrictions) { *restrictions = (aentry->ae_restrictions && aentry->ae_restrictions->mask) ? aentry->ae_restrictions : (restriction_t *) NULL; } } } krb5_free_principal(kcontext, caller_princ); DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n", retval)); return(retval); } kadm5_ret_t kadm5_get_privs(void *server_handle, long *privs) { CHECK_HANDLE(server_handle); /* this is impossible to do with the current interface. For now, return all privs, which will confuse some clients, but not deny any access to users of "smart" clients which try to cache */ *privs = ~0; return KADM5_OK; } /* SUNWresync121 (SEAM1.0) XXX */ kadm5_ret_t __kadm5_get_priv(void *server_handle, long *privs, gss_name_t client) { aent_t *aentry; gss_buffer_desc caller_buff; gss_OID caller_oid; krb5_principal caller_principal; OM_uint32 minor, major; krb5_error_code k_error; kadm5_ret_t retval = KADM5_FAILURE; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if (GSS_ERROR(major = gss_display_name(&minor, client, &caller_buff, &caller_oid))) return(retval); k_error = krb5_parse_name(handle->context, (char *) caller_buff.value, &caller_principal); gss_release_buffer(&minor, &caller_buff); if (k_error) return(retval); if (aentry = kadm5int_acl_find_entry(handle->context, caller_principal, (krb5_principal)NULL)) *privs = aentry->ae_op_allowed; krb5_free_principal(handle->context, caller_principal); return (KADM5_OK); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifdef __cplusplus extern "C" { #endif /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * kadmin/v5server/kadm5_defs.h * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ #ifndef SERVER_ACL_H__ #define SERVER_ACL_H__ #include /* SUNWresync121 XXX */ /* * Debug definitions. */ #define DEBUG_SPROC 1 #define DEBUG_OPERATION 2 #define DEBUG_HOST 4 #define DEBUG_REALM 8 #define DEBUG_REQUESTS 16 #define DEBUG_ACL 32 #define DEBUG_PROTO 64 #define DEBUG_CALLS 128 #define DEBUG_NOSLAVES 256 #ifdef DEBUG #define DPRINT(l1, cl, al) if ((cl & l1) != 0) printf al #else /* DEBUG */ #define DPRINT(l1, cl, al) #endif /* DEBUG */ #define DLOG(l1, cl, msg) if ((cl & l1) != 0) \ com_err(programname, 0, msg) /* * Access control bits. */ #define ACL_INQUIRE 1 /* GET */ #define ACL_ADD 2 #define ACL_MODIFY 4 #define ACL_DELETE 8 #define ACL_LIST 16 #define ACL_CHANGEPW 32 /* #define ACL_CHANGE_OWN_PW 16 */ /* #define ACL_EXTRACT 64 */ #define ACL_SETKEY 256 #define ACL_MIGRATE 512 /* pam_krb5_migrate */ #define ACL_IPROP 65536 /* SUNW IProp */ #define ACL_RENAME (ACL_ADD+ACL_DELETE) #define ACL_ALL_MASK (ACL_ADD | \ ACL_DELETE | \ ACL_MODIFY | \ ACL_CHANGEPW | \ ACL_INQUIRE | \ ACL_LIST | \ ACL_IPROP | \ ACL_MIGRATE | \ ACL_SETKEY) typedef struct _restriction { long mask; krb5_flags require_attrs; krb5_flags forbid_attrs; krb5_deltat princ_lifetime; krb5_deltat pw_lifetime; krb5_deltat max_life; krb5_deltat max_renewable_life; long aux_attributes; char *policy; } restriction_t; krb5_error_code kadm5int_acl_init (krb5_context, int, char *); void kadm5int_acl_finish (krb5_context, int); krb5_boolean kadm5int_acl_check (krb5_context, gss_name_t, krb5_int32, krb5_principal, restriction_t **); krb5_error_code kadm5int_acl_impose_restrictions (krb5_context, kadm5_principal_ent_rec *, long *, restriction_t *); #endif /* SERVER_ACL_H__ */ #ifdef __cplusplus } #endif /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include #include #include #include #include #include #include "server_internal.h" #include #include #include #include #ifdef HAVE_MEMORY_H #include #endif #include "adm_proto.h" #include #include static char **word_list = NULL; /* list of word pointers */ static char *word_block = NULL; /* actual word data */ static unsigned int word_count = 0; /* number of words */ /* * Function: word_compare * * Purpose: compare two words in the dictionary. * * Arguments: * w1 (input) pointer to first word * w2 (input) pointer to second word * result of strcmp * * Requires: * w1 and w2 to point to valid memory * */ static int word_compare(const void *s1, const void *s2) { return (strcasecmp(*(const char **)s1, *(const char **)s2)); } /* * Function: init-dict * * Purpose: Initialize in memory word dictionary * * Arguments: * none * KADM5_OK on success errno on failure; * (but success on ENOENT) * * Requires: * If WORDFILE exists, it must contain a list of words, * one word per-line. * * Effects: * If WORDFILE exists, it is read into memory sorted for future * use. If it does not exist, it syslogs an error message and returns * success. * * Modifies: * word_list to point to a chunck of allocated memory containing * pointers to words * word_block to contain the dictionary. * */ int init_dict(kadm5_config_params *params) { int fd, len, i; char *p, *t; struct stat sb; if(word_list != NULL && word_block != NULL) return KADM5_OK; if (! (params->mask & KADM5_CONFIG_DICT_FILE)) { /* Solaris Kerberos */ krb5_klog_syslog(LOG_INFO, dgettext(TEXT_DOMAIN, "No dictionary file specified, continuing " "without one.")); return KADM5_OK; } if ((fd = open(params->dict_file, O_RDONLY)) == -1) { if (errno == ENOENT) { /* Solaris Kerberos */ krb5_klog_syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "WARNING! Cannot find dictionary file %s, " "continuing without one."), params->dict_file); return KADM5_OK; } else return errno; } if (fstat(fd, &sb) == -1) return errno; if ((word_block = (char *) malloc(sb.st_size + 1)) == NULL) return errno; if (read(fd, word_block, sb.st_size) != sb.st_size) return errno; (void) close(fd); word_block[sb.st_size] = '\0'; p = word_block; len = sb.st_size; while(len > 0 && (t = memchr(p, '\n', len)) != NULL) { *t = '\0'; len -= t - p + 1; p = t + 1; word_count++; } if ((word_list = (char **) malloc(word_count * sizeof(char *))) == NULL) return errno; p = word_block; for (i = 0; i < word_count; i++) { word_list[i] = p; p += strlen(p) + 1; } qsort(word_list, word_count, sizeof(char *), word_compare); return KADM5_OK; } /* * Function: find_word * * Purpose: See if the specified word exists in the in-core dictionary * * Arguments: * word (input) word to search for. * WORD_NOT_FOUND if not in dictionary, * KADM5_OK if if found word * errno if init needs to be called and returns an * error * * Requires: * word to be a null terminated string. * That word_list and word_block besetup * * Effects: * finds word in dictionary. * Modifies: * nothing. * */ int find_word(const char *word) { char **value; if(word_list == NULL || word_block == NULL) return WORD_NOT_FOUND; if ((value = (char **) bsearch(&word, word_list, word_count, sizeof(char *), word_compare)) == NULL) return WORD_NOT_FOUND; else return KADM5_OK; } /* * Function: destroy_dict * * Purpose: destroy in-core copy of dictionary. * * Arguments: * none * none * Requires: * nothing * Effects: * frees up memory occupied by word_list and word_block * sets count back to 0, and resets the pointers to NULL * * Modifies: * word_list, word_block, and word_count. * */ void destroy_dict(void) { if(word_list) { free(word_list); word_list = NULL; } if(word_block) { free(word_block); word_block = NULL; } if(word_count) word_count = 0; return; } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include #include #include "server_internal.h" int _kadm5_check_handle(void *handle) { CHECK_HANDLE(handle); return 0; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * * $Id: server_init.c 18584 2006-09-13 20:30:23Z raeburn $ * $Source$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/server_init.c,v 1.8 2002/10/15 15:40:49 epeisach Exp $"; #endif #include #include #include #include #include "k5-int.h" /* needed for gssapiP_krb5.h */ #include #include #include "server_internal.h" #include /* * Function check_handle * * Purpose: Check a server handle and return a com_err code if it is * invalid or 0 if it is valid. * * Arguments: * * handle The server handle. */ static int check_handle(void *handle) { CHECK_HANDLE(handle); return 0; } static int dup_db_args(kadm5_server_handle_t handle, char **db_args) { int count = 0; int ret = 0; for (count=0; db_args && db_args[count]; count++); if (count == 0) { handle->db_args = NULL; goto clean_n_exit; } handle->db_args = calloc(sizeof(char*), count+1); if (handle->db_args == NULL) { ret=ENOMEM; goto clean_n_exit; } for (count=0; db_args[count]; count++) { handle->db_args[count] = strdup(db_args[count]); if (handle->db_args[count] == NULL) { ret = ENOMEM; goto clean_n_exit; } } clean_n_exit: if (ret && handle->db_args) { for (count=0; handle->db_args[count]; count++) free(handle->db_args[count]); free(handle->db_args), handle->db_args = NULL; } return ret; } static void free_db_args(kadm5_server_handle_t handle) { int count; if (handle->db_args) { for (count=0; handle->db_args[count]; count++) free(handle->db_args[count]); free(handle->db_args), handle->db_args = NULL; } } kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { return kadm5_init(client_name, pass, service_name, params, struct_version, api_version, db_args, server_handle); } kadm5_ret_t kadm5_init_with_creds(char *client_name, krb5_ccache ccache, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { /* * A program calling init_with_creds *never* expects to prompt the * user. Therefore, always pass a dummy password in case this is * KADM5_API_VERSION_1. If this is KADM5_API_VERSION_2 and * MKEY_FROM_KBD is non-zero, return an error. */ if (api_version == KADM5_API_VERSION_2 && params && (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) && params->mkey_from_kbd) return KADM5_BAD_SERVER_PARAMS; return kadm5_init(client_name, NULL, service_name, params, struct_version, api_version, db_args, server_handle); } kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, char *service_name, kadm5_config_params *params, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { /* * A program calling init_with_skey *never* expects to prompt the * user. Therefore, always pass a dummy password in case this is * KADM5_API_VERSION_1. If this is KADM5_API_VERSION_2 and * MKEY_FROM_KBD is non-zero, return an error. */ if (api_version == KADM5_API_VERSION_2 && params && (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) && params->mkey_from_kbd) return KADM5_BAD_SERVER_PARAMS; return kadm5_init(client_name, NULL, service_name, params, struct_version, api_version, db_args, server_handle); } /* * Solaris Kerberos: * A private extended version of kadm5_init which potentially * returns more information in case of an error. */ kadm5_ret_t kadm5_init2(char *client_name, char *pass, char *service_name, kadm5_config_params *params_in, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle, char **emsg) { int ret; kadm5_server_handle_t handle; kadm5_config_params params_local; /* for v1 compat */ if (emsg) *emsg = NULL; if (! server_handle) return EINVAL; if (! client_name) return EINVAL; if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle))) return ENOMEM; memset(handle, 0, sizeof(*handle)); ret = dup_db_args(handle, db_args); if (ret) { free(handle); return ret; } ret = (int) krb5int_init_context_kdc(&(handle->context)); if (ret) { free_db_args(handle); free(handle); return(ret); } handle->magic_number = KADM5_SERVER_HANDLE_MAGIC; handle->struct_version = struct_version; handle->api_version = api_version; /* * Verify the version numbers before proceeding; we can't use * CHECK_HANDLE because not all fields are set yet. */ GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION, KADM5_NEW_SERVER_API_VERSION); /* * Acquire relevant profile entries. In version 2, merge values * in params_in with values from profile, based on * params_in->mask. * * In version 1, we've given a realm (which may be NULL) instead * of params_in. So use that realm, make params_in contain an * empty mask, and behave like version 2. */ memset((char *) ¶ms_local, 0, sizeof(params_local)); if (api_version == KADM5_API_VERSION_1) { params_local.realm = (char *) params_in; if (params_in) params_local.mask = KADM5_CONFIG_REALM; params_in = ¶ms_local; } #if 0 /* Now that we look at krb5.conf as well as kdc.conf, we can expect to see admin_server being set sometimes. */ #define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER) if (params_in && (params_in->mask & ILLEGAL_PARAMS)) { krb5_free_context(handle->context); free_db_args(handle); free(handle); return KADM5_BAD_SERVER_PARAMS; } #endif ret = kadm5_get_config_params(handle->context, 1, params_in, &handle->params); if (ret) { krb5_free_context(handle->context); free_db_args(handle); free(handle); return(ret); } #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME | \ KADM5_CONFIG_ADBNAME | \ KADM5_CONFIG_ADB_LOCKFILE | \ KADM5_CONFIG_ENCTYPE | \ KADM5_CONFIG_FLAGS | \ KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \ KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES) if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) { kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return KADM5_MISSING_CONF_PARAMS; } ret = krb5_set_default_realm(handle->context, handle->params.realm); if (ret) { kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return ret; } ret = krb5_db_open(handle->context, db_args, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN); if (ret) { if (emsg) { const char *m = krb5_get_error_message(handle->context, ret); *emsg = strdup(m); krb5_free_error_message(handle->context, m); } kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return(ret); } if ((ret = krb5_parse_name(handle->context, client_name, &handle->current_caller))) { krb5_db_fini(handle->context); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return ret; } if (! (handle->lhandle = malloc(sizeof(*handle)))) { krb5_db_fini(handle->context); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return ENOMEM; } *handle->lhandle = *handle; handle->lhandle->api_version = KADM5_API_VERSION_2; handle->lhandle->struct_version = KADM5_STRUCT_VERSION; handle->lhandle->lhandle = handle->lhandle; /* can't check the handle until current_caller is set */ ret = check_handle((void *) handle); if (ret) { krb5_db_fini(handle->context); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return ret; } /* * The KADM5_API_VERSION_1 spec said "If pass (or keytab) is NULL * or an empty string, reads the master password from [the stash * file]. Otherwise, the non-NULL password is ignored and the * user is prompted for it via the tty." However, the code was * implemented the other way: when a non-NULL password was * provided, the stash file was used. This is somewhat more * sensible, as then a local or remote client that provides a * password does not prompt the user. This code maintains the * previous actual behavior, and not the old spec behavior, * because that is how the unit tests are written. * * In KADM5_API_VERSION_2, this decision is controlled by * params. * * kdb_init_master's third argument is "from_keyboard". */ /* * Solaris Kerberos: Setting to an unknown enc type will make the function * read the encryption type in the stash file instead of assumming that it * is the default type. */ if (handle->params.enctype == DEFAULT_KDC_ENCTYPE) handle->params.enctype = ENCTYPE_UNKNOWN; ret = kdb_init_master(handle, handle->params.realm, (handle->api_version == KADM5_API_VERSION_1 ? ((pass == NULL) || !(strlen(pass))) : ((handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD) && handle->params.mkey_from_kbd) )); if (ret) { krb5_db_fini(handle->context); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return ret; } /* * Solaris Kerberos: We used the enc type that was discovered in the stash * file to associate with the other magic principals in the database. */ handle->params.enctype = handle->master_keyblock.enctype; ret = kdb_init_hist(handle, handle->params.realm); if (ret) { krb5_db_fini(handle->context); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return ret; } ret = init_dict(&handle->params); if (ret) { krb5_db_fini(handle->context); krb5_free_principal(handle->context, handle->current_caller); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); free_db_args(handle); free(handle); return ret; } *server_handle = (void *) handle; return KADM5_OK; } kadm5_ret_t kadm5_init(char *client_name, char *pass, char *service_name, kadm5_config_params *params_in, krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args, void **server_handle) { return (kadm5_init2(client_name, pass, service_name, params_in, struct_version, api_version, db_args, server_handle, NULL)); } kadm5_ret_t kadm5_destroy(void *server_handle) { kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); destroy_dict(); adb_policy_close(handle); krb5_db_fini(handle->context); krb5_free_principal(handle->context, handle->current_caller); kadm5_free_config_params(handle->context, &handle->params); krb5_free_context(handle->context); handle->magic_number = 0; free(handle->lhandle); free_db_args(handle); free(handle); return KADM5_OK; } kadm5_ret_t kadm5_lock(void *server_handle) { kadm5_server_handle_t handle = server_handle; kadm5_ret_t ret; CHECK_HANDLE(server_handle); ret = krb5_db_lock(handle->context, KRB5_DB_LOCKMODE_EXCLUSIVE); if (ret) return ret; return KADM5_OK; } kadm5_ret_t kadm5_unlock(void *server_handle) { kadm5_server_handle_t handle = server_handle; kadm5_ret_t ret; CHECK_HANDLE(server_handle); ret = krb5_db_unlock(handle->context); if (ret) return ret; return KADM5_OK; } kadm5_ret_t kadm5_flush(void *server_handle) { kadm5_server_handle_t handle = server_handle; kadm5_ret_t ret; CHECK_HANDLE(server_handle); if ((ret = krb5_db_fini(handle->context)) || (ret = krb5_db_open(handle->context, handle->db_args, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN)) || (ret = adb_policy_close(handle)) || (ret = adb_policy_init(handle))) { (void) kadm5_destroy(server_handle); return ret; } return KADM5_OK; } int _kadm5_check_handle(void *handle) { CHECK_HANDLE(handle); return 0; } #include "gssapiP_krb5.h" krb5_error_code kadm5_init_krb5_context (krb5_context *ctx) { /* Solaris Kerberos: not needed */ #if 0 /************** Begin IFDEF'ed OUT *******************************/ static int first_time = 1; if (first_time) { krb5_error_code err; err = krb5_gss_use_kdc_context(); if (err) return err; first_time = 0; } #endif /**************** END IFDEF'ed OUT *******************************/ return krb5int_init_context_kdc(ctx); } krb5_error_code kadm5_init_iprop(void *handle) { kadm5_server_handle_t iprop_h; krb5_error_code retval; iprop_h = handle; if (iprop_h->params.iprop_enabled) { ulog_set_role(iprop_h->context, IPROP_MASTER); if ((retval = ulog_map(iprop_h->context, &iprop_h->params, FKCOMMAND)) != 0) return (retval); } return (0); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include #include #include "k5-int.h" #include #include "server_internal.h" extern caddr_t xdralloc_getdata(XDR *xdrs); extern void xdralloc_create(XDR *xdrs, enum xdr_op op); krb5_principal master_princ; krb5_db_entry master_db; krb5_principal hist_princ; krb5_keyblock hist_key; krb5_db_entry hist_db; krb5_kvno hist_kvno; /* much of this code is stolen from the kdc. there should be some library code to deal with this. */ krb5_error_code kdb_init_master(kadm5_server_handle_t handle, char *r, int from_keyboard) { int ret = 0; char *realm; krb5_boolean from_kbd = FALSE; if (from_keyboard) from_kbd = TRUE; if (r == NULL) { if ((ret = krb5_get_default_realm(handle->context, &realm))) return ret; } else { realm = r; } if ((ret = krb5_db_setup_mkey_name(handle->context, handle->params.mkey_name, realm, NULL, &master_princ))) goto done; /* Solaris Kerberos */ #if 0 master_keyblock.enctype = handle->params.enctype; #endif /* Solaris Kerberos */ ret = krb5_db_fetch_mkey(handle->context, master_princ, handle->params.enctype, from_kbd, FALSE /* only prompt once */, handle->params.stash_file, NULL /* I'm not sure about this, but it's what the kdc does --marc */, &handle->master_keyblock); if (ret) goto done; /* Solaris Kerberos */ if ((ret = krb5_db_verify_master_key(handle->context, master_princ, &handle->master_keyblock))) { krb5_db_fini(handle->context); return ret; } done: if (r == NULL) free(realm); return(ret); } /* * Function: kdb_init_hist * * Purpose: Initializes the global history variables. * * Arguments: * * handle (r) kadm5 api server handle * r (r) realm of history principal to use, or NULL * * Effects: This function sets the value of the following global * variables: * * hist_princ krb5_principal holding the history principal * hist_db krb5_db_entry of the history principal * hist_key krb5_keyblock holding the history principal's key * hist_encblock krb5_encrypt_block holding the procssed hist_key * hist_kvno the version number of the history key * * If the history principal does not already exist, this function * attempts to create it with kadm5_create_principal. WARNING! * If the history principal is deleted and this function is executed * (by kadmind, or kadmin.local, or anything else with permission), * the principal will be assigned a new random key and all existing * password history information will become useless. */ krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r) { int ret = 0; char *realm, *hist_name; krb5_key_data *key_data; krb5_key_salt_tuple ks[1]; if (r == NULL) { if ((ret = krb5_get_default_realm(handle->context, &realm))) return ret; } else { realm = r; } if ((hist_name = (char *) malloc(strlen(KADM5_HIST_PRINCIPAL) + strlen(realm) + 2)) == NULL) goto done; (void) sprintf(hist_name, "%s@%s", KADM5_HIST_PRINCIPAL, realm); if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ))) goto done; if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) { kadm5_principal_ent_rec ent; if (ret != KADM5_UNK_PRINC) goto done; /* try to create the principal */ memset(&ent, 0, sizeof(ent)); ent.principal = hist_princ; ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX; ent.attributes = 0; /* this uses hist_kvno. So we set it to 2, which will be the correct value once the principal is created and randomized. Of course, it doesn't make sense to keep a history for the history principal, anyway. */ hist_kvno = 2; ks[0].ks_enctype = handle->params.enctype; ks[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; ret = kadm5_create_principal_3(handle, &ent, (KADM5_PRINCIPAL | KADM5_MAX_LIFE | KADM5_ATTRIBUTES), 1, ks, "to-be-random"); if (ret) goto done; /* this won't let us randomize the hist_princ. So we cheat. */ hist_princ = NULL; ret = kadm5_randkey_principal_3(handle, ent.principal, 0, 1, ks, NULL, NULL); hist_princ = ent.principal; if (ret) goto done; /* now read the newly-created kdb record out of the database. */ if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) goto done; } ret = krb5_dbe_find_enctype(handle->context, &hist_db, handle->params.enctype, -1, -1, &key_data); if (ret) goto done; /* Solaris Kerberos */ ret = krb5_dbekd_decrypt_key_data(handle->context, &handle->master_keyblock, key_data, &hist_key, NULL); if (ret) goto done; hist_kvno = key_data->key_data_kvno; done: free(hist_name); if (r == NULL) free(realm); return ret; } /* * Function: kdb_get_entry * * Purpose: Gets an entry from the kerberos database and breaks * it out into a krb5_db_entry and an osa_princ_ent_t. * * Arguments: * * handle (r) the server_handle * principal (r) the principal to get * kdb (w) krb5_db_entry to fill in * adb (w) osa_princ_ent_rec to fill in * * when the caller is done with kdb and adb, kdb_free_entry must be * called to release them. The adb record is filled in with the * contents of the KRB5_TL_KADM_DATA record; if that record doesn't * exist, an empty but valid adb record is returned. */ krb5_error_code kdb_get_entry(kadm5_server_handle_t handle, krb5_principal principal, krb5_db_entry *kdb, osa_princ_ent_rec *adb) { krb5_error_code ret; int nprincs; krb5_boolean more; krb5_tl_data tl_data; XDR xdrs; ret = krb5_db_get_principal(handle->context, principal, kdb, &nprincs, &more); if (ret) return(ret); if (more) { krb5_db_free_principal(handle->context, kdb, nprincs); return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); } else if (nprincs != 1) { krb5_db_free_principal(handle->context, kdb, nprincs); return(KADM5_UNK_PRINC); } if (adb) { memset(adb, 0, sizeof(*adb)); tl_data.tl_data_type = KRB5_TL_KADM_DATA; /* * XXX Currently, lookup_tl_data always returns zero; it sets * tl_data->tl_data_length to zero if the type isn't found. * This should be fixed... */ if ((ret = krb5_dbe_lookup_tl_data(handle->context, kdb, &tl_data)) || (tl_data.tl_data_length == 0)) { /* there's no admin data. this can happen, if the admin server is put into production after some principals are created. In this case, return valid admin data (which is all zeros with the hist_kvno filled in), and when the entry is written, the admin data will get stored correctly. */ adb->admin_history_kvno = hist_kvno; return(ret); } /* Solaris Kerberos */ xdrmem_create(&xdrs, (caddr_t)tl_data.tl_data_contents, tl_data.tl_data_length, XDR_DECODE); if (! xdr_osa_princ_ent_rec(&xdrs, adb)) { xdr_destroy(&xdrs); krb5_db_free_principal(handle->context, kdb, 1); return(KADM5_XDR_FAILURE); } xdr_destroy(&xdrs); } return(0); } /* * Function: kdb_free_entry * * Purpose: frees the resources allocated by kdb_get_entry * * Arguments: * * handle (r) the server_handle * kdb (w) krb5_db_entry to fill in * adb (w) osa_princ_ent_rec to fill in * * when the caller is done with kdb and adb, kdb_free_entry must be * called to release them. */ krb5_error_code kdb_free_entry(kadm5_server_handle_t handle, krb5_db_entry *kdb, osa_princ_ent_rec *adb) { XDR xdrs; if (kdb) krb5_db_free_principal(handle->context, kdb, 1); if (adb) { xdrmem_create(&xdrs, NULL, 0, XDR_FREE); xdr_osa_princ_ent_rec(&xdrs, adb); xdr_destroy(&xdrs); } return(0); } /* * Function: kdb_put_entry * * Purpose: Stores the osa_princ_ent_t and krb5_db_entry into to * database. * * Arguments: * * handle (r) the server_handle * kdb (r/w) the krb5_db_entry to store * adb (r) the osa_princ_db_ent to store * * Effects: * * The last modifier field of the kdb is set to the caller at now. * adb is encoded with xdr_osa_princ_ent_ret and stored in kbd as * KRB5_TL_KADM_DATA. kdb is then written to the database. */ krb5_error_code kdb_put_entry(kadm5_server_handle_t handle, krb5_db_entry *kdb, osa_princ_ent_rec *adb) { krb5_error_code ret; krb5_int32 now; XDR xdrs; krb5_tl_data tl_data; int one; ret = krb5_timeofday(handle->context, &now); if (ret) return(ret); ret = krb5_dbe_update_mod_princ_data(handle->context, kdb, now, handle->current_caller); if (ret) return(ret); xdralloc_create(&xdrs, XDR_ENCODE); if(! xdr_osa_princ_ent_rec(&xdrs, adb)) { xdr_destroy(&xdrs); return(KADM5_XDR_FAILURE); } tl_data.tl_data_type = KRB5_TL_KADM_DATA; tl_data.tl_data_length = xdr_getpos(&xdrs); /* Solaris Kerberos */ tl_data.tl_data_contents = (unsigned char *) xdralloc_getdata(&xdrs); ret = krb5_dbe_update_tl_data(handle->context, kdb, &tl_data); xdr_destroy(&xdrs); if (ret) return(ret); one = 1; ret = krb5_db_put_principal(handle->context, kdb, &one); if (ret) return(ret); return(0); } krb5_error_code kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name) { int one = 1; krb5_error_code ret; ret = krb5_db_delete_principal(handle->context, name, &one); return ret; } typedef struct _iter_data { void (*func)(void *, krb5_principal); void *data; } iter_data; static krb5_error_code kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb) { iter_data *id = (iter_data *) data; (*(id->func))(id->data, kdb->princ); return(0); } krb5_error_code kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry, void (*iter_fct)(void *, krb5_principal), void *data) { iter_data id; krb5_error_code ret; id.func = iter_fct; id.data = data; /* Solaris Kerberos: added support for db_args */ ret = krb5_db_iterate(handle->context, match_entry, kdb_iter_func, &id, NULL); if (ret) return(ret); return(0); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include "k5-int.h" #include #include #include /* for strcasecmp */ #include #include "server_internal.h" kadm5_ret_t adb_policy_init(kadm5_server_handle_t handle) { /* now policy is initialized as part of database. No seperate call needed */ /* Solaris Kerberos: krb5_db_inited returns 0 when db has been inited */ if( krb5_db_inited( handle->context ) == 0 ) return KADM5_OK; return krb5_db_open( handle->context, NULL, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN ); } kadm5_ret_t adb_policy_close(kadm5_server_handle_t handle) { /* will be taken care by database close */ return KADM5_OK; } #ifdef HESIOD /* stolen from v4sever/kadm_funcs.c */ static char * reverse(str) char *str; { static char newstr[80]; char *p, *q; int i; i = strlen(str); if (i >= sizeof(newstr)) i = sizeof(newstr)-1; p = str+i-1; q = newstr; q[i]='\0'; for(; i > 0; i--) *q++ = *p--; return(newstr); } #endif /* HESIOD */ #if 0 static int lower(str) char *str; { register char *cp; int effect=0; for (cp = str; *cp; cp++) { if (isupper(*cp)) { *cp = tolower(*cp); effect++; } } return(effect); } #endif #ifdef HESIOD static int str_check_gecos(gecos, pwstr) char *gecos; char *pwstr; { char *cp, *ncp, *tcp; for (cp = gecos; *cp; ) { /* Skip past punctuation */ for (; *cp; cp++) if (isalnum(*cp)) break; /* Skip to the end of the word */ for (ncp = cp; *ncp; ncp++) if (!isalnum(*ncp) && *ncp != '\'') break; /* Delimit end of word */ if (*ncp) *ncp++ = '\0'; /* Check word to see if it's the password */ if (*cp) { if (!strcasecmp(pwstr, cp)) return 1; tcp = reverse(cp); if (!strcasecmp(pwstr, tcp)) return 1; cp = ncp; } else break; } return 0; } #endif /* HESIOD */ /* some of this is stolen from gatekeeper ... */ kadm5_ret_t passwd_check(kadm5_server_handle_t handle, char *password, int use_policy, kadm5_policy_ent_t pol, krb5_principal principal) { int nupper = 0, nlower = 0, ndigit = 0, npunct = 0, nspec = 0; char c, *s, *cp; #ifdef HESIOD extern struct passwd *hes_getpwnam(); struct passwd *ent; #endif if(use_policy) { if(strlen(password) < pol->pw_min_length) return KADM5_PASS_Q_TOOSHORT; s = password; while ((c = *s++)) { if (islower((unsigned char) c)) { nlower = 1; continue; } else if (isupper((unsigned char) c)) { nupper = 1; continue; } else if (isdigit((unsigned char) c)) { ndigit = 1; continue; } else if (ispunct((unsigned char) c)) { npunct = 1; continue; } else { nspec = 1; continue; } } if ((nupper + nlower + ndigit + npunct + nspec) < pol->pw_min_classes) return KADM5_PASS_Q_CLASS; if((find_word(password) == KADM5_OK)) return KADM5_PASS_Q_DICT; else { int i, n = krb5_princ_size(handle->context, principal); cp = krb5_princ_realm(handle->context, principal)->data; if (strcasecmp(cp, password) == 0) return KADM5_PASS_Q_DICT; for (i = 0; i < n ; i++) { cp = krb5_princ_component(handle->context, principal, i)->data; if (strcasecmp(cp, password) == 0) return KADM5_PASS_Q_DICT; #ifdef HESIOD ent = hes_getpwnam(cp); if (ent && ent->pw_gecos) if (str_check_gecos(ent->pw_gecos, password)) return KADM5_PASS_Q_DICT; /* XXX new error code? */ #endif } return KADM5_OK; } } else { if (strlen(password) < 1) return KADM5_PASS_Q_TOOSHORT; } return KADM5_OK; } void trunc_name(size_t *len, char **dots) { *dots = *len > MAXPRINCLEN ? "..." : ""; *len = *len > MAXPRINCLEN ? MAXPRINCLEN : *len; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include "server_internal.h" #include kadm5_ret_t kadm5_chpass_principal_util(void *server_handle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len) { kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); return _kadm5_chpass_principal_util(handle, handle->lhandle, princ, new_pw, ret_pw, msg_ret, msg_len); } kadm5_ret_t kadm5_chpass_principal_v2(void *server_handle, krb5_principal princ, char *password, kadm5_ret_t *srvr_rsp_code, krb5_data *srvr_msg) { /* This method of password changing is not supported by the server */ return (KADM5_FAILURE); } krb5_chgpwd_prot _kadm5_get_kpasswd_protocol(void *handle) { /* * This has to be here because the higher level doesnt know * the details of the handle structure */ kadm5_server_handle_t srvrhdl = (kadm5_server_handle_t)handle; return (srvrhdl->params.kpasswd_protocol); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include "autoconf.h" #if defined(HAVE_COMPILE) && defined(HAVE_STEP) #define SOLARIS_REGEXPS #elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXEC) #define POSIX_REGEXPS #elif defined(HAVE_RE_COMP) && defined(HAVE_RE_EXEC) #define BSD_REGEXPS #else #error I cannot find any regexp functions #endif #include #include #include "server_internal.h" #include #ifdef SOLARIS_REGEXPS #include #endif #ifdef POSIX_REGEXPS #include #endif #include struct iter_data { krb5_context context; char **names; int n_names, sz_names; unsigned int malloc_failed; char *exp; #ifdef SOLARIS_REGEXPS char *expbuf; #endif #ifdef POSIX_REGEXPS regex_t preg; #endif }; /* * Function: glob_to_regexp * * Arguments: * * glob (r) the shell-style glob (?*[]) to convert * realm (r) the default realm to append, or NULL * regexp (w) the ed-style regexp created from glob * * Effects: * * regexp is filled in with allocated memory contained a regular * expression to be used with re_comp/compile that matches what the * shell-style glob would match. If glob does not contain an "@" * character and realm is not NULL, "@*" is appended to the regexp. * * Conversion algorithm: * * quoted characters are copied quoted * ? is converted to . * * is converted to .* * active characters are quoted: ^, $, . * [ and ] are active but supported and have the same meaning, so * they are copied * other characters are copied * regexp is anchored with ^ and $ */ static kadm5_ret_t glob_to_regexp(char *glob, char *realm, char **regexp) { int append_realm; char *p; /* validate the glob */ if (glob[strlen(glob)-1] == '\\') return EINVAL; /* A character of glob can turn into two in regexp, plus ^ and $ */ /* and trailing null. If glob has no @, also allocate space for */ /* the realm. */ append_realm = (realm != NULL) && (strchr(glob, '@') == NULL); p = (char *) malloc(strlen(glob)*2+ 3 + (append_realm ? 2 : 0)); if (p == NULL) return ENOMEM; *regexp = p; *p++ = '^'; while (*glob) { switch (*glob) { case '?': *p++ = '.'; break; case '*': *p++ = '.'; *p++ = '*'; break; case '.': case '^': case '$': *p++ = '\\'; *p++ = *glob; break; case '\\': *p++ = '\\'; *p++ = *++glob; break; default: *p++ = *glob; break; } glob++; } if (append_realm) { *p++ = '@'; *p++ = '*'; } *p++ = '$'; *p++ = '\0'; return KADM5_OK; } static void get_either_iter(struct iter_data *data, char *name) { int match; #ifdef SOLARIS_REGEXPS match = (step(name, data->expbuf) != 0); #endif #ifdef POSIX_REGEXPS match = (regexec(&data->preg, name, 0, NULL, 0) == 0); #endif #ifdef BSD_REGEXPS match = (re_exec(name) != 0); #endif if (match) { if (data->n_names == data->sz_names) { int new_sz = data->sz_names * 2; char **new_names = realloc(data->names, new_sz * sizeof(char *)); if (new_names) { data->names = new_names; data->sz_names = new_sz; } else { data->malloc_failed = 1; free(name); return; } } data->names[data->n_names++] = name; } else free(name); } static void get_pols_iter(void *data, osa_policy_ent_t entry) { char *name; if ((name = strdup(entry->name)) == NULL) return; get_either_iter(data, name); } static void get_princs_iter(void *data, krb5_principal princ) { struct iter_data *id = (struct iter_data *) data; char *name; if (krb5_unparse_name(id->context, princ, &name) != 0) return; get_either_iter(data, name); } static kadm5_ret_t kadm5_get_either(int princ, void *server_handle, char *exp, char ***princs, int *count) { struct iter_data data; #ifdef BSD_REGEXPS char *msg; #endif char *regexp; int i, ret; kadm5_server_handle_t handle = server_handle; *count = 0; if (exp == NULL) exp = "*"; CHECK_HANDLE(server_handle); if ((ret = glob_to_regexp(exp, princ ? handle->params.realm : NULL, ®exp)) != KADM5_OK) return ret; if ( #ifdef SOLARIS_REGEXPS ((data.expbuf = compile(regexp, NULL, NULL)) == NULL) #endif #ifdef POSIX_REGEXPS ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0) #endif #ifdef BSD_REGEXPS ((msg = (char *) re_comp(regexp)) != NULL) #endif ) { /* XXX syslog msg or regerr(regerrno) */ free(regexp); return EINVAL; } data.n_names = 0; data.sz_names = 10; data.malloc_failed = 0; data.names = malloc(sizeof(char *) * data.sz_names); if (data.names == NULL) { free(regexp); return ENOMEM; } if (princ) { data.context = handle->context; ret = kdb_iter_entry(handle, exp, get_princs_iter, (void *) &data); } else { ret = krb5_db_iter_policy(handle->context, exp, get_pols_iter, (void *)&data); } free(regexp); #ifdef POSIX_REGEXPS regfree(&data.preg); #endif if ( !ret && data.malloc_failed) ret = ENOMEM; if ( ret ) { for (i = 0; i < data.n_names; i++) free(data.names[i]); free(data.names); return ret; } *princs = data.names; *count = data.n_names; return KADM5_OK; } kadm5_ret_t kadm5_get_principals(void *server_handle, char *exp, char ***princs, int *count) { return kadm5_get_either(1, server_handle, exp, princs, count); } kadm5_ret_t kadm5_get_policies(void *server_handle, char *exp, char ***pols, int *count) { return kadm5_get_either(0, server_handle, exp, pols, count); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ * */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include #include #include "server_internal.h" kadm5_ret_t kadm5_free_principal_ent(void *server_handle, kadm5_principal_ent_t val) { kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); if(val) { if(val->principal) krb5_free_principal(handle->context, val->principal); if(val->mod_name) krb5_free_principal(handle->context, val->mod_name); if(val->policy) free(val->policy); /* XXX free key_data and tl_data */ if (handle->api_version == KADM5_API_VERSION_1) free(val); } return KADM5_OK; } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * * $Header$ */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header$"; #endif #include "server_internal.h" #include #include #include #include #define MAX_PW_HISTORY 10 #define MIN_PW_HISTORY 1 #define MIN_PW_CLASSES 1 #define MAX_PW_CLASSES 5 #define MIN_PW_LENGTH 1 /* * Function: kadm5_create_policy * * Purpose: Create Policies in the policy DB. * * Arguments: * entry (input) The policy entry to be written out to the DB. * mask (input) Specifies which fields in entry are to ge written out * and which get default values. * 0 if successful otherwise an error code is returned. * * Requires: * Entry must be a valid principal entry, and mask have a valid value. * * Effects: * Verifies that mask does not specify that the refcount should * be set as part of the creation, and calls * kadm5_create_policy_internal. If the refcount *is* * specified, returns KADM5_BAD_MASK. */ kadm5_ret_t kadm5_create_policy(void *server_handle, kadm5_policy_ent_t entry, long mask) { CHECK_HANDLE(server_handle); krb5_clear_error_message(((kadm5_server_handle_t)server_handle)->context); if (mask & KADM5_REF_COUNT) return KADM5_BAD_MASK; else return kadm5_create_policy_internal(server_handle, entry, mask); } /* * Function: kadm5_create_policy_internal * * Purpose: Create Policies in the policy DB. * * Arguments: * entry (input) The policy entry to be written out to the DB. * mask (input) Specifies which fields in entry are to ge written out * and which get default values. * 0 if successful otherwise an error code is returned. * * Requires: * Entry must be a valid principal entry, and mask have a valid value. * * Effects: * Writes the data to the database, and does a database sync if * successful. * */ kadm5_ret_t kadm5_create_policy_internal(void *server_handle, kadm5_policy_ent_t entry, long mask) { kadm5_server_handle_t handle = server_handle; osa_policy_ent_rec pent; int ret; char *p; CHECK_HANDLE(server_handle); if ((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL)) return EINVAL; if(strlen(entry->policy) == 0) return KADM5_BAD_POLICY; if (!(mask & KADM5_POLICY)) return KADM5_BAD_MASK; pent.name = entry->policy; p = entry->policy; while(*p != '\0') { if(*p < ' ' || *p > '~') return KADM5_BAD_POLICY; else p++; } if (!(mask & KADM5_PW_MAX_LIFE)) pent.pw_max_life = 0; else pent.pw_max_life = entry->pw_max_life; if (!(mask & KADM5_PW_MIN_LIFE)) pent.pw_min_life = 0; else { if((mask & KADM5_PW_MAX_LIFE)) { if(entry->pw_min_life > entry->pw_max_life && entry->pw_max_life != 0) return KADM5_BAD_MIN_PASS_LIFE; } pent.pw_min_life = entry->pw_min_life; } if (!(mask & KADM5_PW_MIN_LENGTH)) pent.pw_min_length = MIN_PW_LENGTH; else { if(entry->pw_min_length < MIN_PW_LENGTH) return KADM5_BAD_LENGTH; pent.pw_min_length = entry->pw_min_length; } if (!(mask & KADM5_PW_MIN_CLASSES)) pent.pw_min_classes = MIN_PW_CLASSES; else { if(entry->pw_min_classes > MAX_PW_CLASSES || entry->pw_min_classes < MIN_PW_CLASSES) return KADM5_BAD_CLASS; pent.pw_min_classes = entry->pw_min_classes; } if (!(mask & KADM5_PW_HISTORY_NUM)) pent.pw_history_num = MIN_PW_HISTORY; else { if(entry->pw_history_num < MIN_PW_HISTORY || entry->pw_history_num > MAX_PW_HISTORY) return KADM5_BAD_HISTORY; else pent.pw_history_num = entry->pw_history_num; } if (!(mask & KADM5_REF_COUNT)) pent.policy_refcnt = 0; else pent.policy_refcnt = entry->policy_refcnt; if ((ret = krb5_db_create_policy(handle->context, &pent))) return ret; else return KADM5_OK; } kadm5_ret_t kadm5_delete_policy(void *server_handle, kadm5_policy_t name) { kadm5_server_handle_t handle = server_handle; osa_policy_ent_t entry; int ret; int cnt=1; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); if(name == (kadm5_policy_t) NULL) return EINVAL; if(strlen(name) == 0) return KADM5_BAD_POLICY; if((ret = krb5_db_get_policy(handle->context, name, &entry,&cnt))) return ret; if( cnt != 1 ) return KADM5_UNK_POLICY; if(entry->policy_refcnt != 0) { krb5_db_free_policy(handle->context, entry); return KADM5_POLICY_REF; } krb5_db_free_policy(handle->context, entry); if ((ret = krb5_db_delete_policy(handle->context, name))) return ret; else return KADM5_OK; } kadm5_ret_t kadm5_modify_policy(void *server_handle, kadm5_policy_ent_t entry, long mask) { CHECK_HANDLE(server_handle); krb5_clear_error_message(((kadm5_server_handle_t)server_handle)->context); if (mask & KADM5_REF_COUNT) return KADM5_BAD_MASK; else return kadm5_modify_policy_internal(server_handle, entry, mask); } kadm5_ret_t kadm5_modify_policy_internal(void *server_handle, kadm5_policy_ent_t entry, long mask) { kadm5_server_handle_t handle = server_handle; osa_policy_ent_t p; int ret; int cnt=1; CHECK_HANDLE(server_handle); if((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL)) return EINVAL; if(strlen(entry->policy) == 0) return KADM5_BAD_POLICY; if((mask & KADM5_POLICY)) return KADM5_BAD_MASK; if ((ret = krb5_db_get_policy(handle->context, entry->policy, &p, &cnt))) return ret; if (cnt != 1) return KADM5_UNK_POLICY; if ((mask & KADM5_PW_MAX_LIFE)) p->pw_max_life = entry->pw_max_life; if ((mask & KADM5_PW_MIN_LIFE)) { if(entry->pw_min_life > p->pw_max_life && p->pw_max_life != 0) { krb5_db_free_policy(handle->context, p); return KADM5_BAD_MIN_PASS_LIFE; } p->pw_min_life = entry->pw_min_life; } if ((mask & KADM5_PW_MIN_LENGTH)) { if(entry->pw_min_length < MIN_PW_LENGTH) { krb5_db_free_policy(handle->context, p); return KADM5_BAD_LENGTH; } p->pw_min_length = entry->pw_min_length; } if ((mask & KADM5_PW_MIN_CLASSES)) { if(entry->pw_min_classes > MAX_PW_CLASSES || entry->pw_min_classes < MIN_PW_CLASSES) { krb5_db_free_policy(handle->context, p); return KADM5_BAD_CLASS; } p->pw_min_classes = entry->pw_min_classes; } if ((mask & KADM5_PW_HISTORY_NUM)) { if(entry->pw_history_num < MIN_PW_HISTORY || entry->pw_history_num > MAX_PW_HISTORY) { krb5_db_free_policy(handle->context, p); return KADM5_BAD_HISTORY; } p->pw_history_num = entry->pw_history_num; } if ((mask & KADM5_REF_COUNT)) p->policy_refcnt = entry->policy_refcnt; ret = krb5_db_put_policy(handle->context, p); krb5_db_free_policy(handle->context, p); return ret; } kadm5_ret_t kadm5_get_policy(void *server_handle, kadm5_policy_t name, kadm5_policy_ent_t entry) { osa_policy_ent_t t; kadm5_policy_ent_rec entry_local, **entry_orig, *new; int ret; kadm5_server_handle_t handle = server_handle; int cnt=1; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); /* * In version 1, entry is a pointer to a kadm5_policy_ent_t that * should be filled with allocated memory. */ if (handle->api_version == KADM5_API_VERSION_1) { entry_orig = (kadm5_policy_ent_rec **) entry; *entry_orig = NULL; entry = &entry_local; } if (name == (kadm5_policy_t) NULL) return EINVAL; if(strlen(name) == 0) return KADM5_BAD_POLICY; if((ret = krb5_db_get_policy(handle->context, name, &t, &cnt))) return ret; if( cnt != 1 ) return KADM5_UNK_POLICY; if ((entry->policy = (char *) malloc(strlen(t->name) + 1)) == NULL) { krb5_db_free_policy(handle->context, t); return ENOMEM; } strcpy(entry->policy, t->name); entry->pw_min_life = t->pw_min_life; entry->pw_max_life = t->pw_max_life; entry->pw_min_length = t->pw_min_length; entry->pw_min_classes = t->pw_min_classes; entry->pw_history_num = t->pw_history_num; entry->policy_refcnt = t->policy_refcnt; krb5_db_free_policy(handle->context, t); if (handle->api_version == KADM5_API_VERSION_1) { new = (kadm5_policy_ent_t) malloc(sizeof(kadm5_policy_ent_rec)); if (new == NULL) { free(entry->policy); krb5_db_free_policy(handle->context, t); return ENOMEM; } *new = *entry; *entry_orig = new; } return KADM5_OK; } /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved */ #include #include #include #include "server_internal.h" #include #include #include #include #include #include #include #include #include #ifdef USE_PASSWORD_SERVER #include #endif extern krb5_principal master_princ; extern krb5_principal hist_princ; extern krb5_keyblock hist_key; extern krb5_db_entry master_db; extern krb5_db_entry hist_db; extern krb5_kvno hist_kvno; static int decrypt_key_data(krb5_context context, krb5_keyblock *, int n_key_data, krb5_key_data *key_data, krb5_keyblock **keyblocks, int *n_keys); static krb5_error_code kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc) { register krb5_principal tempprinc; register int i, nelems; tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data)); if (tempprinc == 0) return ENOMEM; memcpy(tempprinc, inprinc, sizeof(krb5_principal_data)); nelems = (int) krb5_princ_size(context, inprinc); tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data)); if (tempprinc->data == 0) { krb5_db_free(context, (char *)tempprinc); return ENOMEM; } for (i = 0; i < nelems; i++) { unsigned int len = krb5_princ_component(context, inprinc, i)->length; krb5_princ_component(context, tempprinc, i)->length = len; if (((krb5_princ_component(context, tempprinc, i)->data = krb5_db_alloc(context, NULL, len)) == 0) && len) { while (--i >= 0) krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); krb5_db_free (context, tempprinc->data); krb5_db_free (context, tempprinc); return ENOMEM; } if (len) memcpy(krb5_princ_component(context, tempprinc, i)->data, krb5_princ_component(context, inprinc, i)->data, len); } tempprinc->realm.data = krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length); if (!tempprinc->realm.data && tempprinc->realm.length) { for (i = 0; i < nelems; i++) krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data); krb5_db_free(context, tempprinc->data); krb5_db_free(context, tempprinc); return ENOMEM; } if (tempprinc->realm.length) memcpy(tempprinc->realm.data, inprinc->realm.data, inprinc->realm.length); *outprinc = tempprinc; return 0; } static void kadm5_free_principal(krb5_context context, krb5_principal val) { register krb5_int32 i; if (!val) return; if (val->data) { i = krb5_princ_size(context, val); while(--i >= 0) krb5_db_free(context, krb5_princ_component(context, val, i)->data); krb5_db_free(context, val->data); } if (val->realm.data) krb5_db_free(context, val->realm.data); krb5_db_free(context, val); } /* * XXX Functions that ought to be in libkrb5.a, but aren't. */ kadm5_ret_t krb5_copy_key_data_contents(context, from, to) krb5_context context; krb5_key_data *from, *to; { int i, idx; *to = *from; idx = (from->key_data_ver == 1 ? 1 : 2); for (i = 0; i < idx; i++) { if ( from->key_data_length[i] ) { to->key_data_contents[i] = malloc(from->key_data_length[i]); if (to->key_data_contents[i] == NULL) { for (i = 0; i < idx; i++) { if (to->key_data_contents[i]) { memset(to->key_data_contents[i], 0, to->key_data_length[i]); free(to->key_data_contents[i]); } } return ENOMEM; } memcpy(to->key_data_contents[i], from->key_data_contents[i], from->key_data_length[i]); } } return 0; } static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) { krb5_tl_data *n; n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); if (n == NULL) return NULL; n->tl_data_contents = malloc(tl->tl_data_length); if (n->tl_data_contents == NULL) { free(n); return NULL; } memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); n->tl_data_type = tl->tl_data_type; n->tl_data_length = tl->tl_data_length; n->tl_data_next = NULL; return n; } /* This is in lib/kdb/kdb_cpw.c, but is static */ static void cleanup_key_data(context, count, data) krb5_context context; int count; krb5_key_data * data; { int i, j; for (i = 0; i < count; i++) for (j = 0; j < data[i].key_data_ver; j++) if (data[i].key_data_length[j]) krb5_db_free(context, data[i].key_data_contents[j]); krb5_db_free(context, data); } kadm5_ret_t kadm5_create_principal(void *server_handle, kadm5_principal_ent_t entry, long mask, char *password) { return kadm5_create_principal_3(server_handle, entry, mask, 0, NULL, password); } kadm5_ret_t kadm5_create_principal_3(void *server_handle, kadm5_principal_ent_t entry, long mask, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *password) { krb5_db_entry kdb; osa_princ_ent_rec adb; kadm5_policy_ent_rec polent; krb5_int32 now; krb5_tl_data *tl_data_tail; unsigned int ret; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); /* * Argument sanity checking, and opening up the DB */ if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) || (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) || (mask & KADM5_FAIL_AUTH_COUNT)) return KADM5_BAD_MASK; if((mask & ~ALL_PRINC_MASK)) return KADM5_BAD_MASK; if (entry == (kadm5_principal_ent_t) NULL || password == NULL) return EINVAL; /* * Check to see if the principal exists */ ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); switch(ret) { case KADM5_UNK_PRINC: /* Solaris Kerberos */ memset(&kdb, 0, sizeof(krb5_db_entry)); memset(&adb, 0, sizeof(osa_princ_ent_rec)); break; case 0: /* * Solaris Kerberos: this allows an addprinc to be done on a mix-in * princ which has no keys initially. */ if (kdb.n_key_data != 0) { /* have a princ with keys, return dupe princ error */ kdb_free_entry(handle, &kdb, &adb); return KADM5_DUP; } else { /* * have a princ with no keys, let's replace it. Note, want to * keep the existing kdb tl_data (specifically the LDAP plugin * adds the DN to the tl_data which is needed to locate the dir. * entry). */ kdb_free_entry(handle, NULL, &adb); memset(&adb, 0, sizeof(osa_princ_ent_rec)); } break; default: return ret; } /* * If a policy was specified, load it. * If we can not find the one specified return an error */ if ((mask & KADM5_POLICY)) { if ((ret = kadm5_get_policy(handle->lhandle, entry->policy, &polent)) != KADM5_OK) { if(ret == EINVAL) return KADM5_BAD_POLICY; else return ret; } } if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY), &polent, entry->principal))) { if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return ret; } /* * Start populating the various DB fields, using the * "defaults" for fields that were not specified by the * mask. */ if ((ret = krb5_timeofday(handle->context, &now))) { if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return ret; } kdb.magic = KRB5_KDB_MAGIC_NUMBER; kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */ /* * Solaris Kerberos: * If KADM5_ATTRIBUTES is set, we want to rope in not only * entry->attributes, but also the generic params.flags * obtained previously via kadm5_get_config_params. */ if ((mask & KADM5_ATTRIBUTES)) { kdb.attributes = handle->params.flags; kdb.attributes |= entry->attributes; } else { kdb.attributes = handle->params.flags; } if ((mask & KADM5_MAX_LIFE)) kdb.max_life = entry->max_life; else kdb.max_life = handle->params.max_life; if (mask & KADM5_MAX_RLIFE) kdb.max_renewable_life = entry->max_renewable_life; else kdb.max_renewable_life = handle->params.max_rlife; if ((mask & KADM5_PRINC_EXPIRE_TIME)) kdb.expiration = entry->princ_expire_time; else kdb.expiration = handle->params.expiration; kdb.pw_expiration = 0; if ((mask & KADM5_POLICY)) { if(polent.pw_max_life) kdb.pw_expiration = now + polent.pw_max_life; else kdb.pw_expiration = 0; } if ((mask & KADM5_PW_EXPIRATION)) kdb.pw_expiration = entry->pw_expiration; kdb.last_success = 0; kdb.last_failed = 0; kdb.fail_auth_count = 0; /* this is kind of gross, but in order to free the tl data, I need to free the entire kdb entry, and that will try to free the principal. */ if ((ret = kadm5_copy_principal(handle->context, entry->principal, &(kdb.princ)))) { if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return(ret); } if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) { krb5_db_free_principal(handle->context, &kdb, 1); if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return(ret); } if (mask & KADM5_TL_DATA) { /* splice entry->tl_data onto the front of kdb.tl_data */ for (tl_data_tail = entry->tl_data; tl_data_tail; tl_data_tail = tl_data_tail->tl_data_next) { ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail); if( ret ) { krb5_db_free_principal(handle->context, &kdb, 1); if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return ret; } } } /* initialize the keys */ if ((ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, n_ks_tuple?ks_tuple:handle->params.keysalts, n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, password, (mask & KADM5_KVNO)?entry->kvno:1, FALSE, &kdb))) { krb5_db_free_principal(handle->context, &kdb, 1); if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return(ret); } /* populate the admin-server-specific fields. In the OV server, this used to be in a separate database. Since there's already marshalling code for the admin fields, to keep things simple, I'm going to keep it, and make all the admin stuff occupy a single tl_data record, */ adb.admin_history_kvno = hist_kvno; if ((mask & KADM5_POLICY)) { adb.aux_attributes = KADM5_POLICY; /* this does *not* need to be strdup'ed, because adb is xdr */ /* encoded in osa_adb_create_princ, and not ever freed */ adb.policy = entry->policy; } /* increment the policy ref count, if any */ if ((mask & KADM5_POLICY)) { polent.policy_refcnt++; if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, KADM5_REF_COUNT)) != KADM5_OK) { krb5_db_free_principal(handle->context, &kdb, 1); if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return(ret); } } /* In all cases key and the principal data is set, let the database provider know */ kdb.mask = mask | KADM5_KEY_DATA | KADM5_PRINCIPAL ; /* store the new db entry */ ret = kdb_put_entry(handle, &kdb, &adb); krb5_db_free_principal(handle->context, &kdb, 1); if (ret) { if ((mask & KADM5_POLICY)) { /* decrement the policy ref count */ polent.policy_refcnt--; /* * if this fails, there's nothing we can do anyway. the * policy refcount wil be too high. */ (void) kadm5_modify_policy_internal(handle->lhandle, &polent, KADM5_REF_COUNT); } if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return(ret); } if (mask & KADM5_POLICY) (void) kadm5_free_policy_ent(handle->lhandle, &polent); return KADM5_OK; } kadm5_ret_t kadm5_delete_principal(void *server_handle, krb5_principal principal) { unsigned int ret; kadm5_policy_ent_rec polent; krb5_db_entry kdb; osa_princ_ent_rec adb; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); if (principal == NULL) return EINVAL; if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return(ret); if ((adb.aux_attributes & KADM5_POLICY)) { if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &polent)) == KADM5_OK) { polent.policy_refcnt--; if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, KADM5_REF_COUNT)) != KADM5_OK) { (void) kadm5_free_policy_ent(handle->lhandle, &polent); kdb_free_entry(handle, &kdb, &adb); return(ret); } } if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) { kdb_free_entry(handle, &kdb, &adb); return ret; } } ret = kdb_delete_entry(handle, principal); kdb_free_entry(handle, &kdb, &adb); return ret; } kadm5_ret_t kadm5_modify_principal(void *server_handle, kadm5_principal_ent_t entry, long mask) { int ret, ret2, i; kadm5_policy_ent_rec npol, opol; int have_npol = 0, have_opol = 0; krb5_db_entry kdb; krb5_tl_data *tl_data_orig; osa_princ_ent_rec adb; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED)) return KADM5_BAD_MASK; if((mask & ~ALL_PRINC_MASK)) return KADM5_BAD_MASK; if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) return KADM5_BAD_MASK; if(entry == (kadm5_principal_ent_t) NULL) return EINVAL; if (mask & KADM5_TL_DATA) { tl_data_orig = entry->tl_data; while (tl_data_orig) { if (tl_data_orig->tl_data_type < 256) return KADM5_BAD_TL_TYPE; tl_data_orig = tl_data_orig->tl_data_next; } } ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); if (ret) return(ret); /* * This is pretty much the same as create ... */ if ((mask & KADM5_POLICY)) { /* get the new policy */ ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol); if (ret) { switch (ret) { case EINVAL: ret = KADM5_BAD_POLICY; break; case KADM5_UNK_POLICY: case KADM5_BAD_POLICY: ret = KADM5_UNK_POLICY; break; } goto done; } have_npol = 1; /* if we already have a policy, get it to decrement the refcnt */ if(adb.aux_attributes & KADM5_POLICY) { /* ... but not if the old and new are the same */ if(strcmp(adb.policy, entry->policy)) { ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); switch(ret) { case EINVAL: case KADM5_BAD_POLICY: case KADM5_UNK_POLICY: break; case KADM5_OK: have_opol = 1; opol.policy_refcnt--; break; default: goto done; break; } npol.policy_refcnt++; } } else npol.policy_refcnt++; /* set us up to use the new policy */ adb.aux_attributes |= KADM5_POLICY; if (adb.policy) free(adb.policy); adb.policy = strdup(entry->policy); /* set pw_max_life based on new policy */ if (npol.pw_max_life) { ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, &(kdb.pw_expiration)); if (ret) goto done; kdb.pw_expiration += npol.pw_max_life; } else { kdb.pw_expiration = 0; } } if ((mask & KADM5_POLICY_CLR) && (adb.aux_attributes & KADM5_POLICY)) { ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); switch(ret) { case EINVAL: case KADM5_BAD_POLICY: case KADM5_UNK_POLICY: ret = KADM5_BAD_DB; goto done; break; case KADM5_OK: have_opol = 1; if (adb.policy) free(adb.policy); adb.policy = NULL; adb.aux_attributes &= ~KADM5_POLICY; kdb.pw_expiration = 0; opol.policy_refcnt--; break; default: goto done; break; } } if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) && (((have_opol) && (ret = kadm5_modify_policy_internal(handle->lhandle, &opol, KADM5_REF_COUNT))) || ((have_npol) && (ret = kadm5_modify_policy_internal(handle->lhandle, &npol, KADM5_REF_COUNT))))) goto done; if ((mask & KADM5_ATTRIBUTES)) kdb.attributes = entry->attributes; if ((mask & KADM5_MAX_LIFE)) kdb.max_life = entry->max_life; if ((mask & KADM5_PRINC_EXPIRE_TIME)) kdb.expiration = entry->princ_expire_time; if (mask & KADM5_PW_EXPIRATION) kdb.pw_expiration = entry->pw_expiration; if (mask & KADM5_MAX_RLIFE) kdb.max_renewable_life = entry->max_renewable_life; if (mask & KADM5_FAIL_AUTH_COUNT) kdb.fail_auth_count = entry->fail_auth_count; if((mask & KADM5_KVNO)) { for (i = 0; i < kdb.n_key_data; i++) kdb.key_data[i].key_data_kvno = entry->kvno; } if (mask & KADM5_TL_DATA) { krb5_tl_data *tl; /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */ for (tl = entry->tl_data; tl; tl = tl->tl_data_next) { ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl); if( ret ) { goto done; } } } /* let the mask propagate to the database provider */ kdb.mask = mask; ret = kdb_put_entry(handle, &kdb, &adb); if (ret) goto done; ret = KADM5_OK; done: if (have_opol) { ret2 = kadm5_free_policy_ent(handle->lhandle, &opol); ret = ret ? ret : ret2; } if (have_npol) { ret2 = kadm5_free_policy_ent(handle->lhandle, &npol); ret = ret ? ret : ret2; } kdb_free_entry(handle, &kdb, &adb); return ret; } kadm5_ret_t kadm5_rename_principal(void *server_handle, krb5_principal source, krb5_principal target) { krb5_db_entry kdb; osa_princ_ent_rec adb; int ret, i; kadm5_server_handle_t handle = server_handle; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); if (source == NULL || target == NULL) return EINVAL; if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) { kdb_free_entry(handle, &kdb, &adb); return(KADM5_DUP); } if ((ret = kdb_get_entry(handle, source, &kdb, &adb))) return ret; /* this is kinda gross, but unavoidable */ for (i=0; icontext, kdb.princ); ret = kadm5_copy_principal(handle->context, target, &kdb.princ); if (ret) { kdb.princ = NULL; /* so freeing the dbe doesn't lose */ goto done; } if ((ret = kdb_put_entry(handle, &kdb, &adb))) goto done; ret = kdb_delete_entry(handle, source); done: kdb_free_entry(handle, &kdb, &adb); return ret; } kadm5_ret_t kadm5_get_principal(void *server_handle, krb5_principal principal, kadm5_principal_ent_t entry, long in_mask) { krb5_db_entry kdb; osa_princ_ent_rec adb; krb5_error_code ret = 0; long mask; int i; kadm5_server_handle_t handle = server_handle; kadm5_principal_ent_rec entry_local, *entry_orig; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); /* * In version 1, all the defined fields are always returned. * entry is a pointer to a kadm5_principal_ent_t_v1 that should be * filled with allocated memory. */ if (handle->api_version == KADM5_API_VERSION_1) { mask = KADM5_PRINCIPAL_NORMAL_MASK; entry_orig = entry; entry = &entry_local; } else { mask = in_mask; } memset((char *) entry, 0, sizeof(*entry)); if (principal == NULL) return EINVAL; if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return ret; if ((mask & KADM5_POLICY) && adb.policy && (adb.aux_attributes & KADM5_POLICY)) { if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) { ret = ENOMEM; goto done; } strcpy(entry->policy, adb.policy); } if (mask & KADM5_AUX_ATTRIBUTES) entry->aux_attributes = adb.aux_attributes; if ((mask & KADM5_PRINCIPAL) && (ret = krb5_copy_principal(handle->context, principal, &entry->principal))) { goto done; } if (mask & KADM5_PRINC_EXPIRE_TIME) entry->princ_expire_time = kdb.expiration; if ((mask & KADM5_LAST_PWD_CHANGE) && (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, &(entry->last_pwd_change)))) { goto done; } if (mask & KADM5_PW_EXPIRATION) entry->pw_expiration = kdb.pw_expiration; if (mask & KADM5_MAX_LIFE) entry->max_life = kdb.max_life; /* this is a little non-sensical because the function returns two */ /* values that must be checked separately against the mask */ if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb, &(entry->mod_date), &(entry->mod_name)); if (ret) { goto done; } if (! (mask & KADM5_MOD_TIME)) entry->mod_date = 0; if (! (mask & KADM5_MOD_NAME)) { krb5_free_principal(handle->context, entry->principal); entry->principal = NULL; } } if (mask & KADM5_ATTRIBUTES) entry->attributes = kdb.attributes; if (mask & KADM5_KVNO) for (entry->kvno = 0, i=0; i entry->kvno) entry->kvno = kdb.key_data[i].key_data_kvno; if (handle->api_version == KADM5_API_VERSION_2) entry->mkvno = 0; else { /* XXX I'll be damned if I know how to deal with this one --marc */ entry->mkvno = 1; } /* * The new fields that only exist in version 2 start here */ if (handle->api_version == KADM5_API_VERSION_2) { if (mask & KADM5_MAX_RLIFE) entry->max_renewable_life = kdb.max_renewable_life; if (mask & KADM5_LAST_SUCCESS) entry->last_success = kdb.last_success; if (mask & KADM5_LAST_FAILED) entry->last_failed = kdb.last_failed; if (mask & KADM5_FAIL_AUTH_COUNT) entry->fail_auth_count = kdb.fail_auth_count; if (mask & KADM5_TL_DATA) { krb5_tl_data *tl, *tl2; entry->tl_data = NULL; tl = kdb.tl_data; while (tl) { if (tl->tl_data_type > 255) { if ((tl2 = dup_tl_data(tl)) == NULL) { ret = ENOMEM; goto done; } tl2->tl_data_next = entry->tl_data; entry->tl_data = tl2; entry->n_tl_data++; } tl = tl->tl_data_next; } } if (mask & KADM5_KEY_DATA) { entry->n_key_data = kdb.n_key_data; if(entry->n_key_data) { entry->key_data = (krb5_key_data *) malloc(entry->n_key_data*sizeof(krb5_key_data)); if (entry->key_data == NULL) { ret = ENOMEM; goto done; } } else entry->key_data = NULL; for (i = 0; i < entry->n_key_data; i++) ret = krb5_copy_key_data_contents(handle->context, &kdb.key_data[i], &entry->key_data[i]); if (ret) goto done; } } /* * If KADM5_API_VERSION_1, we return an allocated structure, and * we need to convert the new structure back into the format the * caller is expecting. */ if (handle->api_version == KADM5_API_VERSION_1) { kadm5_principal_ent_t_v1 newv1; newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1))); if (newv1 == NULL) { ret = ENOMEM; goto done; } newv1->principal = entry->principal; newv1->princ_expire_time = entry->princ_expire_time; newv1->last_pwd_change = entry->last_pwd_change; newv1->pw_expiration = entry->pw_expiration; newv1->max_life = entry->max_life; newv1->mod_name = entry->mod_name; newv1->mod_date = entry->mod_date; newv1->attributes = entry->attributes; newv1->kvno = entry->kvno; newv1->mkvno = entry->mkvno; newv1->policy = entry->policy; newv1->aux_attributes = entry->aux_attributes; *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1; } ret = KADM5_OK; done: if (ret && entry->principal) krb5_free_principal(handle->context, entry->principal); kdb_free_entry(handle, &kdb, &adb); return ret; } /* * Function: check_pw_reuse * * Purpose: Check if a key appears in a list of keys, in order to * enforce password history. * * Arguments: * * context (r) the krb5 context * hist_keyblock (r) the key that hist_key_data is * encrypted in * n_new_key_data (r) length of new_key_data * new_key_data (r) keys to check against * pw_hist_data, encrypted in hist_keyblock * n_pw_hist_data (r) length of pw_hist_data * pw_hist_data (r) passwords to check new_key_data against * * Effects: * For each new_key in new_key_data: * decrypt new_key with the master_keyblock * for each password in pw_hist_data: * for each hist_key in password: * decrypt hist_key with hist_keyblock * compare the new_key and hist_key * * Returns krb5 errors, KADM5_PASS_RESUSE if a key in * new_key_data is the same as a key in pw_hist_data, or 0. */ static kadm5_ret_t check_pw_reuse(krb5_context context, krb5_keyblock *master_keyblock, krb5_keyblock *hist_keyblock, int n_new_key_data, krb5_key_data *new_key_data, unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data) { int x, y, z; krb5_keyblock newkey, histkey; krb5_error_code ret; for (x = 0; x < n_new_key_data; x++) { ret = krb5_dbekd_decrypt_key_data(context, master_keyblock, &(new_key_data[x]), &newkey, NULL); if (ret) return(ret); for (y = 0; y < n_pw_hist_data; y++) { for (z = 0; z < pw_hist_data[y].n_key_data; z++) { ret = krb5_dbekd_decrypt_key_data(context, hist_keyblock, &pw_hist_data[y].key_data[z], &histkey, NULL); if (ret) return(ret); if ((newkey.length == histkey.length) && (newkey.enctype == histkey.enctype) && (memcmp(newkey.contents, histkey.contents, histkey.length) == 0)) { krb5_free_keyblock_contents(context, &histkey); krb5_free_keyblock_contents(context, &newkey); return(KADM5_PASS_REUSE); } krb5_free_keyblock_contents(context, &histkey); } } krb5_free_keyblock_contents(context, &newkey); } return(0); } /* * Function: create_history_entry * * Purpose: Creates a password history entry from an array of * key_data. * * Arguments: * * context (r) krb5_context to use * master_keyblcok (r) master key block * n_key_data (r) number of elements in key_data * key_data (r) keys to add to the history entry * hist (w) history entry to fill in * * Effects: * * hist->key_data is allocated to store n_key_data key_datas. Each * element of key_data is decrypted with master_keyblock, re-encrypted * in hist_key, and added to hist->key_data. hist->n_key_data is * set to n_key_data. */ static int create_history_entry(krb5_context context, krb5_keyblock *master_keyblock, int n_key_data, krb5_key_data *key_data, osa_pw_hist_ent *hist) { int i, ret; krb5_keyblock key; krb5_keysalt salt; hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data)); if (hist->key_data == NULL) return ENOMEM; memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data)); for (i = 0; i < n_key_data; i++) { ret = krb5_dbekd_decrypt_key_data(context, master_keyblock, &key_data[i], &key, &salt); if (ret) return ret; ret = krb5_dbekd_encrypt_key_data(context, &hist_key, &key, &salt, key_data[i].key_data_kvno, &hist->key_data[i]); if (ret) return ret; krb5_free_keyblock_contents(context, &key); /* krb5_free_keysalt(context, &salt); */ } hist->n_key_data = n_key_data; return 0; } static void free_history_entry(krb5_context context, osa_pw_hist_ent *hist) { int i; for (i = 0; i < hist->n_key_data; i++) krb5_free_key_data_contents(context, &hist->key_data[i]); free(hist->key_data); } /* * Function: add_to_history * * Purpose: Adds a password to a principal's password history. * * Arguments: * * context (r) krb5_context to use * adb (r/w) admin principal entry to add keys to * pol (r) adb's policy * pw (r) keys for the password to add to adb's key history * * Effects: * * add_to_history adds a single password to adb's password history. * pw contains n_key_data keys in its key_data, in storage should be * allocated but not freed by the caller (XXX blech!). * * This function maintains adb->old_keys as a circular queue. It * starts empty, and grows each time this function is called until it * is pol->pw_history_num items long. adb->old_key_len holds the * number of allocated entries in the array, and must therefore be [0, * pol->pw_history_num). adb->old_key_next is the index into the * array where the next element should be written, and must be [0, * adb->old_key_len). */ #define KADM_MOD(x) (x + adb->old_key_next) % adb->old_key_len static kadm5_ret_t add_to_history(krb5_context context, osa_princ_ent_t adb, kadm5_policy_ent_t pol, osa_pw_hist_ent *pw) { osa_pw_hist_ent *histp; uint32_t nhist; unsigned int i, knext, nkeys; nhist = pol->pw_history_num; /* A history of 1 means just check the current password */ if (nhist <= 1) return 0; nkeys = adb->old_key_len; knext = adb->old_key_next; /* resize the adb->old_keys array if necessary */ if (nkeys + 1 < nhist) { if (adb->old_keys == NULL) { adb->old_keys = (osa_pw_hist_ent *) malloc((nkeys + 1) * sizeof (osa_pw_hist_ent)); } else { adb->old_keys = (osa_pw_hist_ent *) realloc(adb->old_keys, (nkeys + 1) * sizeof (osa_pw_hist_ent)); } if (adb->old_keys == NULL) return(ENOMEM); memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent)); nkeys = ++adb->old_key_len; /* * To avoid losing old keys, shift forward each entry after * knext. */ for (i = nkeys - 1; i > knext; i--) { adb->old_keys[i] = adb->old_keys[i - 1]; } memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent)); } else if (nkeys + 1 > nhist) { /* * The policy must have changed! Shrink the array. * Can't simply realloc() down, since it might be wrapped. * To understand the arithmetic below, note that we are * copying into new positions 0 .. N-1 from old positions * old_key_next-N .. old_key_next-1, modulo old_key_len, * where N = pw_history_num - 1 is the length of the * shortened list. Matt Crawford, FNAL */ /* * M = adb->old_key_len, N = pol->pw_history_num - 1 * * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M] */ int j; osa_pw_hist_t tmp; tmp = (osa_pw_hist_ent *) malloc((nhist - 1) * sizeof (osa_pw_hist_ent)); if (tmp == NULL) return ENOMEM; for (i = 0; i < nhist - 1; i++) { /* * Add nkeys once before taking remainder to avoid * negative values. */ j = (i + nkeys + knext - (nhist - 1)) % nkeys; tmp[i] = adb->old_keys[j]; } /* Now free the ones we don't keep (the oldest ones) */ for (i = 0; i < nkeys - (nhist - 1); i++) { j = (i + nkeys + knext) % nkeys; histp = &adb->old_keys[j]; for (j = 0; j < histp->n_key_data; j++) { krb5_free_key_data_contents(context, &histp->key_data[j]); } free(histp->key_data); } free((void *)adb->old_keys); adb->old_keys = tmp; nkeys = adb->old_key_len = nhist - 1; knext = adb->old_key_next = 0; } /* * If nhist decreased since the last password change, and nkeys+1 * is less than the previous nhist, it is possible for knext to * index into unallocated space. This condition would not be * caught by the resizing code above. */ if (knext + 1 > nkeys) knext = adb->old_key_next = 0; /* free the old pw history entry if it contains data */ histp = &adb->old_keys[knext]; for (i = 0; i < histp->n_key_data; i++) krb5_free_key_data_contents(context, &histp->key_data[i]); free(histp->key_data); /* store the new entry */ adb->old_keys[knext] = *pw; /* update the next pointer */ if (++adb->old_key_next == nhist - 1) adb->old_key_next = 0; return(0); } #undef KADM_MOD #ifdef USE_PASSWORD_SERVER /* FIXME: don't use global variable for this */ krb5_boolean use_password_server = 0; static krb5_boolean kadm5_use_password_server (void) { return use_password_server; } void kadm5_set_use_password_server (void) { use_password_server = 1; } #endif #ifdef USE_PASSWORD_SERVER /* * kadm5_launch_task () runs a program (task_path) to synchronize the * Apple password server with the Kerberos database. Password server * programs can receive arguments on the command line (task_argv) * and a block of data via stdin (data_buffer). * * Because a failure to communicate with the tool results in the * password server falling out of sync with the database, * kadm5_launch_task() always fails if it can't talk to the tool. */ static kadm5_ret_t kadm5_launch_task (krb5_context context, const char *task_path, char * const task_argv[], const char *data_buffer) { kadm5_ret_t ret = 0; int data_pipe[2]; if (data_buffer != NULL) { ret = pipe (data_pipe); if (ret) { ret = errno; } } if (!ret) { pid_t pid = fork (); if (pid == -1) { ret = errno; } else if (pid == 0) { /* The child: */ if (data_buffer != NULL) { if (dup2 (data_pipe[0], STDIN_FILENO) == -1) { _exit (1); } } else { close (data_pipe[0]); } close (data_pipe[1]); execv (task_path, task_argv); _exit (1); /* Fail if execv fails */ } else { /* The parent: */ int status; if (data_buffer != NULL) { /* Write out the buffer to the child */ if (krb5_net_write (context, data_pipe[1], data_buffer, strlen (data_buffer)) < 0) { /* kill the child to make sure waitpid() won't hang later */ ret = errno; kill (pid, SIGKILL); } } close (data_buffer[0]); close (data_buffer[1]); waitpid (pid, &status, 0); if (!ret) { if (WIFEXITED (status)) { /* child read password and exited. Check the return value. */ if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) { ret = KRB5KDC_ERR_POLICY; /* password change rejected */ } } else { /* child read password but crashed or was killed */ ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */ } } } } return ret; } #endif kadm5_ret_t kadm5_chpass_principal(void *server_handle, krb5_principal principal, char *password) { return kadm5_chpass_principal_3(server_handle, principal, FALSE, 0, NULL, password); } kadm5_ret_t kadm5_chpass_principal_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *password) { krb5_int32 now; kadm5_policy_ent_rec pol; osa_princ_ent_rec adb; krb5_db_entry kdb, kdb_save; int ret, ret2, last_pwd, hist_added; int have_pol = 0; kadm5_server_handle_t handle = server_handle; osa_pw_hist_ent hist; CHECK_HANDLE(server_handle); /* Solaris Kerberos - kadm5_check_min_life checks for null principal. */ ret = kadm5_check_min_life(server_handle,principal,NULL,0); if (ret) return (ret); krb5_clear_error_message(handle->context); hist_added = 0; memset(&hist, 0, sizeof(hist)); if (principal == NULL || password == NULL) return EINVAL; if ((krb5_principal_compare(handle->context, principal, hist_princ)) == TRUE) return KADM5_PROTECT_PRINCIPAL; if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return(ret); /* we are going to need the current keys after the new keys are set */ if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) { kdb_free_entry(handle, &kdb, &adb); return(ret); } if ((adb.aux_attributes & KADM5_POLICY)) { if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) goto done; have_pol = 1; } if ((ret = passwd_check(handle, password, adb.aux_attributes & KADM5_POLICY, &pol, principal))) goto done; ret = krb5_dbe_cpw(handle->context, &handle->master_keyblock, n_ks_tuple?ks_tuple:handle->params.keysalts, n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, password, 0 /* increment kvno */, keepold, &kdb); if (ret) goto done; kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; ret = krb5_timeofday(handle->context, &now); if (ret) goto done; if ((adb.aux_attributes & KADM5_POLICY)) { /* the policy was loaded before */ ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, &last_pwd); if (ret) goto done; #if 0 /* * The spec says this check is overridden if the caller has * modify privilege. The admin server therefore makes this * check itself (in chpass_principal_wrapper, misc.c). A * local caller implicitly has all authorization bits. */ if ((now - last_pwd) < pol.pw_min_life && !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { ret = KADM5_PASS_TOOSOON; goto done; } #endif ret = create_history_entry(handle->context, &handle->master_keyblock, kdb_save.n_key_data, kdb_save.key_data, &hist); if (ret) goto done; ret = check_pw_reuse(handle->context, &handle->master_keyblock, &hist_key, kdb.n_key_data, kdb.key_data, 1, &hist); if (ret) goto done; if (pol.pw_history_num > 1) { if (adb.admin_history_kvno != hist_kvno) { ret = KADM5_BAD_HIST_KEY; goto done; } ret = check_pw_reuse(handle->context, &handle->master_keyblock, &hist_key, kdb.n_key_data, kdb.key_data, adb.old_key_len, adb.old_keys); if (ret) goto done; ret = add_to_history(handle->context, &adb, &pol, &hist); if (ret) goto done; hist_added = 1; } if (pol.pw_max_life) kdb.pw_expiration = now + pol.pw_max_life; else kdb.pw_expiration = 0; } else { kdb.pw_expiration = 0; } #ifdef USE_PASSWORD_SERVER if (kadm5_use_password_server () && (krb5_princ_size (handle->context, principal) == 1)) { krb5_data *princ = krb5_princ_component (handle->context, principal, 0); const char *path = "/usr/sbin/mkpassdb"; char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL }; char *pstring = NULL; char pwbuf[256]; int pwlen = strlen (password); if (pwlen > 254) pwlen = 254; strncpy (pwbuf, password, pwlen); pwbuf[pwlen] = '\n'; pwbuf[pwlen + 1] = '\0'; if (!ret) { pstring = malloc ((princ->length + 1) * sizeof (char)); if (pstring == NULL) { ret = errno; } } if (!ret) { memcpy (pstring, princ->data, princ->length); pstring [princ->length] = '\0'; argv[2] = pstring; ret = kadm5_launch_task (handle->context, path, argv, pwbuf); } if (pstring != NULL) free (pstring); if (ret) goto done; } #endif ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); if (ret) goto done; /* key data and attributes changed, let the database provider know */ /* Solaris Kerberos: adding support for key history in LDAP KDB */ if (hist_added == 1) kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES | KADM5_KEY_HIST /* | KADM5_CPW_FUNCTION */; else kdb.mask = KADM5_KEY_DATA | KADM5_ATTRIBUTES /* | KADM5_CPW_FUNCTION */; if ((ret = kdb_put_entry(handle, &kdb, &adb))) goto done; ret = KADM5_OK; done: if (!hist_added && hist.key_data) free_history_entry(handle->context, &hist); kdb_free_entry(handle, &kdb, &adb); kdb_free_entry(handle, &kdb_save, NULL); krb5_db_free_principal(handle->context, &kdb, 1); if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) && !ret) ret = ret2; return ret; } kadm5_ret_t kadm5_randkey_principal(void *server_handle, krb5_principal principal, krb5_keyblock **keyblocks, int *n_keys) { /* Solaris Kerberos: */ krb5_key_salt_tuple keysalts[2]; /* * Anyone calling this routine is forced to use only DES * enctypes to be compatible with earlier releases that * did not support stronger crypto. * * S10 (and later) kadmin clients will not use this API, * so we can assume the request is from an older version. */ keysalts[0].ks_enctype = ENCTYPE_DES_CBC_MD5; keysalts[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; keysalts[1].ks_enctype = ENCTYPE_DES_CBC_CRC; keysalts[1].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; return (kadm5_randkey_principal_3(server_handle, principal, FALSE, 2, keysalts, keyblocks, n_keys)); } kadm5_ret_t kadm5_randkey_principal_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock **keyblocks, int *n_keys) { krb5_db_entry kdb; osa_princ_ent_rec adb; krb5_int32 now; kadm5_policy_ent_rec pol; krb5_key_data *key_data; int ret, last_pwd, have_pol = 0; kadm5_server_handle_t handle = server_handle; if (keyblocks) *keyblocks = NULL; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); if (principal == NULL) return EINVAL; if (hist_princ && /* this will be NULL when initializing the databse */ ((krb5_principal_compare(handle->context, principal, hist_princ)) == TRUE)) return KADM5_PROTECT_PRINCIPAL; if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return(ret); ret = krb5_dbe_crk(handle->context, &handle->master_keyblock, n_ks_tuple?ks_tuple:handle->params.keysalts, n_ks_tuple?n_ks_tuple:handle->params.num_keysalts, keepold, &kdb); if (ret) goto done; kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; ret = krb5_timeofday(handle->context, &now); if (ret) goto done; if ((adb.aux_attributes & KADM5_POLICY)) { if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)) != KADM5_OK) goto done; have_pol = 1; ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, &last_pwd); if (ret) goto done; #if 0 /* * The spec says this check is overridden if the caller has * modify privilege. The admin server therefore makes this * check itself (in chpass_principal_wrapper, misc.c). A * local caller implicitly has all authorization bits. */ if((now - last_pwd) < pol.pw_min_life && !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { ret = KADM5_PASS_TOOSOON; goto done; } #endif if(pol.pw_history_num > 1) { if(adb.admin_history_kvno != hist_kvno) { ret = KADM5_BAD_HIST_KEY; goto done; } ret = check_pw_reuse(handle->context, &handle->master_keyblock, &hist_key, kdb.n_key_data, kdb.key_data, adb.old_key_len, adb.old_keys); if (ret) goto done; } if (pol.pw_max_life) kdb.pw_expiration = now + pol.pw_max_life; else kdb.pw_expiration = 0; } else { kdb.pw_expiration = 0; } ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); if (ret) goto done; if (keyblocks) { if (handle->api_version == KADM5_API_VERSION_1) { /* Version 1 clients will expect to see a DES_CRC enctype. */ ret = krb5_dbe_find_enctype(handle->context, &kdb, ENCTYPE_DES_CBC_CRC, -1, -1, &key_data); if (ret) goto done; ret = decrypt_key_data(handle->context, &handle->master_keyblock, 1, key_data, keyblocks, NULL); if (ret) goto done; } else { ret = decrypt_key_data(handle->context, &handle->master_keyblock, kdb.n_key_data, kdb.key_data, keyblocks, n_keys); if (ret) goto done; } } /* key data changed, let the database provider know */ kdb.mask = KADM5_KEY_DATA /* | KADM5_RANDKEY_USED */; if ((ret = kdb_put_entry(handle, &kdb, &adb))) goto done; ret = KADM5_OK; done: kdb_free_entry(handle, &kdb, &adb); if (have_pol) kadm5_free_policy_ent(handle->lhandle, &pol); return ret; } #if 0 /* Solaris Kerberos */ /* * kadm5_setv4key_principal: * * Set only ONE key of the principal, removing all others. This key * must have the DES_CBC_CRC enctype and is entered as having the * krb4 salttype. This is to enable things like kadmind4 to work. */ kadm5_ret_t kadm5_setv4key_principal(void *server_handle, krb5_principal principal, krb5_keyblock *keyblock) { krb5_db_entry kdb; osa_princ_ent_rec adb; krb5_int32 now; kadm5_policy_ent_rec pol; krb5_keysalt keysalt; int i, k, kvno, ret, have_pol = 0; #if 0 int last_pwd; #endif kadm5_server_handle_t handle = server_handle; krb5_key_data tmp_key_data; memset( &tmp_key_data, 0, sizeof(tmp_key_data)); CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); if (principal == NULL || keyblock == NULL) return EINVAL; if (hist_princ && /* this will be NULL when initializing the databse */ ((krb5_principal_compare(handle->context, principal, hist_princ)) == TRUE)) return KADM5_PROTECT_PRINCIPAL; if (keyblock->enctype != ENCTYPE_DES_CBC_CRC) return KADM5_SETV4KEY_INVAL_ENCTYPE; if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return(ret); for (kvno = 0, i=0; i kvno) kvno = kdb.key_data[i].key_data_kvno; if (kdb.key_data != NULL) cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data)); if (kdb.key_data == NULL) return ENOMEM; memset(kdb.key_data, 0, sizeof(krb5_key_data)); kdb.n_key_data = 1; keysalt.type = KRB5_KDB_SALTTYPE_V4; /* XXX data.magic? */ keysalt.data.length = 0; keysalt.data.data = NULL; /* use tmp_key_data as temporary location and reallocate later */ ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock, keyblock, &keysalt, kvno + 1, &tmp_key_data); if (ret) { goto done; } for (k = 0; k < tmp_key_data.key_data_ver; k++) { kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k]; kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k]; if (tmp_key_data.key_data_contents[k]) { kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); if (kdb.key_data->key_data_contents[k] == NULL) { cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); kdb.key_data = NULL; kdb.n_key_data = 0; ret = ENOMEM; goto done; } memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); free (tmp_key_data.key_data_contents[k]); tmp_key_data.key_data_contents[k] = NULL; } } kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; ret = krb5_timeofday(handle->context, &now); if (ret) goto done; if ((adb.aux_attributes & KADM5_POLICY)) { if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)) != KADM5_OK) goto done; have_pol = 1; #if 0 /* * The spec says this check is overridden if the caller has * modify privilege. The admin server therefore makes this * check itself (in chpass_principal_wrapper, misc.c). A * local caller implicitly has all authorization bits. */ if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, &last_pwd)) goto done; if((now - last_pwd) < pol.pw_min_life && !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { ret = KADM5_PASS_TOOSOON; goto done; } #endif #if 0 /* * Should we be checking/updating pw history here? */ if(pol.pw_history_num > 1) { if(adb.admin_history_kvno != hist_kvno) { ret = KADM5_BAD_HIST_KEY; goto done; } if (ret = check_pw_reuse(handle->context, &hist_key, kdb.n_key_data, kdb.key_data, adb.old_key_len, adb.old_keys)) goto done; } #endif if (pol.pw_max_life) kdb.pw_expiration = now + pol.pw_max_life; else kdb.pw_expiration = 0; } else { kdb.pw_expiration = 0; } ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now); if (ret) goto done; if ((ret = kdb_put_entry(handle, &kdb, &adb))) goto done; ret = KADM5_OK; done: for (i = 0; i < tmp_key_data.key_data_ver; i++) { if (tmp_key_data.key_data_contents[i]) { memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]); free (tmp_key_data.key_data_contents[i]); } } kdb_free_entry(handle, &kdb, &adb); if (have_pol) kadm5_free_policy_ent(handle->lhandle, &pol); return ret; } #endif kadm5_ret_t kadm5_setkey_principal(void *server_handle, krb5_principal principal, krb5_keyblock *keyblocks, int n_keys) { return kadm5_setkey_principal_3(server_handle, principal, FALSE, 0, NULL, keyblocks, n_keys); } kadm5_ret_t kadm5_setkey_principal_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock *keyblocks, int n_keys) { krb5_db_entry kdb; osa_princ_ent_rec adb; krb5_int32 now; kadm5_policy_ent_rec pol; krb5_key_data *old_key_data; int n_old_keys; int i, j, k, kvno, ret, have_pol = 0; #if 0 int last_pwd; #endif kadm5_server_handle_t handle = server_handle; krb5_boolean similar; krb5_keysalt keysalt; krb5_key_data tmp_key_data; krb5_key_data *tptr; CHECK_HANDLE(server_handle); krb5_clear_error_message(handle->context); if (principal == NULL || keyblocks == NULL) return EINVAL; if (hist_princ && /* this will be NULL when initializing the databse */ ((krb5_principal_compare(handle->context, principal, hist_princ)) == TRUE)) return KADM5_PROTECT_PRINCIPAL; for (i = 0; i < n_keys; i++) { for (j = i+1; j < n_keys; j++) { if ((ret = krb5_c_enctype_compare(handle->context, keyblocks[i].enctype, keyblocks[j].enctype, &similar))) return(ret); if (similar) { if (n_ks_tuple) { if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype) return KADM5_SETKEY_DUP_ENCTYPES; } else return KADM5_SETKEY_DUP_ENCTYPES; } } } if (n_ks_tuple && n_ks_tuple != n_keys) return KADM5_SETKEY3_ETYPE_MISMATCH; if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return(ret); for (kvno = 0, i=0; i kvno) kvno = kdb.key_data[i].key_data_kvno; if (keepold) { old_key_data = kdb.key_data; n_old_keys = kdb.n_key_data; } else { if (kdb.key_data != NULL) cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data); n_old_keys = 0; old_key_data = NULL; } kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys) *sizeof(krb5_key_data)); if (kdb.key_data == NULL) { ret = ENOMEM; goto done; } memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data)); kdb.n_key_data = 0; for (i = 0; i < n_keys; i++) { if (n_ks_tuple) { keysalt.type = ks_tuple[i].ks_salttype; keysalt.data.length = 0; keysalt.data.data = NULL; if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) { ret = KADM5_SETKEY3_ETYPE_MISMATCH; goto done; } } memset (&tmp_key_data, 0, sizeof(tmp_key_data)); ret = krb5_dbekd_encrypt_key_data(handle->context, &handle->master_keyblock, &keyblocks[i], n_ks_tuple ? &keysalt : NULL, kvno + 1, &tmp_key_data); if (ret) { goto done; } tptr = &kdb.key_data[i]; for (k = 0; k < tmp_key_data.key_data_ver; k++) { tptr->key_data_type[k] = tmp_key_data.key_data_type[k]; tptr->key_data_length[k] = tmp_key_data.key_data_length[k]; if (tmp_key_data.key_data_contents[k]) { tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]); if (tptr->key_data_contents[k] == NULL) { int i1; for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) { if (tmp_key_data.key_data_contents[i1]) { memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]); free (tmp_key_data.key_data_contents[i1]); } } ret = ENOMEM; goto done; } memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]); memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]); free (tmp_key_data.key_data_contents[k]); tmp_key_data.key_data_contents[k] = NULL; } } kdb.n_key_data++; } /* copy old key data if necessary */ for (i = 0; i < n_old_keys; i++) { kdb.key_data[i+n_keys] = old_key_data[i]; memset(&old_key_data[i], 0, sizeof (krb5_key_data)); kdb.n_key_data++; } if (old_key_data) krb5_db_free(handle->context, old_key_data); /* assert(kdb.n_key_data == n_keys + n_old_keys) */ kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; if ((ret = krb5_timeofday(handle->context, &now))) goto done; if ((adb.aux_attributes & KADM5_POLICY)) { if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)) != KADM5_OK) goto done; have_pol = 1; #if 0 /* * The spec says this check is overridden if the caller has * modify privilege. The admin server therefore makes this * check itself (in chpass_principal_wrapper, misc.c). A * local caller implicitly has all authorization bits. */ if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, &last_pwd)) goto done; if((now - last_pwd) < pol.pw_min_life && !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { ret = KADM5_PASS_TOOSOON; goto done; } #endif #if 0 /* * Should we be checking/updating pw history here? */ if (pol.pw_history_num > 1) { if(adb.admin_history_kvno != hist_kvno) { ret = KADM5_BAD_HIST_KEY; goto done; } if (ret = check_pw_reuse(handle->context, &handle->master_keyblock, &hist_key, kdb.n_key_data, kdb.key_data, adb.old_key_len, adb.old_keys)) goto done; } #endif if (pol.pw_max_life) kdb.pw_expiration = now + pol.pw_max_life; else kdb.pw_expiration = 0; } else { kdb.pw_expiration = 0; } if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) goto done; if ((ret = kdb_put_entry(handle, &kdb, &adb))) goto done; ret = KADM5_OK; done: kdb_free_entry(handle, &kdb, &adb); if (have_pol) kadm5_free_policy_ent(handle->lhandle, &pol); return ret; } /* * Allocate an array of n_key_data krb5_keyblocks, fill in each * element with the results of decrypting the nth key in key_data with * master_keyblock, and if n_keys is not NULL fill it in with the * number of keys decrypted. */ static int decrypt_key_data(krb5_context context, krb5_keyblock *master_keyblock, int n_key_data, krb5_key_data *key_data, krb5_keyblock **keyblocks, int *n_keys) { krb5_keyblock *keys; int ret, i; keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); if (keys == NULL) return ENOMEM; memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); for (i = 0; i < n_key_data; i++) { ret = krb5_dbekd_decrypt_key_data(context, master_keyblock, &key_data[i], &keys[i], NULL); if (ret) { for (; i >= 0; i--) { if (keys[i].contents) { memset (keys[i].contents, 0, keys[i].length); free( keys[i].contents ); } } memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); free(keys); return ret; } } *keyblocks = keys; if (n_keys) *n_keys = n_key_data; return 0; } /* * Function: kadm5_decrypt_key * * Purpose: Retrieves and decrypts a principal key. * * Arguments: * * server_handle (r) kadm5 handle * entry (r) principal retrieved with kadm5_get_principal * ktype (r) enctype to search for, or -1 to ignore * stype (r) salt type to search for, or -1 to ignore * kvno (r) kvno to search for, -1 for max, 0 for max * only if it also matches ktype and stype * keyblock (w) keyblock to fill in * keysalt (w) keysalt to fill in, or NULL * kvnop (w) kvno to fill in, or NULL * * Effects: Searches the key_data array of entry, which must have been * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to * find a key with a specified enctype, salt type, and kvno in a * principal entry. If not found, return ENOENT. Otherwise, decrypt * it with the master key, and return the key in keyblock, the salt * in salttype, and the key version number in kvno. * * If ktype or stype is -1, it is ignored for the search. If kvno is * -1, ktype and stype are ignored and the key with the max kvno is * returned. If kvno is 0, only the key with the max kvno is returned * and only if it matches the ktype and stype; otherwise, ENOENT is * returned. */ kadm5_ret_t kadm5_decrypt_key(void *server_handle, kadm5_principal_ent_t entry, krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno, krb5_keyblock *keyblock, krb5_keysalt *keysalt, int *kvnop) { kadm5_server_handle_t handle = server_handle; krb5_db_entry dbent; krb5_key_data *key_data; int ret; CHECK_HANDLE(server_handle); if (entry->n_key_data == 0 || entry->key_data == NULL) return EINVAL; /* find_enctype only uses these two fields */ dbent.n_key_data = entry->n_key_data; dbent.key_data = entry->key_data; if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, stype, kvno, &key_data))) return ret; if ((ret = krb5_dbekd_decrypt_key_data(handle->context, &handle->master_keyblock, key_data, keyblock, keysalt))) return ret; /* * Coerce the enctype of the output keyblock in case we got an * inexact match on the enctype; this behavior will go away when * the key storage architecture gets redesigned for 1.3. */ keyblock->enctype = ktype; if (kvnop) *kvnop = key_data->key_data_kvno; return KADM5_OK; } /* Solaris Kerberos */ kadm5_ret_t kadm5_check_min_life(void *server_handle, krb5_principal principal, char *msg_ret, unsigned int msg_len) { krb5_int32 now; kadm5_ret_t ret; kadm5_policy_ent_rec pol; kadm5_principal_ent_rec princ; kadm5_server_handle_t handle = server_handle; if (msg_ret != NULL) *msg_ret = '\0'; ret = krb5_timeofday(handle->context, &now); if (ret) return ret; ret = kadm5_get_principal(handle->lhandle, principal, &princ, KADM5_PRINCIPAL_NORMAL_MASK); if(ret) return ret; if(princ.aux_attributes & KADM5_POLICY) { if((ret=kadm5_get_policy(handle->lhandle, princ.policy, &pol)) != KADM5_OK) { (void) kadm5_free_principal_ent(handle->lhandle, &princ); return ret; } if((now - princ.last_pwd_change) < pol.pw_min_life && !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { if (msg_ret != NULL) { time_t until; char *time_string, *ptr, *errstr; until = princ.last_pwd_change + pol.pw_min_life; time_string = ctime(&until); errstr = (char *)error_message(CHPASS_UTIL_PASSWORD_TOO_SOON); if (strlen(errstr) + strlen(time_string) >= msg_len) { *errstr = '\0'; } else { if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') *ptr = '\0'; sprintf(msg_ret, errstr, time_string); } } (void) kadm5_free_policy_ent(handle->lhandle, &pol); (void) kadm5_free_principal_ent(handle->lhandle, &princ); return KADM5_PASS_TOOSOON; } ret = kadm5_free_policy_ent(handle->lhandle, &pol); if (ret) { (void) kadm5_free_principal_ent(handle->lhandle, &princ); return ret; } } return kadm5_free_principal_ent(handle->lhandle, &princ); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #if !defined(lint) && defined(SCCSIDS) static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro"; #endif /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * */ #include "admin.h" #include #include #include /* Solaris Kerberos - 116 resync */ static bool_t xdralloc_putlong(); static bool_t xdralloc_putbytes(); static unsigned int xdralloc_getpos(); static rpc_inline_t * xdralloc_inline(); static void xdralloc_destroy(); static bool_t xdralloc_notsup_getlong(); static bool_t xdralloc_notsup_getbytes(); static bool_t xdralloc_notsup_setpos(); static struct xdr_ops xdralloc_ops = { xdralloc_notsup_getlong, xdralloc_putlong, xdralloc_notsup_getbytes, xdralloc_putbytes, xdralloc_getpos, xdralloc_notsup_setpos, xdralloc_inline, xdralloc_destroy, }; /* * The procedure xdralloc_create initializes a stream descriptor for a * memory buffer. */ void xdralloc_create(XDR *xdrs, enum xdr_op op) { xdrs->x_op = op; xdrs->x_ops = &xdralloc_ops; xdrs->x_private = (caddr_t) DynCreate(sizeof(char), -4); /* not allowed to fail */ } caddr_t xdralloc_getdata(XDR *xdrs) { return (caddr_t) DynGet((DynObject) xdrs->x_private, 0); } void xdralloc_release(XDR *xdrs) { DynRelease((DynObject) xdrs->x_private); } static void xdralloc_destroy(XDR *xdrs) { DynDestroy((DynObject) xdrs->x_private); } static bool_t xdralloc_notsup_getlong( register XDR *xdrs, long *lp) { return FALSE; } static bool_t xdralloc_putlong( register XDR *xdrs, long *lp) { int l = htonl((uint32_t) *lp); /* XXX need bounds checking */ /* XXX assumes sizeof(int)==4 */ if (DynInsert((DynObject) xdrs->x_private, DynSize((DynObject) xdrs->x_private), &l, sizeof(int)) != DYN_OK) return FALSE; return (TRUE); } static bool_t xdralloc_notsup_getbytes( register XDR *xdrs, caddr_t addr, register unsigned int len) { return FALSE; } static bool_t xdralloc_putbytes( register XDR *xdrs, caddr_t addr, register unsigned int len) { if (DynInsert((DynObject) xdrs->x_private, DynSize((DynObject) xdrs->x_private), addr, (int) len) != DYN_OK) return FALSE; return TRUE; } static unsigned int xdralloc_getpos(XDR *xdrs) { return DynSize((DynObject) xdrs->x_private); } static bool_t xdralloc_notsup_setpos( register XDR *xdrs, unsigned int lp) { return FALSE; } static rpc_inline_t *xdralloc_inline( register XDR *xdrs, int len) { return (rpc_inline_t *) 0; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * lib/kadm/str_conv.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * str_conv.c - Convert between strings and Kerberos internal data. */ /* * Table of contents: * * String decoding: * ---------------- * krb5_string_to_flags() - Convert string to krb5_flags. * * String encoding: * ---------------- * krb5_flags_to_string() - Convert krb5_flags to string. */ #include "k5-int.h" #include "admin_internal.h" #include "adm_proto.h" /* * Local data structures. */ struct flags_lookup_entry { krb5_flags fl_flags; /* Flag */ krb5_boolean fl_sense; /* Sense of the flag */ const char * fl_specifier; /* How to recognize it */ const char * fl_output; /* How to spit it out */ }; /* * Local strings */ static const char default_tupleseps[] = ", \t"; static const char default_ksaltseps[] = ":."; /* Keytype strings */ /* Flags strings */ static const char flags_pdate_in[] = "postdateable"; static const char flags_fwd_in[] = "forwardable"; static const char flags_tgtbased_in[] = "tgt-based"; static const char flags_renew_in[] = "renewable"; static const char flags_proxy_in[] = "proxiable"; static const char flags_dup_skey_in[] = "dup-skey"; static const char flags_tickets_in[] = "allow-tickets"; static const char flags_preauth_in[] = "preauth"; static const char flags_hwauth_in[] = "hwauth"; static const char flags_pwchange_in[] = "pwchange"; static const char flags_service_in[] = "service"; static const char flags_pwsvc_in[] = "pwservice"; static const char flags_md5_in[] = "md5"; static const char flags_pdate_out[] = "Not Postdateable"; static const char flags_fwd_out[] = "Not Forwardable"; static const char flags_tgtbased_out[] = "No TGT-based requests"; static const char flags_renew_out[] = "Not renewable"; static const char flags_proxy_out[] = "Not proxiable"; static const char flags_dup_skey_out[] = "No DUP_SKEY requests"; static const char flags_tickets_out[] = "All Tickets Disallowed"; static const char flags_preauth_out[] = "Preauthorization required"; static const char flags_hwauth_out[] = "HW Authorization required"; static const char flags_pwchange_out[] = "Password Change required"; static const char flags_service_out[] = "Service Disabled"; static const char flags_pwsvc_out[] = "Password Changing Service"; static const char flags_md5_out[] = "RSA-MD5 supported"; static const char flags_default_neg[] = "-"; static const char flags_default_sep[] = " "; /* * Lookup tables. */ static const struct flags_lookup_entry flags_table[] = { /* flag sense input specifier output string */ /*----------------------------- ------- ------------------ ------------------*/ { KRB5_KDB_DISALLOW_POSTDATED, 0, flags_pdate_in, flags_pdate_out }, { KRB5_KDB_DISALLOW_FORWARDABLE,0, flags_fwd_in, flags_fwd_out }, { KRB5_KDB_DISALLOW_TGT_BASED, 0, flags_tgtbased_in, flags_tgtbased_out}, { KRB5_KDB_DISALLOW_RENEWABLE, 0, flags_renew_in, flags_renew_out }, { KRB5_KDB_DISALLOW_PROXIABLE, 0, flags_proxy_in, flags_proxy_out }, { KRB5_KDB_DISALLOW_DUP_SKEY, 0, flags_dup_skey_in, flags_dup_skey_out}, { KRB5_KDB_DISALLOW_ALL_TIX, 0, flags_tickets_in, flags_tickets_out }, { KRB5_KDB_REQUIRES_PRE_AUTH, 1, flags_preauth_in, flags_preauth_out }, { KRB5_KDB_REQUIRES_HW_AUTH, 1, flags_hwauth_in, flags_hwauth_out }, { KRB5_KDB_REQUIRES_PWCHANGE, 1, flags_pwchange_in, flags_pwchange_out}, { KRB5_KDB_DISALLOW_SVR, 0, flags_service_in, flags_service_out }, { KRB5_KDB_PWCHANGE_SERVICE, 1, flags_pwsvc_in, flags_pwsvc_out }, { KRB5_KDB_SUPPORT_DESMD5, 1, flags_md5_in, flags_md5_out } }; static const int flags_table_nents = sizeof(flags_table)/ sizeof(flags_table[0]); krb5_error_code krb5_string_to_flags(string, positive, negative, flagsp) char * string; const char * positive; const char * negative; krb5_flags * flagsp; { int i; int found; const char *neg; size_t nsize, psize; int cpos; int sense; found = 0; /* We need to have a way to negate it. */ neg = (negative) ? negative : flags_default_neg; nsize = strlen(neg); psize = (positive) ? strlen(positive) : 0; cpos = 0; sense = 1; /* First check for positive or negative sense */ if (!strncasecmp(neg, string, nsize)) { sense = 0; cpos += (int) nsize; } else if (psize && !strncasecmp(positive, string, psize)) { cpos += (int) psize; } for (i=0; i= flags_table_nents) return ENOENT; /* End of list */ if(strlen(flags_table[flag].fl_specifier) > buflen) return ENOMEM; strcpy(buffer, flags_table[flag].fl_specifier); return 0; } /* * krb5_keysalt_is_present() - Determine if a key/salt pair is present * in a list of key/salt tuples. * * Salttype may be negative to indicate a search for only a enctype. */ krb5_boolean krb5_keysalt_is_present(ksaltlist, nksalts, enctype, salttype) krb5_key_salt_tuple *ksaltlist; krb5_int32 nksalts; krb5_enctype enctype; krb5_int32 salttype; { krb5_boolean foundit; int i; foundit = 0; if (ksaltlist) { for (i=0; i * or * */ sp = (char *) NULL; /* Attempt to find a separator */ septmp = ksseplist; for (sp = strchr(kp, (int) *septmp); *(++septmp) && !sp; sp = strchr(kp, (int)*septmp)); /* Solaris Kerberos */ if (sp) { /* Separate enctype from salttype */ sepchar = *sp; *sp = '\0'; sp++; } else stype = -1; /* * Attempt to parse enctype and salttype. If we parse well * then make sure that it specifies a unique key/salt combo */ if (!(kret = krb5_string_to_enctype(kp, &ktype)) && (!sp || !(kret = krb5_string_to_salttype(sp, &stype))) && (dups || !krb5_keysalt_is_present(*ksaltp, *nksaltp, ktype, stype))) { /* Squirrel away old keysalt array */ savep = *ksaltp; len = (size_t) *nksaltp; /* Get new keysalt array */ *ksaltp = (krb5_key_salt_tuple *) malloc((len + 1) * sizeof(krb5_key_salt_tuple)); if (*ksaltp) { /* Copy old keysalt if appropriate */ if (savep) { memcpy(*ksaltp, savep, len * sizeof(krb5_key_salt_tuple)); krb5_xfree(savep); } /* Save our values */ (*ksaltp)[(*nksaltp)].ks_enctype = ktype; (*ksaltp)[(*nksaltp)].ks_salttype = stype; (*nksaltp)++; } else { *ksaltp = savep; break; } } /* * Solaris Kerberos * If the string did not yield a valid enctype/keysalt * just ignore it and continue on. MIT kerberos stops * searching when if finds an unknown string. */ if (sp) sp[-1] = sepchar; if (ep) ep[-1] = trailchar; kp = ep; /* Skip over extra separators - like spaces */ if (kp && *tseplist) { septmp = tseplist; while(*septmp && *kp) { if(*septmp == *kp) { /* Increment string - reset separator list */ kp++; septmp = tseplist; } else { septmp++; } } if (!*kp) kp = NULL; } } /* while kp */ return(kret); } /* * krb5_keysalt_iterate() - Do something for each unique key/salt * combination. * * If ignoresalt set, then salttype is ignored. */ krb5_error_code krb5_keysalt_iterate(ksaltlist, nksalt, ignoresalt, iterator, arg) krb5_key_salt_tuple *ksaltlist; krb5_int32 nksalt; krb5_boolean ignoresalt; krb5_error_code (*iterator) (krb5_key_salt_tuple *, krb5_pointer); krb5_pointer arg; { int i; krb5_error_code kret; krb5_key_salt_tuple scratch; kret = 0; for (i=0; i