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