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 break;
261 }
|
262 kumpf 1.4
|
263 kumpf 1.5 #if !defined(PEGASUS_ENABLE_PRIVILEGE_SEPARATION)
264 /* When called from the main cimserver process, the cimservera
265 exit status must be harvested explicitly to prevent zombies.
266 */
|
267 kumpf 1.4
|
268 kumpf 1.5 while ((waitpid(pid, 0, 0) == -1) && (errno == EINTR))
269 ;
270 #endif
|
271 kumpf 1.2 }
272 while (0);
273
274 close(sock);
275
276 return status;
277 }
278
279 /*
280 **==============================================================================
281 **
282 ** struct PAMData
283 **
284 ** Client data passed to PAM routines.
285 **
286 **==============================================================================
287 */
288
289 typedef struct PAMDataStruct
290 {
291 const char* password;
292 kumpf 1.2 }
293 PAMData;
294
295 /*
296 **==============================================================================
297 **
298 ** PAMAuthenticateCallback()
299 **
300 ** Callback used by PAMAuthenticate().
301 **
302 **==============================================================================
303 */
304
305 static int PAMAuthenticateCallback(
306 int num_msg,
307 #if defined(PEGASUS_OS_LINUX)
308 const struct pam_message** msg,
309 #else
310 struct pam_message** msg,
311 #endif
312 struct pam_response** resp,
313 kumpf 1.2 void* appdata_ptr)
314 {
315 PAMData* data = (PAMData*)appdata_ptr;
316 int i;
317
318 if (num_msg > 0)
319 {
320 *resp = (struct pam_response*)calloc(
321 num_msg, sizeof(struct pam_response));
322
323 if (*resp == NULL)
324 return PAM_BUF_ERR;
325 }
326 else
327 return PAM_CONV_ERR;
328
329 for (i = 0; i < num_msg; i++)
330 {
331 switch (msg[i]->msg_style)
332 {
333 case PAM_PROMPT_ECHO_OFF:
334 kumpf 1.2 {
335 resp[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE);
336 Strlcpy(resp[i]->resp, data->password, PAM_MAX_MSG_SIZE);
337 resp[i]->resp_retcode = 0;
338 break;
339 }
340
341 default:
342 return PAM_CONV_ERR;
343 }
344 }
345
346 return PAM_SUCCESS;
347 }
348
349 /*
350 **==============================================================================
351 **
352 ** PAMValidateUserCallback()
353 **
354 ** Callback used by PAMValidateUser().
355 kumpf 1.2 **
356 **==============================================================================
357 */
358
359 static int PAMValidateUserCallback(
360 int num_msg,
361 #if defined(PEGASUS_OS_LINUX)
362 const struct pam_message** msg,
363 #else
364 struct pam_message** msg,
365 #endif
366 struct pam_response** resp,
367 void* appdata_ptr)
368 {
369 /* Unused */
370 msg = 0;
371
372 /* Unused */
373 appdata_ptr = 0;
374
375 if (num_msg > 0)
376 kumpf 1.2 {
377 *resp = (struct pam_response*)calloc(
378 num_msg, sizeof(struct pam_response));
379
380 if (*resp == NULL)
381 return PAM_BUF_ERR;
382 }
383 else
384 return PAM_CONV_ERR;
385
386 return PAM_SUCCESS;
387 }
388
389 /*
390 **==============================================================================
391 **
392 ** PAMAuthenticateInProcess()
393 **
394 ** Performs basic PAM authentication on the given username and password.
395 **
396 **==============================================================================
397 kumpf 1.2 */
398
399 static int PAMAuthenticateInProcess(
400 const char* username, const char* password)
401 {
402 PAMData data;
403 struct pam_conv pconv;
404 pam_handle_t* handle;
405
406 data.password = password;
407 pconv.conv = PAMAuthenticateCallback;
408 pconv.appdata_ptr = &data;
409
410
411 if (pam_start("wbem", username, &pconv, &handle) != PAM_SUCCESS)
412 return -1;
413
414 if (pam_authenticate(handle, 0) != PAM_SUCCESS)
415 {
416 pam_end(handle, 0);
417 return -1;
418 kumpf 1.2 }
419
420 if (pam_acct_mgmt(handle, 0) != PAM_SUCCESS)
421 {
422 pam_end(handle, 0);
423 return -1;
424 }
425
426 pam_end(handle, 0);
427
428 return 0;
429 }
430
431 /*
432 **==============================================================================
433 **
434 ** PAMValidateUserInProcess()
435 **
436 ** Validate that the *username* refers to a valid PAM user.
437 **
438 **==============================================================================
439 kumpf 1.2 */
440
441 static int PAMValidateUserInProcess(const char* username)
442 {
443 PAMData data;
444 struct pam_conv pconv;
445 pam_handle_t* phandle;
446
447 pconv.conv = PAMValidateUserCallback;
448 pconv.appdata_ptr = &data;
449
450 if (pam_start("wbem", username, &pconv, &phandle) != PAM_SUCCESS)
451 return -1;
452
453 if (pam_acct_mgmt(phandle, 0) != PAM_SUCCESS)
454 {
455 pam_end(phandle, 0);
456 return -1;
457 }
458
459 pam_end(phandle, 0);
460 kumpf 1.2
461 return 0;
462 }
463
464 /*
465 **==============================================================================
466 **
467 ** PAMAuthenticate()
468 **
469 ** Performs basic PAM authentication on the given username and password.
470 **
471 **==============================================================================
472 */
473
474 static int PAMAuthenticate(const char* username, const char* password)
475 {
476 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
|
477 kumpf 1.5 return CimserveraProcessOperation("authenticate", username, password);
|
478 kumpf 1.2 #else
479 return PAMAuthenticateInProcess(username, password);
480 #endif
481 }
482
483 /*
484 **==============================================================================
485 **
486 ** PAMValidateUser()
487 **
488 ** Validate that the *username* refers to a valid PAM user.
489 **
490 **==============================================================================
491 */
492
493 static int PAMValidateUser(const char* username)
494 {
495 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
|
496 kumpf 1.5 return CimserveraProcessOperation("validateUser", username, "");
|
497 kumpf 1.2 #else
498 return PAMValidateUserInProcess(username);
499 #endif
500 }
501
502 #endif /* Executor_PAMAuth_h */
|