* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*
- * Copyright 2006 TRI-D Systems, Inc.
+ * Copyright 2006,2007 TRI-D Systems, Inc.
*/
-static const char rcsid[] = "$Id$";
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
-#include <freeradius-devel/autoconf.h>
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
#include "otp.h"
#include "otp_pw_valid.h"
-#include <errno.h>
+#ifdef HAVE_PTHREAD_H
#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#endif
#include <sys/un.h>
-#include <unistd.h>
/* transform otpd return codes into rlm return codes */
otprc2rlmrc(int rc)
{
switch (rc) {
- case OTP_RC_OK: return RLM_MODULE_OK;
- case OTP_RC_USER_UNKNOWN: return RLM_MODULE_REJECT;
- case OTP_RC_AUTHINFO_UNAVAIL: return RLM_MODULE_REJECT;
- case OTP_RC_AUTH_ERR: return RLM_MODULE_REJECT;
- case OTP_RC_MAXTRIES: return RLM_MODULE_USERLOCK;
- case OTP_RC_SERVICE_ERR: return RLM_MODULE_FAIL;
- default: return RLM_MODULE_FAIL;
+ case OTP_RC_OK: return RLM_MODULE_OK;
+ case OTP_RC_USER_UNKNOWN: return RLM_MODULE_REJECT;
+ case OTP_RC_AUTHINFO_UNAVAIL: return RLM_MODULE_REJECT;
+ case OTP_RC_AUTH_ERR: return RLM_MODULE_REJECT;
+ case OTP_RC_MAXTRIES: return RLM_MODULE_USERLOCK;
+ case OTP_RC_NEXTPASSCODE: return RLM_MODULE_USERLOCK;
+ case OTP_RC_IPIN: return RLM_MODULE_REJECT;
+ case OTP_RC_SERVICE_ERR: return RLM_MODULE_FAIL;
+ default: return RLM_MODULE_FAIL;
}
}
int rc;
if (request->username->length > OTP_MAX_USERNAME_LEN) {
- (void) radlog(L_AUTH, "rlm_otp: username [%s] too long\n", username);
+ (void) radlog(L_AUTH, "rlm_otp: username [%s] too long", username);
return RLM_MODULE_REJECT;
}
/* we already know challenge is short enough */
- otp_request.version = 1;
+ otp_request.version = 2;
(void) strcpy(otp_request.username, username);
(void) strcpy(otp_request.challenge, challenge);
otp_request.pwe.pwe = pwe;
/* otp_pwe_present() (done by caller) guarantees that both of these exist */
- cvp = pairfind(request->packet->vps, pwattr[pwe - 1]);
- rvp = pairfind(request->packet->vps, pwattr[pwe]);
+ cvp = pairfind(request->packet->vps, pwattr[pwe - 1]->attr, pwattr[pwe - 1]->vendor);
+ rvp = pairfind(request->packet->vps, pwattr[pwe]->attr, pwattr[pwe]->vendor);
+ /* this is just to quiet Coverity */
+ if (!rvp || !cvp)
+ return RLM_MODULE_REJECT;
/*
* Validate available vps based on pwe type.
switch (otp_request.pwe.pwe) {
case PWE_PAP:
if (rvp->length > OTP_MAX_PASSCODE_LEN) {
- (void) radlog(L_AUTH, "rlm_otp: passcode for [%s] too long\n",
- username);
+ (void) radlog(L_AUTH, "rlm_otp: passcode for [%s] too long", username);
return RLM_MODULE_REJECT;
}
- (void) strcpy(otp_request.pwe.passcode, rvp->vp_strvalue);
+ (void) strcpy(otp_request.pwe.u.pap.passcode, rvp->vp_strvalue);
break;
case PWE_CHAP:
if (cvp->length > 16) {
- (void) radlog(L_AUTH, "rlm_otp: CHAP challenge for [%s] too long\n",
+ (void) radlog(L_AUTH, "rlm_otp: CHAP challenge for [%s] too long",
username);
return RLM_MODULE_INVALID;
}
if (rvp->length != 17) {
- (void) radlog(L_AUTH, "rlm_otp: CHAP response for [%s] wrong size\n",
+ (void) radlog(L_AUTH, "rlm_otp: CHAP response for [%s] wrong size",
username);
return RLM_MODULE_INVALID;
}
- (void) memcpy(otp_request.pwe.challenge, cvp->vp_strvalue, cvp->length);
- otp_request.pwe.clen = cvp->length;
- (void) memcpy(otp_request.pwe.response, rvp->vp_strvalue, rvp->length);
- otp_request.pwe.rlen = rvp->length;
+ (void) memcpy(otp_request.pwe.u.chap.challenge, cvp->vp_strvalue,
+ cvp->length);
+ otp_request.pwe.u.chap.clen = cvp->length;
+ (void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_strvalue,
+ rvp->length);
+ otp_request.pwe.u.chap.rlen = rvp->length;
break;
case PWE_MSCHAP:
if (cvp->length != 8) {
- (void) radlog(L_AUTH, "rlm_otp: MS-CHAP challenge for [%s] wrong size\n",
+ (void) radlog(L_AUTH, "rlm_otp: MS-CHAP challenge for [%s] wrong size",
username);
return RLM_MODULE_INVALID;
}
if (rvp->length != 50) {
- (void) radlog(L_AUTH, "rlm_otp: MS-CHAP response for [%s] wrong size\n",
+ (void) radlog(L_AUTH, "rlm_otp: MS-CHAP response for [%s] wrong size",
username);
return RLM_MODULE_INVALID;
}
- (void) memcpy(otp_request.pwe.challenge, cvp->vp_strvalue, cvp->length);
- otp_request.pwe.clen = cvp->length;
- (void) memcpy(otp_request.pwe.response, rvp->vp_strvalue, rvp->length);
- otp_request.pwe.rlen = rvp->length;
+ (void) memcpy(otp_request.pwe.u.chap.challenge, cvp->vp_strvalue,
+ cvp->length);
+ otp_request.pwe.u.chap.clen = cvp->length;
+ (void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_strvalue,
+ rvp->length);
+ otp_request.pwe.u.chap.rlen = rvp->length;
break;
case PWE_MSCHAP2:
if (cvp->length != 16) {
- (void) radlog(L_AUTH, "rlm_otp: MS-CHAP2 challenge for [%s] wrong size\n",
+ (void) radlog(L_AUTH, "rlm_otp: MS-CHAP2 challenge for [%s] wrong size",
username);
return RLM_MODULE_INVALID;
}
if (rvp->length != 50) {
- (void) radlog(L_AUTH, "rlm_otp: MS-CHAP2 response for [%s] wrong size\n",
+ (void) radlog(L_AUTH, "rlm_otp: MS-CHAP2 response for [%s] wrong size",
username);
return RLM_MODULE_INVALID;
}
- (void) memcpy(otp_request.pwe.challenge, cvp->vp_strvalue, cvp->length);
- otp_request.pwe.clen = cvp->length;
- (void) memcpy(otp_request.pwe.response, rvp->vp_strvalue, rvp->length);
- otp_request.pwe.rlen = rvp->length;
+ (void) memcpy(otp_request.pwe.u.chap.challenge, cvp->vp_strvalue,
+ cvp->length);
+ otp_request.pwe.u.chap.clen = cvp->length;
+ (void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_strvalue,
+ rvp->length);
+ otp_request.pwe.u.chap.rlen = rvp->length;
break;
} /* switch (otp_request.pwe.pwe) */
/* last byte must also be a terminator so otpd can verify length easily */
otp_request.username[OTP_MAX_USERNAME_LEN] = '\0';
otp_request.challenge[OTP_MAX_CHALLENGE_LEN] = '\0';
- otp_request.pwe.passcode[OTP_MAX_PASSCODE_LEN] = '\0';
+ if (otp_request.pwe.pwe == PWE_PAP)
+ otp_request.pwe.u.pap.passcode[OTP_MAX_PASSCODE_LEN] = '\0';
otp_request.allow_sync = opt->allow_sync;
otp_request.allow_async = opt->allow_async;
if (!fdp || fdp->fd == -1)
return -1;
- if ((rc = otp_write(fdp, (const char *) request, sizeof(*request))) != 0) {
- if (rc == EPIPE)
+ if ((rc = otp_write(fdp, (const char *) request, sizeof(*request))) != sizeof(*request)) {
+ if (rc == 0)
goto retry; /* otpd disconnect */ /*TODO: pause */
else
return -1;
(void) radlog(L_AUTH, "rlm_otp: otpd reply for [%s] invalid "
"(version %d != 1)",
request->username, reply->version);
+ otp_putfd(fdp, 1);
return -1;
}
if (reply->passcode[OTP_MAX_PASSCODE_LEN] != '\0') {
(void) radlog(L_AUTH, "rlm_otp: otpd reply for [%s] invalid (passcode)",
request->username);
+ otp_putfd(fdp, 1);
return -1;
}
+ otp_putfd(fdp, 0);
return reply->rc;
}
} else {
(void) radlog(L_ERR, "rlm_otp: %s: read from otpd: %s",
__func__, strerror(errno));
- otp_putfd(fdp);
+ otp_putfd(fdp, 1);
return -1;
}
}
if (!n) {
(void) radlog(L_ERR, "rlm_otp: %s: otpd disconnect", __func__);
- otp_putfd(fdp);
+ otp_putfd(fdp, 1);
return 0;
}
nread += n;
while (nleft) {
if ((nwrote = write(fdp->fd, &buf[len - nleft], nleft)) == -1) {
- if (errno == EINTR || errno == EPIPE) {
+ if (errno == EINTR) {
continue;
} else {
(void) radlog(L_ERR, "rlm_otp: %s: write to otpd: %s",
__func__, strerror(errno));
- otp_putfd(fdp);
+ otp_putfd(fdp, 1);
return errno;
}
}
}
sa.sun_family = AF_UNIX;
(void) strcpy(sa.sun_path, path);
-
+
/* connect to otpd */
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
(void) radlog(L_ERR, "rlm_otp: %s: socket: %s", __func__, strerror(errno));
return fdp;
}
-/* disconnect from otpd */
+/* release fd, and optionally disconnect from otpd */
static void
-otp_putfd(otp_fd_t *fdp)
+otp_putfd(otp_fd_t *fdp, int disconnect)
{
- (void) close(fdp->fd);
- fdp->fd = -1;
+ if (disconnect) {
+ (void) close(fdp->fd);
+ fdp->fd = -1;
+ }
+
/* make connection available to another thread */
otp_pthread_mutex_unlock(&fdp->mutex);
}