1 mike 1.1.2.1 /*
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 mike 1.1.2.1 // 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 mike 1.1.2.1 #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 #define CIMSERVERA "cimservera"
56
57 /*
58 **==============================================================================
59 **
60 ** cimservera
61 **
62 ** This program is used to authenticate users with the "Basic PAM
63 ** Authentication" scheme. It was originally written to isolate memory
64 mike 1.1.2.1 ** PAM module errors to an external process.
65 **
66 ** This header defines two functions that may be called by clients of this
67 ** process (the parent process).
68 **
69 ** CimserveraAuthenticate()
70 ** CimserveraValidateUser()
71 **
72 ** Each functions forks and executes a child process that carries out
73 ** the request and then exits immediately. The parent and child proceses
74 ** communicate over a local domain socket, created by the parent just
75 ** before executing the client program.
76 **
77 ** Both of the functions above are defined in the header to avoid the need
78 ** to link a separate client library.
79 **
80 ** CAUTION: This program must not depend on any Pegasus libraries since
81 ** it is used by the executor process.
82 **
83 **==============================================================================
84 */
85 mike 1.1.2.1
86 /*
87 **==============================================================================
88 **
89 ** CimserveaSend()
90 **
91 ** Sends *size* bytes on the given socket.
92 **
93 **==============================================================================
94 */
95
96 static ssize_t CimserveaSend(int sock, void* buffer, size_t size)
97 {
98 size_t r = size;
99 char* p = (char*)buffer;
100
101 while (r)
102 {
103 ssize_t n;
104 EXECUTOR_RESTART(write(sock, p, r), n);
105
106 mike 1.1.2.1 if (n == -1)
107 return -1;
108 else if (n == 0)
109 return size - r;
110
111 r -= n;
112 p += n;
113 }
114
115 return size - r;
116 }
117
118 /*
119 **==============================================================================
120 **
121 ** CimserveraStart()
122 **
123 ** Starts the cimservera program, returning a socket used to communicate
124 ** with it.
125 **
126 **==============================================================================
127 mike 1.1.2.1 */
128
129 static int CimserveraStart(int* sock)
130 {
131 int pair[2];
132 int pid;
133
134 /* Get absolute path of "cimservera" program. */
135
136 char path[EXECUTOR_BUFFER_SIZE];
137
138 if (PEGASUS_PAM_STANDALONE_PROC_NAME[0] == '/')
139 Strlcpy(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
140 else
141 {
142 /* Flawfinder: ignore */
143 const char* home = getenv("PEGASUS_HOME");
144
145 if (!home)
146 return -1;
147
148 mike 1.1.2.1 Strlcpy(path, home, EXECUTOR_BUFFER_SIZE);
149 Strlcat(path, "/", EXECUTOR_BUFFER_SIZE);
150 Strlcat(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
151 }
152
153 /* Create socket pair for communicating with child process. */
154
155 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0)
156 return -1;
157
158 /* Fork child: */
159
160 pid = fork();
161
162 if (pid < 0)
163 return -1;
164
165 /* Child process: */
166
167 if (pid == 0)
168 {
169 mike 1.1.2.1 char sockStr[32];
170 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
186 /* Flawfinder: ignore */
187 execv(path, argv);
188 close(pair[0]);
189 _exit(0);
190 mike 1.1.2.1 }
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 */
207
208 typedef struct CimserveraRequestStruct
209 {
210 char arg0[EXECUTOR_BUFFER_SIZE];
211 mike 1.1.2.1 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 int pid;
228 int status;
229
230 /* Create the CIMSERVERA process. */
231
232 mike 1.1.2.1 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 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 mike 1.1.2.1 if (CimserveaSend(sock, &request, sizeof(request)) != sizeof(request))
254 {
255 status = -1;
256 break;
257 }
258
259 /* Get exist 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 while (0);
270
271 close(sock);
272
273 return status;
274 mike 1.1.2.1 }
275
276 /*
277 **==============================================================================
278 **
279 ** CimserveraAuthenticate()
280 **
281 **==============================================================================
282 */
283
284 static int CimserveraValidateUser(const char* username)
285 {
286 int sock;
287 int pid;
288 int status;
289
290 /* Create the CIMSERVERA process. */
291
292 pid = CimserveraStart(&sock);
293
294 if (pid == -1)
295 mike 1.1.2.1 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
312 if (CimserveaSend(sock, &request, sizeof(request)) != sizeof(request))
313 {
314 status = -1;
315 break;
316 mike 1.1.2.1 }
317
318 /* Get exist 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 return status;
333 }
334
335 /*
336 **==============================================================================
337 mike 1.1.2.1 **
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 **
354 ** PAMAuthenticateCallback()
355 **
356 ** Callback used by PAMAuthenticate().
357 **
358 mike 1.1.2.1 **==============================================================================
359 */
360
361 static int PAMAuthenticateCallback(
362 int num_msg,
363 const struct pam_message** msg,
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 else
379 mike 1.1.2.1 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 }
400 mike 1.1.2.1
401 /*
402 **==============================================================================
403 **
404 ** PAMValidateUserCallback()
405 **
406 ** Callback used by PAMValidateUser().
407 **
408 **==============================================================================
409 */
410
411 static int PAMValidateUserCallback(
412 int num_msg,
413 const struct pam_message** msg,
414 struct pam_response** resp,
415 void* appdata_ptr)
416 {
417 if (num_msg > 0)
418 {
419 *resp = (struct pam_response*)calloc(
420 num_msg, sizeof(struct pam_response));
421 mike 1.1.2.1
422 if (*resp == NULL)
423 return PAM_BUF_ERR;
424 }
425 else
426 return PAM_CONV_ERR;
427
428 return PAM_SUCCESS;
429 }
430
431 /*
432 **==============================================================================
433 **
434 ** PAMAuthenticateInProcess()
435 **
436 ** Peforms basic PAM authentication on the given username and password.
437 **
438 **==============================================================================
439 */
440
441 static int PAMAuthenticateInProcess(const char* username, const char* password)
442 mike 1.1.2.1 {
443 PAMData data;
444 struct pam_conv pconv;
445 pam_handle_t* handle;
446
447 data.password = password;
448 pconv.conv = PAMAuthenticateCallback;
449 pconv.appdata_ptr = &data;
450
451
452 if (pam_start("wbem", username, &pconv, &handle) != PAM_SUCCESS)
453 return -1;
454
455 if (pam_authenticate(handle, 0) != PAM_SUCCESS)
456 {
457 pam_end(handle, 0);
458 return -1;
459 }
460
461 if (pam_acct_mgmt(handle, 0) != PAM_SUCCESS)
462 {
463 mike 1.1.2.1 pam_end(handle, 0);
464 return -1;
465 }
466
467 pam_end(handle, 0);
468
469 return 0;
470 }
471
472 /*
473 **==============================================================================
474 **
475 ** PAMValidateUserInProcess()
476 **
477 ** Validate that the *username* refers to a valid PAM user.
478 **
479 **==============================================================================
480 */
481
482 static int PAMValidateUserInProcess(const char* username)
483 {
484 mike 1.1.2.1 PAMData data;
485 struct pam_conv pconv;
486 pam_handle_t* phandle;
487
488 pconv.conv = PAMValidateUserCallback;
489 pconv.appdata_ptr = &data;
490
491 if (pam_start("wbem", username, &pconv, &phandle) != PAM_SUCCESS)
492 return -1;
493
494 if (pam_acct_mgmt(phandle, 0) != PAM_SUCCESS)
495 {
496 pam_end(phandle, 0);
497 return -1;
498 }
499
500 pam_end(phandle, 0);
501
502 return 0;
503 }
504
505 mike 1.1.2.1 /*
506 **==============================================================================
507 **
508 ** PAMAuthenticate()
509 **
510 ** Peforms basic PAM authentication on the given username and password.
511 **
512 **==============================================================================
513 */
514
515 static int PAMAuthenticate(const char* username, const char* password)
516 {
517 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
518 return CimserveraAuthenticate(username, password);
519 #else
520 return PAMAuthenticateInProcess(username, password);
521 #endif
522 }
523
524 /*
525 **==============================================================================
526 mike 1.1.2.1 **
527 ** PAMValidateUser()
528 **
529 ** Validate that the *username* refers to a valid PAM user.
530 **
531 **==============================================================================
532 */
533
534 static int PAMValidateUser(const char* username)
535 {
536 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
537 return CimserveraValidateUser(username);
538 #else
539 return PAMValidateUserInProcess(username);
540 #endif
541 }
542
543 #endif /* Executor_PAMAuth_h */
|