OW_PAMAuthentication.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
00029 *******************************************************************************/
00030 
00036 #include "OW_config.h"
00037 #include "OW_String.hpp"
00038 #include "OW_ConfigOpts.hpp"
00039 #include "OW_AuthenticatorIFC.hpp"
00040 #include "OW_Array.hpp"
00041 
00042 #include <string.h>
00043 
00044 #ifdef OW_GNU_LINUX
00045    #ifdef OW_HAVE_PWD_H
00046    #include <pwd.h>
00047    #endif
00048    #ifdef OW_HAVE_UNISTD_H
00049    #include <unistd.h>
00050    #endif
00051    #ifdef OW_HAVE_SYS_TYPES_H
00052    #include <sys/types.h>
00053    #endif
00054 #endif
00055 
00056 
00057 extern "C"
00058 {
00059 #if defined OW_HAVE_PAM_PAM_APPL_H
00060 #include <pam/pam_appl.h>
00061 #elif defined OW_HAVE_SECURITY_PAM_APPL_H
00062 #include <security/pam_appl.h>
00063 #endif
00064 #if defined OW_HAVE_PAM_PAM_MISC_H
00065 #include <pam/pam_misc.h>
00066 #elif defined OW_HAVE_SECURITY_PAM_MISC_H
00067 #include <security/pam_misc.h>
00068 #endif
00069 }
00070 
00071 namespace OW_NAMESPACE
00072 {
00073 
00082 #if defined(OW_HPUX) || defined(OW_SOLARIS) || defined(OW_AIX)
00083 static int PAM_conv(int num_msg, struct pam_message **msgm, struct pam_response **response, void *appdata_ptr);
00084 #else
00085 static int PAM_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr);
00086 #endif
00087 
00088 class LinuxPAMAuthentication : public AuthenticatorIFC
00089 {
00103 private:
00104    virtual bool doAuthenticate(String &userName, const String &info,
00105       String &details, OperationContext& context);
00106    
00107    virtual void doInit(ServiceEnvironmentIFCRef env);
00108    String m_allowedUsers;
00109 };
00110 // See misc_conv.c in libpam for an example.
00112 bool
00113 LinuxPAMAuthentication::doAuthenticate(String &userName, const String &info,
00114    String &details, OperationContext& context)
00115 {
00116    if (info.empty())
00117    {
00118       details = "You must authenticate to access this resource";
00119       return false;
00120    }
00121    Array<String> allowedUsers = m_allowedUsers.tokenize();
00122    bool nameFound = false;
00123    for (size_t i = 0; i < allowedUsers.size(); i++)
00124    {
00125       if (allowedUsers[i].equals(userName)
00126                     || allowedUsers[i].equals("*"))
00127       {
00128          nameFound = true;
00129          break;
00130       }
00131    }
00132    if (!nameFound)
00133    {
00134       details = "You must authenticate to access this resource";
00135       return false;
00136    }
00137    // we free the username
00138    // pam module is responsible to free the password
00139    // http://archives.neohapsis.com/archives/pam-list/2001-04/0002.html
00140    // https://listman.redhat.com/archives/pam-list/2001-April/msg00003.html
00141    char* pPasswd = strdup(info.c_str());
00142    char* pUserName = strdup(userName.c_str());
00143    struct pam_conv conv = {
00144       PAM_conv,
00145       pPasswd
00146    };
00147    pam_handle_t *pamh=NULL;
00148    int rval;
00149    rval = pam_start(OW_PACKAGE_PREFIX"openwbem", pUserName, &conv, &pamh);
00150    if (rval == PAM_SUCCESS)
00151    {
00152       rval = pam_authenticate(pamh, 0);    /* is user really user? */
00153    }
00154    if (rval == PAM_SUCCESS)
00155    {
00156       rval = pam_acct_mgmt(pamh, 0);       /* permitted access? */
00157    }
00158    if (rval == PAM_CONV_ERR)
00159    {
00160       pam_end(pamh, rval);
00161       free(pUserName);
00162       details = "Error in Linux-PAM conversation function";
00163       return false;
00164    }
00165    if (pam_end(pamh,rval) != PAM_SUCCESS)
00166    {     // close Linux-PAM
00167       pamh = NULL;
00168       details = "Unable to close PAM transaction";
00169       return false;
00170    }
00171    free(pUserName);
00172 
00173    bool retval = ( rval == PAM_SUCCESS ? true : false ); // indicate success
00174 
00175    if (!retval)
00176    {
00177       details = "Invalid credentials";
00178    }
00179 
00180 
00181    return retval;
00182 }
00183 
00184 #if !defined(_pam_overwrite)
00185 #define _pam_overwrite(x)        \
00186 do {                             \
00187    register char *__xx__;       \
00188    if ((__xx__=(x)))            \
00189    {                            \
00190       while (*__xx__)          \
00191       {                        \
00192          *__xx__++ = '\0';    \
00193       }                        \
00194    }                            \
00195 } while (0)
00196 
00197 #endif
00198 
00199 
00201 // Static
00202 // TODO clean up, remove all stuff we don't support.
00203 #if defined(OW_HPUX) || defined(OW_SOLARIS) || defined(OW_AIX)
00204 int
00205 PAM_conv(int num_msg, struct pam_message **msgm, struct pam_response **response, void *appdata_ptr)
00206 #else
00207 int
00208 PAM_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr)
00209 #endif
00210 {
00211    int count=0;
00212    struct pam_response *reply;
00213    if (num_msg <= 0)
00214    {
00215       return PAM_CONV_ERR;
00216    }
00217    //D(("allocating empty response structure array."));
00218    reply = static_cast<struct pam_response *>(calloc(num_msg, sizeof(struct pam_response)));
00219    if (reply == NULL)
00220    {
00221       //D(("no memory for responses"));
00222       return PAM_CONV_ERR;
00223    }
00224    bool failed = false;
00225    //D(("entering conversation function."));
00226    for (count=0; count < num_msg; ++count)
00227    {
00228       char *string=NULL;
00229       if (failed == true)
00230       {
00231          break;
00232       }
00233       switch (msgm[count]->msg_style)
00234       {
00235          case PAM_PROMPT_ECHO_OFF:
00236             string = reinterpret_cast<char*>(appdata_ptr);
00237             if (string == NULL)
00238             {
00239                failed = true;
00240             }
00241             break;
00242             /*case PAM_PROMPT_ECHO_ON:
00243                string = read_string(CONV_ECHO_ON,msgm[count]->msg);
00244                if (string == NULL) {
00245                   goto failed_conversation;
00246                }
00247                break;
00248             case PAM_ERROR_MSG:
00249                if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) {
00250                   goto failed_conversation;
00251                }
00252                break;
00253             case PAM_TEXT_INFO:
00254                if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) {
00255                   goto failed_conversation;
00256                }
00257                break;
00258             case PAM_BINARY_PROMPT:
00259                {
00260                   void *pack_out=NULL;
00261                   const void *pack_in = msgm[count]->msg;
00262    
00263                   if (!pam_binary_handler_fn
00264                         || pam_binary_handler_fn(pack_in, &pack_out) != PAM_SUCCESS
00265                         || pack_out == NULL) {
00266                      goto failed_conversation;
00267                   }
00268                   string = (char *) pack_out;
00269                   pack_out = NULL;
00270    
00271                   break;
00272                }*/
00273          default:
00274             //fprintf(stderr, "erroneous conversation (%d)\n"
00275             //      ,msgm[count]->msg_style);
00276             failed = true;
00277       }
00278       if (string)
00279       {                         /* must add to reply array */
00280          /* add string to list of responses */
00281          reply[count].resp_retcode = 0;
00282          reply[count].resp = string;
00283          string = NULL;
00284       }
00285    }
00286    /* New (0.59+) behavior is to always have a reply - this is
00287       compatable with the X/Open (March 1997) spec. */
00288    if (!failed)
00289    {
00290       *response = reply;
00291       reply = NULL;
00292    }
00293    else
00294    {
00295       if (reply)
00296       {
00297          for (count=0; count<num_msg; ++count)
00298          {
00299             if (reply[count].resp == NULL)
00300             {
00301                continue;
00302             }
00303             switch (msgm[count]->msg_style)
00304             {
00305                /*case PAM_PROMPT_ECHO_ON:*/
00306                case PAM_PROMPT_ECHO_OFF:
00307                   _pam_overwrite(reply[count].resp);
00308                   free(reply[count].resp);
00309                   break;
00310                /*case PAM_BINARY_PROMPT:
00311                   pam_binary_handler_free((void **) &reply[count].resp);
00312                   break;
00313                case PAM_ERROR_MSG:
00314                case PAM_TEXT_INFO:
00315                   // should not actually be able to get here...
00316                   free(reply[count].resp);*/
00317             } // switch
00318             reply[count].resp = NULL;
00319          } // for
00320          free(reply);
00321          reply = NULL;
00322       } // if (reply)
00323       return PAM_CONV_ERR;
00324    } // else
00325    return PAM_SUCCESS;
00326 }
00327 void LinuxPAMAuthentication::doInit(ServiceEnvironmentIFCRef env)
00328 {
00329    m_allowedUsers = env->getConfigItem(ConfigOpts::PAM_ALLOWED_USERS_opt);
00330 }
00331 
00332 } // end namespace OW_NAMESPACE
00333 
00334 OW_AUTHENTICATOR_FACTORY(OpenWBEM::LinuxPAMAuthentication,pam);
00335 
00336 

Generated on Thu Feb 9 08:48:07 2006 for openwbem by  doxygen 1.4.6