Example for authentication integration -------------------------------------- Adding LinOTP authentication to your existing source code is quite simple. You will need to use the API as described in section :ref:`validate-controller`. Both examples use cURL [#curl]_ to talk to the LinOTP server. C integration ~~~~~~~~~~~~~ For usual binary programs written in C, you could take a look at the pam_linotp implementation (file libpam-linotp/src/pam_linotp.c) which can be found here: http://linotp.org/download/LinOTP-2.x-CE.tar.gz. .. highlight:: c This could look like this to create the URL, that needs to be sent:: char * createUrl(CURL *curl_handle, const char * validateurl, const char * realm, const char * resConf, const char * user, const char * password) { char * url = NULL; int size = 300; int nchars = 0; // escape user and password char *escPassword; char *escUser; escPassword = curl_easy_escape(curl_handle, password, 0); escUser = curl_easy_escape(curl_handle, user, 0); char *escRealm = curl_easy_escape(curl_handle, realm, 0); char *escResConf = curl_easy_escape(curl_handle, resConf, 0); if (escPassword == NULL || escUser == NULL) { log_error("ERROR: failed to escape user or password"); goto cleanup; } url = (char*) malloc (size); if (url == NULL) { log_error("ERROR: could allocate size for url"); goto cleanup; } // allocate the memory for url string memset(url,'\0',size); nchars = snprintf( url, size-1, "%s?user=%s&pass=%s&realm=%s&resConf=%s", validateurl, escUser, escPassword, escRealm, escResConf ); if (nchars >= size-1) { // reallocate size = nchars +1; url = (char*) myrealloc (url, size); if (url == NULL) { log_error("ERROR: failed to alloc space for url + user and password"); goto cleanup; } memset(url,'\0',size); snprintf(url, size-1, "%s?user=%s&pass=%s&realm=%s&resConf=%s", validateurl, escUser, escPassword, escRealm, escResConf ); } cleanup: return url; } The authentication itself could look like this:: int linotp_auth(const char *user, const char *password, const char *validateurl, const char *realm, const char *resConf, int nosslhostnameverify, int nosslcertverify, int debug) { CURL *curl_handle = NULL; int returnValue = PAM_AUTH_ERR; char *url = NULL; CURLcode all_status = 0; char errorBuffer[CURL_ERROR_SIZE]; struct MemoryStruct chunk; chunk.memory = NULL; /* we expect realloc(NULL, size) to work */ chunk.size = 0; /* no data at this point */ curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); if (curl_handle == NULL) { log_error("ERROR: could not get curl_handle!"); returnValue = PAM_AUTH_ERR; goto cleanup; } curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errorBuffer); url = createUrl(curl_handle, validateurl, realm, resConf, user, password); if (url == NULL) { log_error("ERROR: could allocate size for url"); goto cleanup; } if (debug) { log_debug("DEBUG: connecting to url:%s",url); } all_status = sendRequest(curl_handle, url, (void *)&chunk, nosslhostnameverify, nosslcertverify); /* set default return*/ returnValue = PAM_AUTH_ERR; if (all_status != 0) { log_error("ERROR: Error talking to linotpd server at %s: %s", url, errorBuffer); returnValue = PAM_AUTH_ERR; goto cleanup; } if(chunk.memory == NULL) { log_error("ERROR: No response returned for %s: %s", url, errorBuffer); returnValue = PAM_AUTH_ERR; goto cleanup; } if (strcmp(chunk.memory, LINOTPD_REJECT) == 0) { log_warning("WARNING: user '%s' rejected", user); returnValue = PAM_AUTH_ERR; goto cleanup; } if (strcmp(chunk.memory, LINOTPD_FAIL ) == 0) { log_warning("WARNING: authentication for '%s' failed", user); returnValue = PAM_AUTH_ERR; goto cleanup; } if (strcmp( chunk.memory, LINOTPD_OK ) == 0) { log_info("INFO: user '%s' authenticated successfully\n", user); returnValue = PAM_SUCCESS; goto cleanup; } // default { log_error("ERROR: An error occurred for '%s' on '%s'\n", user, validateurl); returnValue = PAM_AUTH_ERR; goto cleanup; } cleanup: if (chunk.memory!= NULL) { free(chunk.memory); } if (url != NULL) { free(url); } /* we're done with libcurl, so clean it up cleanup also takes care of escPassword and escUser */ curl_global_cleanup(); if (debug) { log_debug("linotp_auth exited normally."); } return (returnValue); } In this example we defined a helper function ``sendRequest``:: int sendRequest(CURL *curl_handle, char * url, struct MemoryStruct * chunk, int nosslhostnameverify, int nosslcertverify) { int all_status = 0; int status = 0; all_status = 0; status = curl_easy_setopt(curl_handle, CURLOPT_URL, url); all_status += status; status = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); all_status += status; status = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, chunk); all_status += status; status = curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); all_status += status; if ( nosslhostnameverify ) status = curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); else status = curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L); all_status += status; if ( nosslcertverify ) status = curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); else status = curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1L); all_status += status; status = curl_easy_perform(curl_handle); all_status += status; curl_easy_cleanup(curl_handle); return all_status; } .. highlight:: guess PHP integration ~~~~~~~~~~~~~~~~ .. highlight:: guess For usual web applications or portals that might be written in PHP you could use code like this:: server; $REQUEST="https://$server/validate/check?pass=$pass&user=$user"; if (""!=$realm) $REQUEST="$REQUEST&realm=$realm"; if (!function_exists("curl_init")) die("cURL extension is not installed!"); $ch=curl_init($REQUEST); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->verify_peer); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $this->verify_host); $r=curl_exec($ch); curl_close($ch); $Object = json_decode($r); if (true == $Object->{'result'}->{'status'} ) if (true == $Object->{'result'}->{'value'} ) $ret=true; } catch (Exception $e) { print "Error in receiving response from LinOTP server: $e"; } return $ret; } ?> .. highlight:: guess .. [#curl] http://curl.haxx.se