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 kumpf 1.5 ** PAMAuthenticate()
67 ** PAMValidateUser()
|
68 kumpf 1.2 **
|
69 kumpf 1.5 ** Depending on the PEGASUS_USE_PAM_STANDALONE_PROC build flag, these
70 ** functions either call PAM directly or fork and execute a child process
71 ** that performs the requested PAM operation and then exits immediately.
72 ** The parent and child proceses communicate over a local domain socket,
73 ** created by the parent just before executing the client program.
|
74 kumpf 1.2 **
|
75 kumpf 1.5 ** These functions are defined in a header file to avoid the need
|
76 kumpf 1.2 ** to link a separate client library.
77 **
78 ** CAUTION: This program must not depend on any Pegasus libraries since
79 ** it is used by the executor process.
80 **
81 **==============================================================================
82 */
83
84 /*
85 **==============================================================================
86 **
87 ** CimserveraStart()
88 **
89 ** Starts the CIMSERVERA program, returning a socket used to communicate
90 ** with it.
91 **
92 **==============================================================================
93 */
94
95 static int CimserveraStart(int* sock)
96 {
97 kumpf 1.2 int pair[2];
98 int pid;
99
100 /* Get absolute path of CIMSERVERA program. */
101
102 char path[EXECUTOR_BUFFER_SIZE];
103
104 if (PEGASUS_PAM_STANDALONE_PROC_NAME[0] == '/')
105 Strlcpy(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
106 else
107 {
108 /* Flawfinder: ignore */
109 const char* home = getenv("PEGASUS_HOME");
110
111 if (!home)
112 return -1;
113
114 Strlcpy(path, home, EXECUTOR_BUFFER_SIZE);
115 Strlcat(path, "/", EXECUTOR_BUFFER_SIZE);
116 Strlcat(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
117 }
118 kumpf 1.2
119 /* Create socket pair for communicating with child process. */
120
121 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0)
122 return -1;
123
124 /* Fork child: */
125
126 pid = fork();
127
128 if (pid < 0)
|
129 kumpf 1.3 {
130 close(pair[0]);
131 close(pair[1]);
|
132 kumpf 1.2 return -1;
|
133 kumpf 1.3 }
|
134 kumpf 1.2
135 /* Child process: */
136
137 if (pid == 0)
138 {
139 char sockStr[32];
140 const char* argv[3];
141
142 close(pair[1]);
143
144 /* Convert socket number to string. */
145
146 sprintf(sockStr, "%d", pair[0]);
147
148 /* Build arguments for execv(). */
149
150 argv[0] = CIMSERVERA;
151 argv[1] = sockStr;
152 argv[2] = 0;
153
154 /* Execute child: */
155 kumpf 1.2
156 /* Flawfinder: ignore */
157 execv(path, (char**)argv);
158 close(pair[0]);
159 _exit(0);
160 }
161
162 /* Parent process: */
163
164 close(pair[0]);
165
166 *sock = pair[1];
167 return pid;
168 }
169
170 /*
171 **==============================================================================
172 **
173 ** CimserveraRequest
174 **
175 **==============================================================================
176 kumpf 1.2 */
177
178 typedef struct CimserveraRequestStruct
179 {
180 char arg0[EXECUTOR_BUFFER_SIZE];
181 char arg1[EXECUTOR_BUFFER_SIZE];
182 char arg2[EXECUTOR_BUFFER_SIZE];
183 }
184 CimserveraRequest;
185
186 /*
187 **==============================================================================
188 **
|
189 kumpf 1.4 ** CimserveraResponse
190 **
191 **==============================================================================
192 */
193
194 typedef struct CimserveraResponseStruct
195 {
196 /* '0' means authentication successful. '-1' means authentication failed. */
197 int status;
198 }
199 CimserveraResponse;
200
201 /*
202 **==============================================================================
203 **
|
204 kumpf 1.5 ** CimserveraProcessOperation()
|
205 kumpf 1.2 **
206 **==============================================================================
207 */
208
|
209 kumpf 1.5 static int CimserveraProcessOperation(
210 const char* operationName,
211 const char* username,
212 const char* password)
|
213 kumpf 1.2 {
214 int sock;
215 int pid;
216 int status;
217
218 /* Create the CIMSERVERA process. */
219
220 pid = CimserveraStart(&sock);
221
222 if (pid == -1)
223 return -1;
224
225 /* Send request, get response. */
226
227 status = 0;
228
229 do
230 {
231 CimserveraRequest request;
|
232 kumpf 1.4 CimserveraResponse response;
|
233 kumpf 1.2
234 /* Send request to CIMSERVERA process. */
235
236 memset(&request, 0, sizeof(request));
|
237 kumpf 1.5 Strlcpy(request.arg0, operationName, EXECUTOR_BUFFER_SIZE);
|
238 kumpf 1.2 Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE);
239 Strlcpy(request.arg2, password, EXECUTOR_BUFFER_SIZE);
240
|
241 kumpf 1.4 if (SendBlock(sock, &request, sizeof(request)) != sizeof(request))
|
242 kumpf 1.2 {
243 status = -1;
244 break;
245 }
246
|
247 kumpf 1.4 /* Receive response from CIMSERVERA process. */
248
249 if (RecvBlock(sock, &response, sizeof(response)) != sizeof(response))
250 {
251 status = -1;
252 break;
253 }
|
254 kumpf 1.2
|
255 kumpf 1.4 /* Check status. */
|
256 kumpf 1.2
|
257 kumpf 1.4 if (response.status != 0)
|
258 kumpf 1.2 {
259 status = -1;
260 }
|
261 venkat.puvvada 1.5.20.1 }
262 while (0);
|
263 kumpf 1.4
|
264 kumpf 1.5 #if !defined(PEGASUS_ENABLE_PRIVILEGE_SEPARATION)
|
265 venkat.puvvada 1.5.20.1 /* When called from the main cimserver process, the cimservera
266 exit status must be harvested explicitly to prevent zombies.
267 */
|
268 kumpf 1.4
|
269 venkat.puvvada 1.5.20.1 while ((waitpid(pid, 0, 0) == -1) && (errno == EINTR))
270 ;
|
271 kumpf 1.5 #endif
|
272 kumpf 1.2
273 close(sock);
274
275 return status;
276 }
277
278 /*
279 **==============================================================================
280 **
281 ** struct PAMData
282 **
283 ** Client data passed to PAM routines.
284 **
285 **==============================================================================
286 */
287
288 typedef struct PAMDataStruct
289 {
290 const char* password;
291 }
292 PAMData;
293 kumpf 1.2
294 /*
295 **==============================================================================
296 **
297 ** PAMAuthenticateCallback()
298 **
299 ** Callback used by PAMAuthenticate().
300 **
301 **==============================================================================
302 */
303
304 static int PAMAuthenticateCallback(
305 int num_msg,
306 #if defined(PEGASUS_OS_LINUX)
307 const struct pam_message** msg,
308 #else
309 struct pam_message** msg,
310 #endif
311 struct pam_response** resp,
312 void* appdata_ptr)
313 {
314 kumpf 1.2 PAMData* data = (PAMData*)appdata_ptr;
315 int i;
316
317 if (num_msg > 0)
318 {
319 *resp = (struct pam_response*)calloc(
320 num_msg, sizeof(struct pam_response));
321
322 if (*resp == NULL)
323 return PAM_BUF_ERR;
324 }
325 else
326 return PAM_CONV_ERR;
327
328 for (i = 0; i < num_msg; i++)
329 {
330 switch (msg[i]->msg_style)
331 {
332 case PAM_PROMPT_ECHO_OFF:
333 {
334 resp[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE);
335 kumpf 1.2 Strlcpy(resp[i]->resp, data->password, PAM_MAX_MSG_SIZE);
336 resp[i]->resp_retcode = 0;
337 break;
338 }
339
340 default:
341 return PAM_CONV_ERR;
342 }
343 }
344
345 return PAM_SUCCESS;
346 }
347
348 /*
349 **==============================================================================
350 **
351 ** PAMValidateUserCallback()
352 **
353 ** Callback used by PAMValidateUser().
354 **
355 **==============================================================================
356 kumpf 1.2 */
357
358 static int PAMValidateUserCallback(
359 int num_msg,
360 #if defined(PEGASUS_OS_LINUX)
361 const struct pam_message** msg,
362 #else
363 struct pam_message** msg,
364 #endif
365 struct pam_response** resp,
366 void* appdata_ptr)
367 {
368 /* Unused */
369 msg = 0;
370
371 /* Unused */
372 appdata_ptr = 0;
373
374 if (num_msg > 0)
375 {
376 *resp = (struct pam_response*)calloc(
377 kumpf 1.2 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 return PAM_SUCCESS;
386 }
387
388 /*
389 **==============================================================================
390 **
391 ** PAMAuthenticateInProcess()
392 **
393 ** Performs basic PAM authentication on the given username and password.
394 **
395 **==============================================================================
396 */
397
398 kumpf 1.2 static int PAMAuthenticateInProcess(
399 const char* username, const char* password)
400 {
401 PAMData data;
402 struct pam_conv pconv;
403 pam_handle_t* handle;
404
405 data.password = password;
406 pconv.conv = PAMAuthenticateCallback;
407 pconv.appdata_ptr = &data;
408
409
410 if (pam_start("wbem", username, &pconv, &handle) != PAM_SUCCESS)
411 return -1;
412
413 if (pam_authenticate(handle, 0) != PAM_SUCCESS)
414 {
415 pam_end(handle, 0);
416 return -1;
417 }
418
419 kumpf 1.2 if (pam_acct_mgmt(handle, 0) != PAM_SUCCESS)
420 {
421 pam_end(handle, 0);
422 return -1;
423 }
424
425 pam_end(handle, 0);
426
427 return 0;
428 }
429
430 /*
431 **==============================================================================
432 **
433 ** PAMValidateUserInProcess()
434 **
435 ** Validate that the *username* refers to a valid PAM user.
436 **
437 **==============================================================================
438 */
439
440 kumpf 1.2 static int PAMValidateUserInProcess(const char* username)
441 {
442 PAMData data;
443 struct pam_conv pconv;
444 pam_handle_t* phandle;
445
446 pconv.conv = PAMValidateUserCallback;
447 pconv.appdata_ptr = &data;
448
449 if (pam_start("wbem", username, &pconv, &phandle) != PAM_SUCCESS)
450 return -1;
451
452 if (pam_acct_mgmt(phandle, 0) != PAM_SUCCESS)
453 {
454 pam_end(phandle, 0);
455 return -1;
456 }
457
458 pam_end(phandle, 0);
459
460 return 0;
461 kumpf 1.2 }
462
463 /*
464 **==============================================================================
465 **
466 ** PAMAuthenticate()
467 **
468 ** Performs basic PAM authentication on the given username and password.
469 **
470 **==============================================================================
471 */
472
473 static int PAMAuthenticate(const char* username, const char* password)
474 {
475 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
|
476 kumpf 1.5 return CimserveraProcessOperation("authenticate", username, password);
|
477 kumpf 1.2 #else
478 return PAMAuthenticateInProcess(username, password);
479 #endif
480 }
481
482 /*
483 **==============================================================================
484 **
485 ** PAMValidateUser()
486 **
487 ** Validate that the *username* refers to a valid PAM user.
488 **
489 **==============================================================================
490 */
491
492 static int PAMValidateUser(const char* username)
493 {
494 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
|
495 kumpf 1.5 return CimserveraProcessOperation("validateUser", username, "");
|
496 kumpf 1.2 #else
497 return PAMValidateUserInProcess(username);
498 #endif
499 }
500
501 #endif /* Executor_PAMAuth_h */
|