1 kumpf 1.2 /*
2 //%2006////////////////////////////////////////////////////////////////////////
3 //
4 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
5 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
6 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
7 // IBM Corp.; EMC Corporation, The Open Group.
8 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
9 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
10 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
11 // EMC Corporation; VERITAS Software Corporation; The Open Group.
12 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
13 // EMC Corporation; Symantec Corporation; The Open Group.
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining a copy
16 // of this software and associated documentation files (the "Software"), to
17 // deal in the Software without restriction, including without limitation the
18 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19 // sell copies of the Software, and to permit persons to whom the Software is
20 // furnished to do so, subject to the following conditions:
21 //
22 kumpf 1.2 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
23 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
24 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
25 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
26 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 //==============================================================================
32 //
33 //%/////////////////////////////////////////////////////////////////////////////
34 */
35
36 #ifndef Executor_PAMAuth_h
37 #define Executor_PAMAuth_h
38
39 #if !defined(PEGASUS_PAM_AUTHENTICATION)
40 # error "Do not include this file without defining PEGASUS_PAM_AUTHENTICATION"
41 #endif
42
43 kumpf 1.2 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/wait.h>
46 #include <unistd.h>
47 #include <stdio.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <Executor/Strlcpy.h>
51 #include <Executor/Strlcat.h>
52 #include <security/pam_appl.h>
|
53 kumpf 1.4 #include <Executor/Defines.h>
54 #include <Executor/Socket.h>
|
55 kumpf 1.2
56 /*
57 **==============================================================================
58 **
59 ** This program is used to authenticate users with the "Basic PAM
60 ** Authentication" scheme. It was originally written to isolate memory
61 ** PAM module errors to an external process.
62 **
63 ** This header defines two functions that may be called by clients of this
64 ** process (the parent process).
65 **
66 ** CimserveraAuthenticate()
67 ** CimserveraValidateUser()
68 **
69 ** Each functions forks and executes a child process that carries out
70 ** the request and then exits immediately. The parent and child proceses
71 ** communicate over a local domain socket, created by the parent just
72 ** before executing the client program.
73 **
74 ** Both of the functions above are defined in the header to avoid the need
75 ** to link a separate client library.
76 kumpf 1.2 **
77 ** CAUTION: This program must not depend on any Pegasus libraries since
78 ** it is used by the executor process.
79 **
80 **==============================================================================
81 */
82
83 /*
84 **==============================================================================
85 **
86 ** CimserveraStart()
87 **
88 ** Starts the CIMSERVERA program, returning a socket used to communicate
89 ** with it.
90 **
91 **==============================================================================
92 */
93
94 static int CimserveraStart(int* sock)
95 {
96 int pair[2];
97 kumpf 1.2 int pid;
98
99 /* Get absolute path of CIMSERVERA program. */
100
101 char path[EXECUTOR_BUFFER_SIZE];
102
103 if (PEGASUS_PAM_STANDALONE_PROC_NAME[0] == '/')
104 Strlcpy(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
105 else
106 {
107 /* Flawfinder: ignore */
108 const char* home = getenv("PEGASUS_HOME");
109
110 if (!home)
111 return -1;
112
113 Strlcpy(path, home, EXECUTOR_BUFFER_SIZE);
114 Strlcat(path, "/", EXECUTOR_BUFFER_SIZE);
115 Strlcat(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
116 }
117
118 kumpf 1.2 /* Create socket pair for communicating with child process. */
119
120 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0)
121 return -1;
122
123 /* Fork child: */
124
125 pid = fork();
126
127 if (pid < 0)
|
128 kumpf 1.3 {
129 close(pair[0]);
130 close(pair[1]);
|
131 kumpf 1.2 return -1;
|
132 kumpf 1.3 }
|
133 kumpf 1.2
134 /* Child process: */
135
136 if (pid == 0)
137 {
138 char sockStr[32];
139 const char* argv[3];
140
141 close(pair[1]);
142
143 /* Convert socket number to string. */
144
145 sprintf(sockStr, "%d", pair[0]);
146
147 /* Build arguments for execv(). */
148
149 argv[0] = CIMSERVERA;
150 argv[1] = sockStr;
151 argv[2] = 0;
152
153 /* Execute child: */
154 kumpf 1.2
155 /* Flawfinder: ignore */
156 execv(path, (char**)argv);
157 close(pair[0]);
158 _exit(0);
159 }
160
161 /* Parent process: */
162
163 close(pair[0]);
164
165 *sock = pair[1];
166 return pid;
167 }
168
169 /*
170 **==============================================================================
171 **
172 ** CimserveraRequest
173 **
174 **==============================================================================
175 kumpf 1.2 */
176
177 typedef struct CimserveraRequestStruct
178 {
179 char arg0[EXECUTOR_BUFFER_SIZE];
180 char arg1[EXECUTOR_BUFFER_SIZE];
181 char arg2[EXECUTOR_BUFFER_SIZE];
182 }
183 CimserveraRequest;
184
185 /*
186 **==============================================================================
187 **
|
188 kumpf 1.4 ** CimserveraResponse
189 **
190 **==============================================================================
191 */
192
193 typedef struct CimserveraResponseStruct
194 {
195 /* '0' means authentication successful. '-1' means authentication failed. */
196 int status;
197 }
198 CimserveraResponse;
199
200 /*
201 **==============================================================================
202 **
|
203 kumpf 1.2 ** CimserveraAuthenticate()
204 **
205 **==============================================================================
206 */
207
208 static int CimserveraAuthenticate(const char* username, const char* password)
209 {
210 int sock;
211 int pid;
212 int status;
213
214 /* Create the CIMSERVERA process. */
215
216 pid = CimserveraStart(&sock);
217
218 if (pid == -1)
219 return -1;
220
221 /* Send request, get response. */
222
223 status = 0;
224 kumpf 1.2
225 do
226 {
227 CimserveraRequest request;
|
228 kumpf 1.4 CimserveraResponse response;
|
229 kumpf 1.2 int childStatus;
230
231 /* Send request to CIMSERVERA process. */
232
233 memset(&request, 0, sizeof(request));
234 Strlcpy(request.arg0, "authenticate", EXECUTOR_BUFFER_SIZE);
235 Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE);
236 Strlcpy(request.arg2, password, EXECUTOR_BUFFER_SIZE);
237
|
238 kumpf 1.4 if (SendBlock(sock, &request, sizeof(request)) != sizeof(request))
|
239 kumpf 1.2 {
240 status = -1;
241 break;
242 }
243
|
244 kumpf 1.4 /* Receive response from CIMSERVERA process. */
245
246 if (RecvBlock(sock, &response, sizeof(response)) != sizeof(response))
247 {
248 status = -1;
249 break;
250 }
|
251 kumpf 1.2
|
252 kumpf 1.4 /* Check status. */
|
253 kumpf 1.2
|
254 kumpf 1.4 if (response.status != 0)
|
255 kumpf 1.2 {
256 status = -1;
257 break;
258 }
|
259 kumpf 1.4
260 /* Get exit status from CIMSERVERA program. */
261
262 waitpid(pid, &childStatus, 0);
|
263 kumpf 1.2 }
264 while (0);
265
266 close(sock);
267
268 return status;
269 }
270
271 /*
272 **==============================================================================
273 **
274 ** CimserveraValidateUser()
275 **
276 **==============================================================================
277 */
278
279 static int CimserveraValidateUser(const char* username)
280 {
281 int sock;
282 int pid;
283 int status;
284 kumpf 1.2
285 /* Create the CIMSERVERA process. */
286
287 pid = CimserveraStart(&sock);
288
289 if (pid == -1)
290 return -1;
291
292 /* Send request, get response. */
293
294 status = 0;
295
296 do
297 {
298 CimserveraRequest request;
|
299 kumpf 1.4 CimserveraResponse response;
|
300 kumpf 1.2 int childStatus;
301
302 /* Send request to CIMSERVERA process. */
303
304 memset(&request, 0, sizeof(request));
305 Strlcpy(request.arg0, "validateUser", EXECUTOR_BUFFER_SIZE);
306 Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE);
307
|
308 kumpf 1.4 if (SendBlock(sock, &request, sizeof(request)) != sizeof(request))
|
309 kumpf 1.2 {
310 status = -1;
311 break;
312 }
313
|
314 kumpf 1.4 /* Receive response from CIMSERVERA process. */
315
316 if (RecvBlock(sock, &response, sizeof(response)) != sizeof(response))
317 {
318 status = -1;
319 break;
320 }
|
321 kumpf 1.2
|
322 kumpf 1.4 /* Check status. */
|
323 kumpf 1.2
|
324 kumpf 1.4 if (response.status != 0)
|
325 kumpf 1.2 {
326 status = -1;
327 break;
328 }
|
329 kumpf 1.4
330 /* Get exit status from CIMSERVERA program. */
331
332 waitpid(pid, &childStatus, 0);
|
333 kumpf 1.2 }
334 while (0);
335
336 close(sock);
337
338 return status;
339 }
340
341 /*
342 **==============================================================================
343 **
344 ** struct PAMData
345 **
346 ** Client data passed to PAM routines.
347 **
348 **==============================================================================
349 */
350
351 typedef struct PAMDataStruct
352 {
353 const char* password;
354 kumpf 1.2 }
355 PAMData;
356
357 /*
358 **==============================================================================
359 **
360 ** PAMAuthenticateCallback()
361 **
362 ** Callback used by PAMAuthenticate().
363 **
364 **==============================================================================
365 */
366
367 static int PAMAuthenticateCallback(
368 int num_msg,
369 #if defined(PEGASUS_OS_LINUX)
370 const struct pam_message** msg,
371 #else
372 struct pam_message** msg,
373 #endif
374 struct pam_response** resp,
375 kumpf 1.2 void* appdata_ptr)
376 {
377 PAMData* data = (PAMData*)appdata_ptr;
378 int i;
379
380 if (num_msg > 0)
381 {
382 *resp = (struct pam_response*)calloc(
383 num_msg, sizeof(struct pam_response));
384
385 if (*resp == NULL)
386 return PAM_BUF_ERR;
387 }
388 else
389 return PAM_CONV_ERR;
390
391 for (i = 0; i < num_msg; i++)
392 {
393 switch (msg[i]->msg_style)
394 {
395 case PAM_PROMPT_ECHO_OFF:
396 kumpf 1.2 {
397 resp[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE);
398 Strlcpy(resp[i]->resp, data->password, PAM_MAX_MSG_SIZE);
399 resp[i]->resp_retcode = 0;
400 break;
401 }
402
403 default:
404 return PAM_CONV_ERR;
405 }
406 }
407
408 return PAM_SUCCESS;
409 }
410
411 /*
412 **==============================================================================
413 **
414 ** PAMValidateUserCallback()
415 **
416 ** Callback used by PAMValidateUser().
417 kumpf 1.2 **
418 **==============================================================================
419 */
420
421 static int PAMValidateUserCallback(
422 int num_msg,
423 #if defined(PEGASUS_OS_LINUX)
424 const struct pam_message** msg,
425 #else
426 struct pam_message** msg,
427 #endif
428 struct pam_response** resp,
429 void* appdata_ptr)
430 {
431 /* Unused */
432 msg = 0;
433
434 /* Unused */
435 appdata_ptr = 0;
436
437 if (num_msg > 0)
438 kumpf 1.2 {
439 *resp = (struct pam_response*)calloc(
440 num_msg, sizeof(struct pam_response));
441
442 if (*resp == NULL)
443 return PAM_BUF_ERR;
444 }
445 else
446 return PAM_CONV_ERR;
447
448 return PAM_SUCCESS;
449 }
450
451 /*
452 **==============================================================================
453 **
454 ** PAMAuthenticateInProcess()
455 **
456 ** Performs basic PAM authentication on the given username and password.
457 **
458 **==============================================================================
459 kumpf 1.2 */
460
461 static int PAMAuthenticateInProcess(
462 const char* username, const char* password)
463 {
464 PAMData data;
465 struct pam_conv pconv;
466 pam_handle_t* handle;
467
468 data.password = password;
469 pconv.conv = PAMAuthenticateCallback;
470 pconv.appdata_ptr = &data;
471
472
473 if (pam_start("wbem", username, &pconv, &handle) != PAM_SUCCESS)
474 return -1;
475
476 if (pam_authenticate(handle, 0) != PAM_SUCCESS)
477 {
478 pam_end(handle, 0);
479 return -1;
480 kumpf 1.2 }
481
482 if (pam_acct_mgmt(handle, 0) != PAM_SUCCESS)
483 {
484 pam_end(handle, 0);
485 return -1;
486 }
487
488 pam_end(handle, 0);
489
490 return 0;
491 }
492
493 /*
494 **==============================================================================
495 **
496 ** PAMValidateUserInProcess()
497 **
498 ** Validate that the *username* refers to a valid PAM user.
499 **
500 **==============================================================================
501 kumpf 1.2 */
502
503 static int PAMValidateUserInProcess(const char* username)
504 {
505 PAMData data;
506 struct pam_conv pconv;
507 pam_handle_t* phandle;
508
509 pconv.conv = PAMValidateUserCallback;
510 pconv.appdata_ptr = &data;
511
512 if (pam_start("wbem", username, &pconv, &phandle) != PAM_SUCCESS)
513 return -1;
514
515 if (pam_acct_mgmt(phandle, 0) != PAM_SUCCESS)
516 {
517 pam_end(phandle, 0);
518 return -1;
519 }
520
521 pam_end(phandle, 0);
522 kumpf 1.2
523 return 0;
524 }
525
526 /*
527 **==============================================================================
528 **
529 ** PAMAuthenticate()
530 **
531 ** Performs basic PAM authentication on the given username and password.
532 **
533 **==============================================================================
534 */
535
536 static int PAMAuthenticate(const char* username, const char* password)
537 {
538 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
539 return CimserveraAuthenticate(username, password);
540 #else
541 return PAMAuthenticateInProcess(username, password);
542 #endif
543 kumpf 1.2 }
544
545 /*
546 **==============================================================================
547 **
548 ** PAMValidateUser()
549 **
550 ** Validate that the *username* refers to a valid PAM user.
551 **
552 **==============================================================================
553 */
554
555 static int PAMValidateUser(const char* username)
556 {
557 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
558 return CimserveraValidateUser(username);
559 #else
560 return PAMValidateUserInProcess(username);
561 #endif
562 }
563
564 kumpf 1.2 #endif /* Executor_PAMAuth_h */
|