]> git.ipfire.org Git - thirdparty/glibc.git/blob - nss/nss_files/files-XXX.c
9cc5137953564db678829378c9941ae9eb697448
[thirdparty/glibc.git] / nss / nss_files / files-XXX.c
1 /* Common code for file-based databases in nss_files module.
2 Copyright (C) 1996-2020 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #include <stdio.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <libc-lock.h>
24 #include "nsswitch.h"
25 #include <nss_files.h>
26
27 #include <kernel-features.h>
28
29 /* These symbols are defined by the including source file:
30
31 ENTNAME -- database name of the structure and functions (hostent, pwent).
32 STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
33 DATABASE -- string of the database file's name ("hosts", "passwd").
34
35 NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
36
37 Also see files-parse.c.
38 */
39
40 #define ENTNAME_r CONCAT(ENTNAME,_r)
41
42 #define DATAFILE "/etc/" DATABASE
43
44 #ifdef NEED_H_ERRNO
45 # include <netdb.h>
46 # define H_ERRNO_PROTO , int *herrnop
47 # define H_ERRNO_ARG , herrnop
48 # define H_ERRNO_SET(val) (*herrnop = (val))
49 #else
50 # define H_ERRNO_PROTO
51 # define H_ERRNO_ARG
52 # define H_ERRNO_SET(val) ((void) 0)
53 #endif
54
55 #ifndef EXTRA_ARGS
56 # define EXTRA_ARGS
57 # define EXTRA_ARGS_DECL
58 # define EXTRA_ARGS_VALUE
59 #endif
60
61 /* Locks the static variables in this file. */
62 __libc_lock_define_initialized (static, lock)
63 \f
64 /* Maintenance of the stream open on the database file. For getXXent
65 operations the stream needs to be held open across calls, the other
66 getXXbyYY operations all use their own stream. */
67
68 static FILE *stream;
69
70 /* Open database file if not already opened. */
71 static enum nss_status
72 internal_setent (FILE **stream)
73 {
74 enum nss_status status = NSS_STATUS_SUCCESS;
75
76 if (*stream == NULL)
77 {
78 *stream = __nss_files_fopen (DATAFILE);
79
80 if (*stream == NULL)
81 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
82 }
83 else
84 rewind (*stream);
85
86 return status;
87 }
88
89
90 /* Thread-safe, exported version of that. */
91 enum nss_status
92 CONCAT(_nss_files_set,ENTNAME) (int stayopen)
93 {
94 enum nss_status status;
95
96 __libc_lock_lock (lock);
97
98 status = internal_setent (&stream);
99
100 __libc_lock_unlock (lock);
101
102 return status;
103 }
104
105
106 /* Close the database file. */
107 static void
108 internal_endent (FILE **stream)
109 {
110 if (*stream != NULL)
111 {
112 fclose (*stream);
113 *stream = NULL;
114 }
115 }
116
117
118 /* Thread-safe, exported version of that. */
119 enum nss_status
120 CONCAT(_nss_files_end,ENTNAME) (void)
121 {
122 __libc_lock_lock (lock);
123
124 internal_endent (&stream);
125
126 __libc_lock_unlock (lock);
127
128 return NSS_STATUS_SUCCESS;
129 }
130 \f
131
132 /* Parsing the database file into `struct STRUCTURE' data structures. */
133 static enum nss_status
134 internal_getent (FILE *stream, struct STRUCTURE *result,
135 char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
136 EXTRA_ARGS_DECL)
137 {
138 char *p;
139 struct parser_data *data = (void *) buffer;
140 size_t linebuflen = buffer + buflen - data->linebuffer;
141 int parse_result;
142
143 if (buflen < sizeof *data + 2)
144 {
145 *errnop = ERANGE;
146 H_ERRNO_SET (NETDB_INTERNAL);
147 return NSS_STATUS_TRYAGAIN;
148 }
149
150 while (true)
151 {
152 ssize_t r = __libc_readline_unlocked
153 (stream, data->linebuffer, linebuflen);
154 if (r < 0)
155 {
156 *errnop = errno;
157 H_ERRNO_SET (NETDB_INTERNAL);
158 if (*errnop == ERANGE)
159 /* Request larger buffer. */
160 return NSS_STATUS_TRYAGAIN;
161 else
162 /* Other read failure. */
163 return NSS_STATUS_UNAVAIL;
164 }
165 else if (r == 0)
166 {
167 /* End of file. */
168 H_ERRNO_SET (HOST_NOT_FOUND);
169 return NSS_STATUS_NOTFOUND;
170 }
171
172 /* Everything OK. Now skip leading blanks. */
173 p = data->linebuffer;
174 while (isspace (*p))
175 ++p;
176
177 /* Ignore empty and comment lines. */
178 if (*p == '\0' || *p == '#')
179 continue;
180
181 /* Parse the line. */
182 *errnop = EINVAL;
183 parse_result = parse_line (p, result, data, buflen, errnop EXTRA_ARGS);
184
185 if (parse_result == -1)
186 {
187 if (*errnop == ERANGE)
188 {
189 /* Return to the original file position at the beginning
190 of the line, so that the next call can read it again
191 if necessary. */
192 if (__fseeko64 (stream, -r, SEEK_CUR) != 0)
193 {
194 if (errno == ERANGE)
195 *errnop = EINVAL;
196 else
197 *errnop = errno;
198 H_ERRNO_SET (NETDB_INTERNAL);
199 return NSS_STATUS_UNAVAIL;
200 }
201 }
202 H_ERRNO_SET (NETDB_INTERNAL);
203 return NSS_STATUS_TRYAGAIN;
204 }
205
206 /* Return the data if parsed successfully. */
207 if (parse_result != 0)
208 return NSS_STATUS_SUCCESS;
209
210 /* If it is invalid, loop to get the next line of the file to
211 parse. */
212 }
213 }
214
215
216 /* Return the next entry from the database file, doing locking. */
217 enum nss_status
218 CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
219 size_t buflen, int *errnop H_ERRNO_PROTO)
220 {
221 /* Return next entry in host file. */
222 enum nss_status status = NSS_STATUS_SUCCESS;
223
224 __libc_lock_lock (lock);
225
226 /* Be prepared that the set*ent function was not called before. */
227 if (stream == NULL)
228 {
229 int save_errno = errno;
230
231 status = internal_setent (&stream);
232
233 __set_errno (save_errno);
234 }
235
236 if (status == NSS_STATUS_SUCCESS)
237 status = internal_getent (stream, result, buffer, buflen, errnop
238 H_ERRNO_ARG EXTRA_ARGS_VALUE);
239
240 __libc_lock_unlock (lock);
241
242 return status;
243 }
244 \f
245 /* Macro for defining lookup functions for this file-based database.
246
247 NAME is the name of the lookup; e.g. `hostbyname'.
248
249 DB_CHAR, KEYPATTERN, KEYSIZE are ignored here but used by db-XXX.c
250 e.g. `1 + sizeof (id) * 4'.
251
252 PROTO is the potentially empty list of other parameters.
253
254 BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
255 to the lookup key arguments and does `break;' if they match. */
256
257 #define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
258 enum nss_status \
259 _nss_files_get##name##_r (proto, \
260 struct STRUCTURE *result, char *buffer, \
261 size_t buflen, int *errnop H_ERRNO_PROTO) \
262 { \
263 enum nss_status status; \
264 FILE *stream = NULL; \
265 \
266 /* Open file. */ \
267 status = internal_setent (&stream); \
268 \
269 if (status == NSS_STATUS_SUCCESS) \
270 { \
271 while ((status = internal_getent (stream, result, buffer, buflen, errnop \
272 H_ERRNO_ARG EXTRA_ARGS_VALUE)) \
273 == NSS_STATUS_SUCCESS) \
274 { break_if_match } \
275 \
276 internal_endent (&stream); \
277 } \
278 \
279 return status; \
280 }