Home | History | Annotate | Line # | Download | only in doc
      1  1.1  elric Currently, getting an initial ticket for a user involves many function
      2  1.1  elric calls, especially when a full set of features including password
      3  1.1  elric expiration and challenge preauthentication is desired.  In order to
      4  1.1  elric solve this problem, a new api is proposed.
      5  1.1  elric 
      6  1.1  elric typedef struct _krb5_prompt {
      7  1.1  elric     char *prompt;
      8  1.1  elric     int hidden;
      9  1.1  elric     krb5_data *reply;
     10  1.1  elric } krb5_prompt;
     11  1.1  elric 
     12  1.1  elric typedef int (*krb5_prompter_fct)(krb5_context context,
     13  1.1  elric 				 void *data,
     14  1.1  elric 				 const char *banner,
     15  1.1  elric 				 int num_prompts,
     16  1.1  elric 				 krb5_prompt prompts[]);
     17  1.1  elric 
     18  1.1  elric typedef struct _krb5_get_init_creds_opt {
     19  1.1  elric     krb5_flags flags;
     20  1.1  elric     krb5_deltat tkt_life;
     21  1.1  elric     krb5_deltat renew_life;
     22  1.1  elric     int forwardable;
     23  1.1  elric     int proxiable;
     24  1.1  elric     krb5_enctype *etype_list;
     25  1.1  elric     int etype_list_length;
     26  1.1  elric     krb5_address **address_list;
     27  1.1  elric 	/* XXX the next three should not be used, as they may be
     28  1.1  elric 	removed later */
     29  1.1  elric     krb5_preauthtype *preauth_list;
     30  1.1  elric     int preauth_list_length;
     31  1.1  elric     krb5_data *salt;
     32  1.1  elric } krb5_get_init_creds_opt;
     33  1.1  elric 
     34  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_TKT_LIFE	0x0001
     35  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE	0x0002
     36  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_FORWARDABLE	0x0004
     37  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_PROXIABLE	0x0008
     38  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST	0x0010
     39  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST	0x0020
     40  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST	0x0040
     41  1.1  elric #define KRB5_GET_INIT_CREDS_OPT_SALT		0x0080
     42  1.1  elric 
     43  1.1  elric void krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt);
     44  1.1  elric 
     45  1.1  elric void krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt,
     46  1.1  elric 					  krb5_deltat tkt_life);
     47  1.1  elric void krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt,
     48  1.1  elric 					    krb5_deltat renew_life);
     49  1.1  elric void krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt,
     50  1.1  elric 					     int forwardable);
     51  1.1  elric void krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt,
     52  1.1  elric 					   int proxiable);
     53  1.1  elric void krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt,
     54  1.1  elric 					    krb5_enctype *etype_list,
     55  1.1  elric 					    int etype_list_length);
     56  1.1  elric void krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt,
     57  1.1  elric 					      krb5_address **addresses);
     58  1.1  elric void krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
     59  1.1  elric 					      krb5_preauthtype *preauth_list,
     60  1.1  elric 					      int preauth_list_length);
     61  1.1  elric void krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
     62  1.1  elric 				      krb5_data *salt);
     63  1.1  elric 
     64  1.1  elric krb5_error_code
     65  1.1  elric krb5_get_init_creds_password(krb5_context context,
     66  1.1  elric 			     krb5_creds *creds,
     67  1.1  elric 			     krb5_principal client,
     68  1.1  elric 			     char *password,
     69  1.1  elric 			     krb5_prompter_fct prompter,
     70  1.1  elric 			     void *data,
     71  1.1  elric 			     krb5_deltat start_time,
     72  1.1  elric 			     char *in_tkt_service,
     73  1.1  elric 			     krb5_get_init_creds_opt *options);
     74  1.1  elric 
     75  1.1  elric This function will attempt to acquire an initial ticket.  The function
     76  1.1  elric will perform whatever tasks are necessary to do so.  This may include
     77  1.1  elric changing an expired password, preauthentication.
     78  1.1  elric 
     79  1.1  elric The arguments divide into two types.  Some arguments are basically
     80  1.1  elric invariant and arbitrary across all initial tickets, and if not
     81  1.1  elric specified are determined by configuration or library defaults.  Some
     82  1.1  elric arguments are different for each execution or application, and if not
     83  1.1  elric specified can be determined correctly from system configuration or
     84  1.1  elric environment.  The former arguments are contained in a structure whose
     85  1.1  elric pointer is passed to the function.  A bitmask specifies which elements
     86  1.1  elric of the structure should be used.  In most cases, a NULL pointer can be
     87  1.1  elric used.  The latter arguments are specified as individual arguments to
     88  1.1  elric the function.
     89  1.1  elric 
     90  1.1  elric If a pointer to a credential is specified, the initial credential is
     91  1.1  elric filled in.  If the caller only wishes to do a simple password check
     92  1.1  elric and will not be doing any other kerberos functions, then a NULL
     93  1.1  elric pointer may be specified, and the credential will be destroyed.
     94  1.1  elric 
     95  1.1  elric If the client name is non-NULL, the initial ticket requested will be
     96  1.1  elric for that principal.  Otherwise, the principal will be the username
     97  1.1  elric specified by the USER environment variable, or if the USER environment
     98  1.1  elric variable is not set, the username corresponding to the real user id of
     99  1.1  elric the caller.
    100  1.1  elric 
    101  1.1  elric If the password is non-NULL, then this string is used as the password.
    102  1.1  elric Otherwise, the prompter function will be used to prompt the user for
    103  1.1  elric the password.
    104  1.1  elric 
    105  1.1  elric If a prompter function is non-NULL, it will be used if additional user
    106  1.1  elric input is required, such as if the user's password has expired and
    107  1.1  elric needs to be changed, or if input preauthentication is necessary.  If
    108  1.1  elric no function is specified and input is required, then the login will
    109  1.1  elric fail.
    110  1.1  elric 
    111  1.1  elric 	The context argument is the same as that passed to krb5_login.
    112  1.1  elric 	The data argument is passed unmodified to the prompter
    113  1.1  elric 	function and is intended to be used to pass application data
    114  1.1  elric 	(such as a display handle) to the prompter function.
    115  1.1  elric 
    116  1.1  elric 	The banner argument, if non-NULL, will indicate what sort of
    117  1.1  elric 	input is expected from the user (for example, "Password has
    118  1.1  elric 	expired and must be changed" or "Enter Activcard response for
    119  1.1  elric 	challenge 012345678"), and should be displayed accordingly.
    120  1.1  elric 	
    121  1.1  elric 	The num_prompts argument indicates the number of values which
    122  1.1  elric 	should be prompted for.  If num_prompts == 0, then the banner
    123  1.1  elric 	contains an informational message which should be displayed to
    124  1.1  elric 	the user.
    125  1.1  elric 
    126  1.1  elric 	The prompts argument contains an array describing the values
    127  1.1  elric 	for which the user should be prompted.  The prompt member
    128  1.1  elric 	indicates the prompt for each value ("Enter new
    129  1.1  elric 	password"/"Enter it again", or "Challenge response").  The
    130  1.1  elric 	hidden member is nonzero if the response should not be
    131  1.1  elric 	displayed back to the user.  The reply member is a pointer to
    132  1.1  elric 	krb5_data structure which has already been allocated.  The
    133  1.1  elric 	prompter should fill in the structure with the NUL-terminated
    134  1.1  elric 	response from the user.
    135  1.1  elric 
    136  1.1  elric 	If the response data does not fit, or if any other error
    137  1.1  elric 	occurs, then the prompter function should return a non-zero
    138  1.1  elric 	value which will be returned by the krb5_get_init_creds
    139  1.1  elric 	function. Otherwise, zero should be returned.
    140  1.1  elric 
    141  1.1  elric 	The library function krb5_prompter_posix() implements
    142  1.1  elric 	a prompter using a posix terminal for user in.  This function
    143  1.1  elric 	does not use the data argument.
    144  1.1  elric 
    145  1.1  elric If the start_time is zero, then the requested ticket will be valid
    146  1.1  elric beginning immediately.  Otherwise, the start_time indicates how far in
    147  1.1  elric the future the ticket should be postdated.
    148  1.1  elric 
    149  1.1  elric If the in_tkt_service name is non-NULL, that principal name will be
    150  1.1  elric used as the server name for the initial ticket request.  The realm of
    151  1.1  elric the name specified will be ignored and will be set to the realm of the
    152  1.1  elric client name.  If no in_tkt_service name is specified,
    153  1.1  elric krbtgt/CLIENT-REALM@CLIENT-REALM will be used.
    154  1.1  elric 
    155  1.1  elric For the rest of arguments, a configuration or library default will be
    156  1.1  elric used if no value is specified in the options structure.
    157  1.1  elric 
    158  1.1  elric If a tkt_life is specified, that will be the lifetime of the ticket.
    159  1.1  elric The library default is 10 hours; there is no configuration variable
    160  1.1  elric (there should be, but it's not there now).
    161  1.1  elric 
    162  1.1  elric If a renew_life is specified and non-zero, then the RENEWABLE option
    163  1.1  elric on the ticket will be set, and the value of the argument will be the
    164  1.1  elric the renewable lifetime.  The configuration variable [libdefaults]
    165  1.1  elric "renew_lifetime" is the renewable lifetime if none is passed in.  The
    166  1.1  elric library default is not to set the RENEWABLE option.
    167  1.1  elric 
    168  1.1  elric If forwardable is specified, the FORWARDABLE option on the ticket will
    169  1.1  elric be set if and only if forwardable is non-zero.  The configuration
    170  1.1  elric variable [libdefaults] "forwardable" is used if no value is passed in.
    171  1.1  elric The option will be set if and only if the variable is "y", "yes",
    172  1.1  elric "true", "t", "1", or "on", case insensitive.  The library default is
    173  1.1  elric not to set the FORWARDABLE option.
    174  1.1  elric 
    175  1.1  elric If proxiable is specified, the PROXIABLE option on the ticket will be
    176  1.1  elric set if and only if proxiable is non-zero.  The configuration variable
    177  1.1  elric [libdefaults] "proxiable" is used if no value is passed in.  The
    178  1.1  elric option will be set if and only if the variable is "y", "yes", "true",
    179  1.1  elric "t", "1", or "on", case insensitive.  The library default is not to
    180  1.1  elric set the PROXIABLE option.
    181  1.1  elric 
    182  1.1  elric If etype_list is specified, it will be used as the list of desired
    183  1.1  elric encryption algorithms in the request.  The configuration variable
    184  1.1  elric [libdefaults] "default_tkt_enctypes" is used if no value is passed in.
    185  1.1  elric The library default is "des-cbc-md5 des-cbc-crc".
    186  1.1  elric 
    187  1.1  elric If address_list is specified, it will be used as the list of addresses
    188  1.1  elric for which the ticket will be valid.  The library default is to use all
    189  1.1  elric local non-loopback addresses.  There is no configuration variable.
    190  1.1  elric 
    191  1.1  elric If preauth_list is specified, it names preauth data types which will
    192  1.1  elric be included in the request.  The library default is to interact with
    193  1.1  elric the kdc to determine the required preauth types.  There is no
    194  1.1  elric configuration variable.
    195  1.1  elric 
    196  1.1  elric If salt is specified, it specifies the salt which will be used when
    197  1.1  elric converting the password to a key.  The library default is to interact
    198  1.1  elric with the kdc to determine the correct salt.  There is no configuration
    199  1.1  elric variable.
    200  1.1  elric 
    201  1.1  elric ================================================================
    202  1.1  elric 
    203  1.1  elric typedef struct _krb5_verify_init_creds_opt {
    204  1.1  elric     krb5_flags flags;
    205  1.1  elric     int ap_req_nofail;
    206  1.1  elric } krb5_verify_init_creds_opt;
    207  1.1  elric 
    208  1.1  elric #define KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL	0x0001
    209  1.1  elric 
    210  1.1  elric void krb5_verify_init_creds_opt_init(krb5_init_creds_opt *options);
    211  1.1  elric void krb5_verify_init_creds_opt_set_ap_req_nofail(krb5_init_creds_opt *options,
    212  1.1  elric 						  int ap_req_nofail);
    213  1.1  elric 
    214  1.1  elric krb5_error_code
    215  1.1  elric krb5_verify_init_creds(krb5_context context,
    216  1.1  elric 		       krb5_creds *creds,
    217  1.1  elric 		       krb5_principal ap_req_server,
    218  1.1  elric 		       krb5_keytab ap_req_keytab,
    219  1.1  elric 		       krb5_ccache *ccache,
    220  1.1  elric 		       krb5_verify_init_creds_opt *options);
    221  1.1  elric 
    222  1.1  elric This function will use the initial ticket in creds to make an AP_REQ
    223  1.1  elric and verify it to insure that the AS_REP has not been spoofed.
    224  1.1  elric 
    225  1.1  elric If the ap_req_server name is non-NULL, then this service name will be
    226  1.1  elric used for the AP_REQ; otherwise, the default host key
    227  1.1  elric (host/hostname.domain@LOCAL-REALM) will be used.
    228  1.1  elric 
    229  1.1  elric If ap_req_keytab is non-NULL, the service key for the verification
    230  1.1  elric will be read from that keytab; otherwise, the service key will be read
    231  1.1  elric from the default keytab. 
    232  1.1  elric 
    233  1.1  elric If the service of the ticket in creds is the same as the service name
    234  1.1  elric for the AP_REQ, then this ticket will be used directly.  If the ticket
    235  1.1  elric is a tgt, then it will be used to obtain credentials for the service.
    236  1.1  elric Otherwise, the verification will fail, and return an error.
    237  1.1  elric 
    238  1.1  elric Other failures of the AP_REQ verification may or may not be considered
    239  1.1  elric errors, as described below.
    240  1.1  elric 
    241  1.1  elric If a pointer to a credential cache handle is specified, and the handle
    242  1.1  elric is NULL, a credential cache handle referring to all credentials
    243  1.1  elric obtained in the course of verifying the user will be returned.  In
    244  1.1  elric order to avoid potential setuid race conditions and other problems
    245  1.1  elric related to file system access, this handle will refer to a memory
    246  1.1  elric credential cache.  If the handle is non-NULL, then the credentials
    247  1.1  elric will be added to the existing ccache.  If the caller only wishes to
    248  1.1  elric verify the password and will not be doing any other kerberos
    249  1.1  elric functions, then a NULL pointer may be specified, and the credentials
    250  1.1  elric will be deleted before the function returns.
    251  1.1  elric 
    252  1.1  elric If ap_req_nofail is specified, then failures of the AP_REQ
    253  1.1  elric verification are considered errors if and only if ap_req_nofail is
    254  1.1  elric non-zero.
    255  1.1  elric 
    256  1.1  elric Whether or not AP_REQ validation is performed and what failures mean
    257  1.1  elric depends on these inputs:
    258  1.1  elric 
    259  1.1  elric  A) The appropriate keytab exists and contains the named key.
    260  1.1  elric 
    261  1.1  elric  B) An AP_REQ request to the kdc succeeds, and the resulting AP_REQ
    262  1.1  elric can be decrypted and verified.
    263  1.1  elric 
    264  1.1  elric  C) The administrator has specified in a configuration file that
    265  1.1  elric AP_REQ validation must succeed.  This is basically a paranoid bit, and
    266  1.1  elric can be overridden by the application based on a command line flag or
    267  1.1  elric other application-specific info.  This flag is especially useful if
    268  1.1  elric the admin is concerned that DNS might be spoofed while determining the
    269  1.1  elric host/FQDN name.  The configuration variable [libdefaults]
    270  1.1  elric "verify_ap_req_nofail" is used if no value is passed in.  The library
    271  1.1  elric default is not to set this option.
    272  1.1  elric 
    273  1.1  elric Initial ticket verification will succeed if and only if:
    274  1.1  elric 
    275  1.1  elric  - A && B    or
    276  1.1  elric  - !A && !C
    277  1.1  elric 
    278  1.1  elric ================================================================
    279  1.1  elric 
    280  1.1  elric For illustrative purposes, here's the invocations I expect some
    281  1.1  elric programs will use.  Of course, error checking needs to be added.
    282  1.1  elric 
    283  1.1  elric kinit:
    284  1.1  elric 
    285  1.1  elric     /* Fill in client from the command line || existing ccache, and,
    286  1.1  elric        start_time, and options.{tkt_life,renew_life,forwardable,proxiable}
    287  1.1  elric        from the command line.  Some or all may remain unset. */
    288  1.1  elric 
    289  1.1  elric     krb5_get_init_creds(context, &creds, client,
    290  1.1  elric 			krb5_initial_prompter_posix, NULL,
    291  1.1  elric 			start_time, NULL, &options);
    292  1.1  elric     krb5_cc_store_cred(context, ccache, &creds);
    293  1.1  elric     krb5_free_cred_contents(context, &creds);
    294  1.1  elric 
    295  1.1  elric login:
    296  1.1  elric 
    297  1.1  elric     krb5_get_init_creds(context, &creds, client,
    298  1.1  elric 			krb5_initial_prompter_posix, NULL,
    299  1.1  elric 			0, NULL, NULL);
    300  1.1  elric     krb5_verify_init_creds(context, &creds, NULL, NULL, &vcc, NULL);
    301  1.1  elric     /* setuid */
    302  1.1  elric     krb5_cc_store_cred(context, ccache, &creds);
    303  1.1  elric     krb5_cc_copy(context, vcc, ccache);
    304  1.1  elric     krb5_free_cred_contents(context, &creds);
    305  1.1  elric     krb5_cc_destroy(context, vcc);
    306  1.1  elric 
    307  1.1  elric xdm:
    308  1.1  elric 
    309  1.1  elric     krb5_get_initial_creds(context, &creds, client,
    310  1.1  elric 			   krb5_initial_prompter_xt, (void *) &xtstuff,
    311  1.1  elric 			   0, NULL, NULL);
    312  1.1  elric     krb5_verify_init_creds(context, &creds, NULL, NULL, &vcc, NULL);
    313  1.1  elric     /* setuid */
    314  1.1  elric     krb5_cc_store_cred(context, ccache, &creds);
    315  1.1  elric     krb5_free_cred_contents(context, &creds);
    316  1.1  elric     krb5_cc_copy(context, vcc, ccache);
    317  1.1  elric     krb5_cc_destroy(context, vcc);
    318  1.1  elric 
    319  1.1  elric passwd:
    320  1.1  elric 
    321  1.1  elric     krb5_init_creds_opt_init(&options);
    322  1.1  elric     krb5_init_creds_opt_set_tkt_life = 300;
    323  1.1  elric     krb5_get_initial_creds(context, &creds, client,
    324  1.1  elric 			   krb5_initial_prompter_posix, NULL,
    325  1.1  elric 			   0, "kadmin/changepw", &options);
    326  1.1  elric     /* change password */
    327  1.1  elric     krb5_free_cred_contents(context, &creds);
    328  1.1  elric 
    329  1.1  elric pop3d (simple password validator when no user interation possible):
    330  1.1  elric 
    331  1.1  elric     krb5_get_initial_creds(context, &creds, client,
    332  1.1  elric 			   NULL, NULL, 0, NULL, NULL);
    333  1.1  elric     krb5_verify_init_creds(context, &creds, NULL, NULL, &vcc, NULL);
    334  1.1  elric     krb5_cc_destroy(context, vcc);
    335  1.1  elric 
    336  1.1  elric ================================================================
    337  1.1  elric 
    338  1.1  elric password expiration has a subtlety.  When a password expires and is
    339  1.1  elric changed, there is a delay between when the master gets the new key
    340  1.1  elric (immediately), and the slaves (propogation interval).  So, when
    341  1.1  elric getting an in_tkt, if the password is expired, the request should be
    342  1.1  elric reissued to the master (this kind of sucks if you have SAM, oh well).
    343  1.1  elric If this says expired, too, then the password should be changed, and
    344  1.1  elric then the initial ticket request should be issued to the master again.
    345  1.1  elric If the master times out, then a message that the password has expired
    346  1.1  elric and cannot be changed due to the master being unreachable should be
    347  1.1  elric displayed.
    348  1.1  elric 
    349  1.1  elric ================================================================
    350  1.1  elric 
    351  1.1  elric get_init_creds reads config stuff from:
    352  1.1  elric 
    353  1.1  elric [libdefaults]
    354  1.1  elric 	varname1 = defvalue
    355  1.1  elric 	REALM = {
    356  1.1  elric 		varname1 = value
    357  1.1  elric 		varname2 = value
    358  1.1  elric 	}
    359  1.1  elric 
    360  1.1  elric typedef struct _krb5_get_init_creds_opt {
    361  1.1  elric     krb5_flags flags;
    362  1.1  elric     krb5_deltat tkt_life;	/* varname = "ticket_lifetime" */
    363  1.1  elric     krb5_deltat renew_life;	/* varname = "renew_lifetime" */
    364  1.1  elric     int forwardable;		/* varname = "forwardable" */
    365  1.1  elric     int proxiable;		/* varname = "proxiable" */
    366  1.1  elric     krb5_enctype *etype_list;	/* varname = "default_tkt_enctypes" */
    367  1.1  elric     int etype_list_length;
    368  1.1  elric     krb5_address **address_list; /* no varname */
    369  1.1  elric     krb5_preauthtype *preauth_list; /* no varname */
    370  1.1  elric     int preauth_list_length;
    371  1.1  elric     krb5_data *salt;
    372  1.1  elric } krb5_get_init_creds_opt;
    373  1.1  elric 
    374  1.1  elric 
    375