1 kumpf 1.1.4.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.1.4.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.1.4.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 #include "Defines.h"
54
55 /*
56 **==============================================================================
57 **
58 ** This program is used to authenticate users with the "Basic PAM
59 ** Authentication" scheme. It was originally written to isolate memory
60 ** PAM module errors to an external process.
61 **
62 ** This header defines two functions that may be called by clients of this
63 ** process (the parent process).
64 kumpf 1.1.4.2 **
65 ** CimserveraAuthenticate()
66 ** CimserveraValidateUser()
67 **
68 ** Each functions forks and executes a child process that carries out
69 ** the request and then exits immediately. The parent and child proceses
70 ** communicate over a local domain socket, created by the parent just
71 ** before executing the client program.
72 **
73 ** Both of the functions above are defined in the header to avoid the need
74 ** to link a separate client library.
75 **
76 ** CAUTION: This program must not depend on any Pegasus libraries since
77 ** it is used by the executor process.
78 **
79 **==============================================================================
80 */
81
82 /*
83 **==============================================================================
84 **
|
85 kumpf 1.1.4.3 ** CimserveraSend()
|
86 kumpf 1.1.4.2 **
87 ** Sends *size* bytes on the given socket.
88 **
89 **==============================================================================
90 */
91
|
92 kumpf 1.1.4.3 static ssize_t CimserveraSend(int sock, void* buffer, size_t size)
|
93 kumpf 1.1.4.2 {
94 size_t r = size;
95 char* p = (char*)buffer;
96
97 while (r)
98 {
99 ssize_t n;
100 EXECUTOR_RESTART(write(sock, p, r), n);
101
102 if (n == -1)
103 return -1;
104 else if (n == 0)
105 return size - r;
106
107 r -= n;
108 p += n;
109 }
110
111 return size - r;
112 }
113
114 kumpf 1.1.4.2 /*
115 **==============================================================================
116 **
117 ** CimserveraStart()
118 **
119 ** Starts the CIMSERVERA program, returning a socket used to communicate
120 ** with it.
121 **
122 **==============================================================================
123 */
124
125 static int CimserveraStart(int* sock)
126 {
127 int pair[2];
128 int pid;
129
130 /* Get absolute path of CIMSERVERA program. */
131
132 char path[EXECUTOR_BUFFER_SIZE];
133
134 if (PEGASUS_PAM_STANDALONE_PROC_NAME[0] == '/')
135 kumpf 1.1.4.2 Strlcpy(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
136 else
137 {
138 /* Flawfinder: ignore */
139 const char* home = getenv("PEGASUS_HOME");
140
141 if (!home)
142 return -1;
143
144 Strlcpy(path, home, EXECUTOR_BUFFER_SIZE);
145 Strlcat(path, "/", EXECUTOR_BUFFER_SIZE);
146 Strlcat(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
147 }
148
149 /* Create socket pair for communicating with child process. */
150
151 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0)
152 return -1;
153
154 /* Fork child: */
155
156 kumpf 1.1.4.2 pid = fork();
157
158 if (pid < 0)
159 return -1;
160
161 /* Child process: */
162
163 if (pid == 0)
164 {
165 char sockStr[32];
166 const char* argv[3];
167
168 close(pair[1]);
169
170 /* Convert socket number to string. */
171
172 sprintf(sockStr, "%d", pair[0]);
173
174 /* Build arguments for execv(). */
175
176 argv[0] = CIMSERVERA;
177 kumpf 1.1.4.2 argv[1] = sockStr;
178 argv[2] = 0;
179
180 /* Execute child: */
181
182 /* Flawfinder: ignore */
183 execv(path, (char**)argv);
184 close(pair[0]);
185 _exit(0);
186 }
187
188 /* Parent process: */
189
190 close(pair[0]);
191
192 *sock = pair[1];
193 return pid;
194 }
195
196 /*
197 **==============================================================================
198 kumpf 1.1.4.2 **
199 ** CimserveraRequest
200 **
201 **==============================================================================
202 */
203
204 typedef struct CimserveraRequestStruct
205 {
206 char arg0[EXECUTOR_BUFFER_SIZE];
207 char arg1[EXECUTOR_BUFFER_SIZE];
208 char arg2[EXECUTOR_BUFFER_SIZE];
209 }
210 CimserveraRequest;
211
212 /*
213 **==============================================================================
214 **
215 ** CimserveraAuthenticate()
216 **
217 **==============================================================================
218 */
219 kumpf 1.1.4.2
220 static int CimserveraAuthenticate(const char* username, const char* password)
221 {
222 int sock;
223 int pid;
224 int status;
225
226 /* Create the CIMSERVERA process. */
227
228 pid = CimserveraStart(&sock);
229
230 if (pid == -1)
231 return -1;
232
233 /* Send request, get response. */
234
235 status = 0;
236
237 do
238 {
239 CimserveraRequest request;
240 kumpf 1.1.4.2 int childStatus;
241
242 /* Send request to CIMSERVERA process. */
243
244 memset(&request, 0, sizeof(request));
245 Strlcpy(request.arg0, "authenticate", EXECUTOR_BUFFER_SIZE);
246 Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE);
247 Strlcpy(request.arg2, password, EXECUTOR_BUFFER_SIZE);
248
|
249 kumpf 1.1.4.3 if (CimserveraSend(sock, &request, sizeof(request)) != sizeof(request))
|
250 kumpf 1.1.4.2 {
251 status = -1;
252 break;
253 }
254
|
255 kumpf 1.1.4.3 /* Get exit status from CIMSERVERA program. */
|
256 kumpf 1.1.4.2
257 waitpid(pid, &childStatus, 0);
258
259 if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0)
260 {
261 status = -1;
262 break;
263 }
264 }
265 while (0);
266
267 close(sock);
268
269 return status;
270 }
271
272 /*
273 **==============================================================================
274 **
|
275 kumpf 1.1.4.4 ** CimserveraValidateUser()
|
276 kumpf 1.1.4.2 **
277 **==============================================================================
278 */
279
280 static int CimserveraValidateUser(const char* username)
281 {
282 int sock;
283 int pid;
284 int status;
285
286 /* Create the CIMSERVERA process. */
287
288 pid = CimserveraStart(&sock);
289
290 if (pid == -1)
291 return -1;
292
293 /* Send request, get response. */
294
295 status = 0;
296
297 kumpf 1.1.4.2 do
298 {
299 CimserveraRequest request;
300 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.1.4.3 if (CimserveraSend(sock, &request, sizeof(request)) != sizeof(request))
|
309 kumpf 1.1.4.2 {
310 status = -1;
311 break;
312 }
313
|
314 kumpf 1.1.4.3 /* Get exit status from CIMSERVERA program. */
|
315 kumpf 1.1.4.2
316 waitpid(pid, &childStatus, 0);
317
318 if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0)
319 {
320 status = -1;
321 break;
322 }
323 }
324 while (0);
325
326 close(sock);
327
328 return status;
329 }
330
331 /*
332 **==============================================================================
333 **
334 ** struct PAMData
335 **
336 kumpf 1.1.4.2 ** Client data passed to PAM routines.
337 **
338 **==============================================================================
339 */
340
341 typedef struct PAMDataStruct
342 {
343 const char* password;
344 }
345 PAMData;
346
347 /*
348 **==============================================================================
349 **
350 ** PAMAuthenticateCallback()
351 **
352 ** Callback used by PAMAuthenticate().
353 **
354 **==============================================================================
355 */
356
357 kumpf 1.1.4.2 static int PAMAuthenticateCallback(
358 int num_msg,
359 #if defined(PEGASUS_OS_LINUX)
360 const struct pam_message** msg,
361 #else
362 struct pam_message** msg,
363 #endif
364 struct pam_response** resp,
365 void* appdata_ptr)
366 {
367 PAMData* data = (PAMData*)appdata_ptr;
368 int i;
369
370 if (num_msg > 0)
371 {
372 *resp = (struct pam_response*)calloc(
373 num_msg, sizeof(struct pam_response));
374
375 if (*resp == NULL)
376 return PAM_BUF_ERR;
377 }
378 kumpf 1.1.4.2 else
379 return PAM_CONV_ERR;
380
381 for (i = 0; i < num_msg; i++)
382 {
383 switch (msg[i]->msg_style)
384 {
385 case PAM_PROMPT_ECHO_OFF:
386 {
387 resp[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE);
388 Strlcpy(resp[i]->resp, data->password, PAM_MAX_MSG_SIZE);
389 resp[i]->resp_retcode = 0;
390 break;
391 }
392
393 default:
394 return PAM_CONV_ERR;
395 }
396 }
397
398 return PAM_SUCCESS;
399 kumpf 1.1.4.2 }
400
401 /*
402 **==============================================================================
403 **
404 ** PAMValidateUserCallback()
405 **
406 ** Callback used by PAMValidateUser().
407 **
408 **==============================================================================
409 */
410
411 static int PAMValidateUserCallback(
412 int num_msg,
413 #if defined(PEGASUS_OS_LINUX)
414 const struct pam_message** msg,
415 #else
416 struct pam_message** msg,
417 #endif
418 struct pam_response** resp,
419 void* appdata_ptr)
420 kumpf 1.1.4.2 {
421 /* Unused */
422 msg = 0;
423
424 /* Unused */
425 appdata_ptr = 0;
426
427 if (num_msg > 0)
428 {
429 *resp = (struct pam_response*)calloc(
430 num_msg, sizeof(struct pam_response));
431
432 if (*resp == NULL)
433 return PAM_BUF_ERR;
434 }
435 else
436 return PAM_CONV_ERR;
437
438 return PAM_SUCCESS;
439 }
440
441 kumpf 1.1.4.2 /*
442 **==============================================================================
443 **
444 ** PAMAuthenticateInProcess()
445 **
|
446 kumpf 1.1.4.5 ** Performs basic PAM authentication on the given username and password.
|
447 kumpf 1.1.4.2 **
448 **==============================================================================
449 */
450
451 static int PAMAuthenticateInProcess(
452 const char* username, const char* password)
453 {
454 PAMData data;
455 struct pam_conv pconv;
456 pam_handle_t* handle;
457
458 data.password = password;
459 pconv.conv = PAMAuthenticateCallback;
460 pconv.appdata_ptr = &data;
461
462
463 if (pam_start("wbem", username, &pconv, &handle) != PAM_SUCCESS)
464 return -1;
465
466 if (pam_authenticate(handle, 0) != PAM_SUCCESS)
467 {
468 kumpf 1.1.4.2 pam_end(handle, 0);
469 return -1;
470 }
471
472 if (pam_acct_mgmt(handle, 0) != PAM_SUCCESS)
473 {
474 pam_end(handle, 0);
475 return -1;
476 }
477
478 pam_end(handle, 0);
479
480 return 0;
481 }
482
483 /*
484 **==============================================================================
485 **
486 ** PAMValidateUserInProcess()
487 **
488 ** Validate that the *username* refers to a valid PAM user.
489 kumpf 1.1.4.2 **
490 **==============================================================================
491 */
492
493 static int PAMValidateUserInProcess(const char* username)
494 {
495 PAMData data;
496 struct pam_conv pconv;
497 pam_handle_t* phandle;
498
499 pconv.conv = PAMValidateUserCallback;
500 pconv.appdata_ptr = &data;
501
502 if (pam_start("wbem", username, &pconv, &phandle) != PAM_SUCCESS)
503 return -1;
504
505 if (pam_acct_mgmt(phandle, 0) != PAM_SUCCESS)
506 {
507 pam_end(phandle, 0);
508 return -1;
509 }
510 kumpf 1.1.4.2
511 pam_end(phandle, 0);
512
513 return 0;
514 }
515
516 /*
517 **==============================================================================
518 **
519 ** PAMAuthenticate()
520 **
|
521 kumpf 1.1.4.5 ** Performs basic PAM authentication on the given username and password.
|
522 kumpf 1.1.4.2 **
523 **==============================================================================
524 */
525
526 static int PAMAuthenticate(const char* username, const char* password)
527 {
528 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
529 return CimserveraAuthenticate(username, password);
530 #else
531 return PAMAuthenticateInProcess(username, password);
532 #endif
533 }
534
535 /*
536 **==============================================================================
537 **
538 ** PAMValidateUser()
539 **
540 ** Validate that the *username* refers to a valid PAM user.
541 **
542 **==============================================================================
543 kumpf 1.1.4.2 */
544
545 static int PAMValidateUser(const char* username)
546 {
547 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
548 return CimserveraValidateUser(username);
549 #else
550 return PAMValidateUserInProcess(username);
551 #endif
552 }
553
554 #endif /* Executor_PAMAuth_h */
|