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