Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.git] / login-utils / islocal.c
1 /* 
2    islocal.c - returns true if user is registered in the local
3    /etc/passwd file. Written by Alvaro Martinez 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
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25
26 #include "nls.h"
27 #include "pathnames.h"
28 #include "islocal.h"
29
30 static int
31 is_local_in_file(const char *user, const char *filename)
32 {
33         int local = 0;
34         size_t match;
35         int chin, skip;
36         FILE *f;
37
38         if (NULL == (f=fopen(filename, "r")))
39                 return -1;
40
41         match = 0u;
42         skip = 0;
43         while ((chin = getc(f)) != EOF) {
44                 if (skip) {
45                         /* Looking for the start of the next line. */
46                         if ('\n' == chin) {
47                                 /* Start matching username at the next char. */
48                                 skip = 0;
49                                 match = 0u;
50                         }
51                 } else {
52                         if (':' == chin) {
53                                 if (0 == user[match]) {
54                                         local = 1; /* Success. */
55                                         /* next line has no test coverage, but it is
56                                          * just an optimisation anyway. */
57                                         break;
58                                 } else {
59                                         /* we read a whole username, but it is
60                                          * the wrong user.  Skip to the next
61                                          * line. */
62                                         skip = 1;
63                                 }
64                         } else if ('\n' == chin) {
65                                 /* This line contains no colon; it's malformed.
66                                  * No skip since we are already at the start of
67                                  * 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
82 is_local(const char *user)
83 {
84         int rv;
85         if ((rv = is_local_in_file(user, _PATH_PASSWD)) < 0) {
86                 perror(_PATH_PASSWD);
87                 fprintf(stderr, _("Failed to open %s for reading, exiting."),
88                         _PATH_PASSWD);
89                 exit(1);
90         } else {
91                 return rv;
92         }
93 }
94
95 #if MAIN_TEST_ISLOCAL
96 int
97 main (int argc, char *argv[])
98 {
99         if (argc < 2) {
100                 fprintf(stderr, "No test passwd file was specified.\n");
101                 return 1;
102         } else {
103                 int i;
104                 for (i = 2; i < argc; i++) {
105                         const int rv = is_local_in_file(argv[i], argv[1]);
106                         if (rv < 0) {
107                                 perror(argv[1]);
108                                 return 2;
109                         }
110                         printf("%d:%s\n", rv, argv[i]);
111                 }
112                 return 0;
113         }
114 }
115 #endif