4a4580a1e6cb3fd987dbe62df54f7b8fa6d47931
[jlayton/glibc.git] / nis / nis_subr.c
1 /* Copyright (c) 1997-2014 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
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 <errno.h>
20 #include <string.h>
21 #include <rpcsvc/nis.h>
22
23 nis_name
24 nis_leaf_of (const_nis_name name)
25 {
26   static char result[NIS_MAXNAMELEN + 1];
27
28   return nis_leaf_of_r (name, result, NIS_MAXNAMELEN);
29 }
30
31 nis_name
32 nis_leaf_of_r (const_nis_name name, char *buffer, size_t buflen)
33 {
34   size_t i = 0;
35
36   buffer[0] = '\0';
37
38   while (name[i] != '.' && name[i] != '\0')
39     i++;
40
41   if (__builtin_expect (i >= buflen, 0))
42     {
43       __set_errno (ERANGE);
44       return NULL;
45     }
46
47   *((char *) __mempcpy (buffer, name, i)) = '\0';
48
49   return buffer;
50 }
51 libnsl_hidden_def (nis_leaf_of_r)
52
53 nis_name
54 nis_name_of (const_nis_name name)
55 {
56   static char result[NIS_MAXNAMELEN + 1];
57
58   return nis_name_of_r (name, result, NIS_MAXNAMELEN);
59 }
60
61 nis_name
62 nis_name_of_r (const_nis_name name, char *buffer, size_t buflen)
63 {
64   char *local_domain;
65   int diff;
66
67   local_domain = nis_local_directory ();
68
69   diff = strlen (name) - strlen (local_domain);
70   if (diff <= 0)
71     return NULL;
72
73   if (strcmp (&name[diff], local_domain) != 0)
74     return NULL;
75
76   if ((size_t) diff >= buflen)
77     {
78       __set_errno (ERANGE);
79       return NULL;
80     }
81
82   *((char *) __mempcpy (buffer, name, diff - 1)) = '\0';
83
84   if (diff - 1 == 0)
85     return NULL;
86
87   return buffer;
88 }
89 libnsl_hidden_def (nis_name_of_r)
90
91 static int __always_inline
92 count_dots (const_nis_name str)
93 {
94   int count = 0;
95
96   for (size_t i = 0; str[i] != '\0'; ++i)
97     if (str[i] == '.')
98       ++count;
99
100   return count;
101 }
102
103 /* If we run out of memory, we don't give already allocated memory
104    free. The overhead for bringing getnames back in a safe state to
105    free it is to big. */
106 nis_name *
107 nis_getnames (const_nis_name name)
108 {
109   const char *local_domain = nis_local_directory ();
110   size_t local_domain_len = strlen (local_domain);
111   size_t name_len = strlen (name);
112   char *path;
113   int pos = 0;
114   char *saveptr = NULL;
115   int have_point;
116   const char *cp;
117   const char *cp2;
118
119   int count = 2;
120   nis_name *getnames = malloc ((count + 1) * sizeof (char *));
121   if (__builtin_expect (getnames == NULL, 0))
122       return NULL;
123
124   /* Do we have a fully qualified NIS+ name ? If yes, give it back */
125   if (name[name_len - 1] == '.')
126     {
127       if ((getnames[0] = strdup (name)) == NULL)
128         {
129         free_null:
130           while (pos-- > 0)
131             free (getnames[pos]);
132           free (getnames);
133           return NULL;
134         }
135
136       getnames[1] = NULL;
137
138       return getnames;
139     }
140
141   /* If the passed NAME is shared a suffix (the latter of course with
142      a final dot) with each other we pass back NAME with a final
143      dot.  */
144   if (local_domain_len > 2)
145     {
146       have_point = 0;
147       cp = &local_domain[local_domain_len - 2];
148       cp2 = &name[name_len - 1];
149
150       while (*cp == *cp2)
151         {
152           if (*cp == '.')
153             have_point = 1;
154           --cp;
155           --cp2;
156           if (cp < local_domain)
157             {
158               have_point = cp2 < name || *cp2 == '.';
159               break;
160             }
161           if (cp2 < name)
162             {
163               have_point = *cp == '.';
164               break;
165             }
166         }
167
168       if (have_point)
169         {
170           getnames[0] = malloc (name_len + 2);
171           if (getnames[0] == NULL)
172             goto free_null;
173
174           strcpy (stpcpy (getnames[0], name), ".");
175           ++pos;
176         }
177     }
178
179   /* Get the search path, where we have to search "name" */
180   path = getenv ("NIS_PATH");
181   if (path == NULL)
182     path = strdupa ("$");
183   else
184     path = strdupa (path);
185
186   have_point = strchr (name, '.') != NULL;
187
188   cp = __strtok_r (path, ":", &saveptr);
189   while (cp)
190     {
191       if (strcmp (cp, "$") == 0)
192         {
193           const char *cptr = local_domain;
194           char *tmp;
195
196           while (*cptr != '\0' && count_dots (cptr) >= 2)
197             {
198               if (pos >= count)
199                 {
200                   count += 5;
201                   nis_name *newp = realloc (getnames,
202                                             (count + 1) * sizeof (char *));
203                   if (__builtin_expect (newp == NULL, 0))
204                     goto free_null;
205                   getnames = newp;
206                 }
207               tmp = malloc (strlen (cptr) + local_domain_len + name_len + 2);
208               if (__builtin_expect (tmp == NULL, 0))
209                 goto free_null;
210
211               getnames[pos] = tmp;
212               tmp = stpcpy (tmp, name);
213               *tmp++ = '.';
214               if (cptr[1] != '\0')
215                 stpcpy (tmp, cptr);
216               else
217                 ++cptr;
218
219               ++pos;
220
221               while (*cptr != '.' && *cptr != '\0')
222                 ++cptr;
223               if (cptr[0] != '\0' && cptr[1] != '\0')
224                 /* If we have only ".", don't remove the "." */
225                 ++cptr;
226             }
227         }
228       else
229         {
230           char *tmp;
231           size_t cplen = strlen (cp);
232
233           if (cp[cplen - 1] == '$')
234             {
235               char *p;
236
237               tmp = malloc (cplen + local_domain_len + name_len + 2);
238               if (__builtin_expect (tmp == NULL, 0))
239                 goto free_null;
240
241               p = __stpcpy (tmp, name);
242               *p++ = '.';
243               p = __mempcpy (p, cp, cplen);
244               --p;
245               if (p[-1] != '.')
246                 *p++ = '.';
247               __stpcpy (p, local_domain);
248             }
249           else
250             {
251               char *p;
252
253               tmp = malloc (cplen + name_len + 3);
254               if (__builtin_expect (tmp == NULL, 0))
255                 goto free_null;
256
257               p = __mempcpy (tmp, name, name_len);
258               *p++ = '.';
259               p = __mempcpy (p, cp, cplen);
260               if (p[-1] != '.')
261                 *p++ = '.';
262               *p = '\0';
263             }
264
265           if (pos >= count)
266             {
267               count += 5;
268               nis_name *newp = realloc (getnames,
269                                         (count + 1) * sizeof (char *));
270               if (__builtin_expect (newp == NULL, 0))
271                 goto free_null;
272               getnames = newp;
273             }
274           getnames[pos] = tmp;
275           ++pos;
276         }
277       cp = __strtok_r (NULL, ":", &saveptr);
278     }
279
280   if (pos == 0
281       && __asprintf (&getnames[pos++], "%s%s%s%s",
282                      name, name[name_len - 1] == '.' ? "" : ".",
283                      local_domain,
284                      local_domain[local_domain_len - 1] == '.' ? "" : ".") < 0)
285     goto free_null;
286
287   getnames[pos] = NULL;
288
289   return getnames;
290 }
291 libnsl_hidden_def (nis_getnames)
292
293 void
294 nis_freenames (nis_name *names)
295 {
296   int i = 0;
297
298   while (names[i] != NULL)
299     {
300       free (names[i]);
301       ++i;
302     }
303
304   free (names);
305 }
306 libnsl_hidden_def  (nis_freenames)
307
308 name_pos
309 nis_dir_cmp (const_nis_name n1, const_nis_name n2)
310 {
311   int len1, len2;
312
313   len1 = strlen (n1);
314   len2 = strlen (n2);
315
316   if (len1 == len2)
317     {
318       if (strcmp (n1, n2) == 0)
319         return SAME_NAME;
320       else
321         return NOT_SEQUENTIAL;
322     }
323
324   if (len1 < len2)
325     {
326       if (n2[len2 - len1 - 1] != '.')
327         return NOT_SEQUENTIAL;
328       else if (strcmp (&n2[len2 - len1], n1) == 0)
329         return HIGHER_NAME;
330       else
331         return NOT_SEQUENTIAL;
332     }
333   else
334     {
335       if (n1[len1 - len2 - 1] != '.')
336         return NOT_SEQUENTIAL;
337       else if (strcmp (&n1[len1 - len2], n2) == 0)
338         return LOWER_NAME;
339       else
340         return NOT_SEQUENTIAL;
341
342     }
343 }
344 libnsl_hidden_def (nis_dir_cmp)
345
346 void
347 nis_destroy_object (nis_object *obj)
348 {
349   nis_free_object (obj);
350 }
351 libnsl_hidden_def (nis_destroy_object)