]>
git.ipfire.org Git - thirdparty/glibc.git/blob - nss/nss_files/files-alias.c
1 /* Mail alias file parser in nss_files module.
2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
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.
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
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
24 #include <libc-lock.h>
29 #include <kernel-features.h>
32 #include <nss_files.h>
34 NSS_DECLARE_MODULE_FUNCTIONS (files
)
36 /* Locks the static variables in this file. */
37 __libc_lock_define_initialized (static, lock
)
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. */
46 static enum nss_status
47 internal_setent (FILE **stream
)
49 enum nss_status status
= NSS_STATUS_SUCCESS
;
53 *stream
= __nss_files_fopen ("/etc/aliases");
56 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
65 /* Thread-safe, exported version of that. */
67 _nss_files_setaliasent (void)
69 enum nss_status status
;
71 __libc_lock_lock (lock
);
73 status
= internal_setent (&stream
);
75 __libc_lock_unlock (lock
);
81 /* Close the database file. */
83 internal_endent (FILE **stream
)
93 /* Thread-safe, exported version of that. */
95 _nss_files_endaliasent (void)
97 __libc_lock_lock (lock
);
99 internal_endent (&stream
);
101 __libc_lock_unlock (lock
);
103 return NSS_STATUS_SUCCESS
;
106 /* Parsing the database file into `struct aliasent' data structures. */
107 static enum nss_status
108 get_next_alias (FILE *stream
, const char *match
, struct aliasent
*result
,
109 char *buffer
, size_t buflen
, int *errnop
)
111 enum nss_status status
= NSS_STATUS_NOTFOUND
;
114 result
->alias_members_len
= 0;
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 *));
126 /* Check whether the buffer is large enough for even trying to
131 /* Read the first line. It must contain the alias name and
132 possibly some alias names. */
133 first_unused
[room_left
- 1] = '\xff';
134 line
= fgets_unlocked (first_unused
, room_left
, stream
);
136 /* Nothing to read. */
138 else if (first_unused
[room_left
- 1] != '\xff')
140 /* The line is too long for our buffer. */
143 status
= NSS_STATUS_TRYAGAIN
;
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
153 if (ignore
&& isspace (*first_unused
))
156 /* Terminate the line for any case. */
157 cp
= strpbrk (first_unused
, "#\n");
161 /* Skip leading blanks. */
162 while (isspace (*line
))
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. */
172 *first_unused
++ = '\0';
173 if (room_left
< (size_t) (first_unused
- result
->alias_name
))
175 room_left
-= first_unused
- result
->alias_name
;
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
183 ignore
= (match
!= NULL
184 && __strcasecmp (result
->alias_name
, match
) != 0);
188 while (isspace (*line
))
192 while (*line
!= '\0' && *line
!= ',')
193 *first_unused
++ = *line
++;
195 if (first_unused
!= cp
)
197 /* OK, we can have a regular entry or an include
201 *first_unused
++ = '\0';
203 if (strncmp (cp
, ":include:", 9) != 0)
205 if (room_left
< (first_unused
- cp
) + sizeof (char *))
207 room_left
-= (first_unused
- cp
) + sizeof (char *);
209 ++result
->alias_members_len
;
213 /* Oh well, we have to read the addressed file. */
215 char *old_line
= NULL
;
219 listfile
= __nss_files_fopen (&cp
[9]);
220 /* If the file does not exist we simply ignore
223 && (old_line
= strdup (line
)) != NULL
)
225 while (! feof_unlocked (listfile
))
234 first_unused
[room_left
- 1] = '\xff';
235 line
= fgets_unlocked (first_unused
, room_left
,
239 if (first_unused
[room_left
- 1] != '\xff')
246 /* Parse the line. */
247 cp
= strpbrk (line
, "#\n");
253 while (isspace (*line
))
257 while (*line
!= '\0' && *line
!= ',')
258 *first_unused
++ = *line
++;
263 if (first_unused
!= cp
)
265 *first_unused
++ = '\0';
266 if (room_left
< ((first_unused
- cp
)
267 + __alignof__ (char *)))
273 room_left
-= ((first_unused
- cp
)
274 + __alignof__ (char *));
275 ++result
->alias_members_len
;
278 while (*line
!= '\0');
282 first_unused
[room_left
- 1] = '\0';
283 strncpy (first_unused
, old_line
, room_left
);
288 if (first_unused
[room_left
- 1] != '\0')
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. */
305 ch
= fgetc_unlocked (stream
);
306 if (ch
== EOF
|| ch
== '\n' || !isspace (ch
))
310 /* Now prepare the return. Provide string
311 pointers for the currently selected aliases. */
315 /* Adjust the pointer so it is aligned for
317 first_unused
+= __alignof__ (char *) - 1;
318 first_unused
-= ((first_unused
- (char *) 0)
319 % __alignof__ (char *));
320 result
->alias_members
= (char **) first_unused
;
322 /* Compute addresses of alias entry strings. */
323 cp
= result
->alias_name
;
324 for (cnt
= 0; cnt
< result
->alias_members_len
; ++cnt
)
326 cp
= strchr (cp
, '\0') + 1;
327 result
->alias_members
[cnt
] = cp
;
330 status
= (result
->alias_members_len
== 0
331 ? NSS_STATUS_RETURN
: NSS_STATUS_SUCCESS
);
335 /* The just read character is a white space and so
337 first_unused
[room_left
- 1] = '\xff';
338 line
= fgets_unlocked (first_unused
, room_left
, stream
);
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
349 if (first_unused
[room_left
- 1] != '\xff')
351 cp
= strpbrk (line
, "#\n");
358 if (status
!= NSS_STATUS_NOTFOUND
)
359 /* We read something. In any case break here. */
368 _nss_files_getaliasent_r (struct aliasent
*result
, char *buffer
, size_t buflen
,
371 /* Return next entry in host file. */
372 enum nss_status status
= NSS_STATUS_SUCCESS
;
374 __libc_lock_lock (lock
);
376 /* Be prepared that the set*ent function was not called before. */
378 status
= internal_setent (&stream
);
380 if (status
== NSS_STATUS_SUCCESS
)
382 result
->alias_local
= 1;
384 /* Read lines until we get a definite result. */
386 status
= get_next_alias (stream
, NULL
, result
, buffer
, buflen
, errnop
);
387 while (status
== NSS_STATUS_RETURN
);
390 __libc_lock_unlock (lock
);
397 _nss_files_getaliasbyname_r (const char *name
, struct aliasent
*result
,
398 char *buffer
, size_t buflen
, int *errnop
)
400 /* Return next entry in host file. */
401 enum nss_status status
= NSS_STATUS_SUCCESS
;
406 __set_errno (EINVAL
);
407 return NSS_STATUS_UNAVAIL
;
410 /* Open the stream. */
411 status
= internal_setent (&stream
);
413 if (status
== NSS_STATUS_SUCCESS
)
415 result
->alias_local
= 1;
417 /* Read lines until we get a definite result. */
419 status
= get_next_alias (stream
, name
, result
, buffer
, buflen
, errnop
);
420 while (status
== NSS_STATUS_RETURN
);
423 internal_endent (&stream
);