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