/* 
   islocal.c - returns true if user is registered in the local
   /etc/passwd file. Written by Alvaro Martinez Echevarria, 
   alvaro@enano.etsit.upm.es, to allow peaceful coexistence with yp. Nov 94.

   Hacked a bit by poe@daimi.aau.dk
   See also ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil*

   Hacked by Peter Breitenlohner, peb@mppmu.mpg.de,
     to distinguish user names where one is a prefix of the other,
     and to use "pathnames.h". Oct 5, 96.   

   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.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "nls.h"
#include "pathnames.h"
#include "islocal.h"

static int
is_local_in_file(const char *user, const char *filename)
{
	int local = 0;
	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(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
