From ed8c513a74ef3f55722a09596bf6a573e778fe92 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 2 Oct 2002 17:33:17 +0000 Subject: 2002-10-02 Eric Norum * src/getpwent.c: Per PR283, reimplement to address reentrancy problems. * src/getgrent.c: Removed as functionality is now just a wrapper for common routines in src/getpwent.c. * Makefile.am: Reflect file removal. --- cpukit/libcsupport/ChangeLog | 7 + cpukit/libcsupport/Makefile.am | 2 +- cpukit/libcsupport/src/getgrent.c | 193 ----------------- cpukit/libcsupport/src/getpwent.c | 439 ++++++++++++++++++++++++++++---------- 4 files changed, 334 insertions(+), 307 deletions(-) delete mode 100644 cpukit/libcsupport/src/getgrent.c (limited to 'cpukit') diff --git a/cpukit/libcsupport/ChangeLog b/cpukit/libcsupport/ChangeLog index 1de58634a4..baa0e21330 100644 --- a/cpukit/libcsupport/ChangeLog +++ b/cpukit/libcsupport/ChangeLog @@ -1,3 +1,10 @@ +2002-10-02 Eric Norum + + * src/getpwent.c: Per PR283, reimplement to address reentrancy problems. + * src/getgrent.c: Removed as functionality is now just a wrapper for + common routines in src/getpwent.c. + * Makefile.am: Reflect file removal. + 2002-09-14 Joel Sherrill * include/rtems/libio.h: Change rtems_filesystem_read_t and diff --git a/cpukit/libcsupport/Makefile.am b/cpukit/libcsupport/Makefile.am index b758db0d61..1a6e154179 100644 --- a/cpukit/libcsupport/Makefile.am +++ b/cpukit/libcsupport/Makefile.am @@ -117,7 +117,7 @@ DIRECTORY_SCAN_C_FILES = src/opendir.c src/closedir.c src/readdir.c \ MALLOC_C_FILES = src/malloc.c src/mallocfreespace.c src/__brk.c src/__sbrk.c -PASSWORD_GROUP_C_FILES = src/getpwent.c src/getgrent.c +PASSWORD_GROUP_C_FILES = src/getpwent.c TERMINAL_IDENTIFICATION_C_FILES = src/ctermid.c src/isatty.c src/ttyname.c \ src/ttyname_r.c diff --git a/cpukit/libcsupport/src/getgrent.c b/cpukit/libcsupport/src/getgrent.c deleted file mode 100644 index 104b0a317f..0000000000 --- a/cpukit/libcsupport/src/getgrent.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * POSIX 1003.1b - 9.2.1 - Group 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.OARcorp.com/rtems/license.html. - * - * $Id$ - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -static struct group gr_group; /* password structure */ -static FILE *group_fp; - -/* - * The size of these buffers is arbitrary and there is no provision - * to protect any of them from overflowing. The scanf patterns - * need to be changed to prevent overflowing. In addition, - * the limits on these needs to be examined. - */ - -static char groupname[8]; -static char password[1024]; -static char groups[1024]; -static char *gr_mem[16] = { } ; - -extern void init_etc_passwd_group(void); - -int getgrnam_r( - const char *name, - struct group *grp, - char *buffer, - size_t bufsize, - struct group **result -) -{ - FILE *fp; - rtems_user_env_t * aux=rtems_current_user_env; /* save */ - - init_etc_passwd_group(); - rtems_current_user_env=&rtems_global_user_env; /* set root */ - - if ((fp = fopen ("/etc/group", "r")) == NULL) { - errno = EINVAL; - rtems_current_user_env=aux; /* restore */ - return -1; - } - - while (fgets (buffer, bufsize, fp)) { - sscanf (buffer, "%[^:]:%[^:]:%d:%s\n", - groupname, password, (int *) &grp->gr_gid, - groups); - grp->gr_name = groupname; - grp->gr_passwd = password; - grp->gr_mem = gr_mem ; - - if (!strcmp (groupname, name)) { - fclose (fp); - *result = grp; - rtems_current_user_env=aux; /* restore */ - return 0; - } - } - fclose (fp); - errno = EINVAL; - rtems_current_user_env=aux; /* restore */ - return -1; -} - -struct group *getgrnam( - const char *name -) -{ - char buf[1024]; - struct group *g; - - if ( getgrnam_r( name, &gr_group, buf, 1024, &g ) ) - return NULL; - - return g; -} - -int getgrgid_r( - gid_t gid, - struct group *grp, - char *buffer, - size_t bufsize, - struct group **result -) -{ - FILE *fp; - rtems_user_env_t * aux=rtems_current_user_env; /* save */ - - - init_etc_passwd_group(); - rtems_current_user_env=&rtems_global_user_env; /* set root */ - - if ((fp = fopen ("/etc/group", "r")) == NULL) { - errno = EINVAL; - rtems_current_user_env=aux; /* restore */ - return -1; - } - - while (fgets (buffer, bufsize, fp)) { - sscanf (buffer, "%[^:]:%[^:]:%d:%s\n", - groupname, password, (int *) &gr_group.gr_gid, - groups); - gr_group.gr_name = groupname; - gr_group.gr_passwd = password; - gr_group.gr_mem = gr_mem ; - - - if (gid == gr_group.gr_gid) { - fclose (fp); - *result = grp; - rtems_current_user_env=aux; /* restore */ - return 0; - } - } - fclose (fp); - errno = EINVAL; - rtems_current_user_env=aux; /* restore */ - return -1; -} - -struct group *getgrgid ( - gid_t gid -) -{ - char buf[1024]; - struct group *g; - - if ( getgrgid_r( gid, &gr_group, buf, 1024, &g ) ) - return NULL; - - return g; -} - -struct group *getgrent( void ) -{ - char buf[1024]; - - if (group_fp == NULL) - return NULL; - - if (fgets (buf, sizeof (buf), group_fp) == NULL) - return NULL; - - sscanf (buf, "%[^:]:%[^:]:%d:%s\n", - groupname, password, (int *) &gr_group.gr_gid, - groups); - gr_group.gr_name = groupname; - gr_group.gr_passwd = password; - gr_group.gr_mem = gr_mem ; - - return &gr_group; -} - -void -setgrent () -{ - rtems_user_env_t * aux=rtems_current_user_env; /* save */ - init_etc_passwd_group(); - rtems_current_user_env=&rtems_global_user_env; /* set root */ - - if (group_fp != NULL) - fclose (group_fp); - - group_fp = fopen ("/etc/group", "r"); - rtems_current_user_env=aux; /* restore */ -} - -void -endgrent () -{ - if (group_fp != NULL) - fclose (group_fp); -} diff --git a/cpukit/libcsupport/src/getpwent.c b/cpukit/libcsupport/src/getpwent.c index 91b6550f59..00ae4a47f6 100644 --- a/cpukit/libcsupport/src/getpwent.c +++ b/cpukit/libcsupport/src/getpwent.c @@ -15,81 +15,168 @@ #include #include #include +#include #include #include #include #include #include -#include -#include +#include #include -static struct passwd pw_passwd; /* password structure */ -static FILE *passwd_fp; - /* - * The size of these buffers is arbitrary and there is no provision - * to protect any of them from overflowing. The scanf patterns - * need to be changed to prevent overflowing. In addition, - * the limits on these needs to be examined. + * Static, thread-unsafe, buffers */ - -static char logname[8]; -static char password[1024]; -static char comment[1024]; -static char gecos[1024]; -static char dir[1024]; -static char shell[1024]; +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 a useable but dummy /etc/passwd - * - * NOTE: Ignore all errors. - * + * Initialize useable but dummy databases */ - -static char etc_passwd_initted = 0; - void init_etc_passwd_group(void) { FILE *fp; + static char etc_passwd_initted = 0; - if ( etc_passwd_initted ) + if (etc_passwd_initted) return; etc_passwd_initted = 1; - - (void) mkdir( "/etc", 0777); + mkdir("/etc", 0777); /* * Initialize /etc/passwd */ - - if ((fp = fopen ("/etc/passwd", "w")) == NULL) - return; - - 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 ); + 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); + } +} - if ((fp = fopen ("/etc/group", "w")) == NULL) - return; +/* + * 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; +} - fprintf( fp, "root:x:0:root\n" - "rtems:x:1:rtems\n" - "tty:x:2:tty\n" ); +/* + * 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; +} - fclose( fp ); +/* + * 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; } -int getpwnam_r( +static int getpw_r( const char *name, + int uid, struct passwd *pwd, char *buffer, size_t bufsize, @@ -97,52 +184,62 @@ int getpwnam_r( ) { FILE *fp; + int match; rtems_user_env_t * aux=rtems_current_user_env; /* save */ init_etc_passwd_group(); rtems_current_user_env=&rtems_global_user_env; /* set root */ - if ((fp = fopen ("/etc/passwd", "r")) == NULL) { + if ((fp = fopen("/etc/passwd", "r")) == NULL) { errno = EINVAL; rtems_current_user_env=aux; /* restore */ return -1; } - - while (fgets (buffer, bufsize, fp)) { - sscanf (buffer, "%[^:]:%[^:]:%d:%d:%[^:]:%[^:]:%[^:]:%s\n", - logname, password, &pwd->pw_uid, - &pwd->pw_gid, comment, gecos, - dir, shell); - pwd->pw_name = logname; - pwd->pw_passwd = password; - pwd->pw_comment = comment; - pwd->pw_gecos = gecos; - pwd->pw_dir = dir; - pwd->pw_shell = shell; - - if (!strcmp (logname, name)) { - fclose (fp); + for(;;) { + if (!scanpw(fp, pwd, buffer, bufsize)) { + errno = EINVAL; + fclose(fp); + rtems_current_user_env=aux; /* restore */ + return -1; + } + if (name) { + match = (strcmp(pwd->pw_name, name) == 0); + } + else { + match = (pwd->pw_uid == uid); + } + if (match) { + fclose(fp); *result = pwd; rtems_current_user_env=aux; /* restore */ return 0; } } - fclose (fp); + fclose(fp); errno = EINVAL; - rtems_current_user_env=aux; /* restore */ + rtems_current_user_env=aux; /* restore */ return -1; } -struct passwd *getpwnam( +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 ) { - char buf[1024]; struct passwd *p; - if ( getpwnam_r( name, &pw_passwd, buf, 1024, &p ) ) + if(getpwnam_r(name, &pwent, pwbuf, sizeof pwbuf, &p)) return NULL; - return p; } @@ -153,96 +250,212 @@ int getpwuid_r( 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) +{ + rtems_user_env_t * aux=rtems_current_user_env; /* save */ + init_etc_passwd_group(); + rtems_current_user_env=&rtems_global_user_env; /* set root */ + + if (passwd_fp != NULL) + fclose(passwd_fp); + passwd_fp = fopen("/etc/passwd", "r"); + rtems_current_user_env=aux; /* restore */ +} + +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 **)(((unsigned long)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; rtems_user_env_t * aux=rtems_current_user_env; /* save */ init_etc_passwd_group(); rtems_current_user_env=&rtems_global_user_env; /* set root */ - if ((fp = fopen ("/etc/passwd", "r")) == NULL) { + if ((fp = fopen("/etc/group", "r")) == NULL) { errno = EINVAL; rtems_current_user_env=aux; /* restore */ return -1; } - - while (fgets (buffer, bufsize, fp)) { - sscanf (buffer, "%[^:]:%[^:]:%d:%d:%[^:]:%[^:]:%[^:]:%s\n", - logname, password, &pw_passwd.pw_uid, - &pw_passwd.pw_gid, comment, gecos, - dir, shell); - pwd->pw_name = logname; - pwd->pw_passwd = password; - pwd->pw_comment = comment; - pwd->pw_gecos = gecos; - pwd->pw_dir = dir; - pwd->pw_shell = shell; - - if (uid == pwd->pw_uid) { - fclose (fp); - *result = pwd; + for(;;) { + if (!scangr(fp, grp, buffer, bufsize)) { + errno = EINVAL; + fclose(fp); + rtems_current_user_env=aux; /* restore */ + return -1; + } + if (name) { + match = (strcmp(grp->gr_name, name) == 0); + } + else { + match = (grp->gr_gid == gid); + } + if (match) { + fclose(fp); + *result = grp; rtems_current_user_env=aux; /* restore */ return 0; } } - fclose (fp); + fclose(fp); errno = EINVAL; rtems_current_user_env=aux; /* restore */ return -1; } -struct passwd *getpwuid( - uid_t uid +int getgrnam_r( + const char *name, + struct group *grp, + char *buffer, + size_t bufsize, + struct group **result ) { - char buf[1024]; - struct passwd *p; + return getgr_r(name, 0, grp, buffer, bufsize, result); +} - if ( getpwuid_r( uid, &pw_passwd, buf, 1024, &p ) ) - return NULL; +struct group *getgrnam( + const char *name +) +{ + struct group *p; + if(getgrnam_r(name, &grent, grbuf, sizeof grbuf, &p)) + return NULL; return p; } -struct passwd *getpwent() +int getgrgid_r( + gid_t gid, + struct group *grp, + char *buffer, + size_t bufsize, + struct group **result +) { - char buf[1024]; + return getgr_r(NULL, gid, grp, buffer, bufsize, result); +} - if (passwd_fp == NULL) - return NULL; +struct group *getgrgid( + gid_t gid +) +{ + struct group *p; - if (fgets (buf, sizeof (buf), passwd_fp) == NULL) + if(getgrgid_r(gid, &grent, grbuf, sizeof grbuf, &p)) return NULL; + return p; +} - sscanf (buf, "%[^:]:%[^:]:%d:%d:%[^:]:%[^:]:%[^:]:%s\n", - logname, password, &pw_passwd.pw_uid, - &pw_passwd.pw_gid, comment, gecos, - dir, shell); - pw_passwd.pw_name = logname; - pw_passwd.pw_passwd = password; - pw_passwd.pw_comment = comment; - pw_passwd.pw_gecos = gecos; - pw_passwd.pw_dir = dir; - pw_passwd.pw_shell = shell; - - return &pw_passwd; +struct group *getgrent() +{ + if (group_fp == NULL) + return NULL; + if (!scangr(group_fp, &grent, grbuf, sizeof grbuf)) + return NULL; + return &grent; } -void setpwent( void ) +void setgrent(void) { rtems_user_env_t * aux=rtems_current_user_env; /* save */ init_etc_passwd_group(); rtems_current_user_env=&rtems_global_user_env; /* set root */ - if (passwd_fp != NULL) - fclose (passwd_fp); - - passwd_fp = fopen ("/etc/passwd", "r"); + if (group_fp != NULL) + fclose(group_fp); + group_fp = fopen("/etc/group", "r"); rtems_current_user_env=aux; /* restore */ } -void endpwent( void ) +void endgrent(void) { - if (passwd_fp != NULL) - fclose (passwd_fp); + if (group_fp != NULL) + fclose(group_fp); } -- cgit v1.2.3