-rw-r--r-- | acinclude.m4 | 6 | ||||
-rw-r--r-- | configure.ac | 41 | ||||
-rw-r--r-- | lib/consumer.cc | 53 |
3 files changed, 88 insertions, 12 deletions
diff --git a/acinclude.m4 b/acinclude.m4 index 349d3cf..532f978 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -63,50 +63,50 @@ AC_DEFUN([AC_WITH_DOXYGEN],[ dnl AC_WITH_DOT([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) dnl Outputs: dnl AC_SUBST: DOT HAVE_DOT dnl AM_CONDITIONAL: HAVE_DOT AC_DEFUN([AC_WITH_DOT],[ HAVE_DOT="no" AC_PATH_PROG([DOT],[dot],[false]) if test "${DOT}" = "false" ; then ifelse([$2], , :, [$2]) else HAVE_DOT="yes" AC_SUBST([DOT]) $1 fi AC_SUBST([HAVE_DOT]) AM_CONDITIONAL([HAVE_DOT],[test "${HAVE_DOT}" = "yes"]) ]) dnl AC_WITH_PCRE([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) dnl Outputs: dnl AC_SUBST: PCRE_CONFIG PCRE_PREFIX PCRE_EXEC_PREFIX dnl PCRE_VERSION PCRE_CFLAGS PCRE_LIBS dnl PCRE_LIBS_POSIX PCRE_CFLAGS_POSIX -dnl AM_CONDITIONAL: HAVE_PCRE dnl AC_DEFINE: HAVE_PCRE PCRE_VERSION +dnl env: HAVE_PCRE=yes|no AC_DEFUN([AC_WITH_PCRE],[ HAVE_PCRE="no" PCRE_CONFIG="" PCRE_PREFIX="" PCRE_EXEC_PREFIX="" PCRE_VERSION="" PCRE_CFLAGS="" PCRE_LIBS="" PCRE_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin" test -z "$WANT_PCRE" && WANT_PCRE="" AC_ARG_WITH([pcre], AC_HELP_STRING([--with-pcre=location],[Look for pcre in specified locations]), [ if test "${withval}" = "no" ; then WANT_PCRE="no" else if test -x "${withval}" ; then PCRE_CONFIG="${withval}" elif test -x "${withval}/pcre-config" ; then PCRE_CONFIG="${withval}/pcre-config" elif test -x "${withval}/bin/pcre-config" ; then PCRE_CONFIG="${withval}/bin/pcre-config" fi fi @@ -121,57 +121,56 @@ AC_DEFUN([AC_WITH_PCRE],[ ifelse([$2], , :, [$2]) else HAVE_PCRE="yes" PCRE_PREFIX="`${PCRE_CONFIG} --prefix`" PCRE_EXEC_PREFIX="`${PCRE_CONFIG} --exec-prefix`" PCRE_VERSION="`${PCRE_CONFIG} --version`" PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`" PCRE_LIBS="`${PCRE_CONFIG} --libs`" PCRE_CFLAGS_POSIX="`${PCRE_CONFIG} --cflags-posix`" PCRE_LIBS_POSIX="`${PCRE_CONFIG} --libs-posix`" AC_SUBST([PCRE_CONFIG]) AC_SUBST([PCRE_PREFIX]) AC_SUBST([PCRE_EXEC_PREFIX]) AC_SUBST([PCRE_VERSION]) AC_SUBST([PCRE_CFLAGS]) AC_SUBST([PCRE_LIBS]) AC_SUBST([PCRE_CFLAGS_POSIX]) AC_SUBST([PCRE_LIBS_POSIX]) AC_DEFINE([HAVE_PCRE],,[pcre support]) AC_DEFINE_UNQUOTED([PCRE_VERSION],["${PCRE_VERSION}"],[pcre version]) $1 fi fi fi - AM_CONDITIONAL([HAVE_PCRE],[test "${HAVE_PCRE}" = "yes"]) ]) dnl AC_WITH_PCREPP([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) dnl Outputs: dnl AC_SUBST: PCREPP_CONFIG PCREPP_PREFIX PCREPP_EXEC_PREFIX dnl PCREPP_VERSION PCREPP_CFLAGS PCREPP_LIBS -dnl AM_CONDITIONAL: HAVE_PCREPP dnl AC_DEFINE: HAVE_PCREPP PCREPP_VERSION +dnl env: HAVE_PCREPP=yes|no AC_DEFUN([AC_WITH_PCREPP],[ HAVE_PCREPP="no" PCREPP_CONFIG="" PCREPP_PREFIX="" PCREPP_EXEC_PREFIX="" PCREPP_VERSION="" PCREPP_CFLAGS="" PCREPP_LIBS="" PCREPP_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin" test -z "$WANT_PCREPP" && WANT_PCREPP="" AC_ARG_WITH([pcrepp], AC_HELP_STRING([--with-pcrepp=location],[Look for pcre++ in specified locations]), [ if test "${withval}" = "no" ; then WANT_PCREPP="no" else if test -x "${withval}" ; then PCREPP_CONFIG="${withval}" elif test -x "${withval}/pcre++-config" ; then PCREPP_CONFIG="${withval}/pcre++-config" elif test -x "${withval}/bin/pcre++-config" ; then PCREPP_CONFIG="${withval}/bin/pcre++-config" fi fi @@ -186,28 +185,27 @@ AC_DEFUN([AC_WITH_PCREPP],[ if test -z "${PCREPP_CONFIG}" ; then AC_PATH_PROG([PCREPP_CONFIG],[pcre++-config],false,[${PCREPP_LOCATIONS}]) if test "${PCREPP_CONFIG}" = "false" ; then ifelse([$2], , :, [$2]) else HAVE_PCREPP="yes" PCREPP_PREFIX="`${PCREPP_CONFIG} --prefix`" PCREPP_EXEC_PREFIX="`${PCREPP_CONFIG} --exec-prefix`" PCREPP_VERSION="`${PCREPP_CONFIG} --version`" PCREPP_CFLAGS="`${PCREPP_CONFIG} --cflags` ${PCRE_CFLAGS}" PCREPP_LIBS="`${PCREPP_CONFIG} --libs` ${PCRE_LIBS}" AC_SUBST([PCREPP_CONFIG]) AC_SUBST([PCREPP_PREFIX]) AC_SUBST([PCREPP_EXEC_PREFIX]) AC_SUBST([PCREPP_VERSION]) AC_SUBST([PCREPP_CFLAGS]) AC_SUBST([PCREPP_LIBS]) AC_DEFINE([HAVE_PCREPP],,[pcre++ support]) AC_DEFINE_UNQUOTED([PCREPP_VERSION],["${PCREPP_VERSION}"],[pcre++ version]) $1 fi fi fi fi - AM_CONDITIONAL([HAVE_PCREPP],[test "${HAVE_PCREPP}" = "yes"]) ]) m4_include([acinclude.d/libcurl.m4]) diff --git a/configure.ac b/configure.ac index 2094273..00c6bc4 100644 --- a/configure.ac +++ b/configure.ac @@ -31,56 +31,93 @@ if test "${WANT_KONFORKA}" = "yes" ; then AC_DEFINE([HAVE_KONFORKA],,[defined in presence of konforka library]) AC_DEFINE([OPKELE_HAVE_KONFORKA],,[defined in presence of konforka library]) AC_SUBST([KONFORKA_KONFORKA],[konforka]) ],[true]) fi WANT_DOXYGEN="yes" AC_ARG_ENABLE([doxygen], AC_HELP_STRING([--disable-doxygen],[do not generate documentation]), [ test "${enableval}" = "no" && WANT_DOXYGEN="no" ] ) if test "${WANT_DOXYGEN}" = "yes" ; then AC_WITH_DOXYGEN AC_WITH_DOT else AM_CONDITIONAL([HAVE_DOXYGEN],[false]) AM_CONDITIONAL([HAVE_DOT],[false]) fi LIBCURL_CHECK_CONFIG(,,,[ AC_MSG_ERROR([no required libcurl library. get one from http://curl.haxx.se/]) ]) + +want_pcre_impl="" +AC_ARG_WITH([pcre-bindings], + AC_HELP_STRING([--with-pcre-bindings=(pcrepp|none|libpcrecpp)],[Specify which pcre c++ bindings to use. 'pcrepp' stands for quite sensible library, found at http://www.daemon.de/PCRE/, 'libcrecpp' makes use of crappy bindings by google and 'none' disables internal implementation of OP discovery]), + [ + case "$withval" in + pcrepp) want_pcre_impl="pcrepp" ;; + libpcrecpp) want_pcre_impl="libpcrecpp" ;; + none) want_pcre_impl="none";; + *) AC_MSG_ERROR([I'm not sure I understand what do you want for a pcre c++ bindings]) ;; + esac + ] +) + +found_pcre_impl="" + +if test -z "$want_pcre_impl" -o "$want_pcre_impl" = "pcrepp" ; then AC_WITH_PCRE([ - AC_WITH_PCREPP(,[ - AC_MSG_ERROR([no pcre++ library found. get one at http://www.daemon.de/PCRE]) + AC_WITH_PCREPP([ + found_pcre_impl=pcrepp ]) ],[ AC_MSG_ERROR([no pcre library found. get one at http://www.pcre.org/]) ] ) + test "$want_pcre_impl,$found_pcre_impl" = "pcrepp," && AC_MSG_ERROR([no pcre++ library found. get one at http://www.daemon.de/PCRE]) +fi + +if test "$found_pcre_impl,$want_pcre_impl" = "," -o "$want_pcre_impl" = "libpcrecpp" ; then + test -z "$want_pcre_impl" || AC_MSG_NOTICE([You want to use crappy libpcre c++ bindings]) + PKG_CHECK_MODULES([LIBPCRECPP],[libpcrecpp],[ + found_pcre_impl=libpcrecpp + CXXFLAGS="$CXXFLAGS $LIBPCRECPP_CFLAGS" + LIBS="$LIBS $LIBPCRECPP_LIBS" + ],[ + test -z "$want_pcre_impl" || AC_MSG_ERROR([no libpcre c++ bindings found. why would you want it if you don't have it installed?]) + ] + ) +fi +test "$want_pcre_impl,$found_pcre_impl" = "," && AC_MSG_ERROR([no pcre c++ bindings found, use --with-pcre-bindings=none to disable code that makes use of it]) + +case "$found_pcre_impl" in + pcrepp) AC_DEFINE([USE_PCREPP],,[defined if pcre++ is to be used]) ;; + libpcrecpp) AC_DEFINE([USE_LIBPCRECPP],,[defined if crappy google bindings are to be used]) ;; +esac curl_ssl_verify_host="true" AC_ARG_ENABLE([ssl-verify-host], AC_HELP_STRING([--disable-ssl-verify-host],[disable cURL cert/host relationships verification]), [ test "${enableval}" = "no" && curl_ssl_verify_host="false" ] ) ${curl_ssl_verify_host} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYHOST],,[defined if cURL is not to verify cert/host]) curl_ssl_verify_peer="true" AC_ARG_ENABLE([ssl-verify-peer], AC_HELP_STRING([--disable-ssl-verify-peer],[disable cURL cert validity verification]), [ test "${enableval}" = "no" && curl_ssl_verify_peer="false" ] ) ${curl_ssl_verify_peer} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYPEER],,[defined if cURL is not to verify cert validity]) postels_law=true AC_ARG_ENABLE([postels-law], AC_HELP_STRING([--disable-postels-law],[Be strict, do not adhere to Postel's Law ("be conservative in what you do, be liberal in what you accept from others", RFC 793)]), [ test "${enableval}" = "no" && postels_law=false ] ) $postels_law && AC_DEFINE([POSTELS_LAW],,[defined if we want to adhere to Postel's Law]) AC_DEFINE_UNQUOTED([OPKELE_SRC_DIR],["$PWD"],[source directory]) diff --git a/lib/consumer.cc b/lib/consumer.cc index 8f66688..299b3bc 100644 --- a/lib/consumer.cc +++ b/lib/consumer.cc @@ -1,39 +1,46 @@ #include <algorithm> #include <cassert> #include <opkele/util.h> #include <opkele/exception.h> #include <opkele/data.h> #include <opkele/consumer.h> #include <openssl/sha.h> #include <openssl/hmac.h> #include <curl/curl.h> -#include <pcre++.h> #include <iostream> #include "config.h" +#if defined(USE_LIBPCRECPP) +# include <pcrecpp.h> +#elif defined(USE_PCREPP) +# include <pcre++.h> +#else + /* internal implementation won't be built */ +#endif + namespace opkele { using namespace std; class curl_t { public: CURL *_c; curl_t() : _c(0) { } curl_t(CURL *c) : _c(c) { } ~curl_t() throw() { if(_c) curl_easy_cleanup(_c); } curl_t& operator=(CURL *c) { if(_c) curl_easy_cleanup(_c); _c=c; return *this; } operator const CURL*(void) const { return _c; } operator CURL*(void) { return _c; } }; static CURLcode curl_misc_sets(CURL* c) { CURLcode r; (r=curl_easy_setopt(c,CURLOPT_FOLLOWLOCATION,1)) || (r=curl_easy_setopt(c,CURLOPT_MAXREDIRS,5)) || (r=curl_easy_setopt(c,CURLOPT_DNS_CACHE_TIMEOUT,120)) || (r=curl_easy_setopt(c,CURLOPT_DNS_USE_GLOBAL_CACHE,1)) || (r=curl_easy_setopt(c,CURLOPT_USERAGENT,PACKAGE_NAME"/"PACKAGE_VERSION)) @@ -240,93 +247,127 @@ namespace opkele { || (r=curl_easy_setopt(curl,CURLOPT_POST,1)) || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDS,request.data())) || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,request.length())) || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring)) || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&response)) ; if(r) throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r); if(r=curl_easy_perform(curl)) throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r); params_t pp; pp.parse_keyvalues(response); if(pp.has_param("invalidate_handle")) invalidate_assoc(server,pp.get_param("invalidate_handle")); if(pp.has_param("is_valid")) { if(pp.get_param("is_valid")=="true") return; }else if(pp.has_param("lifetime")) { if(util::string_to_long(pp.get_param("lifetime"))) return; } throw failed_check_authentication(OPKELE_CP_ "failed to verify response"); } void consumer_t::retrieve_links(const string& url,string& server,string& delegate) { +#if defined(USE_LIBPCRECPP) || defined(USE_PCREPP) server.erase(); delegate.erase(); curl_t curl = curl_easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to curl_easy_init()"); string html; CURLcode r; (r=curl_misc_sets(curl)) || (r=curl_easy_setopt(curl,CURLOPT_URL,url.c_str())) || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring)) || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&html)) ; if(r) throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r); r = curl_easy_perform(curl); if(r && r!=CURLE_WRITE_ERROR) throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r); - pcrepp::Pcre bre("<body\\b",PCRE_CASELESS); // strip out everything past body + static const char *re_hdre = "<head[^>]*>", + *re_lre = "<link\\b([^>]+)>", + *re_rre = "\\brel=['\"]([^'\"]+)['\"]", + *re_hre = "\\bhref=['\"]([^'\"]+)['\"]"; +#if defined(USE_LIBPCRECPP) + static pcrecpp::RE_Options ro(PCRE_CASELESS|PCRE_DOTALL); + static pcrecpp::RE + bre("<body\\b.*",ro), hdre(re_hdre,ro), + lre(re_lre,ro), rre(re_rre), hre(re_hre,ro); + bre.Replace("",&html); + pcrecpp::StringPiece hpiece(html); + if(!hdre.FindAndConsume(&hpiece)) + throw bad_input(OPKELE_CP_ "failed to find head"); + string attrs; + while(lre.FindAndConsume(&hpiece,&attrs)) { + pcrecpp::StringPiece rel, href; + if(!(rre.PartialMatch(attrs,&rel) && hre.PartialMatch(attrs,&href))) + continue; + if(rel=="openid.server") { + href.CopyToString(&server); + if(!delegate.empty()) + break; + }else if(rel=="openid.delegate") { + href.CopyToString(&delegate); + if(!server.empty()) + break; + } + } +#elif defined(USE_PCREPP) + pcrepp::Pcre bre("<body\\b",PCRE_CASELESS); if(bre.search(html)) html.erase(bre.get_match_start()); - pcrepp::Pcre hdre("<head[^>]*>",PCRE_CASELESS); + pcrepp::Pcre hdre(re_hdre,PCRE_CASELESS); if(!hdre.search(html)) throw bad_input(OPKELE_CP_ "failed to find head"); html.erase(0,hdre.get_match_end()+1); - pcrepp::Pcre lre("<link\\b([^>]+)>",PCRE_CASELESS), - rre("\\brel=['\"]([^'\"]+)['\"]",PCRE_CASELESS), - hre("\\bhref=['\"]([^'\"]+)['\"]",PCRE_CASELESS); + pcrepp::Pcre lre(re_lre,PCRE_CASELESS), rre(re_rre,PCRE_CASELESS), hre(re_hre,PCRE_CASELESS); while(lre.search(html)) { string attrs = lre[0]; html.erase(0,lre.get_match_end()+1); if(!(rre.search(attrs)&&hre.search(attrs))) continue; if(rre[0]=="openid.server") { server = hre[0]; if(!delegate.empty()) break; }else if(rre[0]=="openid.delegate") { delegate = hre[0]; if(!server.empty()) break; } } +#else + #error "I must have gone crazy" +#endif if(server.empty()) throw failed_assertion(OPKELE_CP_ "The location has no openid.server declaration"); +#else /* none of the RE bindings enabled */ + throw not_implemented(OPKELE_CP_ "No internal implementation of retrieve_links were provided at compile-time"); +#endif } assoc_t consumer_t::find_assoc(const string& server) { throw failed_lookup(OPKELE_CP_ "no find_assoc() provided"); } string consumer_t::normalize(const string& url) { string rv = url; // strip leading and trailing spaces string::size_type i = rv.find_first_not_of(" \t\r\n"); if(i==string::npos) throw bad_input(OPKELE_CP_ "empty URL"); if(i) rv.erase(0,i); i = rv.find_last_not_of(" \t\r\n"); assert(i!=string::npos); if(i<(rv.length()-1)) rv.erase(i+1); // add missing http:// i = rv.find("://"); if(i==string::npos) { // primitive. but do we need more? rv.insert(0,"http://"); i = sizeof("http://")-1; }else{ |