krb5_error_code verify_securid_data_2(krb5_context context, krb5_db_entry *client, krb5_sam_response_2 *sr2, krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *pa, krb5_sam_challenge_2 **sc2_out) { krb5_error_code retval; int new_pin = 0; krb5_key_data *client_key_data = NULL; krb5_keyblock client_key; krb5_data scratch; krb5_enc_sam_response_enc_2 *esre2 = NULL; struct securid_track_data sid_track_data, *trackp = NULL; krb5_data tmp_data; SDI_HANDLE sd_handle = SDI_HANDLE_NONE; krb5_sam_challenge_2 *sc2p = NULL; char *cp, *user = NULL; char *securid_user = NULL; char passcode[LENPRNST+1]; char max_pin_len, min_pin_len, alpha_pin; memset(&client_key, 0, sizeof(client_key)); memset(&scratch, 0, sizeof(scratch)); *sc2_out = NULL; retval = krb5_unparse_name(context, client->princ, &user); if (retval != 0) { com_err("krb5kdc", retval, "while unparsing client name in verify_securid_data_2"); return retval; } if ((sr2->sam_enc_nonce_or_sad.ciphertext.data == NULL) || (sr2->sam_enc_nonce_or_sad.ciphertext.length <= 0)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(context, retval, "No preauth data supplied in " "verify_securid_data_2 (%s)", user); goto cleanup; } retval = krb5_dbe_find_enctype(context, client, sr2->sam_enc_nonce_or_sad.enctype, KRB5_KDB_SALTTYPE_NORMAL, sr2->sam_enc_nonce_or_sad.kvno, &client_key_data); if (retval) { com_err("krb5kdc", retval, "while getting client key in verify_securid_data_2 (%s)", user); goto cleanup; } retval = krb5_dbe_decrypt_key_data(context, NULL, client_key_data, &client_key, NULL); if (retval != 0) { com_err("krb5kdc", retval, "while decrypting client key in verify_securid_data_2 (%s)", user); goto cleanup; } scratch.length = sr2->sam_enc_nonce_or_sad.ciphertext.length; scratch.data = k5alloc(scratch.length, &retval); if (retval) goto cleanup; retval = krb5_c_decrypt(context, &client_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE, 0, &sr2->sam_enc_nonce_or_sad, &scratch); if (retval) { com_err("krb5kdc", retval, "while decrypting SAD in verify_securid_data_2 (%s)", user); goto cleanup; } retval = decode_krb5_enc_sam_response_enc_2(&scratch, &esre2); if (retval) { com_err("krb5kdc", retval, "while decoding SAD in verify_securid_data_2 (%s)", user); esre2 = NULL; goto cleanup; } if (sr2->sam_nonce != esre2->sam_nonce) { com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "while checking nonce in verify_securid_data_2 (%s)", user); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } if (esre2->sam_sad.length == 0 || esre2->sam_sad.data == NULL) { com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "No SecurID passcode in verify_securid_data_2 (%s)", user); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } /* Copy out SAD to null-terminated buffer */ memset(passcode, 0, sizeof(passcode)); if (esre2->sam_sad.length > (sizeof(passcode) - 1)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; com_err("krb5kdc", retval, "SecurID passcode/PIN too long (%d bytes) in " "verify_securid_data_2 (%s)", esre2->sam_sad.length, user); goto cleanup; } memcpy(passcode, esre2->sam_sad.data, esre2->sam_sad.length); securid_user = strdup(user); if (!securid_user) { retval = ENOMEM; com_err("krb5kdc", ENOMEM, "while copying user name in verify_securid_data_2 (%s)", user); goto cleanup; } cp = strchr(securid_user, '@'); if (cp != NULL) *cp = '\0'; /* Check for any track_id data that may have state from a previous attempt * at SecurID authentication. */ if (sr2->sam_track_id.data && (sr2->sam_track_id.length > 0)) { krb5_data track_id_data; memset(&track_id_data, 0, sizeof(track_id_data)); retval = securid_decrypt_track_data_2(context, client, &sr2->sam_track_id, &track_id_data); if (retval) { com_err("krb5kdc", retval, "while decrypting SecurID trackID in " "verify_securid_data_2 (%s)", user); goto cleanup; } if (track_id_data.length < sizeof (struct securid_track_data)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; com_err("krb5kdc", retval, "Length of track data incorrect"); goto cleanup; } trackp = (struct securid_track_data *)track_id_data.data; if(trackp->hostid != gethostid()) { krb5_klog_syslog(LOG_INFO, "Unexpected challenge response"); retval = KRB5KDC_ERR_DISCARD; goto cleanup; } switch(trackp->state) { case SECURID_STATE_INITIAL: goto initial; break; case SECURID_STATE_NEW_PIN_AGAIN: { int pin1_len, pin2_len; trackp->handle = ntohl(trackp->handle); pin2_len = strlen(passcode); pin1_len = strlen(trackp->passcode); if ((pin1_len != pin2_len) || (memcmp(passcode, trackp->passcode, pin1_len) != 0)) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "New SecurID PIN Failed for user " "%s: PIN mis-match", user); break; } retval = SD_Pin(trackp->handle, passcode); SD_Close(trackp->handle); if (retval == ACM_NEW_PIN_ACCEPTED) { enc_tkt_reply->flags|= TKT_FLG_HW_AUTH; enc_tkt_reply->flags|= TKT_FLG_PRE_AUTH; krb5_klog_syslog(LOG_INFO, "SecurID PIN Accepted for %s in " "verify_securid_data_2", securid_user); retval = 0; } else { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "SecurID PIN Failed for user %s (AceServer " "returns %d) in verify_securid_data_2", user, retval); } break; } case SECURID_STATE_NEW_PIN: { krb5_sam_challenge_2_body sc2b; sc2p = k5alloc(sizeof *sc2p, &retval); if (retval) goto cleanup; memset(sc2p, 0, sizeof(*sc2p)); memset(&sc2b, 0, sizeof(sc2b)); sc2b.sam_type = PA_SAM_TYPE_SECURID; sc2b.sam_response_prompt.data = NEW_PIN_AGAIN_message; sc2b.sam_response_prompt.length = strlen(sc2b.sam_response_prompt.data); sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD; sc2b.sam_etype = client_key.enctype; tmp_data.data = (char *)&sc2b.sam_nonce; tmp_data.length = sizeof(sc2b.sam_nonce); if ((retval = krb5_c_random_make_octets(context, &tmp_data))) { com_err("krb5kdc", retval, "while making nonce for SecurID new " "PIN2 SAM_CHALLENGE_2 (%s)", user); goto cleanup; } sid_track_data.state = SECURID_STATE_NEW_PIN_AGAIN; sid_track_data.handle = trackp->handle; sid_track_data.hostid = gethostid(); /* Should we complain if sizes don't work ?? */ memcpy(sid_track_data.passcode, passcode, sizeof(sid_track_data.passcode)); tmp_data.data = (char *)&sid_track_data; tmp_data.length = sizeof(sid_track_data); if ((retval = securid_encrypt_track_data_2(context, client, &tmp_data, &sc2b.sam_track_id))) { com_err("krb5kdc", retval, "while encrypting NEW PIN2 SecurID " "track data for SAM_CHALLENGE_2 (%s)", securid_user); goto cleanup; } retval = securid_make_sam_challenge_2_and_cksum(context, sc2p, &sc2b, &client_key); if (retval) { com_err("krb5kdc", retval, "while making cksum for " "SAM_CHALLENGE_2 (new PIN2) (%s)", securid_user); goto cleanup; } krb5_klog_syslog(LOG_INFO, "Requesting verification of new PIN for user %s", securid_user); *sc2_out = sc2p; sc2p = NULL; /*sc2_out may be set even on error path*/ retval = KRB5KDC_ERR_PREAUTH_REQUIRED; goto cleanup; } case SECURID_STATE_NEXT_CODE: trackp->handle = ntohl(trackp->handle); retval = SD_Next(trackp->handle, passcode); SD_Close(trackp->handle); if (retval == ACM_OK) { enc_tkt_reply->flags |= TKT_FLG_HW_AUTH | TKT_FLG_PRE_AUTH; krb5_klog_syslog(LOG_INFO, "Next SecurID Code Accepted for " "user %s", securid_user); retval = 0; } else { krb5_klog_syslog(LOG_INFO, "Next SecurID Code Failed for user " "%s (AceServer returns %d) in " "verify_securid_data_2", user, retval); retval = KRB5KDC_ERR_PREAUTH_FAILED; } break; } } else { /* No track data, this is first of N attempts */ initial: retval = SD_Init(&sd_handle); if (retval) { com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "SD_Init() returns error %d in verify_securid_data_2 (%s)", retval, securid_user); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } retval = SD_Lock(sd_handle, securid_user); if (retval != ACM_OK) { SD_Close(sd_handle); retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "SD_Lock() failed (AceServer returns %d) for %s", retval, securid_user); goto cleanup; } retval = SD_Check(sd_handle, passcode, securid_user); switch (retval) { case ACM_OK: SD_Close(sd_handle); enc_tkt_reply->flags|= TKT_FLG_HW_AUTH; enc_tkt_reply->flags|= TKT_FLG_PRE_AUTH; krb5_klog_syslog(LOG_INFO, "SecurID passcode accepted for user %s", user); retval = 0; break; case ACM_ACCESS_DENIED: SD_Close(sd_handle); retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_klog_syslog(LOG_INFO, "AceServer returns Access Denied for " "user %s (SAM2)", user); goto cleanup; case ACM_NEW_PIN_REQUIRED: new_pin = 1; /*fall through*/ case ACM_NEXT_CODE_REQUIRED: { krb5_sam_challenge_2_body sc2b; sc2p = k5alloc(sizeof *sc2p, &retval); if (retval) goto cleanup; memset(sc2p, 0, sizeof(*sc2p)); memset(&sc2b, 0, sizeof(sc2b)); sc2b.sam_type = PA_SAM_TYPE_SECURID; sc2b.sam_response_prompt.data = NEXT_PASSCODE_message; sc2b.sam_response_prompt.length = strlen(sc2b.sam_response_prompt.data); sc2b.sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD; sc2b.sam_etype = client_key.enctype; if (new_pin) { if ((AceGetMaxPinLen(sd_handle, &max_pin_len) == ACE_SUCCESS) && (AceGetMinPinLen(sd_handle, &min_pin_len) == ACE_SUCCESS) && (AceGetAlphanumeric(sd_handle, &alpha_pin) == ACE_SUCCESS)) { sprintf(PIN_message, "New PIN must contain %d to %d %sdigits", min_pin_len, max_pin_len, (alpha_pin == 0) ? "" : "alphanumeric "); sc2b.sam_challenge_label.data = PIN_message; sc2b.sam_challenge_label.length = strlen(sc2b.sam_challenge_label.data); } else { sc2b.sam_challenge_label.length = 0; } } tmp_data.data = (char *)&sc2b.sam_nonce; tmp_data.length = sizeof(sc2b.sam_nonce); if ((retval = krb5_c_random_make_octets(context, &tmp_data))) { com_err("krb5kdc", retval, "while making nonce for SecurID SAM_CHALLENGE_2 (%s)", user); goto cleanup; } if (new_pin) sid_track_data.state = SECURID_STATE_NEW_PIN; else sid_track_data.state = SECURID_STATE_NEXT_CODE; sid_track_data.handle = htonl(sd_handle); sid_track_data.hostid = gethostid(); tmp_data.data = (char *)&sid_track_data; tmp_data.length = sizeof(sid_track_data); retval = securid_encrypt_track_data_2(context, client, &tmp_data, &sc2b.sam_track_id); if (retval) { com_err("krb5kdc", retval, "while encrypting SecurID track " "data for SAM_CHALLENGE_2 (%s)", securid_user); goto cleanup; } retval = securid_make_sam_challenge_2_and_cksum(context, sc2p, &sc2b, &client_key); if (retval) { com_err("krb5kdc", retval, "while making cksum for SAM_CHALLENGE_2 (%s)", securid_user); } if (new_pin) krb5_klog_syslog(LOG_INFO, "New SecurID PIN required for " "user %s", securid_user); else krb5_klog_syslog(LOG_INFO, "Next SecurID passcode required " "for user %s", securid_user); *sc2_out = sc2p; sc2p = NULL; retval = KRB5KDC_ERR_PREAUTH_REQUIRED; /*sc2_out is permitted as an output on error path*/ goto cleanup; } default: com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_FAILED, "AceServer returns unknown error code %d " "in verify_securid_data_2\n", retval); retval = KRB5KDC_ERR_PREAUTH_FAILED; goto cleanup; } } /* no track_id data */ cleanup: krb5_free_keyblock_contents(context, &client_key); free(scratch.data); krb5_free_enc_sam_response_enc_2(context, esre2); free(user); free(securid_user); free(trackp); krb5_free_sam_challenge_2(context, sc2p); return retval; }
static SECURID_AUTH_RC securidAuth(void *instance, REQUEST *request, const char* username, const char* passcode, char* replyMsgBuffer,int replyMsgBufferSize) { rlm_securid_t *inst = (rlm_securid_t *) instance; int acmRet; SD_PIN pinParams; char newPin[10]; char format[30]; SECURID_SESSION *pSecurid_session=NULL; int rc=-1; if (!username) { radlog(L_ERR, "SecurID username is NULL"); return RC_SECURID_AUTH_FAILURE; } if (!passcode) { radlog(L_ERR, "SecurID passcode is NULL for %s user",username); return RC_SECURID_AUTH_FAILURE; } *replyMsgBuffer = '\0'; pSecurid_session = securid_sessionlist_find(inst,request); if (pSecurid_session == NULL) { /* securid session not found */ SDI_HANDLE sdiHandle = SDI_HANDLE_NONE; acmRet = SD_Init(&sdiHandle); if (acmRet != ACM_OK) { radlog(L_ERR, "Cannot communicate with the ACE/Server"); return -1; } acmRet = SD_Lock(sdiHandle, (SD_CHAR*)username); if (acmRet != ACM_OK) { radlog(L_ERR,"SecurID: Access denied. Name [%s] lock failed.",username); return -2; } acmRet = SD_Check(sdiHandle, (SD_CHAR*) passcode, (SD_CHAR*) username); switch (acmRet) { case ACM_OK: /* we are in now */ RDEBUG("SecurID authentication successful for %s.", username); SD_Close(sdiHandle); return RC_SECURID_AUTH_SUCCESS; case ACM_ACCESS_DENIED: /* not this time */ RDEBUG("SecurID Access denied for %s", username); SD_Close(sdiHandle); return RC_SECURID_AUTH_ACCESS_DENIED_FAILURE; case ACM_INVALID_SERVER: radlog(L_ERR,"SecurID: Invalid ACE server."); return RC_SECURID_AUTH_INVALID_SERVER_FAILURE; case ACM_NEW_PIN_REQUIRED: RDEBUG2("SecurID new pin required for %s", username); /* create a new session */ pSecurid_session = securid_session_alloc(); pSecurid_session->sdiHandle = sdiHandle; /* save ACE handle for future use */ pSecurid_session->securidSessionState = NEW_PIN_REQUIRED_STATE; pSecurid_session->identity = strdup(username); /* Get PIN requirements */ acmRet = AceGetPinParams(sdiHandle, &pinParams); /* If a system-generated PIN is required */ if (pinParams.Selectable == CANNOT_CHOOSE_PIN) { /* Prompt user to accept a system generated PIN */ snprintf(replyMsgBuffer, replyMsgBufferSize, "\r\nAre you prepared to accept a new system-generated PIN [y/n]?"); pSecurid_session->securidSessionState = NEW_PIN_SYSTEM_ACCEPT_STATE; } else if (pinParams.Selectable == USER_SELECTABLE) { //may be returned by AM 6.x servers. snprintf(replyMsgBuffer, replyMsgBufferSize, "\r\nPress 'y' to generate a new PIN\r\nOR\r\n'n'to enter a new PIN yourself [y/n]"); pSecurid_session->securidSessionState = NEW_PIN_USER_SELECT_STATE; } else { if (pinParams.Alphanumeric) { strcpy(format, "alphanumeric characters"); } else { strcpy(format, "digits"); } snprintf(replyMsgBuffer, replyMsgBufferSize, " \r\n Enter your new PIN of %d to %d %s,\r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:", pinParams.Min, pinParams.Max, format); } /* insert new session in the session list */ securid_sessionlist_add(inst,request,pSecurid_session); return RC_SECURID_AUTH_CHALLENGE; case ACM_NEXT_CODE_REQUIRED: RDEBUG2("Next securid token code required for %s", username); /* create a new session */ pSecurid_session = securid_session_alloc(); pSecurid_session->sdiHandle = sdiHandle; pSecurid_session->securidSessionState = NEXT_CODE_REQUIRED_STATE; pSecurid_session->identity = strdup(username); /* insert new session in the session list */ securid_sessionlist_add(inst,request,pSecurid_session); strlcpy(replyMsgBuffer, "\r\nPlease Enter the Next Code from Your Token:", replyMsgBufferSize); return RC_SECURID_AUTH_CHALLENGE; default: radlog(L_ERR,"SecurID: Unexpected error from ACE/Agent API acmRet=%d",acmRet); return RC_SECURID_AUTH_FAILURE; } } else { /* existing session found */ RDEBUG("Continuing previous session found for user [%s]",username); /* continue previous session */ switch (pSecurid_session->securidSessionState) { case NEXT_CODE_REQUIRED_STATE: DEBUG2("Securid NEXT_CODE_REQUIRED_STATE: User [%s]",username); /* next token code mode */ acmRet = SD_Next(pSecurid_session->sdiHandle, (SD_CHAR*)passcode); if (acmRet == ACM_OK) { radlog(L_INFO,"Next SecurID token accepted for [%s].",pSecurid_session->identity); rc = RC_SECURID_AUTH_SUCCESS; } else { radlog(L_INFO,"SecurID: Next token rejected for [%s].",pSecurid_session->identity); rc = RC_SECURID_AUTH_FAILURE; } /* deallocate session */ securid_session_free(inst,request,pSecurid_session); return rc; case NEW_PIN_REQUIRED_STATE: RDEBUG2("SecurID NEW_PIN_REQUIRED_STATE for %s", username); /* save the previous pin */ if (pSecurid_session->pin) { free(pSecurid_session->pin); pSecurid_session->pin = NULL; } pSecurid_session->pin = strdup(passcode); strlcpy(replyMsgBuffer,"\r\n Please re-enter new PIN:", replyMsgBufferSize); /* set next state */ pSecurid_session->securidSessionState = NEW_PIN_USER_CONFIRM_STATE; /* insert the updated session in the session list */ securid_sessionlist_add(inst,request,pSecurid_session); return RC_SECURID_AUTH_CHALLENGE; case NEW_PIN_USER_CONFIRM_STATE: RDEBUG2("SecurID NEW_PIN_USER_CONFIRM_STATE: User [%s]",username); /* compare previous pin and current pin */ if (!pSecurid_session->pin || strcmp(pSecurid_session->pin,passcode)) { RDEBUG2("Pin confirmation failed. Pins do not match [%s] and [%s]", SAFE_STR(pSecurid_session->pin), passcode); /* pins do not match */ /* challenge the user again */ AceGetPinParams(pSecurid_session->sdiHandle, &pinParams); if (pinParams.Alphanumeric) { strcpy(format, "alphanumeric characters"); } else { strcpy(format, "digits"); } snprintf(replyMsgBuffer, replyMsgBufferSize, " \r\n Pins do not match--Please try again.\r\n Enter your new PIN of %d to %d %s,\r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:", pinParams.Min, pinParams.Max, format); pSecurid_session->securidSessionState = NEW_PIN_REQUIRED_STATE; /* insert the updated session in the session list */ securid_sessionlist_add(inst,request,pSecurid_session); rc = RC_SECURID_AUTH_CHALLENGE; } else { /* pins match */ RDEBUG2("Pin confirmation succeeded. Pins match"); acmRet = SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)passcode); if (acmRet == ACM_NEW_PIN_ACCEPTED) { RDEBUG("New SecurID pin accepted for %s.",pSecurid_session->identity); pSecurid_session->securidSessionState = NEW_PIN_AUTH_VALIDATE_STATE; /* insert the updated session in the session list */ securid_sessionlist_add(inst,request,pSecurid_session); rc = RC_SECURID_AUTH_CHALLENGE; strlcpy(replyMsgBuffer," \r\n\r\nWait for the code on your card to change, then enter new PIN and TokenCode\r\n\r\nEnter PASSCODE:", replyMsgBufferSize); } else { RDEBUG("SecurID: New SecurID pin rejected for %s.",pSecurid_session->identity); SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)""); /* cancel PIN */ rc = RC_SECURID_AUTH_FAILURE; /* deallocate session */ securid_session_free(inst, request, pSecurid_session); } } return rc; case NEW_PIN_AUTH_VALIDATE_STATE: acmRet = SD_Check(pSecurid_session->sdiHandle, (SD_CHAR*)passcode, (SD_CHAR*)username); if (acmRet == ACM_OK) { RDEBUG("New SecurID passcode accepted for %s.", pSecurid_session->identity); rc = RC_SECURID_AUTH_SUCCESS; } else { radlog(L_INFO,"SecurID: New passcode rejected for [%s].",pSecurid_session->identity); rc = RC_SECURID_AUTH_FAILURE; } /* deallocate session */ securid_session_free(inst,request,pSecurid_session); return rc; case NEW_PIN_SYSTEM_ACCEPT_STATE: if (!strcmp(passcode, "y")) { AceGetSystemPin(pSecurid_session->sdiHandle, newPin); /* Save the PIN for the next session * continuation */ if (pSecurid_session->pin) { free(pSecurid_session->pin); pSecurid_session->pin = NULL; } pSecurid_session->pin = strdup(newPin); snprintf(replyMsgBuffer, replyMsgBufferSize, "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?", newPin); pSecurid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE; /* insert the updated session in the * session list */ securid_sessionlist_add(inst, request, pSecurid_session); rc = RC_SECURID_AUTH_CHALLENGE; } else { SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)""); //Cancel new PIN /* deallocate session */ securid_session_free(inst, request, pSecurid_session); rc = RC_SECURID_AUTH_FAILURE; } return rc; case NEW_PIN_SYSTEM_CONFIRM_STATE: acmRet = SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)pSecurid_session->pin); if (acmRet == ACM_NEW_PIN_ACCEPTED) { strlcpy(replyMsgBuffer," \r\n\r\nPin Accepted. Wait for the code on your card to change, then enter new PIN and TokenCode\r\n\r\nEnter PASSCODE:",replyMsgBufferSize); pSecurid_session->securidSessionState = NEW_PIN_AUTH_VALIDATE_STATE; /* insert the updated session in the session list */ securid_sessionlist_add(inst,request,pSecurid_session); rc = RC_SECURID_AUTH_CHALLENGE; } else { SD_Pin(pSecurid_session->sdiHandle, (SD_CHAR*)""); //Cancel new PIN strlcpy(replyMsgBuffer," \r\n\r\nPin Rejected. Wait for the code on your card to change, then try again.\r\n\r\nEnter PASSCODE:",replyMsgBufferSize); /* deallocate session */ securid_session_free(inst, request, pSecurid_session); rc = RC_SECURID_AUTH_FAILURE; } return rc; /* USER_SELECTABLE state should be implemented to preserve compatibility with AM 6.x servers, which can return this state */ case NEW_PIN_USER_SELECT_STATE: if (!strcmp(passcode, "y")) { /* User has opted for a system-generated PIN */ AceGetSystemPin(pSecurid_session->sdiHandle, newPin); snprintf(replyMsgBuffer, replyMsgBufferSize, "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?", newPin); pSecurid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE; /* insert the updated session in the session list */ securid_sessionlist_add(inst, request, pSecurid_session); rc = RC_SECURID_AUTH_CHALLENGE; } else { /* User has opted for a user-defined PIN */ AceGetPinParams(pSecurid_session->sdiHandle, &pinParams); if (pinParams.Alphanumeric) { strcpy(format, "alphanumeric characters"); } else { strcpy(format, "digits"); } snprintf(replyMsgBuffer, replyMsgBufferSize, " \r\n Enter your new PIN of %d to %d %s,\r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:", pinParams.Min, pinParams.Max, format); pSecurid_session->securidSessionState = NEW_PIN_REQUIRED_STATE; /* insert the updated session in the session list */ securid_sessionlist_add(inst, request, pSecurid_session); rc = RC_SECURID_AUTH_CHALLENGE; } return rc; default: radlog(L_ERR|L_CONS, "rlm_securid: Invalid session state %d for user [%s]", pSecurid_session->securidSessionState, username); break; } } return 0; }
/* * securid_verify - Authenticates user and handles ACE responses * * Arguments in: * pw - struct passwd for username * pass - UNUSED * auth - sudo authentication structure for SecurID handle * * Results out: * return code - Success on successful authentication, failure on * incorrect authentication, fatal on errors */ int sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback) { SDI_HANDLE *sd = (SDI_HANDLE *) auth->data; int ret; debug_decl(sudo_securid_verify, SUDOERS_DEBUG_AUTH) pass = auth_getpass("Enter your PASSCODE: ", SUDO_CONV_PROMPT_ECHO_OFF, callback); /* Have ACE verify password */ switch (SD_Check(*sd, pass, pw->pw_name)) { case ACM_OK: ret = AUTH_SUCESS; break; case ACE_UNDEFINED_PASSCODE: sudo_warnx(U_("invalid passcode length for SecurID")); ret = AUTH_FATAL; break; case ACE_UNDEFINED_USERNAME: sudo_warnx(U_("invalid username length for SecurID")); ret = AUTH_FATAL; break; case ACE_ERR_INVALID_HANDLE: sudo_warnx(U_("invalid Authentication Handle for SecurID")); ret = AUTH_FATAL; break; case ACM_ACCESS_DENIED: ret = AUTH_FAILURE; break; case ACM_NEXT_CODE_REQUIRED: /* Sometimes (when current token close to expire?) ACE challenges for the next token displayed (entered without the PIN) */ if (pass != NULL) { memset_s(pass, SUDO_PASS_MAX, 0, strlen(pass)); free(pass); } pass = auth_getpass("\ !!! ATTENTION !!!\n\ Wait for the token code to change, \n\ then enter the new token code.\n", \ SUDO_CONV_PROMPT_ECHO_OFF, callback); if (SD_Next(*sd, pass) == ACM_OK) { ret = AUTH_SUCCESS; break; } ret = AUTH_FAILURE; break; case ACM_NEW_PIN_REQUIRED: /* * This user's SecurID has not been activated yet, * or the pin has been reset */ /* XXX - Is setting up a new PIN within sudo's scope? */ SD_Pin(*sd, ""); sudo_printf(SUDO_CONV_ERROR_MSG, "Your SecurID access has not yet been set up.\n"); sudo_printf(SUDO_CONV_ERROR_MSG, "Please set up a PIN before you try to authenticate.\n"); ret = AUTH_FATAL; break; default: sudo_warnx(U_("unknown SecurID error")); ret = AUTH_FATAL; break; } /* Free resources */ SD_Close(*sd); if (pass != NULL) { memset_s(pass, SUDO_PASS_MAX, 0, strlen(pass)); free(pass); } /* Return stored state to calling process */ debug_return_int(ret); }