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