/*********************************************************************** * * Copyright (C) 2006 Novell, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * This library 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 * Library Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, Novell, Inc. * * To contact Novell about this file by physical or electronic mail, * you may find current contact information at www.novell.com. * * Author: Juan Carlos Luciani * ***********************************************************************/ //===[ Include files ]===================================================== #include #include #include #include #include #include #include #include #include #include //===[ Type definitions ]================================================== typedef struct _AppUserData { char *pUserName; char *pAuthToken; } AppUserData, *PAppUserData; // // DbgTrace macro define // #define DbgTrace(LEVEL, X, Y) { \ if (LEVEL == 0) \ printf(X, Y); \ else if (DebugLevel >= LEVEL) \ printf(X, Y); \ } // // Socket Mapping definitions // #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define LINGER struct linger #define SOCKADDR_IN struct sockaddr_in #define closesocket close //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== // Usage string char usage[] = "\nPamTest: usage: -s serviceName [-D DebugLevel]\n"; // Debug Level int DebugLevel = 3; char *pServiceName = NULL; //++======================================================================= int Converse(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) // // Arguments: // // Returns: // // Abstract: // // Notes: // // Environment: // //=======================================================================-- { int retStatus = PAM_SUCCESS; int replies = 0; struct pam_response *reply = NULL; AppUserData *pAppUserData = (PAppUserData) appdata_ptr; // Initialize output parameters *resp = NULL; // Check input parameters if (num_msg <= 0 || appdata_ptr == NULL) return PAM_CONV_ERR; // Allocate enough space for the replies reply = malloc(sizeof(struct pam_response) * num_msg); if (!reply) return PAM_CONV_ERR; // Zero the reply buffer memset(reply, 0, sizeof(struct pam_response) * num_msg); for (replies = 0; replies < num_msg && retStatus == PAM_SUCCESS; replies++) { switch (msg[replies]->msg_style) { case PAM_PROMPT_ECHO_ON: // The caller wants the username reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = malloc(strlen(pAppUserData->pUserName) + 1); if (reply[replies].resp) strcpy(reply[replies].resp, pAppUserData->pUserName); else { DbgTrace(0, "Converse- Buffer allocation failure\n", 0); retStatus = PAM_CONV_ERR; } break; case PAM_PROMPT_ECHO_OFF: // The caller wants the authentication token reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = malloc(strlen(pAppUserData->pAuthToken) + 1); if (reply[replies].resp) { strcpy(reply[replies].resp, pAppUserData->pAuthToken); } else { DbgTrace(0, "Converse- Buffer allocation failure\n", 0); retStatus = PAM_CONV_ERR; } break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: // Just return success reply[replies].resp_retcode = PAM_SUCCESS; reply[replies].resp = NULL; break; default: // Un-expected retStatus = PAM_CONV_ERR; } } // Proceed based on the status if (retStatus == PAM_SUCCESS) { *resp = reply; } else { // Free buffers allocated for the reply for (replies = 0; replies < num_msg && retStatus == PAM_SUCCESS; replies++) { if (reply[replies].resp != NULL) free(reply[replies].resp); } free(reply); } return retStatus; } //++======================================================================= int ReadLineIntoBuffer(int connSock, char *pBuffer) // // Arguments: // // Returns: // // Abstract: // // Notes: // // Environment: // //=======================================================================-- { int i = 0; char c; int bytesReceived = 0; DbgTrace(2, "ReadLineIntoBuffer- Start\n", 0); // Receive the line while ((bytesReceived = recv(connSock, &c, 1, 0)) == 1) { if (c == '\n') break; else { pBuffer[i] = c; i ++; } } // Check for a socket error if (bytesReceived == 0) { DbgTrace(0, "ReadLineIntoBuffer- Socket error\n", 0); } DbgTrace(2, "ReadLineIntoBuffer- End, lineLength = %d\n", i); return i; } //++======================================================================= void ProcessConnection(int connSock) // // Arguments: // // Returns: // // Abstract: // // Notes: // // Environment: // //=======================================================================-- { char userName[] = "CasaPrincipal"; char token[8192] = {0}; char helloString[100] = {0}; AppUserData appUserData = {userName, token}; struct pam_conv conv = {Converse, &appUserData}; pam_handle_t *pamh; int pam_status; DbgTrace(1, "ProcessConnection- Start\n", 0); // We have received a connection printf("\n\nConnection received\n"); // Receive the token if (ReadLineIntoBuffer(connSock, token) == 0) { DbgTrace(0, "ProcessConnection- Error receiving token\n", 0); goto exit; } //printf("Token received = %s\n", token); // We obtained authentication token credentials to authenticate // to the service, now verify the credentials using PAM_Authenticate. // // Open a PAM Handle pam_status = pam_start(pServiceName, userName, &conv, &pamh); if (pam_status == PAM_SUCCESS) { // Now authenticate the user pam_status = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK); if (pam_status == PAM_SUCCESS) { char **pam_envlist; char **pam_env; char *pUsername; DbgTrace(1, "ProcessConnection- pam_authenticate success\n", 0); printf("Authentication succeeded\n"); printf("The DUDE is cool\n"); // Get the identity information about the DUDE // Notice that the username may have been updated during the authentication process if (pam_get_item(pamh, PAM_USER, (void*) &pUsername) == PAM_SUCCESS && pUsername != NULL) { printf("The username of the authenticated identity is %s\n", pUsername); } else { DbgTrace(0, "ProcessConnection- pam_get_item did not return the username\n", 0); } // Show identity information obtained during the authentication process and maintained // as PAM environment variables. pam_envlist = pam_getenvlist(pamh); if (pam_envlist != NULL) { // Display the environment variables and free the memory associated // with them. for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) { printf("%s\n", *pam_env); free(*pam_env); } free(pam_envlist); } else { DbgTrace(0, "ProcessConnection- pam_getenvlist did not return any data\n", 0); } } else { DbgTrace(0, "ProcessConnection- pam_authenticate failure, error = %s\n", pam_strerror(pamh, pam_status)); printf("The DUDE is a fake\n"); } // Close the PAM Handle pam_end(pamh, pam_status | PAM_DATA_SILENT); } else { DbgTrace(0, "ProcessConnection- pam_start failure, status = %08X\n", pam_status); } exit: DbgTrace(1, "ProcessConnection- End\n", 0); } //++======================================================================= void ExecuteTests(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // Environment: // //=======================================================================-- { int connSock; int listenSock; struct sockaddr_in localAddr = {0}; struct sockaddr_in boundAddr = {0}; struct sockaddr_in remoteAddr = {0}; struct linger linger_opt = {1, 15}; int on = 1; socklen_t addrLen = sizeof(struct sockaddr_in); DbgTrace(1, "ExecuteTests- Start\n", 0); // Open listen socket listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listenSock != INVALID_SOCKET) { // Setup the local address structure localAddr.sin_family = AF_INET; localAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Set the SO_REUSEADDR option on the socket to avoid // problems in case of a re-start. setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); // Bind socket if (!bind(listenSock, (const struct sockaddr*) &localAddr, sizeof(struct sockaddr_in))) { // Display the local address information if (getsockname(listenSock, (struct sockaddr*) &boundAddr, &addrLen) != SOCKET_ERROR) { printf("Listen port = %d\n", htons(boundAddr.sin_port)); // Now start linstening for connections if (listen(listenSock, SOMAXCONN) != SOCKET_ERROR) { // Loop accepting connections while (1) { addrLen = sizeof(remoteAddr); connSock = accept(listenSock, (struct sockaddr*) &remoteAddr, &addrLen); if (connSock != INVALID_SOCKET) { ProcessConnection(connSock); // Close the connection socket closesocket(connSock); } else { DbgTrace(0, "ExecuteTests- - Accept failed, error = %08X\n", errno); break; } } } else { DbgTrace(0, "ExecuteTests- Unable to start listening, error = %d", errno); } } else { DbgTrace(0, "ExecuteTests- Unable to obtain local address information, error = %d", errno); } } else { DbgTrace(0, "ExecuteTests- Unable to bind socket, error = %d", errno); } // Close the listen socket closesocket(listenSock); } else { DbgTrace(0, "ExecuteTests- Unable to open socket, error = %d\n", errno); } DbgTrace(1, "ExecuteTests- End\n", 0); } //++======================================================================= int main( int argc, char* argv[]) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int optionsSpecified = 0; bool doneScanning = false; bool invalidOption = false; int option; printf("**** server auth_token test ****\n"); // Scan through the options specified while (!doneScanning) { opterr = 0; option = getopt(argc, argv, "s:D:"); // Proceed based on the result switch (option) { case 'D': // Set the debug level printf("DebugLevel = %s\n", optarg); DebugLevel = atoi(optarg); optionsSpecified++; break; case 's': // Set the service name printf("Service name = %s\n", optarg); pServiceName = optarg; optionsSpecified++; break; case '?': // Invalid option detected doneScanning = true; invalidOption = true; break; default: // Done scanning doneScanning = true; break; } } // Do some sanity checking if (!invalidOption && pServiceName != NULL) { ExecuteTests(); } else { // Invalid option detected printf(usage, argv[0]); } return 0; } /*-- main() --*/