summaryrefslogblamecommitdiffstats
path: root/cpukit/libcsupport/src/getpwent.c
blob: af77444a868688afaa8f88bda5fb305b56c46606 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                                                           
                                         



        



                   


                      
                




                   
                  
 

                         
  
                                 
   





                           
 
  
                                         
   


                                
                                     
 
                         

                         
                      



                            








                                                             



                           









                                                     
 

































                                                                         
 




































                                                    
 























                                                             

 
                   
                       
                      




                          

           
            
 

                          
                                                 


                   



                                            









                                                

                    
     
   
             

                 

 










                                                        
                        

                  
 
                   
 
                                                       
                

           
 







                          
























                                                          
                          



                                        









































                                                                     
                                                          























                                                    
           
            
 

                          
                                                


                   



                                            










                                                
               
     
   
             



                 





                          

 

                                                        
 
                       



                  
 

                                                       
           

 






                          
 

                                                          
 




                       
 
                                                      
                

           
 






                                                     

 
                   
 

                          


                                      

 
                   
 

                       
 
/*
 *  POSIX 1003.1b - 9.2.2 - User Database Access Routines
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id$
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>

#include <rtems/libio_.h>

/*
 * Static, thread-unsafe, buffers
 */
static FILE *passwd_fp;
static char pwbuf[200];
static struct passwd pwent;
static FILE *group_fp;
static char grbuf[200];
static struct group grent;

/*
 * Initialize useable but dummy databases
 */
void init_etc_passwd_group(void)
{
  FILE *fp;
  static char etc_passwd_initted = 0;

  if (etc_passwd_initted)
    return;
  etc_passwd_initted = 1;
  mkdir("/etc", 0777);

  /*
   *  Initialize /etc/passwd
   */
  if ((fp = fopen("/etc/passwd", "r")) != NULL) {
    fclose(fp);
  }
  else if ((fp = fopen("/etc/passwd", "w")) != NULL) {
    fprintf(fp, "root:*:0:0:root::/:/bin/sh\n"
                 "rtems:*:1:1:RTEMS Application::/:/bin/sh\n"
                 "tty:!:2:2:tty owner::/:/bin/false\n" );
    fclose(fp);
  }

  /*
   *  Initialize /etc/group
   */
  if ((fp = fopen("/etc/group", "r")) != NULL) {
    fclose(fp);
  }
  else if ((fp = fopen("/etc/group", "w")) != NULL) {
    fprintf( fp, "root:x:0:root\n"
                 "rtems:x:1:rtems\n"
                 "tty:x:2:tty\n" );
    fclose(fp);
  }
}

/*
 * Extract a string value from the database
 */
static int
scanString(FILE *fp, char **name, char **bufp, size_t *nleft, int nlFlag)
{
  int c;

  *name = *bufp;
  for (;;) {
    c = getc(fp);
    if (c == ':') {
        if (nlFlag)
            return 0;
        break;
    }
    if (c == '\n') {
        if (!nlFlag)
            return 0;
        break;
    }
    if (c == EOF)
      return 0;
    if (*nleft < 2)
      return 0;
    **bufp = c;
    ++(*bufp);
    --(*nleft);
  }
  **bufp = '\0';
  ++(*bufp);
  --(*nleft);
  return 1;
}

/*
 * Extract an integer value from the database
 */
static int
scanInt(FILE *fp, int *val)
{
  int c;
  unsigned int i = 0;
  unsigned int limit = INT_MAX;
  int sign = 0;
  int d;

  for (;;) {
    c = getc(fp);
    if (c == ':')
      break;
    if (sign == 0) {
      if (c == '-') {
        sign = -1;
        limit++;
        continue;
      }
      sign = 1;
    }
    if (!isdigit(c))
      return 0;
    d = c - '0';
    if ((i > (limit / 10))
     || ((i == (limit / 10)) && (d > (limit % 10))))
      return 0;
    i = i * 10 + d;
  }
  if (sign == 0)
    return 0;
  *val = i * sign;
  return 1;
}

/*
 * Extract a single password record from the database
 */
static int scanpw(
  FILE *fp,
  struct passwd *pwd,
  char *buffer,
  size_t bufsize
)
{
  int pwuid, pwgid;

  if (!scanString(fp, &pwd->pw_name, &buffer, &bufsize, 0)
   || !scanString(fp, &pwd->pw_passwd, &buffer, &bufsize, 0)
   || !scanInt(fp, &pwuid)
   || !scanInt(fp, &pwgid)
   || !scanString(fp, &pwd->pw_comment, &buffer, &bufsize, 0)
   || !scanString(fp, &pwd->pw_gecos, &buffer, &bufsize, 0)
   || !scanString(fp, &pwd->pw_dir, &buffer, &bufsize, 0)
   || !scanString(fp, &pwd->pw_shell, &buffer, &bufsize, 1))
    return 0;
  pwd->pw_uid = pwuid;
  pwd->pw_gid = pwgid;
  return 1;
}

static int getpw_r(
  const char     *name,
  int             uid,
  struct passwd  *pwd,
  char           *buffer,
  size_t          bufsize,
  struct passwd **result
)
{
  FILE *fp;
  int match;

  init_etc_passwd_group();

  if ((fp = fopen("/etc/passwd", "r")) == NULL) {
    errno = EINVAL;
    return -1;
  }
  for(;;) {
    if (!scanpw(fp, pwd, buffer, bufsize)) {
      errno = EINVAL;
      fclose(fp);
      return -1;
    }
    if (name) {
      match = (strcmp(pwd->pw_name, name) == 0);
    }
    else {
      match = (pwd->pw_uid == uid);
    }
    if (match) {
      fclose(fp);
      *result = pwd;
      return 0;
    }
  }
  fclose(fp);
  errno = EINVAL;
  return -1;
}

int getpwnam_r(
  const char     *name,
  struct passwd  *pwd,
  char           *buffer,
  size_t          bufsize,
  struct passwd **result
)
{
  return getpw_r(name, 0, pwd, buffer, bufsize, result);
}

struct passwd *getpwnam(
  const char *name
)
{
  struct passwd *p;

  if(getpwnam_r(name, &pwent, pwbuf, sizeof pwbuf, &p))
    return NULL;
  return p;
}

int getpwuid_r(
  uid_t           uid,
  struct passwd  *pwd,
  char           *buffer,
  size_t          bufsize,
  struct passwd **result
)
{
  return getpw_r(NULL, uid, pwd, buffer, bufsize, result);
}

struct passwd *getpwuid(
  uid_t uid
)
{
  struct passwd *p;

  if(getpwuid_r(uid, &pwent, pwbuf, sizeof pwbuf, &p))
    return NULL;
  return p;
}

struct passwd *getpwent()
{
  if (passwd_fp == NULL)
    return NULL;
  if (!scanpw(passwd_fp, &pwent, pwbuf, sizeof pwbuf))
    return NULL;
  return &pwent;
}

void setpwent(void)
{
  init_etc_passwd_group();

  if (passwd_fp != NULL)
    fclose(passwd_fp);
  passwd_fp = fopen("/etc/passwd", "r");
}

void endpwent(void)
{
  if (passwd_fp != NULL)
    fclose(passwd_fp);
}

/*
 * Extract a single group record from the database
 */
static int scangr(
  FILE *fp,
  struct group *grp,
  char *buffer,
  size_t bufsize
)
{
  int grgid;
  char *grmem, *cp;
  int memcount;

  if (!scanString(fp, &grp->gr_name, &buffer, &bufsize, 0)
   || !scanString(fp, &grp->gr_passwd, &buffer, &bufsize, 0)
   || !scanInt(fp, &grgid)
   || !scanString(fp, &grmem, &buffer, &bufsize, 1))
    return 0;
  grp->gr_gid = grgid;

  /*
   * Determine number of members
   */
  for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
    if(*cp == ',')
      memcount++;
  }

  /*
   * Hack to produce (hopefully) a suitably-aligned array of pointers
   */
  if (bufsize < (((memcount+1)*sizeof(char *)) + 15))
    return 0;
  grp->gr_mem = (char **)(((uintptr_t)buffer + 15) & ~15);

  /*
   * Fill in pointer array
   */
  grp->gr_mem[0] = grmem;
  for (cp = grmem, memcount = 1 ; *cp != 0 ; cp++) {
    if(*cp == ',') {
      *cp = '\0';
      grp->gr_mem[memcount++] = cp + 1;
    }
  }
  grp->gr_mem[memcount] = NULL;
  return 1;
}

static int getgr_r(
  const char     *name,
  int             gid,
  struct group   *grp,
  char           *buffer,
  size_t          bufsize,
  struct group  **result
)
{
  FILE *fp;
  int match;

  init_etc_passwd_group();

  if ((fp = fopen("/etc/group", "r")) == NULL) {
    errno = EINVAL;
    return -1;
  }
  for(;;) {
    if (!scangr(fp, grp, buffer, bufsize)) {
      errno = EINVAL;
      fclose(fp);
      return -1;
    }
    if (name) {
      match = (strcmp(grp->gr_name, name) == 0);
    }
    else {
      match = (grp->gr_gid == gid);
    }
    if (match) {
      fclose(fp);
      *result = grp;
      return 0;
    }
  }
  fclose(fp);
  errno = EINVAL;
  return -1;
}

int getgrnam_r(
  const char     *name,
  struct group   *grp,
  char           *buffer,
  size_t          bufsize,
  struct group  **result
)
{
  return getgr_r(name, 0, grp, buffer, bufsize, result);
}

struct group *getgrnam(
  const char *name
)
{
  struct group *p;

  if(getgrnam_r(name, &grent, grbuf, sizeof grbuf, &p))
    return NULL;
  return p;
}

int getgrgid_r(
  gid_t           gid,
  struct group   *grp,
  char           *buffer,
  size_t          bufsize,
  struct group  **result
)
{
  return getgr_r(NULL, gid, grp, buffer, bufsize, result);
}

struct group *getgrgid(
  gid_t gid
)
{
  struct group *p;

  if(getgrgid_r(gid, &grent, grbuf, sizeof grbuf, &p))
    return NULL;
  return p;
}

struct group *getgrent()
{
  if (group_fp == NULL)
    return NULL;
  if (!scangr(group_fp, &grent, grbuf, sizeof grbuf))
    return NULL;
  return &grent;
}

void setgrent(void)
{
  init_etc_passwd_group();

  if (group_fp != NULL)
    fclose(group_fp);
  group_fp = fopen("/etc/group", "r");
}

void endgrent(void)
{
  if (group_fp != NULL)
    fclose(group_fp);
}