⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 x99_rlm.c

📁 RADIUS认证协议
💻 C
📖 第 1 页 / 共 2 页
字号:
    }    /*     * Mark the packet as an Access-Challenge packet.     * The server will take care of sending it to the user.     */    request->reply->code = PW_ACCESS_CHALLENGE;    DEBUG("rlm_x99_token: Sending Access-Challenge.");    /* TODO: support config-specific auth-type */    if (!auth_type_found)	pairadd(&request->config_items,		pairmake("Auth-Type", "x99_token", T_OP_EQ));    return RLM_MODULE_HANDLED;}/* Verify the response entered by the user. */static intx99_token_authenticate(void *instance, REQUEST *request){    x99_token_t *inst = (x99_token_t *) instance;    x99_user_info_t user_info;    char *username;    int i, pwattr, rc, fc;    int32_t sflags = 0; 	/* flags from state */    time_t last_auth;		/* time of last authentication */    unsigned auth_pos = 0;	/* window position of last authentication */    char challenge[MAX_CHALLENGE_LEN + 1];    char e_response[9];		/* expected response */    VALUE_PAIR *add_vps = NULL;    /* User-Name attribute required. */    if (!request->username) {	x99_log(X99_LOG_AUTH,		"auth: Attribute \"User-Name\" required for authentication.");	return RLM_MODULE_INVALID;    }    username = request->username->strvalue;    if ((pwattr = x99_pw_present(request)) == 0) {	x99_log(X99_LOG_AUTH, "auth: Attribute \"User-Password\" "		"or equivalent required for authentication.");	return RLM_MODULE_INVALID;    }    /* Add a message to the auth log. */    pairadd(&request->packet->vps, pairmake("Module-Failure-Message",					    X99_MODULE_NAME, T_OP_EQ));    pairadd(&request->packet->vps, pairmake("Module-Success-Message",					    X99_MODULE_NAME, T_OP_EQ));    /* Look up the user's info. */    if (x99_get_user_info(inst->pwdfile, username, &user_info) != 0) {#if 0	/* x99_get_user_info() logs a more useful message, this is noisy. */	x99_log(X99_LOG_AUTH, "auth: error reading user [%s] info", username);#endif	return RLM_MODULE_REJECT;    }    /* Retrieve the challenge (from State attribute), unless (fast_sync). */    if (pairfind(request->config_items, PW_X99_FAST) == NULL) {	VALUE_PAIR	*vp;	unsigned char	*state;	time_t		then;	if ((vp = pairfind(request->packet->vps, PW_STATE)) != NULL) {	    int e_length = inst->chal_len;	    /* Extend expected length if state should have been protected. */	    if (user_info.card_id & X99_CF_AM)		e_length += 4 + 4 + 16; /* sflags + time + hmac */	    if (vp->length != e_length) {		x99_log(X99_LOG_AUTH,			"auth: bad state for [%s]: length", username);		return RLM_MODULE_INVALID;	    }	    /* Fast path if we didn't protect the state. */	    if (!(user_info.card_id & X99_CF_AM))		goto good_state;	    /* Verify the state. */	    (void) memset(challenge, 0, sizeof(challenge));	    (void) memcpy(challenge, vp->strvalue, inst->chal_len);	    (void) memcpy(&sflags, vp->strvalue + inst->chal_len, 4);	    (void) memcpy(&then, vp->strvalue + inst->chal_len + 4, 4);	    if (x99_gen_state(NULL,&state,challenge,sflags,then,hmac_key) != 0){		x99_log(X99_LOG_ERR, "auth: failed to generate state");		return RLM_MODULE_FAIL;	    }	    if (memcmp(state, vp->strvalue, vp->length)) {		x99_log(X99_LOG_AUTH,			"auth: bad state for [%s]: hmac", username);		free(state);		return RLM_MODULE_REJECT;	    }	    free(state);	    /* State is valid, but check expiry. */	    then = ntohl(then);	    if (time(NULL) - then > inst->chal_delay) {		x99_log(X99_LOG_AUTH,			"auth: bad state for [%s]: expired", username);		return RLM_MODULE_REJECT;	    }	} else {	    /* This should only happen if the authorize code didn't run. */	    x99_log(X99_LOG_ERR, "auth: bad state for [%s]: missing "		    "(is x99_token listed in radiusd.conf's authorize stanza?)",		    username);	    return RLM_MODULE_FAIL;	}    } /* if (!fast_sync) */good_state:	    /* State is good! */    /* Get the time of the last authentication. */    if (x99_get_last_auth(inst->syncdir, username, &last_auth) != 0) {	x99_log(X99_LOG_ERR,		"auth: unable to get last auth time for [%s]", username);	return RLM_MODULE_FAIL;    }    /* Check failure count. */    fc = x99_check_failcount(username, inst);    if ((fc == FAIL_ERR) || (fc == FAIL_HARD))	return RLM_MODULE_USERLOCK;    /* Some checks for ewindow2_size logic. */    if (fc == FAIL_SOFT) {	if (!inst->ewindow2_size)	/* no auto-resync */	    return RLM_MODULE_USERLOCK;	if (!pairfind(request->config_items, PW_X99_FAST)) {	    /*	     * ewindow2 softfail override requires two consecutive sync	     * responses.  Fail, and record that this was async.	     */	    if (x99_set_last_auth_pos(inst->syncdir, username, 0))		x99_log(X99_LOG_ERR,			"auth: failed to record last auth pos for [%s]",			username);	    return RLM_MODULE_USERLOCK;	}	/* We're now in "ewindow2 mode" ... subsequent logic must test fc */	goto sync_response;    }    /*     * Don't bother to check async response if either     * - the card doesn't support it, or     * - we're doing fast_sync.     */    if (!(user_info.card_id & X99_CF_AM) ||	pairfind(request->config_items, PW_X99_FAST)) {	goto sync_response;    }    /* Perform any site-specific transforms of the challenge. */    if (x99_challenge_transform(username, challenge) != 0) {	x99_log(X99_LOG_ERR,		"auth: challenge transform failed for [%s]", username);	return RLM_MODULE_FAIL;	/* NB: last_auth, failcount not updated. */    }    /* Calculate and test the async response. */    if (x99_response(challenge, e_response, user_info.card_id,		     user_info.keyblock) != 0) {	x99_log(X99_LOG_ERR,		"auth: unable to calculate async response for [%s], "		"to challenge %s", username, challenge);	return RLM_MODULE_FAIL;	/* NB: last_auth, failcount not updated. */    }    DEBUG("rlm_x99_token: auth: [%s], async challenge %s, "	  "expecting response %s", username, challenge, e_response);    if (x99_pw_valid(request, inst, pwattr, e_response, &add_vps)) {	/* Password matches.  Is this allowed? */	if (!inst->allow_async) {	    x99_log(X99_LOG_AUTH,		    "auth: bad async for [%s]: disallowed by config", username);	    rc = RLM_MODULE_REJECT;	    goto return_pw_valid;	    /* NB: last_auth, failcount not updated. */	}	/* Make sure this isn't a replay by forcing a delay. */	if (time(NULL) - last_auth < inst->chal_delay) {	    x99_log(X99_LOG_AUTH,		    "auth: bad async for [%s]: too soon", username);	    rc = RLM_MODULE_REJECT;	    goto return_pw_valid;	    /* NB: last_auth, failcount not updated. */	}	if (user_info.card_id & X99_CF_SM) {	    x99_log(X99_LOG_INFO,		    "auth: [%s] authenticated in async mode", username);	}	rc = RLM_MODULE_OK;	if (ntohl(sflags) & 1) {	    /*	     * Resync the card.  The sync data doesn't mean anything for	     * async-only cards, but we want the side effects of resetting	     * the failcount and the last auth time.  We "fail-out" if we	     * can't do this, because if we can't update the last auth time,	     * we will be open to replay attacks over the lifetime of the	     * State attribute (inst->chal_delay).	     */	    if (x99_get_sync_data(inst->syncdir, username, user_info.card_id,				  1, 0, challenge, user_info.keyblock) != 0) {		x99_log(X99_LOG_ERR, "auth: unable to get sync data "			"e:%d t:%d for [%s] (for resync)", 1, 0, username);		rc = RLM_MODULE_FAIL;	    } else if (x99_set_sync_data(inst->syncdir, username, challenge,					 user_info.keyblock) != 0) {		x99_log(X99_LOG_ERR,			"auth: unable to set sync data for [%s] (for resync)",			username);		rc = RLM_MODULE_FAIL;	    }	} else {	    /* Just update failcount, last_auth, auth_pos. */	    if (x99_reset_failcount(inst->syncdir, username) != 0) {		x99_log(X99_LOG_ERR,			"auth: unable to reset failcount for [%s]", username);		rc = RLM_MODULE_FAIL;	    }	}	goto return_pw_valid;    } /* if (user authenticated async) */sync_response:    /*     * Calculate and test sync responses in the window.     * Note that we always accept a sync response, even     * if a challenge or resync was explicitly requested.     */    if ((user_info.card_id & X99_CF_SM) && inst->allow_sync) {	int start = 0, end = inst->ewindow_size;	/*	 * Tweak start,end for ewindow2_size logic.	 *	 * If user is in softfail, and their last response was correct,	 * start at that response.  We used to start at the NEXT	 * response (the one that will let them in), but the MS Windows	 * "incorrect password" dialog is confusing and users end up	 * reusing the same password twice; this has the effect that	 * ewindow2 doesn't work at all for them (they enter 1,1,2,2,3,3;	 * the 1,2 or 2,3 wouldn't work since the repeat would reset the	 * sequence).	 *	 * The response sequence 6,5,6 won't work (but 6,5,6,7 will).	 * That's OK; we want to optimize for the 6,7 sequence.  The user	 * can't generate the 6,5 sequence from the token anyway.	 *	 * If the user starts at the left edge of the window (0,1,2) they	 * have to enter three responses.  We don't accept the zeroeth	 * response as part of the sequence because we can't differentiate	 * between a correct entry of the zeroeth response (which stores	 * 0 as the last_auth_pos) and an incorrect entry (which "resets"	 * the last_auth_pos to 0).	 */	if (fc == FAIL_SOFT) {	    start = x99_get_last_auth_pos(inst->syncdir, username);	    end = inst->ewindow2_size;	}	challenge[0] = '\0';	/* initialize for x99_get_sync_data() */	for (i = start; i <= end; ++i) {	    /* Get sync challenge and key. */	    if (x99_get_sync_data(inst->syncdir, username, user_info.card_id,				  i, 0, challenge, user_info.keyblock) != 0) {		x99_log(X99_LOG_ERR,			"auth: unable to get sync data e:%d t:%d for [%s]",			i, 0, username);		rc = RLM_MODULE_FAIL;		goto return_pw_valid;		/* NB: last_auth, failcount not updated. */	    }	    /* Calculate sync response. */	    if (x99_response(challenge, e_response, user_info.card_id,			     user_info.keyblock) != 0) {		x99_log(X99_LOG_ERR, "auth: unable to calculate sync response "			"e:%d t:%d for [%s], to challenge %s",			i, 0, username, challenge);		rc = RLM_MODULE_FAIL;		goto return_pw_valid;		/* NB: last_auth, failcount not updated. */	    }	    DEBUG("rlm_x99_token: auth: [%s], sync challenge %d %s, "		  "expecting response %s", username, i, challenge, e_response);	    /* Test user-supplied passcode. */	    if (x99_pw_valid(request, inst, pwattr, e_response, &add_vps)) {		/*		 * Yay!  User authenticated via sync mode.  Resync.		 */		rc = RLM_MODULE_OK;		/*		 * ewindow2_size logic		 */		if (fc == FAIL_SOFT) {		    /* User must authenticate twice in a row, ... */		    if (start && (i == start + 1) &&			/* ... within ewindow2_delay seconds. */			(time(NULL) - last_auth < inst->ewindow2_delay)) {			/* This is the 2nd of two consecutive responses. */			x99_log(X99_LOG_AUTH,				"auth: ewindow2 softfail override for [%s] at "				"window position %d", username, i);		    } else {			/* correct, but not consecutive or not soon enough */			DEBUG("rlm_x99_token: auth: [%s] ewindow2 candidate "			      "at position %i", username, i);			auth_pos = i;			rc = RLM_MODULE_REJECT;			break;		    }		}		/*		 * The same failure/replay issue applies here as in the		 * identical code block in the async section above, with		 * the additional problem that a response can be reused		 * indefinitely!  (until the sync data is updated)		 */		if (x99_get_sync_data(inst->syncdir,username,user_info.card_id,				      1, 0, challenge,user_info.keyblock) != 0){		    x99_log(X99_LOG_ERR, "auth: unable to get sync data "			    "e:%d t:%d for [%s] (for resync)", 1, 0, username);		    rc = RLM_MODULE_FAIL;		} else if (x99_set_sync_data(inst->syncdir, username, challenge,					     user_info.keyblock) != 0) {		    x99_log(X99_LOG_ERR,			    "auth: unable to set sync data for [%s] "			    "(for resync)", username);		    rc = RLM_MODULE_FAIL;		}		goto return_pw_valid;	    } /* if (passcode is valid) */	} /* for (each slot in the window) */    } /* if (card is in sync mode and sync mode allowed) */    /* Both async and sync mode failed. */    if ((fc != FAIL_SOFT) /* !already incremented by x99_check_failcount() */ &&	(x99_incr_failcount(inst->syncdir, username) != 0)) {	x99_log(X99_LOG_ERR,		"auth: unable to increment failure count for user [%s]",		username);    }    if (x99_set_last_auth_pos(inst->syncdir, username, auth_pos)) {	x99_log(X99_LOG_ERR,		"auth: unable to set ewindow2 position for user [%s]",		username);    }    return RLM_MODULE_REJECT;    /* Must exit here after a successful return from x99_pw_valid(). */return_pw_valid:    /* Handle any vps returned from x99_pw_valid(). */    if (rc == RLM_MODULE_OK) {	pairadd(&request->reply->vps, add_vps);    } else {	pairfree(&add_vps);    }    return rc;}/* per-instance destruction */static intx99_token_detach(void *instance){    x99_token_t *inst = (x99_token_t *) instance;    free(inst->pwdfile);    free(inst->syncdir);    free(inst->chal_prompt);    free(inst->chal_req);    free(inst->resync_req);    free(instance);    return 0;}/* per-module destruction */static intx99_token_destroy(void){    (void) memset(hmac_key, 0, sizeof(hmac_key));    (void) close(rnd_fd);    return 0;}/* *	If the module needs to temporarily modify it's instantiation *	data, the type should be changed to RLM_TYPE_THREAD_UNSAFE. *	The server will then take care of ensuring that the module *	is single-threaded. */module_t rlm_x99_token = {	"x99_token",	RLM_TYPE_THREAD_SAFE,		/* type */	x99_token_init,			/* initialization */	x99_token_instantiate,		/* instantiation */	{		x99_token_authenticate,	/* authentication */		x99_token_authorize,	/* authorization */		NULL,			/* preaccounting */		NULL,			/* accounting */		NULL,			/* checksimul */		NULL,			/* pre-proxy */		NULL,			/* post-proxy */		NULL			/* post-auth */	},	x99_token_detach,		/* detach */	x99_token_destroy,		/* destroy */};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -