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