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 #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.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.2 ** CimserveraSend()
86 **
87 ** Sends *size* bytes on the given socket.
88 **
89 **==============================================================================
90 */
91
92 static ssize_t CimserveraSend(int sock, void* buffer, size_t size)
93 {
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 kumpf 1.2
107 r -= n;
108 p += n;
109 }
110
111 return size - r;
112 }
113
114 /*
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 kumpf 1.2 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 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 kumpf 1.2
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 pid = fork();
157
158 if (pid < 0)
|
164 kumpf 1.2
165 /* Child process: */
166
167 if (pid == 0)
168 {
169 char sockStr[32];
170 const char* argv[3];
171
172 close(pair[1]);
173
174 /* Convert socket number to string. */
175
176 sprintf(sockStr, "%d", pair[0]);
177
178 /* Build arguments for execv(). */
179
180 argv[0] = CIMSERVERA;
181 argv[1] = sockStr;
182 argv[2] = 0;
183
184 /* Execute child: */
185 kumpf 1.2
186 /* Flawfinder: ignore */
187 execv(path, (char**)argv);
188 close(pair[0]);
189 _exit(0);
190 }
191
192 /* Parent process: */
193
194 close(pair[0]);
195
196 *sock = pair[1];
197 return pid;
198 }
199
200 /*
201 **==============================================================================
202 **
203 ** CimserveraRequest
204 **
205 **==============================================================================
206 kumpf 1.2 */
207
208 typedef struct CimserveraRequestStruct
209 {
210 char arg0[EXECUTOR_BUFFER_SIZE];
211 char arg1[EXECUTOR_BUFFER_SIZE];
212 char arg2[EXECUTOR_BUFFER_SIZE];
213 }
214 CimserveraRequest;
215
216 /*
217 **==============================================================================
218 **
219 ** CimserveraAuthenticate()
220 **
221 **==============================================================================
222 */
223
224 static int CimserveraAuthenticate(const char* username, const char* password)
225 {
226 int sock;
227 kumpf 1.2 int pid;
228 int status;
229
230 /* Create the CIMSERVERA process. */
231
232 pid = CimserveraStart(&sock);
233
234 if (pid == -1)
235 return -1;
236
237 /* Send request, get response. */
238
239 status = 0;
240
241 do
242 {
243 CimserveraRequest request;
244 int childStatus;
245
246 /* Send request to CIMSERVERA process. */
247
248 kumpf 1.2 memset(&request, 0, sizeof(request));
249 Strlcpy(request.arg0, "authenticate", EXECUTOR_BUFFER_SIZE);
250 Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE);
251 Strlcpy(request.arg2, password, EXECUTOR_BUFFER_SIZE);
252
253 if (CimserveraSend(sock, &request, sizeof(request)) != sizeof(request))
254 {
255 status = -1;
256 break;
257 }
258
259 /* Get exit status from CIMSERVERA program. */
260
261 waitpid(pid, &childStatus, 0);
262
263 if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0)
264 {
265 status = -1;
266 break;
267 }
268 }
269 kumpf 1.2 while (0);
270
271 close(sock);
272
273 return status;
274 }
275
276 /*
277 **==============================================================================
278 **
279 ** CimserveraValidateUser()
280 **
281 **==============================================================================
282 */
283
284 static int CimserveraValidateUser(const char* username)
285 {
286 int sock;
287 int pid;
288 int status;
289
290 kumpf 1.2 /* Create the CIMSERVERA process. */
291
292 pid = CimserveraStart(&sock);
293
294 if (pid == -1)
295 return -1;
296
297 /* Send request, get response. */
298
299 status = 0;
300
301 do
302 {
303 CimserveraRequest request;
304 int childStatus;
305
306 /* Send request to CIMSERVERA process. */
307
308 memset(&request, 0, sizeof(request));
309 Strlcpy(request.arg0, "validateUser", EXECUTOR_BUFFER_SIZE);
310 Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE);
311 kumpf 1.2
312 if (CimserveraSend(sock, &request, sizeof(request)) != sizeof(request))
313 {
314 status = -1;
315 break;
316 }
317
318 /* Get exit status from CIMSERVERA program. */
319
320 waitpid(pid, &childStatus, 0);
321
322 if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0)
323 {
324 status = -1;
325 break;
326 }
327 }
328 while (0);
329
330 close(sock);
331
332 kumpf 1.2 return status;
333 }
334
335 /*
336 **==============================================================================
337 **
338 ** struct PAMData
339 **
340 ** Client data passed to PAM routines.
341 **
342 **==============================================================================
343 */
344
345 typedef struct PAMDataStruct
346 {
347 const char* password;
348 }
349 PAMData;
350
351 /*
352 **==============================================================================
353 kumpf 1.2 **
354 ** PAMAuthenticateCallback()
355 **
356 ** Callback used by PAMAuthenticate().
357 **
358 **==============================================================================
359 */
360
361 static int PAMAuthenticateCallback(
362 int num_msg,
363 #if defined(PEGASUS_OS_LINUX)
364 const struct pam_message** msg,
365 #else
366 struct pam_message** msg,
367 #endif
368 struct pam_response** resp,
369 void* appdata_ptr)
370 {
371 PAMData* data = (PAMData*)appdata_ptr;
372 int i;
373
374 kumpf 1.2 if (num_msg > 0)
375 {
376 *resp = (struct pam_response*)calloc(
377 num_msg, sizeof(struct pam_response));
378
379 if (*resp == NULL)
380 return PAM_BUF_ERR;
381 }
382 else
383 return PAM_CONV_ERR;
384
385 for (i = 0; i < num_msg; i++)
386 {
387 switch (msg[i]->msg_style)
388 {
389 case PAM_PROMPT_ECHO_OFF:
390 {
391 resp[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE);
392 Strlcpy(resp[i]->resp, data->password, PAM_MAX_MSG_SIZE);
393 resp[i]->resp_retcode = 0;
394 break;
395 kumpf 1.2 }
396
397 default:
398 return PAM_CONV_ERR;
399 }
400 }
401
402 return PAM_SUCCESS;
403 }
404
405 /*
406 **==============================================================================
407 **
408 ** PAMValidateUserCallback()
409 **
410 ** Callback used by PAMValidateUser().
411 **
412 **==============================================================================
413 */
414
415 static int PAMValidateUserCallback(
416 kumpf 1.2 int num_msg,
417 #if defined(PEGASUS_OS_LINUX)
418 const struct pam_message** msg,
419 #else
420 struct pam_message** msg,
421 #endif
422 struct pam_response** resp,
423 void* appdata_ptr)
424 {
425 /* Unused */
426 msg = 0;
427
428 /* Unused */
429 appdata_ptr = 0;
430
431 if (num_msg > 0)
432 {
433 *resp = (struct pam_response*)calloc(
434 num_msg, sizeof(struct pam_response));
435
436 if (*resp == NULL)
437 kumpf 1.2 return PAM_BUF_ERR;
438 }
439 else
440 return PAM_CONV_ERR;
441
442 return PAM_SUCCESS;
443 }
444
445 /*
446 **==============================================================================
447 **
448 ** PAMAuthenticateInProcess()
449 **
450 ** Performs basic PAM authentication on the given username and password.
451 **
452 **==============================================================================
453 */
454
455 static int PAMAuthenticateInProcess(
456 const char* username, const char* password)
457 {
458 kumpf 1.2 PAMData data;
459 struct pam_conv pconv;
460 pam_handle_t* handle;
461
462 data.password = password;
463 pconv.conv = PAMAuthenticateCallback;
464 pconv.appdata_ptr = &data;
465
466
467 if (pam_start("wbem", username, &pconv, &handle) != PAM_SUCCESS)
468 return -1;
469
470 if (pam_authenticate(handle, 0) != PAM_SUCCESS)
471 {
472 pam_end(handle, 0);
473 return -1;
474 }
475
476 if (pam_acct_mgmt(handle, 0) != PAM_SUCCESS)
477 {
478 pam_end(handle, 0);
479 kumpf 1.2 return -1;
480 }
481
482 pam_end(handle, 0);
483
484 return 0;
485 }
486
487 /*
488 **==============================================================================
489 **
490 ** PAMValidateUserInProcess()
491 **
492 ** Validate that the *username* refers to a valid PAM user.
493 **
494 **==============================================================================
495 */
496
497 static int PAMValidateUserInProcess(const char* username)
498 {
499 PAMData data;
500 kumpf 1.2 struct pam_conv pconv;
501 pam_handle_t* phandle;
502
503 pconv.conv = PAMValidateUserCallback;
504 pconv.appdata_ptr = &data;
505
506 if (pam_start("wbem", username, &pconv, &phandle) != PAM_SUCCESS)
507 return -1;
508
509 if (pam_acct_mgmt(phandle, 0) != PAM_SUCCESS)
510 {
511 pam_end(phandle, 0);
512 return -1;
513 }
514
515 pam_end(phandle, 0);
516
517 return 0;
518 }
519
520 /*
521 kumpf 1.2 **==============================================================================
522 **
523 ** PAMAuthenticate()
524 **
525 ** Performs basic PAM authentication on the given username and password.
526 **
527 **==============================================================================
528 */
529
530 static int PAMAuthenticate(const char* username, const char* password)
531 {
532 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
533 return CimserveraAuthenticate(username, password);
534 #else
535 return PAMAuthenticateInProcess(username, password);
536 #endif
537 }
538
539 /*
540 **==============================================================================
541 **
542 kumpf 1.2 ** PAMValidateUser()
543 **
544 ** Validate that the *username* refers to a valid PAM user.
545 **
546 **==============================================================================
547 */
548
549 static int PAMValidateUser(const char* username)
550 {
551 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
552 return CimserveraValidateUser(username);
553 #else
554 return PAMValidateUserInProcess(username);
555 #endif
556 }
557
558 #endif /* Executor_PAMAuth_h */
|