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
|