(file) Return to PAMBasicAuthenticatorUnix.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Security / Authentication

  1 karl  1.25 //%2005////////////////////////////////////////////////////////////////////////
  2 kumpf 1.1  //
  3 karl  1.24 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
  4            // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
  5            // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
  6 karl  1.14 // IBM Corp.; EMC Corporation, The Open Group.
  7 karl  1.24 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8            // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9 karl  1.25 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11 kumpf 1.1  //
 12 kumpf 1.5  // Permission is hereby granted, free of charge, to any person obtaining a copy
 13            // of this software and associated documentation files (the "Software"), to
 14            // deal in the Software without restriction, including without limitation the
 15            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 16            // sell copies of the Software, and to permit persons to whom the Software is
 17            // furnished to do so, subject to the following conditions:
 18            // 
 19            // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 20            // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 21            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 22            // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 23            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 24            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 25            // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 26            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 27 kumpf 1.1  //
 28            //==============================================================================
 29            //
 30            // Author: Nag Boranna, Hewlett-Packard Company(nagaraja_boranna@hp.com)
 31            //
 32 kumpf 1.10 // Modified By: Yi Zhou, Hewlett-Packard Company(yi_zhou@hp.com)
 33 kumpf 1.12 //            : Sushma Fernandes, Hewlett-Packard Company 
 34            //                (sushma_fernandes@hp.com)
 35 joyce.j 1.26 //                Josephine Eskaline Joyce (jojustin@in.ibm.com) for PEP#101
 36 kumpf   1.1  //
 37              //%/////////////////////////////////////////////////////////////////////////////
 38              
 39              #include <Pegasus/Common/System.h>
 40              #include <Pegasus/Common/Tracer.h>
 41              #include <Pegasus/Config/ConfigManager.h>
 42 kumpf   1.15 #include <Pegasus/Common/FileSystem.h>
 43 kumpf   1.1  
 44 kumpf   1.15 #if defined (PEGASUS_OS_HPUX)
 45              #include <prot.h>
 46              #endif
 47              
 48              #if defined (PEGASUS_USE_PAM_STANDALONE_PROC)
 49              #include <Pegasus/Common/Logger.h>
 50              #include <Pegasus/Common/IPC.h>
 51 kumpf   1.10 #include <pwd.h>
 52 kumpf   1.15 #include <sys/stat.h>
 53              #include <unistd.h>
 54              #include <sys/types.h>
 55              #include <sys/resource.h>
 56 kumpf   1.10 #endif
 57              
 58 konrad.r 1.20 
 59 kumpf    1.1  #include "PAMBasicAuthenticator.h"
 60               
 61               PEGASUS_USING_STD;
 62               
 63               PEGASUS_NAMESPACE_BEGIN
 64 kumpf    1.3  
 65               #include <security/pam_appl.h>
 66 kumpf    1.1  
 67 konrad.r 1.23 #if defined(PEGASUS_OS_LSB)
 68               #ifndef PAM_MAX_MSG_SIZE
 69               #define PAM_MAX_MSG_SIZE      512
 70               #endif
 71               #endif
 72               
 73 kumpf    1.10 #define BUFFERLEN 1024
 74 kumpf    1.1  
 75               /**
 76                   Constant representing the Basic authentication challenge header.
 77               */
 78               static const String BASIC_CHALLENGE_HEADER = "WWW-Authenticate: Basic \"";
 79               
 80 kumpf    1.13 Mutex PAMBasicAuthenticator::_authSerializeMutex;
 81 kumpf    1.1  
 82               /** Service name for pam_start */
 83               const char *service = "wbem";
 84               
 85 kumpf    1.10 typedef struct
 86 kumpf    1.9  {
 87                   CString userPassword;
 88               } APP_DATA;
 89               
 90 kumpf    1.1  /* constructor. */
 91               PAMBasicAuthenticator::PAMBasicAuthenticator() 
 92               { 
 93                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
 94                       "PAMBasicAuthenticator::PAMBasicAuthenticator()");
 95               
 96                   //
 97                   // get the local system name
 98                   //
 99                   _realm.assign(System::getHostName());
100               
101                   //
102                   // get the configured port number
103                   //
104                   ConfigManager* configManager = ConfigManager::getInstance();
105               
106 kumpf    1.4      String port = configManager->getCurrentValue("httpPort");
107 kumpf    1.1  
108                   //
109                   // Create realm that will be used for Basic challenges
110                   //
111                   _realm.append(":");
112                   _realm.append(port);
113               
114                   PEG_METHOD_EXIT();
115               }
116               
117               /* destructor. */
118               PAMBasicAuthenticator::~PAMBasicAuthenticator() 
119               { 
120                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
121                       "PAMBasicAuthenticator::~PAMBasicAuthenticator()");
122               
123                   PEG_METHOD_EXIT();
124               }
125               
126               Boolean PAMBasicAuthenticator::authenticate(
127                   const String& userName, 
128 kumpf    1.1      const String& password) 
129               {
130                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
131                       "PAMBasicAuthenticator::authenticate()");
132               
133 kumpf    1.10     Boolean authenticated;
134               
135 kumpf    1.15 #if !defined(PEGASUS_USE_PAM_STANDALONE_PROC)
136 kumpf    1.19         authenticated = _authenticateByPAM(userName, password);
137 kumpf    1.10 #else
138 kumpf    1.19         //
139                       // Mutex to Serialize Authentication calls.
140                       //
141                       Tracer::trace(TRC_AUTHENTICATION, Tracer::LEVEL4,
142                          "Authentication Mutex lock.");
143                       AutoMutex lock(_authSerializeMutex);
144 kumpf    1.27         authenticated = _pamBasicAuthenticatorStandAlone.authenticate(
145                           userName, password);
146 kumpf    1.10 #endif
147               
148                   PEG_METHOD_EXIT();
149                   return (authenticated);
150               }
151               
152               Boolean PAMBasicAuthenticator::_authenticateByPAM(
153                   const String& userName, 
154                   const String& password) 
155               {
156                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
157                       "PAMBasicAuthenticator::_authenticateByPAM()");
158               
159 kumpf    1.2      Boolean authenticated = false;
160 kumpf    1.1      struct pam_conv pconv;
161                   pam_handle_t *phandle;
162                   char *name;
163 kumpf    1.9      APP_DATA mydata;
164               
165                   //
166                   // Store the password for PAM authentication
167                   //
168                   mydata.userPassword = password.getCString();
169 kumpf    1.1  
170                   pconv.conv = PAMBasicAuthenticator::PAMCallback;
171 kumpf    1.9      pconv.appdata_ptr = &mydata;
172 kumpf    1.8  
173               //    WARNING: Should only be uncommented for debugging in a secure environment.
174               //    Tracer::trace(TRC_AUTHENTICATION, Tracer::LEVEL4,
175 kumpf    1.10 //       "PAMBasicAuthenticator::_authenticateByPAM() - userName = %s; userPassword = %s",
176 kumpf    1.9  //       (const char *)userName.getCString(), (const char *)password.getCString());
177 kumpf    1.1  
178                   //
179 kumpf    1.2      //Call pam_start since you need to before making any other PAM calls
180 kumpf    1.1      //
181                   if ( ( pam_start(service, 
182 kumpf    1.6          (const char *)userName.getCString(), &pconv, &phandle) ) != PAM_SUCCESS ) 
183 kumpf    1.1      {
184                       PEG_METHOD_EXIT();
185                       return (authenticated);
186                   }
187               
188                   //
189                   //Call pam_authenticate to authenticate the user
190                   //
191 kumpf    1.2      if ( ( pam_authenticate(phandle, 0) ) == PAM_SUCCESS ) 
192 kumpf    1.1      {
193 kumpf    1.8         Tracer::trace(TRC_AUTHENTICATION, Tracer::LEVEL4,
194 kumpf    1.12          "pam_authenticate successful.");
195 kumpf    1.2          //
196                       //Call pam_acct_mgmt, to check if the user account is valid. This includes 
197                       //checking for password and account expiration, as well as verifying access 
198                       //hour restrictions.
199                       //
200                       if ( ( pam_acct_mgmt(phandle, 0) ) == PAM_SUCCESS ) 
201                       {
202 kumpf    1.8             Tracer::trace(TRC_AUTHENTICATION, Tracer::LEVEL4,
203 kumpf    1.12               "pam_acct_mgmt successful.");
204 kumpf    1.2              authenticated = true;
205                       }
206 kumpf    1.1      }
207               
208                   //
209                   //Call pam_end to end our PAM work
210                   //
211 kumpf    1.2      pam_end(phandle, 0);
212 kumpf    1.10 
213                   PEG_METHOD_EXIT();
214               
215                   return (authenticated);
216               }
217               
218 kumpf    1.1  //
219               // Create authentication response header
220               //
221               String PAMBasicAuthenticator::getAuthResponseHeader()
222               {
223                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
224                       "PAMBasicAuthenticator::getAuthResponseHeader()");
225               
226                   // 
227                   // build response header using realm
228                   //
229                   String responseHeader = BASIC_CHALLENGE_HEADER;
230                   responseHeader.append(_realm);
231                   responseHeader.append("\"");
232               
233                   PEG_METHOD_EXIT();
234               
235                   return (responseHeader);
236               }
237               
238 kumpf    1.8  #if defined PEGASUS_OS_LINUX
239               Sint32 PAMBasicAuthenticator::PAMCallback(Sint32 num_msg, const struct pam_message **msg,
240                       struct pam_response **resp, void *appdata_ptr)
241               #else
242 kumpf    1.1  Sint32 PAMBasicAuthenticator::PAMCallback(Sint32 num_msg, struct pam_message **msg,
243                       struct pam_response **resp, void *appdata_ptr)
244 kumpf    1.8  #endif
245 kumpf    1.1  {
246                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
247                       "PAMBasicAuthenticator::PAMCallback()");
248 kumpf    1.9  
249                   //
250                   // Copy the application specific data from the PAM structure.
251                   //
252                   APP_DATA *mydata;
253                   mydata = (APP_DATA *) appdata_ptr;
254               
255 kumpf    1.1      // 
256                   // Allocate the response buffers 
257                   // 
258                   if ( num_msg > 0 ) 
259                   {
260 kumpf    1.13         // 
261                       // Since resp->resp needs to be initialized in all possible scenarios,
262                       // use calloc for memory allocation. 
263                       //
264                       *resp = (struct pam_response *)calloc(num_msg, sizeof(struct pam_response));
265 kumpf    1.1  
266                       if ( *resp == NULL ) 
267                       {
268                           PEG_METHOD_EXIT();
269                           return PAM_BUF_ERR;
270                       }
271                   } 
272                   else 
273                   {
274                       PEG_METHOD_EXIT();
275                       return PAM_CONV_ERR;
276                   }
277               
278 kumpf    1.8      for ( Sint32 i = 0; i < num_msg; i++ ) 
279 kumpf    1.1      {
280                       switch ( msg[i]->msg_style ) 
281                       {
282                           case PAM_PROMPT_ECHO_OFF:
283                               // 
284                               // copy the user password
285                               // 
286                               resp[i]->resp = (char *)malloc(PAM_MAX_MSG_SIZE);
287 kumpf    1.9                  strcpy(resp[i]->resp, mydata->userPassword);
288 kumpf    1.1                  resp[i]->resp_retcode = 0;
289                               break;
290               
291                           default:
292 kumpf    1.13                PEG_METHOD_EXIT();
293                              return PAM_CONV_ERR;
294 kumpf    1.1          }
295                   }
296               
297                   PEG_METHOD_EXIT();
298               
299                   return PAM_SUCCESS;
300               }
301               
302 kumpf    1.15 /** Routines to access PAM Authentication via a standalone process **/
303               
304               #if defined(PEGASUS_USE_PAM_STANDALONE_PROC)
305               
306               int     fd_1[2], fd_2[2];
307               Boolean continue_PAMauthentication;
308               Boolean printed_err_since_success=false;
309               
310               /* constructor. */
311               PAMBasicAuthenticatorStandAlone::PAMBasicAuthenticatorStandAlone()
312               {
313                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
314                       "PAMBasicAuthenticatorStandAlone::PAMBasicAuthenticatorStandAlone()");
315               
316                   _createPAMStandalone();
317               
318                   PEG_METHOD_EXIT();
319               }
320               
321               /* destructor. */
322               PAMBasicAuthenticatorStandAlone::~PAMBasicAuthenticatorStandAlone()
323 kumpf    1.15 {
324                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
325                       "PAMBasicAuthenticatorStandAlone::~PAMBasicAuthenticatorStandAlone()");
326               
327                   PEG_METHOD_EXIT();
328               }
329               
330               Boolean PAMBasicAuthenticatorStandAlone::authenticate(
331                   const String& userName,
332                   const String& password)
333               {
334                   PEG_METHOD_ENTER(TRC_AUTHENTICATION,
335                       "PAMBasicAuthenticatorStandAlone::authenticate()");
336               
337                   Boolean authenticated;
338                   char    auth_reply[10];
339                   char    line[BUFFERLEN];
340                   int     n, ret_code;
341               
342                   try
343                   {
344 kumpf    1.15             // Callout to stand-alone process replaces above call...
345               
346                           // Send over the username ...
347                           CString copy_of_userName=userName.getCString();
348                           n = strlen(copy_of_userName);
349                           sprintf(line, "%4u%s", n, (const char*)copy_of_userName);
350                           n = strlen(line);
351                           ret_code = write(fd_1[1], line, n);
352                           if (ret_code != n)
353                           {
354                               continue_PAMauthentication = false;
355                               if (printed_err_since_success == false)
356                               {
357                                   printed_err_since_success = true;
358                                   Logger::put(Logger::ERROR_LOG, "CIMServer",
359                                      Logger::SEVERE,
360                                      "Error processing PAM Authentication request (write).");
361                               }
362                               //
363                               // on EPIPE, try restarting the authentication process
364                               //
365 kumpf    1.15                 if (errno == EPIPE)
366                               {
367                                 close(fd_1[1]);   // Close to keep used fd number down
368                                 close(fd_2[0]);   // Close to keep used fd number down
369                                 _createPAMStandalone();
370                                 ret_code = write(fd_1[1], line, n);
371                                 if (ret_code != n)
372                                 {
373                                   continue_PAMauthentication = false;
374                                   if (printed_err_since_success == false)
375                                   {
376                                     printed_err_since_success = true;
377                                     //L10N TODO
378                                     Logger::put(Logger::ERROR_LOG, "CIMServer",
379                                       Logger::SEVERE,
380                                       "Error processing PAM Authentication request (write).");
381                                   }
382                                 }
383                               }  //  if (errno == EPIPE)
384                           } // if (ret_code != n) from 1st write
385               
386 kumpf    1.15             // Send over the password ... */
387                           if (continue_PAMauthentication)
388                           {
389                               CString copy_of_password = password.getCString();
390                               n = strlen(copy_of_password);
391                               sprintf(line, "%4u%s", n, (const char*)copy_of_password);
392                               n = strlen(line);
393                               if (write(fd_1[1], line, n) != n) {
394                                   continue_PAMauthentication = false;
395                                   if (printed_err_since_success == false)
396                                   {
397                                     printed_err_since_success = true;
398                                     //L10N TODO
399                                     Logger::put(Logger::ERROR_LOG, "CIMServer",
400                                       Logger::SEVERE,
401                                       "Error processing PAM Authentication request (write).");
402                                   }
403                               }
404                           }
405               
406                           // Now read back the PAM Authentication status value (T/F)
407 kumpf    1.15             if (continue_PAMauthentication)
408                           {
409                               n = read(fd_2[0], auth_reply, 2);  /* read back the reply */
410               
411                               if (n < 0)
412                               {
413                                   continue_PAMauthentication = false;
414                                   if (printed_err_since_success == false)
415                                   {
416                                     printed_err_since_success = true;
417                                     //L10N TODO
418                                     Logger::put(Logger::ERROR_LOG, "CIMServer",
419                                       Logger::SEVERE,
420                                       "Error processing PAM Authentication request (read).");
421                                   }
422                               }
423                               else
424                               {
425                                   auth_reply[n] = '\0';
426                               }
427                           }
428 kumpf    1.15 
429                           authenticated = false;
430                           if ((continue_PAMauthentication) && (auth_reply[0] == 'T'))
431                           {
432                               authenticated = true;
433                               printed_err_since_success = false;
434                           }
435                   }
436                   catch (...)
437                   {
438                        throw;
439                   }
440               
441                   PEG_METHOD_EXIT();
442                   return (authenticated);
443               }
444               
445               
446               void PAMBasicAuthenticatorStandAlone::_createPAMStandalone()
447               {
448                   pid_t   pid;
449 kumpf    1.15 
450                   continue_PAMauthentication = true;
451                   if (pipe(fd_1) < 0)   // Pipe to write to authentication proc
452                   {
453                       continue_PAMauthentication = false;
454                       if (printed_err_since_success == false)
455                       {
456                           printed_err_since_success = true;
457                           //L10N TODO
458                           Logger::put(Logger::ERROR_LOG, "CIMServer",
459                                 Logger::SEVERE,
460                                 "Error processing PAM Authtication request (pipe).");
461                       }
462                   }
463                   if (continue_PAMauthentication)
464                   {
465                       if (pipe(fd_2) < 0)   // Pipe to read from the authentication proc
466                       {
467                           continue_PAMauthentication = false;
468                           if (printed_err_since_success == false)
469                           {
470 kumpf    1.15                 printed_err_since_success = true;
471                               //L10N TODO
472                               Logger::put(Logger::ERROR_LOG, "CIMServer",
473                                     Logger::SEVERE,
474                                     "Error processing PAM Authentication request (pipe).");
475                           }
476                       }
477                   }
478                   if (continue_PAMauthentication)
479                   {
480                       if ((pid = fork()) < 0)
481                       {
482                           continue_PAMauthentication = false;
483                           if (printed_err_since_success == false)
484                           {
485                               printed_err_since_success = true;
486                               //L10N TODO
487                               Logger::put(Logger::ERROR_LOG, "CIMServer",
488                                     Logger::SEVERE,
489                                     "Error processing PAM Authentication request (fork).");
490                           }
491 kumpf    1.15         }
492                       else if (pid > 0)       // This is the PARENT side of the fork
493                       {
494                           close(fd_1[0]);     // close read end on 1st pipe
495                           close(fd_2[1]);     // close write end on 2nd pipe
496                       }
497                       else                     // This is the CHILD side of the fork
498                       {
499                           close(fd_1[1]);      // close write end on 1st pipe
500                           close(fd_2[0]);      // close read end on 2nd pipe
501                           if (fd_1[0] != STDIN_FILENO)
502                           {
503                               if (dup2(fd_1[0], STDIN_FILENO) == -1)
504                               {
505                                   continue_PAMauthentication = false;
506                                   if (printed_err_since_success == false)
507                                   {
508                                       printed_err_since_success = true;
509                                       //L10N TODO
510                                       Logger::put(Logger::ERROR_LOG, "CIMServer",
511                                             Logger::SEVERE,
512 kumpf    1.15                               "Error processing PAM Authentication request (dup2).");
513                                   }
514                               }
515                               close(fd_1[0]);  // don't need this after dup2
516                           }
517                           if (continue_PAMauthentication)
518                           {
519                               if (fd_2[1] != STDOUT_FILENO)
520                               {
521                                   if (dup2(fd_2[1], STDOUT_FILENO) == -1)
522                                   {
523                                       continue_PAMauthentication = false;
524                                       if (printed_err_since_success == false)
525                                       {
526                                           printed_err_since_success = true;
527                                           //L10N TODO
528                                           Logger::put(Logger::ERROR_LOG, "CIMServer",
529                                               Logger::SEVERE,
530                                               "Error processing PAM Authentication request (dup2).");
531                                       }
532                                   }
533 kumpf    1.15                     close(fd_2[1]);   // don't need this after dup2
534                               }
535                               if (continue_PAMauthentication)
536                               {
537                                   //
538                                   // Get environment variables:
539                                   //
540 kumpf    1.17                     String certpath = ConfigManager::getHomedPath(
541 kumpf    1.19                         PEGASUS_PAM_STANDALONE_PROC_NAME);
542 kumpf    1.15                     if (execl((const char*)certpath.getCString(),
543                                             (const char*)certpath.getCString(), (char*)0) < 0)
544                                   {
545                                       continue_PAMauthentication = false;
546                                       if (printed_err_since_success == false)
547                                       {
548                                           printed_err_since_success = true;
549                                           //L10N TODO
550                                           Logger::put(Logger::ERROR_LOG, "CIMServer",
551                                               Logger::SEVERE,
552                                               "Error creating PAM Authentication process (execl).");
553                                       }
554                                       exit(0);
555                                   }
556                               }
557                           }
558                       }
559                   }
560               }
561               
562               #endif  /* if defined(PEGASUS_OS_HPUX) || ... */
563 kumpf    1.15 
564               
565               
566               
567               
568 kumpf    1.1  PEGASUS_NAMESPACE_END
569 kumpf    1.15 

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2