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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2