1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include "user.h"
26 #include "log.h"
27
28
29 #if defined(CONFIG_POSIX)
30 # include "credcache.h"
31 # include <unistd.h>
32 # include <sys/types.h>
33 # include <pwd.h>
34 # include <grp.h>
35 # if defined(CONFIG_OS_DARWIN) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 1058
36 # include <pam/pam_appl.h>
37 # else
38 # include <security/pam_appl.h>
39 # endif
40 # include <signal.h>
41 # include <sys/wait.h>
42 # include <sys/socket.h>
43 mike 1.1 # include <sys/un.h>
44 # include <unistd.h>
45 # include <fcntl.h>
46 # include <sys/stat.h>
47 #elif defined(CONFIG_OS_WINDOWS)
48 #endif
49
50 #include "paths.h"
51
52 #define USERNAME_SIZE 128
53 #define GROUPNAME_SIZE 128
54
55 #if defined(CONFIG_POSIX)
56 static int s_ignoreAuthCalls;
57 #endif
58
59 #if defined(CONFIG_OS_WINDOWS)
60 /*
61 Validates user name and password;
62 Returns:
63 '0' if user account is valid and authorized to use CIM server
64 mike 1.1 '-1' otherwise
65 */
66 int AuthenticateUser(const char* user, const char* password)
67 {
68 MI_UNUSED(user);
69 MI_UNUSED(password);
70 return 0;
71 }
72
73 /*
74 Validates user's account for correct account name, expiration etc.
75 Returns:
76 '0' if user account is valid and authorized to use CIM server
77 '-1' otherwise
78 */
79 int ValidateUser(const char* user)
80 {
81 MI_UNUSED(user);
82 return 0;
83 }
84
85 mike 1.1 int LookupUser(const char* user, uid_t* uid, gid_t* gid)
86 {
87 MI_UNUSED(user);
88 *uid = -1;
89 *gid = -1;
90 return 0;
91 }
92
93 int GetUserGidByUid(uid_t uid, gid_t* gid)
94 {
95 MI_UNUSED(uid);
96 *gid = -1;
97 return 0;
98 }
99
100
101 int GetUIDByConnection(int fd, uid_t* uid, gid_t* gid)
102 {
103 MI_UNUSED(fd);
104 *uid = -1;
105 *gid = -1;
106 mike 1.1 return -1;
107 }
108
109 /*
110 Creates file with random data owned by user and RO by user only
111 Parameters:
112 uid - user ID
113 size - number of bytes to write
114 path - [out] - resulting file name
115
116 Returns:
117 0 if operation was successful; -1 otherwise
118 */
119 int CreateAuthFile(
120 uid_t uid,
121 char* content,
122 size_t size,
123 char path[MAX_PATH_SIZE])
124 {
125 MI_UNUSED(uid);
126 MI_UNUSED(size);
127 mike 1.1 MI_UNUSED(path);
128 MI_UNUSED(content);
129
130 return -1;
131 }
132
133 #elif defined(CONFIG_POSIX)
134 static int GetUserName(
135 uid_t uid,
136 char name[USERNAME_SIZE]);
137
138 static int GetGroupName(
139 gid_t gid,
140 char name[GROUPNAME_SIZE]);
141
142 static int _authCallback(
143 int numMessages,
144 #if defined(CONFIG_OS_LINUX) || defined(CONFIG_OS_DARWIN)
145 const struct pam_message** messages,
146 #else
147 struct pam_message** messages,
148 mike 1.1 #endif
149 struct pam_response** response,
150 void* applicationData)
151 {
152 const char* password = (const char*)applicationData;
153 int i;
154
155 /* If zero (or megative) messages, return now */
156
157 if (numMessages <= 0)
158 {
159 return PAM_CONV_ERR;
160 }
161
162 /* Allocate the responses */
163
164 *response = (struct pam_response*)calloc(
165 numMessages,
166 sizeof(struct pam_response));
167
168 if (!*response)
169 mike 1.1 {
170 return PAM_BUF_ERR;
171 }
172
173 /* Copy the password to the response messages */
174
175 for (i = 0; i < numMessages; i++)
176 {
177 if (PAM_PROMPT_ECHO_OFF == messages[i]->msg_style)
178 {
179 response[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE);
180 Strlcpy(response[i]->resp, password, PAM_MAX_MSG_SIZE);
181 response[i]->resp_retcode = 0;
182 }
183 else
184 {
185 return PAM_CONV_ERR;
186 }
187 }
188
189 return PAM_SUCCESS;
190 mike 1.1 }
191
192 static int _PamCheckUser(
193 const char* user,
194 const char* password)
195 {
196 struct pam_conv conv;
197 pam_handle_t* t = 0;
198
199 memset(&conv, 0, sizeof(conv));
200
201 conv.conv = _authCallback;
202 conv.appdata_ptr = (void*)password;
203
204 if (PAM_SUCCESS != pam_start("omi", user, &conv, &t))
205 return -1;
206
207 if (PAM_SUCCESS != pam_authenticate(t, 0))
208 {
209 pam_end(t,0);
210 return -1;
211 mike 1.1 }
212
213 if (PAM_SUCCESS != pam_acct_mgmt(t, 0))
214 {
215 pam_end(t,0);
216 return -1;
217 }
218
219 pam_end(t, 0);
220
221 return 0;
222 }
223
224 static int _CreateChildProcess(
225 int* fd,
226 pid_t* child,
227 const char* user,
228 const char* password)
229 {
230 int s[2];
231 int fdLimit;
232 mike 1.1
233 /* create communication pipe */
234 if(0 != socketpair(AF_UNIX, SOCK_STREAM, 0, s))
235 {
236 LOGW_CHAR(("socketpair() failed\n"));
237 return -1;
238 }
239
240 *child = fork();
241
242 if (*child < 0)
243 {
244 close(s[0]);
245 close(s[1]);
246 return -1; /* Failed */
247 }
248
249 if (*child > 0)
250 {
251 close(s[1]);
252 *fd = s[0];
253 mike 1.1
254 return 0; /* Started */
255 }
256
257 /* We are in child process here */
258
259 /* Close all open file descriptors except provided socket
260 (Some systems have UNLIMITED of 2^64; limit to something reasonable) */
261
262 fdLimit = getdtablesize();
263 if (fdLimit > 2500 || fdLimit < 0)
264 {
265 fdLimit = 2500;
266 }
267
268 /* ATTN: close first 3 also! Left for debugging only */
269 {
270 int i;
271 for (i = 3; i < fdLimit; ++i)
272 {
273 if (i != s[1])
274 mike 1.1 close(i);
275 }
276 }
277
278 /* perform operation in quesiton */
279 {
280 int r = _PamCheckUser(user, password);
281
282 write(s[1], &r, sizeof(r));
283 close(s[1]);
284 }
285
286 _exit(0);
287 }
288
289 /*
290 Validates user name and password;
291 Returns:
292 '0' if user account is valid and authorized to use CIM server
293 '-1' otherwise
294 */
295 mike 1.1 int AuthenticateUser(const char* user, const char* password)
296 {
297 int fd = 0;
298 pid_t child = 0;
299 int r = -1;
300
301 if (s_ignoreAuthCalls)
302 return 0;
303
304 /* Verify if user is in cache already */
305 if (0 == CredCache_CheckUser(user, password))
306 return 0;
307
308 if (0 != _CreateChildProcess(&fd, &child, user, password))
309 {
310 return -1;
311 }
312
313 if (sizeof(int) != read(fd, &r, sizeof(int)))
314 {
315 LOGE_CHAR(("failed to read result from child"));
316 mike 1.1 r = -1;
317 goto done;
318 }
319
320 done:
321 close(fd);
322 /* SIGCHILD HANDLER will take care of pid waiting */
323 #if 0
324 {
325 int loc = 0;
326 pid_t p = waitpid(child, &loc, 0 /*WNOHANG*/);
327
328 if (p != child)
329 LOGW_CHAR(("waitpid returned %d, loc %d",(int)p, loc));
330 }
331 #endif
332
333 /* Add user to cache if auth was ok */
334 if (0 == r)
335 CredCache_PutUser(user, password);
336
337 mike 1.1 return r;
338 }
339
340 /*
341 Validates user's account for correct account name, expiration etc.
342 Returns:
343 '0' if user account is valid and authorized to use CIM server
344 '-1' otherwise
345 */
346 int ValidateUser(const char* user)
347 {
348 if (s_ignoreAuthCalls)
349 return 0;
350
351 MI_UNUSED(user);
352 return 0;
353 }
354
355 /*
356 Disables authentication calls so 'AuthUser' always retunrs 'ok';
357 used for unit-test only
358 mike 1.1 */
359 void IgnoreAuthCalls(int flag)
360 {
361 s_ignoreAuthCalls = flag;
362 }
363
364
365 /*
366 Looks for user's account and retrieves uid/gid.
367 Parameters:
368 user - user name
369 uid [out] user ID
370 gid [out] group ID
371
372 Returns:
373 0 if operation was successful; -1 otherwise
374 */
375 int LookupUser(const char* user, uid_t* uid, gid_t* gid)
376 {
377 char buf[1024];
378 struct passwd pwd;
379 mike 1.1 struct passwd* ppwd = 0;
380
381 if (s_ignoreAuthCalls)
382 return 0;
383
384 if (0 != getpwnam_r(user, &pwd, buf, sizeof(buf), &ppwd) ||
385 !ppwd)
386 {
387 LOGW_CHAR(("getpwnam_r filed, errno %d", errno));
388 return -1;
389 }
390
391 *uid = pwd.pw_uid;
392 *gid = pwd.pw_gid;
393 return 0;
394 }
395
396 int GetUserGidByUid(uid_t uid, gid_t* gid)
397 {
398 /* user name */
399 char name[USERNAME_SIZE];
400 mike 1.1
401 if (0 != GetUserName(uid, name))
402 return -1;
403
404 return LookupUser(name, &uid, gid);
405 }
406
407 /*
408 Changes user/group IDs of current process.
409 Parameters:
410 uid - user ID
411 gid - group ID
412
413 Returns:
414 0 if operation was successful; -1 otherwise
415 */
416 int SetUser(uid_t uid, gid_t gid)
417 {
418 if (s_ignoreAuthCalls)
419 return 0;
420
421 mike 1.1 if (setgid(gid) != 0)
422 {
423 LOGW_CHAR(("setgid failed: errno (%d)",errno));
424 return -1;
425 }
426
427 if (setuid(uid) != 0)
428 {
429 LOGW_CHAR(("setuid failed: errno (%d)",errno));
430 return -1;
431 }
432
433 return 0;
434 }
435
436 /*
437 Verifies if current process is running as root
438 Returns:
439 0 - current process is root
440 -1 - current process is not root.
441 */
442 mike 1.1 int IsRoot()
443 {
444 uid_t uid = geteuid();
445
446 return uid == 0 ? 0 : -1;
447 }
448
449 int GetUIDByConnection(int fd, uid_t* uid, gid_t* gid)
450 {
451 #if defined(CONFIG_OS_LINUX)
452 struct ucred credentials;
453 socklen_t ucred_size = (socklen_t)sizeof(credentials);
454
455 /*fill in the user data structure */
456 if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_size))
457 return -1;
458
459 /* the process ID of the process on the other side of the socket */
460 // credentials.pid;
461
462 /* the effective UID of the process on the other side of the socket */
463 mike 1.1 *uid = credentials.uid;
464
465 /* the effective primary GID of the process on the other side of the socket */
466 *gid = credentials.gid;
467
468 return 0;
469 #else
470
471 MI_UNUSED(fd);
472 *uid = -1;
473 *gid = -1;
474 return -1;
475 #endif
476 }
477
478 /*
479 Creates file with random data owned by user and RO by user only
480 Parameters:
481 uid - user ID
482 size - number of bytes to write
483 path - [out] - resulting file name
484 mike 1.1
485 Returns:
486 0 if operation was successful; -1 otherwise
487 */
488 int CreateAuthFile(uid_t uid, char* content, size_t size, char path[MAX_PATH_SIZE])
489 {
490 static MI_Uint32 counter;
491
492 counter ++;
493
494 /* Format file name as <dir>/<user>.<counter> */
495 {
496 /* user name */
497 char name[USERNAME_SIZE];
498 char numBuf[12];
499 size_t dummy;
500
501 if (0 != GetUserName(uid, name))
502 return -1;
503
504 if (Strlcpy(path, GetPath(ID_AUTHDIR), MAX_PATH_SIZE) >= MAX_PATH_SIZE)
505 mike 1.1 return -1;
506
507 if (Strlcat(path, "/", MAX_PATH_SIZE) >= MAX_PATH_SIZE)
508 return -1;
509
510 if (Strlcat(path, name, MAX_PATH_SIZE) >= MAX_PATH_SIZE)
511 return -1;
512
513 if (Strlcat(path, ".", MAX_PATH_SIZE) >= MAX_PATH_SIZE)
514 return -1;
515
516 if (Strlcat(path, Uint32ToStr(numBuf, counter, &dummy), MAX_PATH_SIZE) >= MAX_PATH_SIZE)
517 return -1;
518 }
519
520 /* Generate random */
521 if (0 != CredCache_GenerateRandom(content, size))
522 return -1;
523
524 /* write file */
525 unlink(path);
526 mike 1.1
527 {
528 int fd;
529
530 /* Create auth file */
531 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR);
532 if (fd == -1)
533 {
534 LOGW_CHAR(("failed to create auth file %s", path));
535 return -1;
536 }
537 if (write(fd, content, size) != (int)size)
538 {
539 close(fd);
540 unlink(path);
541 return -1;
542 }
543
544 if (0 != fchown(fd, uid, -1))
545 {
546 LOGW_CHAR(("failed to chown auth file %s", path));
547 mike 1.1 close(fd);
548 unlink(path);
549 return -1;
550 }
551
552 close(fd);
553 }
554
555 return 0;
556 }
557
558 static int GetUserName(
559 uid_t uid,
560 char name[USERNAME_SIZE])
561 {
562 struct passwd pwbuf;
563 char buf[1024];
564 struct passwd* pw;
565
566 if (getpwuid_r(uid, &pwbuf, buf, sizeof(buf), &pw) != 0)
567 return -1;
568 mike 1.1
569 if (!pw)
570 return -1;
571
572 if (Strlcpy(name, pw->pw_name, USERNAME_SIZE) >= USERNAME_SIZE)
573 return -1;
574
575 return 0;
576 }
577
578 static int GetGroupName(
579 gid_t gid,
580 char name[GROUPNAME_SIZE])
581 {
582 struct group grbuf;
583 char buf[1024];
584 struct group* gr;
585
586 if (getgrgid_r(gid, &grbuf, buf, sizeof(buf), &gr) != 0)
587 return -1;
588
589 mike 1.1 if (!gr)
590 return -1;
591
592 if (Strlcpy(name, gr->gr_name, GROUPNAME_SIZE) >= GROUPNAME_SIZE)
593 return -1;
594
595 return 0;
596 }
597
598 int FormatLogFileName(
599 uid_t uid,
600 gid_t gid,
601 char path[MAX_PATH_SIZE])
602 {
603 char user[USERNAME_SIZE];
604 char group[GROUPNAME_SIZE];
605
606 if (Strlcpy(path, GetPath(ID_LOGDIR), MAX_PATH_SIZE) >= MAX_PATH_SIZE)
607 return -1;
608
609 Strlcat(path, "/omiagent.", MAX_PATH_SIZE);
610 mike 1.1
611 /* Append user name */
612 if (GetUserName(getuid(), user) == 0)
613 {
614 Strlcat(path, user, MAX_PATH_SIZE);
615 }
616 else
617 {
618 char buf[11];
619 sprintf(buf, "%u", getuid());
620 Strlcat(path, buf, MAX_PATH_SIZE);
621 }
622
623 /* Append group name */
624 if (GetGroupName(getgid(), group) == 0)
625 {
626 Strlcat(path, ".", MAX_PATH_SIZE);
627 Strlcat(path, group, MAX_PATH_SIZE);
628 }
629 else
630 {
631 mike 1.1 char buf[11];
632 sprintf(buf, "%u", getgid());
633 Strlcat(path, ".", MAX_PATH_SIZE);
634 Strlcat(path, buf, MAX_PATH_SIZE);
635 }
636
637 Strlcat(path, ".log", MAX_PATH_SIZE);
638
639 return 0;
640 }
641
642 #endif
643
|