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