1 kumpf 1.2 /*
|
2 martin 1.6 //%LICENSE////////////////////////////////////////////////////////////////
|
3 martin 1.7 //
|
4 martin 1.6 // Licensed to The Open Group (TOG) under one or more contributor license
5 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
6 // this work for additional information regarding copyright ownership.
7 // Each contributor licenses this file to you under the OpenPegasus Open
8 // Source License; you may not use this file except in compliance with the
9 // License.
|
10 martin 1.7 //
|
11 martin 1.6 // Permission is hereby granted, free of charge, to any person obtaining a
12 // copy of this software and associated documentation files (the "Software"),
13 // to deal in the Software without restriction, including without limitation
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 // and/or sell copies of the Software, and to permit persons to whom the
16 // Software is furnished to do so, subject to the following conditions:
|
17 martin 1.7 //
|
18 martin 1.6 // The above copyright notice and this permission notice shall be included
19 // in all copies or substantial portions of the Software.
|
20 martin 1.7 //
|
21 martin 1.6 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
22 martin 1.7 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
23 martin 1.6 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28 martin 1.7 //
|
29 martin 1.6 //////////////////////////////////////////////////////////////////////////
|
30 kumpf 1.2 */
31
32 #ifndef Executor_PAMAuth_h
33 #define Executor_PAMAuth_h
34
35 #if !defined(PEGASUS_PAM_AUTHENTICATION)
36 # error "Do not include this file without defining PEGASUS_PAM_AUTHENTICATION"
37 #endif
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/wait.h>
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <Executor/Strlcpy.h>
47 #include <Executor/Strlcat.h>
48 #include <security/pam_appl.h>
|
49 kumpf 1.4 #include <Executor/Defines.h>
50 #include <Executor/Socket.h>
|
51 kumpf 1.2
|
52 s.kodali 1.9 #ifdef PEGASUS_FLAVOR
53 # define PAM_CONFIG_FILE "wbem" PEGASUS_FLAVOR
54 #else
55 # define PAM_CONFIG_FILE "wbem"
56 #endif
57
|
58 kumpf 1.2 /*
59 **==============================================================================
60 **
61 ** This program is used to authenticate users with the "Basic PAM
62 ** Authentication" scheme. It was originally written to isolate memory
63 ** PAM module errors to an external process.
64 **
65 ** This header defines two functions that may be called by clients of this
66 ** process (the parent process).
67 **
|
68 kumpf 1.5 ** PAMAuthenticate()
69 ** PAMValidateUser()
|
70 kumpf 1.2 **
|
71 kumpf 1.5 ** Depending on the PEGASUS_USE_PAM_STANDALONE_PROC build flag, these
72 ** functions either call PAM directly or fork and execute a child process
73 ** that performs the requested PAM operation and then exits immediately.
74 ** The parent and child proceses communicate over a local domain socket,
75 ** created by the parent just before executing the client program.
|
76 kumpf 1.2 **
|
77 kumpf 1.5 ** These functions are defined in a header file to avoid the need
|
78 kumpf 1.2 ** 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
86 /*
87 **==============================================================================
88 **
89 ** CimserveraStart()
90 **
91 ** Starts the CIMSERVERA program, returning a socket used to communicate
92 ** with it.
93 **
94 **==============================================================================
95 */
96
97 static int CimserveraStart(int* sock)
98 {
99 kumpf 1.2 int pair[2];
100 int pid;
101
102 /* Get absolute path of CIMSERVERA program. */
103
104 char path[EXECUTOR_BUFFER_SIZE];
105
106 if (PEGASUS_PAM_STANDALONE_PROC_NAME[0] == '/')
107 Strlcpy(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
108 else
109 {
110 /* Flawfinder: ignore */
111 const char* home = getenv("PEGASUS_HOME");
112
113 if (!home)
114 return -1;
115
116 Strlcpy(path, home, EXECUTOR_BUFFER_SIZE);
117 Strlcat(path, "/", EXECUTOR_BUFFER_SIZE);
118 Strlcat(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE);
119 }
120 kumpf 1.2
121 /* Create socket pair for communicating with child process. */
122
123 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0)
124 return -1;
125
126 /* Fork child: */
127
128 pid = fork();
129
130 if (pid < 0)
|
131 kumpf 1.3 {
132 close(pair[0]);
133 close(pair[1]);
|
134 kumpf 1.2 return -1;
|
135 kumpf 1.3 }
|
136 kumpf 1.2
137 /* Child process: */
138
139 if (pid == 0)
140 {
141 char sockStr[32];
142 const char* argv[3];
143
144 close(pair[1]);
145
146 /* Convert socket number to string. */
147
148 sprintf(sockStr, "%d", pair[0]);
149
150 /* Build arguments for execv(). */
151
152 argv[0] = CIMSERVERA;
153 argv[1] = sockStr;
154 argv[2] = 0;
155
156 /* Execute child: */
157 kumpf 1.2
158 /* Flawfinder: ignore */
159 execv(path, (char**)argv);
160 close(pair[0]);
161 _exit(0);
162 }
163
164 /* Parent process: */
165
166 close(pair[0]);
167
168 *sock = pair[1];
169 return pid;
170 }
171
172 /*
173 **==============================================================================
174 **
175 ** CimserveraRequest
176 **
177 **==============================================================================
178 kumpf 1.2 */
179
180 typedef struct CimserveraRequestStruct
181 {
182 char arg0[EXECUTOR_BUFFER_SIZE];
183 char arg1[EXECUTOR_BUFFER_SIZE];
184 char arg2[EXECUTOR_BUFFER_SIZE];
185 }
186 CimserveraRequest;
187
188 /*
189 **==============================================================================
190 **
|
191 kumpf 1.4 ** CimserveraResponse
192 **
193 **==============================================================================
194 */
195
196 typedef struct CimserveraResponseStruct
197 {
|
198 marek 1.10 /* '-1' means authentication failed / something went wrong in the
199 communication
200 '>=0' means PAM return code. */
|
201 kumpf 1.4 int status;
202 }
203 CimserveraResponse;
204
205 /*
206 **==============================================================================
207 **
|
208 kumpf 1.5 ** CimserveraProcessOperation()
|
209 kumpf 1.2 **
210 **==============================================================================
211 */
212
|
213 kumpf 1.5 static int CimserveraProcessOperation(
214 const char* operationName,
215 const char* username,
216 const char* password)
|
217 kumpf 1.2 {
218 int sock;
219 int pid;
220 int status;
221
222 /* Create the CIMSERVERA process. */
223
224 pid = CimserveraStart(&sock);
225
226 if (pid == -1)
227 return -1;
228
229 /* Send request, get response. */
230
231 status = 0;
232
233 do
234 {
235 CimserveraRequest request;
|
236 kumpf 1.4 CimserveraResponse response;
|
237 kumpf 1.2
238 /* Send request to CIMSERVERA process. */
239
240 memset(&request, 0, sizeof(request));
|
241 kumpf 1.5 Strlcpy(request.arg0, operationName, EXECUTOR_BUFFER_SIZE);
|
242 kumpf 1.2 Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE);
243 Strlcpy(request.arg2, password, EXECUTOR_BUFFER_SIZE);
244
|
245 kumpf 1.4 if (SendBlock(sock, &request, sizeof(request)) != sizeof(request))
|
246 kumpf 1.2 {
247 status = -1;
248 break;
249 }
250
|
251 kumpf 1.4 /* Receive response from CIMSERVERA process. */
252
253 if (RecvBlock(sock, &response, sizeof(response)) != sizeof(response))
254 {
255 status = -1;
256 break;
257 }
|
258 kumpf 1.2
|
259 marek 1.10 /* Store status. */
|
260 kumpf 1.2
|
261 marek 1.10 status = response.status;
|
262 venkat.puvvada 1.8 }
263 while (0);
|
264 kumpf 1.4
|
265 kumpf 1.5 #if !defined(PEGASUS_ENABLE_PRIVILEGE_SEPARATION)
|
266 venkat.puvvada 1.8 /* When called from the main cimserver process, the cimservera
267 exit status must be harvested explicitly to prevent zombies.
268 */
|
269 kumpf 1.4
|
270 venkat.puvvada 1.8 while ((waitpid(pid, 0, 0) == -1) && (errno == EINTR))
271 ;
|
272 kumpf 1.5 #endif
|
273 kumpf 1.2
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 }
293 PAMData;
294 kumpf 1.2
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 void* appdata_ptr)
314 {
315 kumpf 1.2 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 {
335 resp[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE);
336 kumpf 1.2 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 **
356 **==============================================================================
357 kumpf 1.2 */
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 {
377 *resp = (struct pam_response*)calloc(
378 kumpf 1.2 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 */
398
399 kumpf 1.2 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 marek 1.10 int pam_rc;
|
406 kumpf 1.2
407 data.password = password;
408 pconv.conv = PAMAuthenticateCallback;
409 pconv.appdata_ptr = &data;
410
|
411 marek 1.10 /* commented out statement in place to allow triggering a Http 500 Error */
412 /* intentionally for testing purposes */
413 /* return PAM_SERVICE_ERR; */
|
414 kumpf 1.2
|
415 marek 1.10 pam_rc = pam_start(PAM_CONFIG_FILE, username, &pconv, &handle);
|
416 kumpf 1.2
|
417 marek 1.10 if (pam_rc != PAM_SUCCESS)
|
418 kumpf 1.2 {
|
419 marek 1.10 return pam_rc;
|
420 kumpf 1.2 }
421
|
422 marek 1.10 pam_rc = pam_authenticate(handle, 0);
423 if (pam_rc != PAM_SUCCESS)
|
424 kumpf 1.2 {
425 pam_end(handle, 0);
|
426 marek 1.10 return pam_rc;
|
427 kumpf 1.2 }
428
|
429 marek 1.10 pam_rc = pam_acct_mgmt(handle, 0);
430
|
431 kumpf 1.2 pam_end(handle, 0);
|
432 marek 1.10 return pam_rc;
|
433 kumpf 1.2 }
434
435 /*
436 **==============================================================================
437 **
438 ** PAMValidateUserInProcess()
439 **
440 ** Validate that the *username* refers to a valid PAM user.
441 **
442 **==============================================================================
443 */
444
445 static int PAMValidateUserInProcess(const char* username)
446 {
447 PAMData data;
448 struct pam_conv pconv;
449 pam_handle_t* phandle;
|
450 marek 1.10 int pam_rc;
|
451 kumpf 1.2
452 pconv.conv = PAMValidateUserCallback;
453 pconv.appdata_ptr = &data;
454
|
455 marek 1.10 pam_rc = pam_start(PAM_CONFIG_FILE, username, &pconv, &phandle);
456 if (pam_rc != PAM_SUCCESS)
|
457 kumpf 1.2 {
|
458 marek 1.10 return pam_rc;
|
459 kumpf 1.2 }
460
|
461 marek 1.10 pam_rc = pam_acct_mgmt(phandle, 0);
462
|
463 kumpf 1.2 pam_end(phandle, 0);
|
464 marek 1.10 return pam_rc;
|
465 kumpf 1.2 }
466
467 /*
468 **==============================================================================
469 **
470 ** PAMAuthenticate()
471 **
472 ** Performs basic PAM authentication on the given username and password.
473 **
474 **==============================================================================
475 */
476
477 static int PAMAuthenticate(const char* username, const char* password)
478 {
479 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
|
480 kumpf 1.5 return CimserveraProcessOperation("authenticate", username, password);
|
481 kumpf 1.2 #else
482 return PAMAuthenticateInProcess(username, password);
483 #endif
484 }
485
486 /*
487 **==============================================================================
488 **
489 ** PAMValidateUser()
490 **
491 ** Validate that the *username* refers to a valid PAM user.
492 **
493 **==============================================================================
494 */
495
496 static int PAMValidateUser(const char* username)
497 {
498 #ifdef PEGASUS_USE_PAM_STANDALONE_PROC
|
499 kumpf 1.5 return CimserveraProcessOperation("validateUser", username, "");
|
500 kumpf 1.2 #else
501 return PAMValidateUserInProcess(username);
502 #endif
503 }
504
505 #endif /* Executor_PAMAuth_h */
|