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