Fix call to otp_write
[freeradius.git] / src / modules / rlm_otp / otp_pw_valid.c
index 4611b3a..914b6e9 100644 (file)
  *   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>
 
@@ -31,14 +31,10 @@ static const char rcsid[] = "$Id$";
 #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 */
@@ -46,13 +42,15 @@ static int
 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;
   }
 }
 
@@ -83,19 +81,22 @@ otp_pw_valid(REQUEST *request, int pwe, const char *challenge,
   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.
@@ -104,69 +105,75 @@ otp_pw_valid(REQUEST *request, int pwe, const char *challenge,
   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;
@@ -199,8 +206,8 @@ retry:
   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;
@@ -218,15 +225,18 @@ retry:
     (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;
 }
 
@@ -247,13 +257,13 @@ otp_read(otp_fd_t *fdp, char *buf, size_t len)
       } 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;
@@ -274,12 +284,12 @@ otp_write(otp_fd_t *fdp, const char *buf, size_t len)
 
   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;
       }
     }
@@ -306,7 +316,7 @@ otp_connect(const char *path)
   }
   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));
@@ -366,12 +376,15 @@ otp_getfd(const otp_option_t *opt)
   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);
 }