]> git.ipfire.org Git - thirdparty/glibc.git/blame - nss/nss_files/files-alias.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / nss / nss_files / files-alias.c
CommitLineData
26761c28 1/* Mail alias file parser in nss_files module.
2b778ceb 2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
26761c28
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
26761c28
UD
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
26761c28 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6 17 License along with the GNU C Library; if not, see
5a82c748 18 <https://www.gnu.org/licenses/>. */
26761c28
UD
19
20#include <aliases.h>
21#include <ctype.h>
54d79e99 22#include <errno.h>
3996f34b 23#include <fcntl.h>
ec999b8e 24#include <libc-lock.h>
26761c28
UD
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28
aa132749
UD
29#include <kernel-features.h>
30
26761c28 31#include "nsswitch.h"
299210c1 32#include <nss_files.h>
26761c28 33
680f1093
FW
34NSS_DECLARE_MODULE_FUNCTIONS (files)
35
26761c28
UD
36/* Locks the static variables in this file. */
37__libc_lock_define_initialized (static, lock)
38\f
b13b96ca
AS
39/* Maintenance of the stream open on the database file. For getXXent
40 operations the stream needs to be held open across calls, the other
41 getXXbyYY operations all use their own stream. */
26761c28
UD
42
43static FILE *stream;
26761c28
UD
44
45
46static enum nss_status
b13b96ca 47internal_setent (FILE **stream)
26761c28
UD
48{
49 enum nss_status status = NSS_STATUS_SUCCESS;
50
b13b96ca 51 if (*stream == NULL)
26761c28 52 {
299210c1 53 *stream = __nss_files_fopen ("/etc/aliases");
26761c28 54
b13b96ca 55 if (*stream == NULL)
0413b54c 56 status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
26761c28
UD
57 }
58 else
b13b96ca 59 rewind (*stream);
26761c28
UD
60
61 return status;
62}
63
64
65/* Thread-safe, exported version of that. */
66enum nss_status
67_nss_files_setaliasent (void)
68{
69 enum nss_status status;
70
71 __libc_lock_lock (lock);
72
b13b96ca 73 status = internal_setent (&stream);
26761c28
UD
74
75 __libc_lock_unlock (lock);
76
77 return status;
78}
79
80
81/* Close the database file. */
82static void
b13b96ca 83internal_endent (FILE **stream)
26761c28 84{
b13b96ca 85 if (*stream != NULL)
26761c28 86 {
b13b96ca
AS
87 fclose (*stream);
88 *stream = NULL;
26761c28
UD
89 }
90}
91
92
93/* Thread-safe, exported version of that. */
94enum nss_status
95_nss_files_endaliasent (void)
96{
97 __libc_lock_lock (lock);
98
b13b96ca 99 internal_endent (&stream);
26761c28
UD
100
101 __libc_lock_unlock (lock);
102
103 return NSS_STATUS_SUCCESS;
104}
105\f
106/* Parsing the database file into `struct aliasent' data structures. */
107static enum nss_status
b13b96ca 108get_next_alias (FILE *stream, const char *match, struct aliasent *result,
9756dfe1 109 char *buffer, size_t buflen, int *errnop)
26761c28
UD
110{
111 enum nss_status status = NSS_STATUS_NOTFOUND;
112 int ignore = 0;
113
114 result->alias_members_len = 0;
115
116 while (1)
117 {
118 /* Now we are ready to process the input. We have to read a
119 line and all its continuations and construct the array of
120 string pointers. This pointers and the names itself have to
121 be placed in BUFFER. */
122 char *first_unused = buffer;
123 size_t room_left = buflen - (buflen % __alignof__ (char *));
124 char *line;
125
4caef86c 126 /* Check whether the buffer is large enough for even trying to
89f447ed 127 read something. */
4caef86c
UD
128 if (room_left < 2)
129 goto no_more_room;
130
26761c28
UD
131 /* Read the first line. It must contain the alias name and
132 possibly some alias names. */
af69217f 133 first_unused[room_left - 1] = '\xff';
4caef86c 134 line = fgets_unlocked (first_unused, room_left, stream);
26761c28
UD
135 if (line == NULL)
136 /* Nothing to read. */
137 break;
af69217f 138 else if (first_unused[room_left - 1] != '\xff')
26761c28
UD
139 {
140 /* The line is too long for our buffer. */
141 no_more_room:
d71b808a 142 *errnop = ERANGE;
26761c28
UD
143 status = NSS_STATUS_TRYAGAIN;
144 break;
145 }
146 else
147 {
148 char *cp;
149
150 /* If we are in IGNORE mode and the first character in the
151 line is a white space we ignore the line and start
152 reading the next. */
afd4eb37 153 if (ignore && isspace (*first_unused))
26761c28
UD
154 continue;
155
156 /* Terminate the line for any case. */
157 cp = strpbrk (first_unused, "#\n");
158 if (cp != NULL)
159 *cp = '\0';
160
161 /* Skip leading blanks. */
162 while (isspace (*line))
163 ++line;
164
165 result->alias_name = first_unused;
166 while (*line != '\0' && *line != ':')
167 *first_unused++ = *line++;
168 if (*line == '\0' || result->alias_name == first_unused)
169 /* No valid name. Ignore the line. */
170 continue;
171
172 *first_unused++ = '\0';
173 if (room_left < (size_t) (first_unused - result->alias_name))
174 goto no_more_room;
175 room_left -= first_unused - result->alias_name;
176 ++line;
177
178 /* When we search for a specific alias we can avoid all the
179 difficult parts and compare now with the name we are
180 looking for. If it does not match we simply ignore all
181 lines until the next line containing the start of a new
182 alias is found. */
74015205 183 ignore = (match != NULL
14ea22e9 184 && __strcasecmp (result->alias_name, match) != 0);
26761c28
UD
185
186 while (! ignore)
187 {
188 while (isspace (*line))
189 ++line;
190
191 cp = first_unused;
192 while (*line != '\0' && *line != ',')
193 *first_unused++ = *line++;
194
195 if (first_unused != cp)
196 {
afd4eb37
UD
197 /* OK, we can have a regular entry or an include
198 request. */
26761c28 199 if (*line != '\0')
afd4eb37
UD
200 ++line;
201 *first_unused++ = '\0';
26761c28
UD
202
203 if (strncmp (cp, ":include:", 9) != 0)
204 {
205 if (room_left < (first_unused - cp) + sizeof (char *))
206 goto no_more_room;
207 room_left -= (first_unused - cp) + sizeof (char *);
208
209 ++result->alias_members_len;
210 }
211 else
212 {
213 /* Oh well, we have to read the addressed file. */
214 FILE *listfile;
215 char *old_line = NULL;
216
217 first_unused = cp;
218
299210c1 219 listfile = __nss_files_fopen (&cp[9]);
26761c28
UD
220 /* If the file does not exist we simply ignore
221 the statement. */
222 if (listfile != NULL
223 && (old_line = strdup (line)) != NULL)
224 {
89f447ed 225 while (! feof_unlocked (listfile))
26761c28 226 {
e95c6f61
FW
227 if (room_left < 2)
228 {
229 free (old_line);
230 fclose (listfile);
231 goto no_more_room;
232 }
233
af69217f 234 first_unused[room_left - 1] = '\xff';
4caef86c
UD
235 line = fgets_unlocked (first_unused, room_left,
236 listfile);
26761c28
UD
237 if (line == NULL)
238 break;
af69217f 239 if (first_unused[room_left - 1] != '\xff')
26761c28
UD
240 {
241 free (old_line);
e95c6f61 242 fclose (listfile);
26761c28
UD
243 goto no_more_room;
244 }
245
246 /* Parse the line. */
247 cp = strpbrk (line, "#\n");
248 if (cp != NULL)
249 *cp = '\0';
250
251 do
252 {
253 while (isspace (*line))
254 ++line;
255
256 cp = first_unused;
257 while (*line != '\0' && *line != ',')
258 *first_unused++ = *line++;
259
260 if (*line != '\0')
261 ++line;
262
263 if (first_unused != cp)
264 {
265 *first_unused++ = '\0';
266 if (room_left < ((first_unused - cp)
267 + __alignof__ (char *)))
268 {
269 free (old_line);
e95c6f61 270 fclose (listfile);
26761c28
UD
271 goto no_more_room;
272 }
273 room_left -= ((first_unused - cp)
274 + __alignof__ (char *));
275 ++result->alias_members_len;
276 }
277 }
278 while (*line != '\0');
279 }
280 fclose (listfile);
281
282 first_unused[room_left - 1] = '\0';
283 strncpy (first_unused, old_line, room_left);
284
3f1e9205
UD
285 free (old_line);
286 line = first_unused;
26761c28
UD
287
288 if (first_unused[room_left - 1] != '\0')
289 goto no_more_room;
290 }
291 }
292 }
293
294 if (*line == '\0')
295 {
296 /* Get the next line. But we must be careful. We
297 must not read the whole line at once since it
298 might belong to the current alias. Simply read
299 the first character. If it is a white space we
300 have a continuation line. Otherwise it is the
301 beginning of a new alias and we can push back the
302 just read character. */
303 int ch;
304
775a77e7 305 ch = fgetc_unlocked (stream);
afd4eb37 306 if (ch == EOF || ch == '\n' || !isspace (ch))
26761c28
UD
307 {
308 size_t cnt;
309
310 /* Now prepare the return. Provide string
311 pointers for the currently selected aliases. */
312 if (ch != EOF)
313 ungetc (ch, stream);
314
315 /* Adjust the pointer so it is aligned for
316 storing pointers. */
317 first_unused += __alignof__ (char *) - 1;
318 first_unused -= ((first_unused - (char *) 0)
319 % __alignof__ (char *));
320 result->alias_members = (char **) first_unused;
321
322 /* Compute addresses of alias entry strings. */
323 cp = result->alias_name;
324 for (cnt = 0; cnt < result->alias_members_len; ++cnt)
325 {
326 cp = strchr (cp, '\0') + 1;
327 result->alias_members[cnt] = cp;
328 }
329
330 status = (result->alias_members_len == 0
331 ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS);
332 break;
333 }
334
335 /* The just read character is a white space and so
336 can be ignored. */
af69217f 337 first_unused[room_left - 1] = '\xff';
4caef86c 338 line = fgets_unlocked (first_unused, room_left, stream);
2bac7daa
FW
339 if (line == NULL)
340 {
341 /* Continuation line without any data and
342 without a newline at the end. Treat it as an
343 empty line and retry, reaching EOF once
344 more. */
345 line = first_unused;
346 *line = '\0';
347 continue;
348 }
af69217f 349 if (first_unused[room_left - 1] != '\xff')
afd4eb37 350 goto no_more_room;
26761c28
UD
351 cp = strpbrk (line, "#\n");
352 if (cp != NULL)
353 *cp = '\0';
354 }
355 }
356 }
357
358 if (status != NSS_STATUS_NOTFOUND)
359 /* We read something. In any case break here. */
360 break;
361 }
362
363 return status;
364}
365
366
367enum nss_status
d71b808a
UD
368_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
369 int *errnop)
26761c28
UD
370{
371 /* Return next entry in host file. */
372 enum nss_status status = NSS_STATUS_SUCCESS;
373
374 __libc_lock_lock (lock);
375
376 /* Be prepared that the set*ent function was not called before. */
377 if (stream == NULL)
b13b96ca 378 status = internal_setent (&stream);
26761c28
UD
379
380 if (status == NSS_STATUS_SUCCESS)
381 {
b13b96ca 382 result->alias_local = 1;
26761c28 383
b13b96ca
AS
384 /* Read lines until we get a definite result. */
385 do
386 status = get_next_alias (stream, NULL, result, buffer, buflen, errnop);
387 while (status == NSS_STATUS_RETURN);
26761c28
UD
388 }
389
390 __libc_lock_unlock (lock);
391
392 return status;
393}
394
395
396enum nss_status
397_nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
d71b808a 398 char *buffer, size_t buflen, int *errnop)
26761c28
UD
399{
400 /* Return next entry in host file. */
401 enum nss_status status = NSS_STATUS_SUCCESS;
b13b96ca 402 FILE *stream = NULL;
26761c28
UD
403
404 if (name == NULL)
405 {
406 __set_errno (EINVAL);
407 return NSS_STATUS_UNAVAIL;
408 }
409
b13b96ca
AS
410 /* Open the stream. */
411 status = internal_setent (&stream);
26761c28
UD
412
413 if (status == NSS_STATUS_SUCCESS)
414 {
415 result->alias_local = 1;
416
417 /* Read lines until we get a definite result. */
418 do
b13b96ca 419 status = get_next_alias (stream, name, result, buffer, buflen, errnop);
26761c28
UD
420 while (status == NSS_STATUS_RETURN);
421 }
422
b13b96ca 423 internal_endent (&stream);
26761c28
UD
424
425 return status;
426}