27#define "rlm_securid - "
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/server/module_rlm.h>
36 RC_SECURID_AUTH_SUCCESS = 0,
37 RC_SECURID_AUTH_FAILURE = -3,
38 RC_SECURID_AUTH_ACCESS_DENIED_FAILURE = -4,
39 RC_SECURID_AUTH_INVALID_SERVER_FAILURE = -5,
40 RC_SECURID_AUTH_CHALLENGE = -17
74static SD_CHAR empty_pin[] =
"";
77static int securid_session_cmp(
void const *a,
void const *b)
87 if (ret != 0)
return ret;
93static SECURID_AUTH_RC securidAuth(
void *instance,
request_t *request,
96 char *replyMsgBuffer,
size_t replyMsgBufferSize)
106 SD_CHAR *securid_user, *securid_pass;
109 ERROR(
"SecurID username is NULL");
110 return RC_SECURID_AUTH_FAILURE;
115 return RC_SECURID_AUTH_FAILURE;
118 memcpy(&securid_user, &
username,
sizeof(securid_user));
119 memcpy(&securid_pass, &passcode,
sizeof(securid_pass));
121 *replyMsgBuffer =
'\0';
124 if (!securid_session) {
126 SDI_HANDLE sdiHandle = SDI_HANDLE_NONE;
128 acm_ret = SD_Init(&sdiHandle);
129 if (acm_ret != ACM_OK) {
130 RERROR(
"Cannot communicate with the ACE/Server");
134 acm_ret = SD_Lock(sdiHandle, securid_user);
135 if (acm_ret != ACM_OK) {
140 acm_ret = SD_Check(sdiHandle, securid_pass, securid_user);
147 return RC_SECURID_AUTH_SUCCESS;
149 case ACM_ACCESS_DENIED:
153 return RC_SECURID_AUTH_ACCESS_DENIED_FAILURE;
155 case ACM_INVALID_SERVER:
156 RERROR(
"SecurID: Invalid ACE server");
157 return RC_SECURID_AUTH_INVALID_SERVER_FAILURE;
159 case ACM_NEW_PIN_REQUIRED:
169 acm_ret = AceGetPinParams(sdiHandle, &pin_params);
172 if (pin_params.Selectable == CANNOT_CHOOSE_PIN) {
174 snprintf(replyMsgBuffer, replyMsgBufferSize,
175 "\r\nAre you prepared to accept a new system-generated PIN [y/n]?");
178 }
else if (pin_params.Selectable == USER_SELECTABLE) {
179 snprintf(replyMsgBuffer, replyMsgBufferSize,
180 "\r\nPress 'y' to generate a new PIN\r\nOR\r\n'n'to enter a new PIN yourself [y/n]");
184 if (pin_params.Alphanumeric) {
185 strcpy(format,
"alphanumeric characters");
189 snprintf(replyMsgBuffer, replyMsgBufferSize,
190 " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
191 pin_params.Min, pin_params.Max, format);
197 return RC_SECURID_AUTH_CHALLENGE;
199 case ACM_NEXT_CODE_REQUIRED:
200 RDEBUG2(
"Next securid token code required for %s",
212 strlcpy(replyMsgBuffer,
"\r\nPlease Enter the Next Code from Your Token:", replyMsgBufferSize);
213 return RC_SECURID_AUTH_CHALLENGE;
216 ERROR(
"SecurID: Unexpected error from ACE/Agent API acm_ret=%d", acm_ret);
218 return RC_SECURID_AUTH_FAILURE;
232 acm_ret = SD_Next(securid_session->
sdiHandle, securid_pass);
233 if (acm_ret == ACM_OK) {
234 INFO(
"Next SecurID token accepted for [%s].", securid_session->
identity);
235 rc = RC_SECURID_AUTH_SUCCESS;
238 INFO(
"SecurID: Next token rejected for [%s].", securid_session->
identity);
239 rc = RC_SECURID_AUTH_FAILURE;
247 RDEBUG2(
"SecurID NEW_PIN_REQUIRED_STATE for %s",
251 if (securid_session->
pin) TALLOC_FREE(securid_session->
pin);
254 strlcpy(replyMsgBuffer,
"\r\n Please re-enter new PIN:", replyMsgBufferSize);
261 return RC_SECURID_AUTH_CHALLENGE;
266 if (!securid_session->
pin || strcmp(securid_session->
pin, passcode)) {
267 RDEBUG2(
"Pin confirmation failed. Pins do not match [%s] and [%s]",
272 AceGetPinParams(securid_session->
sdiHandle, &pin_params);
273 if (pin_params.Alphanumeric) {
274 strcpy(format,
"alphanumeric characters");
278 snprintf(replyMsgBuffer, replyMsgBufferSize,
279 " \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:",
280 pin_params.Min, pin_params.Max, format);
286 rc = RC_SECURID_AUTH_CHALLENGE;
290 RDEBUG2(
"Pin confirmation succeeded. Pins match");
291 acm_ret = SD_Pin(securid_session->
sdiHandle, securid_pass);
292 if (acm_ret == ACM_NEW_PIN_ACCEPTED) {
293 RDEBUG2(
"New SecurID pin accepted for %s.", securid_session->
identity);
300 rc = RC_SECURID_AUTH_CHALLENGE;
301 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);
303 RDEBUG2(
"SecurID: New SecurID pin rejected for %s.", securid_session->
identity);
304 SD_Pin(securid_session->
sdiHandle, &empty_pin[0]);
307 rc = RC_SECURID_AUTH_FAILURE;
315 acm_ret = SD_Check(securid_session->
sdiHandle, securid_pass, securid_user);
316 if (acm_ret == ACM_OK) {
317 RDEBUG2(
"New SecurID passcode accepted for %s", securid_session->
identity);
318 rc = RC_SECURID_AUTH_SUCCESS;
321 INFO(
"SecurID: New passcode rejected for [%s]", securid_session->
identity);
322 rc = RC_SECURID_AUTH_FAILURE;
330 if (!strcmp(passcode,
"y")) {
331 AceGetSystemPin(securid_session->
sdiHandle, new_pin);
335 if (securid_session->
pin) TALLOC_FREE(securid_session->
pin);
338 snprintf(replyMsgBuffer, replyMsgBufferSize,
339 "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
347 rc = RC_SECURID_AUTH_CHALLENGE;
350 SD_Pin(securid_session->
sdiHandle, &empty_pin[0]);
354 rc = RC_SECURID_AUTH_FAILURE;
360 acm_ret = SD_Pin(securid_session->
sdiHandle, (SD_CHAR*)securid_session->
pin);
361 if (acm_ret == ACM_NEW_PIN_ACCEPTED) {
362 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);
366 rc = RC_SECURID_AUTH_CHALLENGE;
369 SD_Pin(securid_session->
sdiHandle, &empty_pin[0]);
370 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);
373 rc = RC_SECURID_AUTH_FAILURE;
380 if (!strcmp(passcode,
"y")) {
382 AceGetSystemPin(securid_session->
sdiHandle, new_pin);
383 snprintf(replyMsgBuffer, replyMsgBufferSize,
384 "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
391 rc = RC_SECURID_AUTH_CHALLENGE;
395 AceGetPinParams(securid_session->
sdiHandle,
397 if (pin_params.Alphanumeric) {
398 strcpy(format,
"alphanumeric characters");
403 snprintf(replyMsgBuffer, replyMsgBufferSize,
404 " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
405 pin_params.Min, pin_params.Max, format);
411 rc = RC_SECURID_AUTH_CHALLENGE;
433 if (
inst->session_tree) {
435 inst->session_tree = NULL;
438 pthread_mutex_destroy(&(
inst->session_mutex));
453 if (!
inst->session_tree) {
454 ERROR(
"Cannot initialize session tree");
458 pthread_mutex_init(&(
inst->session_mutex), NULL);
482 REDEBUG(
"Attribute \"User-Name\" is required for authentication");
487 REDEBUG(
"Attribute \"User-Password\" is required for authentication");
494 if (password->vp_length == 0) {
495 REDEBUG(
"Password should not be empty");
500 RDEBUG3(
"Login attempt with password \"%pV\"", &password->data);
502 RDEBUG2(
"Login attempt with password");
505 rcode = securidAuth(
inst, request,
username->vp_strvalue, password->vp_strvalue,
509 case RC_SECURID_AUTH_SUCCESS:
513 case RC_SECURID_AUTH_CHALLENGE:
522 RDEBUG2(
"Sending Access-Challenge");
526 case RC_SECURID_AUTH_FAILURE:
527 case RC_SECURID_AUTH_ACCESS_DENIED_FAILURE:
528 case RC_SECURID_AUTH_INVALID_SERVER_FAILURE:
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
static int const char char buffer[256]
strcpy(log_entry->msg, buffer)
#define CONF_PARSER_TERMINATOR
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Defines a CONF_PAIR to C data type mapping.
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
#define DICT_AUTOLOAD_TERMINATOR
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Module instance to detach.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
module_t common
Common fields presented by all modules.
SECURID_SESSION * securid_sessionlist_find(rlm_securid_t *inst, request_t *request)
int securid_sessionlist_add(rlm_securid_t *inst, request_t *request, SECURID_SESSION *session)
SECURID_SESSION * securid_session_alloc(void)
void securid_session_free(UNUSED rlm_securid_t *inst, request_t *request, SECURID_SESSION *session)
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
static const conf_parser_t config[]
static fr_dict_attr_t const * attr_user_password
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_user_name
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
#define RETURN_UNLANG_INVALID
#define RETURN_UNLANG_RCODE(_rcode)
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
static const conf_parser_t module_config[]
static fr_dict_attr_t const * attr_reply_message
static unlang_action_t mod_authenticate(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static int mod_detach(module_detach_ctx_t *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
SECURID_SESSION_STATE securidSessionState
@ NEW_PIN_SYSTEM_CONFIRM_STATE
@ NEW_PIN_USER_SELECT_STATE
@ NEW_PIN_AUTH_VALIDATE_STATE
@ NEW_PIN_SYSTEM_ACCEPT_STATE
@ NEXT_CODE_REQUIRED_STATE
@ NEW_PIN_USER_CONFIRM_STATE
HIDDEN fr_dict_attr_t const * attr_prompt
char state[SECURID_STATE_LEN]
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
Stores an attribute, a value and various bits of other data.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
#define talloc_get_type_abort_const
#define FR_MAX_STRING_LEN
int format(printf, 5, 0))