1 /* Mail alias file parser in nss_files module.
2 Copyright (C) 1996-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
23 #include <libc-lock.h>
28 #include <kernel-features.h>
31 #include <nss_files.h>
34 /* Maintenance of the stream open on the database file. For getXXent
35 operations the stream needs to be held open across calls, the other
36 getXXbyYY operations all use their own stream. */
38 static enum nss_status
39 internal_setent (FILE **stream
)
41 enum nss_status status
= NSS_STATUS_SUCCESS
;
45 *stream
= __nss_files_fopen ("/etc/aliases");
48 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
57 /* Thread-safe, exported version of that. */
59 _nss_files_setaliasent (void)
61 return __nss_files_data_setent (nss_file_aliasent
, "/etc/aliases");
63 libc_hidden_def (_nss_files_setaliasent
)
66 _nss_files_endaliasent (void)
68 return __nss_files_data_endent (nss_file_aliasent
);
70 libc_hidden_def (_nss_files_endaliasent
)
72 /* Parsing the database file into `struct aliasent' data structures. */
73 static enum nss_status
74 get_next_alias (FILE *stream
, const char *match
, struct aliasent
*result
,
75 char *buffer
, size_t buflen
, int *errnop
)
77 enum nss_status status
= NSS_STATUS_NOTFOUND
;
80 result
->alias_members_len
= 0;
84 /* Now we are ready to process the input. We have to read a
85 line and all its continuations and construct the array of
86 string pointers. This pointers and the names itself have to
87 be placed in BUFFER. */
88 char *first_unused
= buffer
;
89 size_t room_left
= buflen
- (buflen
% __alignof__ (char *));
92 /* Check whether the buffer is large enough for even trying to
97 /* Read the first line. It must contain the alias name and
98 possibly some alias names. */
99 first_unused
[room_left
- 1] = '\xff';
100 line
= __fgets_unlocked (first_unused
, room_left
, stream
);
102 /* Nothing to read. */
104 else if (first_unused
[room_left
- 1] != '\xff')
106 /* The line is too long for our buffer. */
109 status
= NSS_STATUS_TRYAGAIN
;
116 /* If we are in IGNORE mode and the first character in the
117 line is a white space we ignore the line and start
119 if (ignore
&& isspace (*first_unused
))
122 /* Terminate the line for any case. */
123 cp
= strpbrk (first_unused
, "#\n");
127 /* Skip leading blanks. */
128 while (isspace (*line
))
131 result
->alias_name
= first_unused
;
132 while (*line
!= '\0' && *line
!= ':')
133 *first_unused
++ = *line
++;
134 if (*line
== '\0' || result
->alias_name
== first_unused
)
135 /* No valid name. Ignore the line. */
138 *first_unused
++ = '\0';
139 if (room_left
< (size_t) (first_unused
- result
->alias_name
))
141 room_left
-= first_unused
- result
->alias_name
;
144 /* When we search for a specific alias we can avoid all the
145 difficult parts and compare now with the name we are
146 looking for. If it does not match we simply ignore all
147 lines until the next line containing the start of a new
149 ignore
= (match
!= NULL
150 && __strcasecmp (result
->alias_name
, match
) != 0);
154 while (isspace (*line
))
158 while (*line
!= '\0' && *line
!= ',')
159 *first_unused
++ = *line
++;
161 if (first_unused
!= cp
)
163 /* OK, we can have a regular entry or an include
167 *first_unused
++ = '\0';
169 if (strncmp (cp
, ":include:", 9) != 0)
171 if (room_left
< (first_unused
- cp
) + sizeof (char *))
173 room_left
-= (first_unused
- cp
) + sizeof (char *);
175 ++result
->alias_members_len
;
179 /* Oh well, we have to read the addressed file. */
181 char *old_line
= NULL
;
185 listfile
= __nss_files_fopen (&cp
[9]);
186 /* If the file does not exist we simply ignore
189 && (old_line
= __strdup (line
)) != NULL
)
191 while (! __feof_unlocked (listfile
))
200 first_unused
[room_left
- 1] = '\xff';
201 line
= __fgets_unlocked (first_unused
, room_left
,
205 if (first_unused
[room_left
- 1] != '\xff')
212 /* Parse the line. */
213 cp
= strpbrk (line
, "#\n");
219 while (isspace (*line
))
223 while (*line
!= '\0' && *line
!= ',')
224 *first_unused
++ = *line
++;
229 if (first_unused
!= cp
)
231 *first_unused
++ = '\0';
232 if (room_left
< ((first_unused
- cp
)
233 + __alignof__ (char *)))
239 room_left
-= ((first_unused
- cp
)
240 + __alignof__ (char *));
241 ++result
->alias_members_len
;
244 while (*line
!= '\0');
248 first_unused
[room_left
- 1] = '\0';
249 strncpy (first_unused
, old_line
, room_left
);
254 if (first_unused
[room_left
- 1] != '\0')
262 /* Get the next line. But we must be careful. We
263 must not read the whole line at once since it
264 might belong to the current alias. Simply read
265 the first character. If it is a white space we
266 have a continuation line. Otherwise it is the
267 beginning of a new alias and we can push back the
268 just read character. */
271 ch
= __getc_unlocked (stream
);
272 if (ch
== EOF
|| ch
== '\n' || !isspace (ch
))
276 /* Now prepare the return. Provide string
277 pointers for the currently selected aliases. */
281 /* Adjust the pointer so it is aligned for
283 first_unused
+= __alignof__ (char *) - 1;
284 first_unused
-= ((first_unused
- (char *) 0)
285 % __alignof__ (char *));
286 result
->alias_members
= (char **) first_unused
;
288 /* Compute addresses of alias entry strings. */
289 cp
= result
->alias_name
;
290 for (cnt
= 0; cnt
< result
->alias_members_len
; ++cnt
)
292 cp
= strchr (cp
, '\0') + 1;
293 result
->alias_members
[cnt
] = cp
;
296 status
= (result
->alias_members_len
== 0
297 ? NSS_STATUS_RETURN
: NSS_STATUS_SUCCESS
);
301 /* The just read character is a white space and so
303 first_unused
[room_left
- 1] = '\xff';
304 line
= __fgets_unlocked (first_unused
, room_left
, stream
);
307 /* Continuation line without any data and
308 without a newline at the end. Treat it as an
309 empty line and retry, reaching EOF once
315 if (first_unused
[room_left
- 1] != '\xff')
317 cp
= strpbrk (line
, "#\n");
324 if (status
!= NSS_STATUS_NOTFOUND
)
325 /* We read something. In any case break here. */
334 _nss_files_getaliasent_r (struct aliasent
*result
, char *buffer
, size_t buflen
,
337 /* Return next entry in host file. */
339 struct nss_files_per_file_data
*data
;
340 enum nss_status status
= __nss_files_data_open (&data
, nss_file_aliasent
,
341 "/etc/aliases", errnop
, NULL
);
342 if (status
!= NSS_STATUS_SUCCESS
)
345 result
->alias_local
= 1;
347 /* Read lines until we get a definite result. */
349 status
= get_next_alias (data
->stream
, NULL
, result
, buffer
, buflen
,
351 while (status
== NSS_STATUS_RETURN
);
353 __nss_files_data_put (data
);
356 libc_hidden_def (_nss_files_getaliasent_r
)
359 _nss_files_getaliasbyname_r (const char *name
, struct aliasent
*result
,
360 char *buffer
, size_t buflen
, int *errnop
)
362 /* Return next entry in host file. */
363 enum nss_status status
= NSS_STATUS_SUCCESS
;
368 __set_errno (EINVAL
);
369 return NSS_STATUS_UNAVAIL
;
372 /* Open the stream. */
373 status
= internal_setent (&stream
);
375 if (status
== NSS_STATUS_SUCCESS
)
377 result
->alias_local
= 1;
379 /* Read lines until we get a definite result. */
381 status
= get_next_alias (stream
, name
, result
, buffer
, buflen
, errnop
);
382 while (status
== NSS_STATUS_RETURN
);
389 libc_hidden_def (_nss_files_getaliasbyname_r
)