(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           #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           

ViewCVS 0.9.2