]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * islocal.c - returns true if user is registered in the local | |
3 | * /etc/passwd file. Written by Álvaro Martínez Echevarria, | |
4 | * alvaro@enano.etsit.upm.es, to allow peaceful coexistence with yp. Nov 94. | |
5 | * | |
6 | * Hacked a bit by poe@daimi.aau.dk | |
7 | * See also ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil* | |
8 | * | |
9 | * Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, | |
10 | * to distinguish user names where one is a prefix of the other, | |
11 | * and to use "pathnames.h". Oct 5, 96. | |
12 | * | |
13 | * 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL> | |
14 | * - added Native Language Support | |
15 | * | |
16 | * 2008-04-06 James Youngman, jay@gnu.org | |
17 | * - Completely rewritten to remove assumption that /etc/passwd | |
18 | * lines are < 1024 characters long. Also added unit tests. | |
19 | */ | |
20 | ||
21 | #include <stddef.h> | |
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | ||
25 | #include "closestream.h" | |
26 | #include "islocal.h" | |
27 | #include "nls.h" | |
28 | #include "pathnames.h" | |
29 | ||
30 | static int is_local_in_file(const char *user, const char *filename) | |
31 | { | |
32 | int local = 0; | |
33 | size_t match; | |
34 | int chin, skip; | |
35 | FILE *f; | |
36 | ||
37 | if (NULL == (f = fopen(filename, "r"))) | |
38 | return -1; | |
39 | ||
40 | match = 0u; | |
41 | skip = 0; | |
42 | while ((chin = fgetc(f)) != EOF) { | |
43 | if (skip) { | |
44 | /* Looking for the start of the next line. */ | |
45 | if ('\n' == chin) { | |
46 | /* Start matching username at the next char. */ | |
47 | skip = 0; | |
48 | match = 0u; | |
49 | } | |
50 | } else { | |
51 | if (':' == chin) { | |
52 | if (0 == user[match]) { | |
53 | /* Success. */ | |
54 | local = 1; | |
55 | /* next line has no test coverage, | |
56 | * but it is just an optimisation | |
57 | * anyway. */ | |
58 | break; | |
59 | } | |
60 | /* we read a whole username, but it | |
61 | * is the wrong user. Skip to the | |
62 | * next line. */ | |
63 | skip = 1; | |
64 | } else if ('\n' == chin) { | |
65 | /* This line contains no colon; it's | |
66 | * malformed. No skip since we are already | |
67 | * at the start of the next line. */ | |
68 | match = 0u; | |
69 | } else if (chin != user[match]) { | |
70 | /* username does not match. */ | |
71 | skip = 1; | |
72 | } else { | |
73 | ++match; | |
74 | } | |
75 | } | |
76 | } | |
77 | fclose(f); | |
78 | return local; | |
79 | } | |
80 | ||
81 | int is_local(const char *user) | |
82 | { | |
83 | int rv; | |
84 | ||
85 | if ((rv = is_local_in_file(user, _PATH_PASSWD)) < 0) | |
86 | err(EXIT_FAILURE, _("cannot open %s"), _PATH_PASSWD); | |
87 | return rv; | |
88 | } | |
89 | ||
90 | #ifdef TEST_PROGRAM | |
91 | int main(int argc, char *argv[]) | |
92 | { | |
93 | close_stdout_atexit(); | |
94 | if (argc <= 2) { | |
95 | fprintf(stderr, _("Usage: %s <passwordfile> <username>...\n"), | |
96 | argv[0]); | |
97 | return 1; | |
98 | } | |
99 | ||
100 | int i; | |
101 | for (i = 2; i < argc; i++) { | |
102 | const int rv = is_local_in_file(argv[i], argv[1]); | |
103 | if (rv < 0) { | |
104 | perror(argv[1]); | |
105 | return 2; | |
106 | } | |
107 | printf("%d:%s\n", rv, argv[i]); | |
108 | } | |
109 | return 0; | |
110 | } | |
111 | #endif |