/* * Find existing session if any which matches the State variable in current AccessRequest * Then, release the session from the list, and return it to * the caller. * */ SECURID_SESSION *securid_sessionlist_find(rlm_securid_t *inst, REQUEST *request) { VALUE_PAIR *state; SECURID_SESSION* session; SECURID_SESSION mySession; /* clean expired sessions if any */ pthread_mutex_lock(&(inst->session_mutex)); securid_sessionlist_clean_expired(inst, request, request->timestamp); pthread_mutex_unlock(&(inst->session_mutex)); /* * We key the sessions off of the 'state' attribute */ state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY); if (!state) { return NULL; } if (state->length != SECURID_STATE_LEN) { radlog(L_ERR,"rlm_securid: Invalid State variable. length=%d",state->length); return NULL; } memset(&mySession,0,sizeof(mySession)); mySession.src_ipaddr = request->packet->src_ipaddr; memcpy(mySession.state, state->vp_strvalue, sizeof(mySession.state)); /* * Playing with a data structure shared among threads * means that we need a lock, to avoid conflict. */ pthread_mutex_lock(&(inst->session_mutex)); session = securid_sessionlist_delete(inst, &mySession); pthread_mutex_unlock(&(inst->session_mutex)); /* * Might not have been there. */ if (!session) { radlog(L_ERR,"rlm_securid: No SECURID session matching the State variable."); return NULL; } RDEBUG2("Session found identity='%s' state='%s', released from the list", SAFE_STR(session->identity),session->state); if (session->trips >= inst->max_trips_per_session) { RDEBUG2("More than %d authentication packets for this SECURID session. Aborted.",inst->max_trips_per_session); securid_session_free(inst,request,session); return NULL; } session->trips++; return session; }
void securid_sessionlist_free(rlm_securid_t *inst,REQUEST *request) { SECURID_SESSION *node, *next; pthread_mutex_lock(&(inst->session_mutex)); for (node = inst->session_head; node != NULL; node = next) { next = node->next; securid_session_free(inst,request,node); } inst->session_head = inst->session_tail = NULL; pthread_mutex_unlock(&(inst->session_mutex)); }
static void securid_sessionlist_clean_expired(rlm_securid_t *inst, REQUEST *request, time_t timestamp) { int num_sessions; SECURID_SESSION *session; num_sessions = rbtree_num_elements(inst->session_tree); RDEBUG2("There are %d sessions in the tree\n",num_sessions); /* * Delete old sessions from the list * */ while((session = inst->session_head)) { if ((timestamp - session->timestamp) > inst->timer_limit) { rbnode_t *node; node = rbtree_find(inst->session_tree, session); rad_assert(node != NULL); rbtree_delete(inst->session_tree, node); /* * session == inst->session_head */ inst->session_head = session->next; if (session->next) { session->next->prev = NULL; } else { inst->session_head = NULL; inst->session_tail = NULL; } RDEBUG2("Cleaning expired session: identity='%s' state='%s'\n", SAFE_STR(session->identity),session->state); securid_session_free(inst,request,session); } else { /* no need to check all sessions since they are sorted by age */ break; } } }
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("SeecurID 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; }