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