/** * Check credentials */ OPENVPN_EXPORT int openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) { /* get username/password from envp string array */ const char *username = get_env ("username", envp); const char *password = get_env ("password", envp); const char *ip = get_env ("untrusted_ip", envp); const char *port = get_env ("untrusted_port", envp); const int ulen = strlen(username); const int pwlen = strlen(password); if ( ulen > MAXWORDLEN || ulen == 0 || pwlen > MAXWORDLEN || pwlen == 0) { return OPENVPN_PLUGIN_FUNC_ERROR; } /* check entered username/password against what we require */ int ok = otp_verify(username, password); if (ok == 1) { LOG("OTP-AUTH: authentication succeeded for username '%s', remote %s:%s\n", username, ip, port); return OPENVPN_PLUGIN_FUNC_SUCCESS; } else { LOG("OTP-AUTH: authentication failed for username '%s', remote %s:%s\n", username, ip, port); return OPENVPN_PLUGIN_FUNC_ERROR; } }
static int check_password(struct passwd *pwd, const char *password) { if(pwd->pw_passwd == NULL) return 1; if(pwd->pw_passwd[0] == '\0'){ #ifdef ALLOW_NULL_PASSWORD return password[0] != '\0'; #else return 1; #endif } if(strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) == 0) return 0; #ifdef KRB5 if(krb5_verify(pwd, password) == 0) { auth = AUTH_KRB5; return 0; } #endif #ifdef OTP if (otp_verify (pwd, password) == 0) { auth = AUTH_OTP; return 0; } #endif return 1; }
/* * 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! */ int otp_pw_valid(REQUEST *request, int pwe, char const *challenge, rlm_otp_t const *opt, char passcode[OTP_MAX_PASSCODE_LEN + 1]) { otp_request_t otp_request; otp_reply_t otp_reply; VALUE_PAIR *cvp, *rvp; char const *username = request->username->vp_strvalue; int rc; if (request->username->length > OTP_MAX_USERNAME_LEN) { AUTH("rlm_otp: username [%s] too long", username); return RLM_MODULE_REJECT; } /* we already know challenge is short enough */ otp_request.version = 2; strcpy(otp_request.username, username); 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]->attr, pwattr[pwe - 1]->vendor, TAG_ANY); rvp = pairfind(request->packet->vps, pwattr[pwe]->attr, pwattr[pwe]->vendor, TAG_ANY); /* 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 >= sizeof(otp_request.pwe.u.pap.passcode)) { 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) { AUTH("rlm_otp: CHAP challenge for [%s] " "too long", username); return RLM_MODULE_INVALID; } if (rvp->length != 17) { AUTH("rlm_otp: CHAP response for [%s] " "wrong size", username); return RLM_MODULE_INVALID; } (void) memcpy(otp_request.pwe.u.chap.challenge, cvp->vp_octets, cvp->length); otp_request.pwe.u.chap.clen = cvp->length; (void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_octets, rvp->length); otp_request.pwe.u.chap.rlen = rvp->length; break; case PWE_MSCHAP: if (cvp->length != 8) { AUTH("rlm_otp: MS-CHAP challenge for " "[%s] wrong size", username); return RLM_MODULE_INVALID; } if (rvp->length != 50) { 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_octets, cvp->length); otp_request.pwe.u.chap.clen = cvp->length; (void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_octets, rvp->length); otp_request.pwe.u.chap.rlen = rvp->length; break; case PWE_MSCHAP2: if (cvp->length != 16) { AUTH("rlm_otp: MS-CHAP2 challenge for " "[%s] wrong size", username); return RLM_MODULE_INVALID; } if (rvp->length != 50) { 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_octets, cvp->length); otp_request.pwe.u.chap.clen = cvp->length; (void) memcpy(otp_request.pwe.u.chap.response, rvp->vp_octets, 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); }