(file) Return to user.c CVS log (file) (dir) Up to [OMI] / omi / base

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

ViewCVS 0.9.2