/** * tries connecting to the domain controllers in the "controllers" ring, * with failover if the adequate option is specified. */ const char * obtain_challenge() { int j = 0; const char *ch = NULL; for (j = 0; j < numcontrollers; j++) { debug("obtain_challenge: selecting %s\\%s (attempt #%d)\n", current_dc->domain, current_dc->controller, j + 1); if (current_dc->dead != 0) { if (time(NULL) - current_dc->dead >= DEAD_DC_RETRY_INTERVAL) { /* mark helper as retry-worthy if it's so. */ debug("Reviving DC\n"); current_dc->dead = 0; } else { /* skip it */ debug("Skipping it\n"); continue; } } /* else branch. Here we KNOW that the DC is fine */ debug("attempting challenge retrieval\n"); ch = make_challenge(current_dc->domain, current_dc->controller); debug("make_challenge retuned %p\n", ch); if (ch) { debug("Got it\n"); return ch; /* All went OK, returning */ } /* Huston, we've got a problem. Take this DC out of the loop */ debug("Marking DC as DEAD\n"); current_dc->dead = time(NULL); /* Try with the next */ debug("moving on to next controller\n"); current_dc = current_dc->next; } /* all DCs failed. */ return NULL; }
/* Outputs the selected tokeninfo and possibly a value and pin. * Prompting may occur. */ static krb5_error_code prompt_for_token(krb5_context context, krb5_prompter_fct prompter, void *prompter_data, krb5_otp_tokeninfo **tis, krb5_otp_tokeninfo **out_ti, krb5_data *out_value, krb5_data *out_pin) { krb5_otp_tokeninfo **filtered = NULL; krb5_otp_tokeninfo *ti = NULL; krb5_error_code retval; int i, challengers = 0; char *challenge = NULL; char otpvalue[1024]; krb5_data value, pin; memset(otpvalue, 0, sizeof(otpvalue)); if (tis == NULL || tis[0] == NULL || out_ti == NULL) return EINVAL; /* Count how many challenges we have. */ for (i = 0; tis[i] != NULL; i++) { if (tis[i]->challenge.data != NULL) challengers++; } /* If we have only one tokeninfo as input, choose it. */ if (i == 1) ti = tis[0]; /* Setup our challenge, if present. */ if (challengers > 0) { /* If we have multiple tokeninfos still, choose now. */ if (ti == NULL) { retval = prompt_for_tokeninfo(context, prompter, prompter_data, tis, &ti); if (retval != 0) return retval; } /* Create the challenge prompt. */ retval = make_challenge(ti, &challenge); if (retval != 0) return retval; } /* Prompt for token value. */ retval = doprompt(context, prompter, prompter_data, challenge, _("Enter OTP Token Value"), otpvalue, sizeof(otpvalue)); free(challenge); if (retval != 0) return retval; if (ti == NULL) { /* Filter out tokeninfos that don't match our token value. */ retval = filter_tokeninfos(context, otpvalue, tis, &filtered, &ti); if (retval != 0) return retval; /* If we still don't have a single tokeninfo, choose now. */ if (filtered != NULL) { retval = prompt_for_tokeninfo(context, prompter, prompter_data, filtered, &ti); free(filtered); if (retval != 0) return retval; } } assert(ti != NULL); /* Set the value. */ value = make_data(strdup(otpvalue), strlen(otpvalue)); if (value.data == NULL) return ENOMEM; /* Collect the PIN, if necessary. */ retval = collect_pin(context, prompter, prompter_data, ti, &pin); if (retval != 0) { krb5_free_data_contents(context, &value); return retval; } *out_value = value; *out_pin = pin; *out_ti = ti; return 0; }