Update copyright notices with scripts/update-copyrights.
[jlayton/glibc.git] / nis / nss_nis / nis-alias.c
1 /* Copyright (C) 1996-2013 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
4
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.
9
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.
14
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    <http://www.gnu.org/licenses/>.  */
18
19 #include <nss.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <aliases.h>
24 #include <bits/libc-lock.h>
25 #include <rpcsvc/yp.h>
26 #include <rpcsvc/ypclnt.h>
27
28 #include "nss-nis.h"
29
30 __libc_lock_define_initialized (static, lock)
31
32 static bool_t new_start = 1;
33 static char *oldkey;
34 static int oldkeylen;
35
36 static int
37 _nss_nis_parse_aliasent (const char *key, char *alias, struct aliasent *result,
38                          char *buffer, size_t buflen, int *errnop)
39 {
40   char *first_unused = buffer + strlen (alias) + 1;
41   size_t room_left =
42     buflen - (buflen % __alignof__ (char *)) - strlen (alias) - 2;
43   char *line;
44   char *cp;
45
46   result->alias_members_len = 0;
47   *first_unused = '\0';
48   first_unused++;
49   strcpy (first_unused, key);
50
51   if (first_unused[room_left - 1] != '\0')
52     {
53       /* The line is too long for our buffer.  */
54     no_more_room:
55       *errnop = ERANGE;
56       return -1;
57     }
58
59   result->alias_name = first_unused;
60
61   /* Terminate the line for any case.  */
62   cp = strpbrk (alias, "#\n");
63   if (cp != NULL)
64     *cp = '\0';
65
66   first_unused += strlen (result->alias_name) + 1;
67   /* Adjust the pointer so it is aligned for
68      storing pointers.  */
69   first_unused += __alignof__ (char *) - 1;
70   first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
71   result->alias_members = (char **) first_unused;
72
73   line = alias;
74
75   while (*line != '\0')
76     {
77       /* Skip leading blanks.  */
78       while (isspace (*line))
79         line++;
80
81       if (*line == '\0')
82         break;
83
84       if (room_left < sizeof (char *))
85           goto no_more_room;
86       room_left -= sizeof (char *);
87       result->alias_members[result->alias_members_len] = line;
88
89       while (*line != '\0' && *line != ',')
90         line++;
91
92       if (line != result->alias_members[result->alias_members_len])
93         {
94           *line = '\0';
95           line++;
96           result->alias_members_len++;
97         }
98     }
99   return result->alias_members_len == 0 ? 0 : 1;
100 }
101
102 enum nss_status
103 _nss_nis_setaliasent (void)
104 {
105   __libc_lock_lock (lock);
106
107   new_start = 1;
108   if (oldkey != NULL)
109     {
110       free (oldkey);
111       oldkey = NULL;
112       oldkeylen = 0;
113     }
114
115   __libc_lock_unlock (lock);
116
117   return NSS_STATUS_SUCCESS;
118 }
119 /* The 'endaliasent' function is identical.  */
120 strong_alias (_nss_nis_setaliasent, _nss_nis_endaliasent)
121
122 static enum nss_status
123 internal_nis_getaliasent_r (struct aliasent *alias, char *buffer,
124                             size_t buflen, int *errnop)
125 {
126   char *domain;
127
128   if (__builtin_expect (yp_get_default_domain (&domain), 0))
129     return NSS_STATUS_UNAVAIL;
130
131   alias->alias_local = 0;
132
133   /* Get the next entry until we found a correct one. */
134   int parse_res;
135   do
136     {
137       char *result;
138       int len;
139       char *outkey;
140       int keylen;
141       int yperr;
142
143       if (new_start)
144         yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result,
145                           &len);
146       else
147         yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey,
148                          &keylen, &result, &len);
149
150       if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
151         {
152           enum nss_status retval = yperr2nss (yperr);
153
154           if (retval == NSS_STATUS_TRYAGAIN)
155             *errnop = errno;
156           return retval;
157         }
158
159       if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
160         {
161           free (result);
162           *errnop = ERANGE;
163           return NSS_STATUS_TRYAGAIN;
164         }
165       char *p = strncpy (buffer, result, len);
166       buffer[len] = '\0';
167       while (isspace (*p))
168         ++p;
169       free (result);
170
171       parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer,
172                                            buflen, errnop);
173       if (__builtin_expect (parse_res == -1, 0))
174         {
175           free (outkey);
176           *errnop = ERANGE;
177           return NSS_STATUS_TRYAGAIN;
178         }
179
180       free (oldkey);
181       oldkey = outkey;
182       oldkeylen = keylen;
183       new_start = 0;
184     }
185   while (!parse_res);
186
187   return NSS_STATUS_SUCCESS;
188 }
189
190 enum nss_status
191 _nss_nis_getaliasent_r (struct aliasent *alias, char *buffer, size_t buflen,
192                         int *errnop)
193 {
194   enum nss_status status;
195
196   __libc_lock_lock (lock);
197
198   status = internal_nis_getaliasent_r (alias, buffer, buflen, errnop);
199
200   __libc_lock_unlock (lock);
201
202   return status;
203 }
204
205 enum nss_status
206 _nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
207                            char *buffer, size_t buflen, int *errnop)
208 {
209   if (name == NULL)
210     {
211       *errnop = EINVAL;
212       return NSS_STATUS_UNAVAIL;
213     }
214
215   char *domain;
216   if (__builtin_expect (yp_get_default_domain (&domain), 0))
217     return NSS_STATUS_UNAVAIL;
218
219   size_t namlen = strlen (name);
220   char *name2;
221   int use_alloca = __libc_use_alloca (namlen + 1);
222   if (use_alloca)
223     name2 = __alloca (namlen + 1);
224   else
225     {
226       name2 = malloc (namlen + 1);
227       if (name2 == NULL)
228         {
229           *errnop = ENOMEM;
230           return NSS_STATUS_TRYAGAIN;
231         }
232     }
233
234   /* Convert name to lowercase.  */
235   size_t i;
236   for (i = 0; i < namlen; ++i)
237     name2[i] = _tolower (name[i]);
238   name2[i] = '\0';
239
240   char *result;
241   int len;
242   int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len);
243
244   if (!use_alloca)
245     free (name2);
246
247   if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
248     {
249       enum nss_status retval = yperr2nss (yperr);
250
251       if (retval == NSS_STATUS_TRYAGAIN)
252         *errnop = errno;
253       return retval;
254     }
255
256   if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
257     {
258       free (result);
259       *errnop = ERANGE;
260       return NSS_STATUS_TRYAGAIN;
261     }
262
263   char *p = strncpy (buffer, result, len);
264   buffer[len] = '\0';
265   while (isspace (*p))
266     ++p;
267   free (result);
268
269   alias->alias_local = 0;
270   int parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen,
271                                            errnop);
272   if (__builtin_expect (parse_res < 1, 0))
273     {
274       if (parse_res == -1)
275         return NSS_STATUS_TRYAGAIN;
276       else
277         return NSS_STATUS_NOTFOUND;
278     }
279
280   return NSS_STATUS_SUCCESS;
281 }