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
|