diff options
author | James Youngman | 2008-04-12 13:53:07 +0200 |
---|---|---|
committer | Karel Zak | 2008-04-14 13:12:14 +0200 |
commit | 8e0259728e6b7c447d795898f60a9281053c8303 (patch) | |
tree | 4a6c4c13bb423513fefb035df70f48c1f46f1866 /login-utils/islocal.c | |
parent | docs: cleanup README.devel, add note about coding style and Signed-off-by (diff) | |
download | kernel-qcow2-util-linux-8e0259728e6b7c447d795898f60a9281053c8303.tar.gz kernel-qcow2-util-linux-8e0259728e6b7c447d795898f60a9281053c8303.tar.xz kernel-qcow2-util-linux-8e0259728e6b7c447d795898f60a9281053c8303.zip |
login: rewrite is_local() to remove limits on line length
Signed-off-by: James Youngman <jay@gnu.org>
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'login-utils/islocal.c')
-rw-r--r-- | login-utils/islocal.c | 105 |
1 files changed, 84 insertions, 21 deletions
diff --git a/login-utils/islocal.c b/login-utils/islocal.c index 297698041..762a4e990 100644 --- a/login-utils/islocal.c +++ b/login-utils/islocal.c @@ -12,7 +12,10 @@ 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL> - added Native Language Support - + + 2008-04-06 James Youngman, jay@gnu.org + - Completely rewritten to remove assumption that /etc/passwd + lines are < 1024 characters long. Also added unit tests. */ @@ -24,29 +27,89 @@ #include "pathnames.h" #include "islocal.h" -#define MAX_LENGTH 1024 - -int -is_local(char *user) +static int +is_local_in_file(const char *user, const char *filename) { - FILE *fd; - char line[MAX_LENGTH]; int local = 0; - size_t len; - - if(!(fd = fopen(_PATH_PASSWD, "r"))) { - fprintf(stderr,_("Can't read %s, exiting."),_PATH_PASSWD); - exit(1); - } - - len = strlen(user); - while(fgets(line, MAX_LENGTH, fd)) { - if(!strncmp(line, user, len) && line[len] == ':') { - local = 1; - break; - } + size_t match; + int chin, skip; + FILE *f; + + if (NULL == (f=fopen(filename, "r"))) + return -1; + + match = 0u; + skip = 0; + while ((chin = getc(f)) != EOF) { + if (skip) { + /* Looking for the start of the next line. */ + if ('\n' == chin) { + /* Start matching username at the next char. */ + skip = 0; + match = 0u; + } + } else { + if (':' == chin) { + if (0 == user[match]) { + local = 1; /* Success. */ + /* next line has no test coverage, but it is + * just an optimisation anyway. */ + break; + } else { + /* we read a whole username, but it is + * the wrong user. Skip to the next + * line. */ + skip = 1; + } + } else if ('\n' == chin) { + /* This line contains no colon; it's malformed. + * No skip since we are already at the start of + * the next line. */ + match = 0u; + } else if (chin != user[match]) { + /* username does not match. */ + skip = 1; + } else { + ++match; + } + } } - fclose(fd); + fclose(f); return local; } +int +is_local(const char *user) +{ + int rv; + if ((rv = is_local_in_file(user, _PATH_PASSWD)) < 0) { + perror(_PATH_PASSWD); + fprintf(stderr, _("Failed to open %s for reading, exiting."), + _PATH_PASSWD); + exit(1); + } else { + return rv; + } +} + +#if MAIN_TEST_ISLOCAL +int +main (int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "No test passwd file was specified.\n"); + return 1; + } else { + int i; + for (i = 2; i < argc; i++) { + const int rv = is_local_in_file(argv[i], argv[1]); + if (rv < 0) { + perror(argv[1]); + return 2; + } + printf("%d:%s\n", rv, argv[i]); + } + return 0; + } +} +#endif |