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

📄 otp_pw_valid.c

📁 使用最广泛的radius的linux的源码
💻 C
字号:
/* * $Id: otp_pw_valid.c,v 1.13 2007/05/25 00:44:21 fcusack Exp $ * * Passcode verification function (otpd client) for rlm_otp. * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * * Copyright 2006,2007 TRI-D Systems, Inc. */#include <freeradius-devel/ident.h>RCSID("$Id: otp_pw_valid.c,v 1.13 2007/05/25 00:44:21 fcusack Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/modules.h>#include "extern.h"#include "otp.h"#include "otp_pw_valid.h"#ifdef HAVE_PTHREAD_H#include <pthread.h>#endif#include <sys/un.h>/* transform otpd return codes into rlm return codes */static intotprc2rlmrc(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_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;  }}static otp_fd_t *otp_fd_head;static pthread_mutex_t otp_fd_head_mutex = PTHREAD_MUTEX_INITIALIZER;/* * Test for passcode validity by asking otpd. * * If challenge is supplied, it is used to generate the card response * against which the passcode will be compared.  If challenge is not * supplied, or if the comparison fails, synchronous responses are * generated and tested.  NOTE: for async authentications, sync mode * responses are still considered valid!  (Assuming module configuration * allows sync mode.) * * Returns one of the RLM_MODULE_* codes.  passcode is filled in. * NB: The returned passcode will contain the PIN!  DO NOT LOG! */intotp_pw_valid(REQUEST *request, int pwe, const char *challenge,             const otp_option_t *opt, char passcode[OTP_MAX_PASSCODE_LEN + 1]){  otp_request_t	otp_request;  otp_reply_t	otp_reply;  VALUE_PAIR	*cvp, *rvp;  char		*username = request->username->vp_strvalue;  int		rc;  if (request->username->length > OTP_MAX_USERNAME_LEN) {    (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 = 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]);  /* this is just to quiet Coverity */  if (!rvp || !cvp)    return RLM_MODULE_REJECT;  /*   * Validate available vps based on pwe type.   * Unfortunately (?) otpd must do this also.   */  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", username);      return RLM_MODULE_REJECT;    }    (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",                    username);      return RLM_MODULE_INVALID;    }    if (rvp->length != 17) {      (void) radlog(L_AUTH, "rlm_otp: CHAP response for [%s] wrong size",                    username);      return RLM_MODULE_INVALID;    }    (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",                    username);      return RLM_MODULE_INVALID;    }    if (rvp->length != 50) {      (void) radlog(L_AUTH, "rlm_otp: MS-CHAP response for [%s] wrong size",                    username);      return RLM_MODULE_INVALID;    }    (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",                    username);      return RLM_MODULE_INVALID;    }    if (rvp->length != 50) {      (void) radlog(L_AUTH, "rlm_otp: MS-CHAP2 response for [%s] wrong size",                    username);      return RLM_MODULE_INVALID;    }    (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';  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;  otp_request.challenge_delay = opt->challenge_delay;  otp_request.resync = 1;  rc = otp_verify(opt, &otp_request, &otp_reply);  if (rc == OTP_RC_OK)    (void) strcpy(passcode, otp_reply.passcode);  return otprc2rlmrc(rc);}/* * Verify an otp by asking otpd. * Returns an OTP_* code, or -1 on system failure. * Fills in reply. */static intotp_verify(const otp_option_t *opt,           const otp_request_t *request, otp_reply_t *reply){  otp_fd_t *fdp;  int rc;  int tryagain = 2;retry:  if (!tryagain--)    return -1;  fdp = otp_getfd(opt);  if (!fdp || fdp->fd == -1)    return -1;  if ((rc = otp_write(fdp, (const char *) request, sizeof(*request))) != 0) {    if (rc == EPIPE)      goto retry;	/* otpd disconnect */	/*TODO: pause */    else      return -1;  }  if ((rc = otp_read(fdp, (char *) reply, sizeof(*reply))) != sizeof(*reply)) {    if (rc == 0)      goto retry;	/* otpd disconnect */	/*TODO: pause */    else      return -1;  }  /* validate the reply */  if (reply->version != 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;}/* * Full read with logging, and close on failure. * Returns nread on success, 0 on EOF, -1 on other failures. */static intotp_read(otp_fd_t *fdp, char *buf, size_t len){  ssize_t n;  size_t nread = 0;	/* bytes read into buf */  while (nread < len) {    if ((n = read(fdp->fd, &buf[nread], len - nread)) == -1) {      if (errno == EINTR) {        continue;      } else {        (void) radlog(L_ERR, "rlm_otp: %s: read from otpd: %s",                      __func__, strerror(errno));        otp_putfd(fdp, 1);        return -1;      }    }    if (!n) {      (void) radlog(L_ERR, "rlm_otp: %s: otpd disconnect", __func__);      otp_putfd(fdp, 1);      return 0;    }    nread += n;  } /* while (more to read) */  return nread;}/* * Full write with logging, and close on failure. * Returns 0 on success, errno on failure. */static intotp_write(otp_fd_t *fdp, const char *buf, size_t len){  size_t nleft = len;  ssize_t nwrote;  while (nleft) {    if ((nwrote = write(fdp->fd, &buf[len - nleft], nleft)) == -1) {      if (errno == EINTR || errno == EPIPE) {        continue;      } else {        (void) radlog(L_ERR, "rlm_otp: %s: write to otpd: %s",                      __func__, strerror(errno));        otp_putfd(fdp, 1);        return errno;      }    }    nleft -= nwrote;  }  return 0;}/* connect to otpd and return fd */static intotp_connect(const char *path){  int fd;  struct sockaddr_un sa;  size_t sp_len;		/* sun_path length (strlen) */  /* setup for unix domain socket */  sp_len = strlen(path);  if (sp_len > sizeof(sa.sun_path) - 1) {    (void) radlog(L_ERR, "rlm_otp: %s: rendezvous point name too long",                  __func__);    return -1;  }  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 -1;  }  if (connect(fd, (struct sockaddr *) &sa,              sizeof(sa.sun_family) + sp_len) == -1) {    (void) radlog(L_ERR, "rlm_otp: %s: connect(%s): %s",                  __func__, path, strerror(errno));    (void) close(fd);    return -1;  }  return fd;}/* * Retrieve an fd (from pool) to use for otpd connection. * It'd be simpler to use TLS but FR can have lots of threads * and we don't want to waste fd's that way. * We can't have a global fd because we'd then be pipelining * requests to otpd and we have no way to demultiplex * the responses. */static otp_fd_t *otp_getfd(const otp_option_t *opt){  int rc;  otp_fd_t *fdp;  /* walk the connection pool looking for an available fd */  for (fdp = otp_fd_head; fdp; fdp = fdp->next) {    rc = otp_pthread_mutex_trylock(&fdp->mutex);    if (!rc)      if (!strcmp(fdp->path, opt->otpd_rp))	/* could just use == */        break;  }  if (!fdp) {    /* no fd was available, add a new one */    fdp = rad_malloc(sizeof(*fdp));    otp_pthread_mutex_init(&fdp->mutex, NULL);    otp_pthread_mutex_lock(&fdp->mutex);    /* insert new fd at head */    otp_pthread_mutex_lock(&otp_fd_head_mutex);    fdp->next = otp_fd_head;    otp_fd_head = fdp;    otp_pthread_mutex_unlock(&otp_fd_head_mutex);    /* initialize */    fdp->path = opt->otpd_rp;    fdp->fd = -1;  }  /* establish connection */  if (fdp->fd == -1)    fdp->fd = otp_connect(fdp->path);  return fdp;}/* release fd, and optionally disconnect from otpd */static voidotp_putfd(otp_fd_t *fdp, int disconnect){  if (disconnect) {    (void) close(fdp->fd);    fdp->fd = -1;  }  /* make connection available to another thread */  otp_pthread_mutex_unlock(&fdp->mutex);}

⌨️ 快捷键说明

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