diff options
Diffstat (limited to 'cpukit/libcsupport/src/getpwent.c')
-rw-r--r-- | cpukit/libcsupport/src/getpwent.c | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/cpukit/libcsupport/src/getpwent.c b/cpukit/libcsupport/src/getpwent.c new file mode 100644 index 0000000000..210f4bedd5 --- /dev/null +++ b/cpukit/libcsupport/src/getpwent.c @@ -0,0 +1,438 @@ +/* + * 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> +#include <rtems/seterr.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) + rtems_set_errno_and_return_minus_one( EINVAL ); + + for(;;) { + if (!scanpw(fp, pwd, buffer, bufsize)) + goto error_einval; + + if (name) { + match = (strcmp(pwd->pw_name, name) == 0); + } else { + match = (pwd->pw_uid == uid); + } + + if (match) { + fclose(fp); + *result = pwd; + return 0; + } + } +error_einval: + fclose(fp); + rtems_set_errno_and_return_minus_one( EINVAL ); +} + +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(void) +{ + 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) + rtems_set_errno_and_return_minus_one( EINVAL ); + + for(;;) { + if (!scangr(fp, grp, buffer, bufsize)) + goto error_einval; + + if (name) { + match = (strcmp(grp->gr_name, name) == 0); + } else { + match = (grp->gr_gid == gid); + } + + if (match) { + fclose(fp); + *result = grp; + return 0; + } + } +error_einval: + fclose(fp); + rtems_set_errno_and_return_minus_one( EINVAL ); +} + +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(void) +{ + 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); +} |