]>
Commit | Line | Data |
---|---|---|
d614a753 | 1 | /* Copyright (C) 1997-2020 Free Software Foundation, Inc. |
e61abf83 UD |
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 | |
41bdb6e2 AJ |
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. | |
e61abf83 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
e61abf83 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
e61abf83 | 18 | |
636e689e | 19 | #include <atomic.h> |
e61abf83 UD |
20 | #include <nss.h> |
21 | #include <errno.h> | |
22 | #include <ctype.h> | |
23 | #include <string.h> | |
24 | #include <aliases.h> | |
ec999b8e | 25 | #include <libc-lock.h> |
e61abf83 | 26 | #include <rpcsvc/nis.h> |
e61abf83 UD |
27 | |
28 | #include "nss-nisplus.h" | |
29 | ||
30 | __libc_lock_define_initialized (static, lock) | |
31 | ||
fc9f33e3 UD |
32 | static nis_result *result; |
33 | static u_long next_entry; | |
34 | static nis_name tablename_val; | |
636e689e | 35 | static size_t tablename_len; |
e61abf83 | 36 | |
3fc044a1 UD |
37 | #define NISENTRYVAL(idx, col, res) \ |
38 | (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) | |
e61abf83 | 39 | |
3fc044a1 UD |
40 | #define NISENTRYLEN(idx, col, res) \ |
41 | (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) | |
2d7da676 UD |
42 | |
43 | static enum nss_status | |
d71b808a | 44 | _nss_create_tablename (int *errnop) |
2d7da676 UD |
45 | { |
46 | if (tablename_val == NULL) | |
47 | { | |
636e689e UD |
48 | const char *local_dir = nis_local_directory (); |
49 | size_t local_dir_len = strlen (local_dir); | |
50 | static const char prefix[] = "mail_aliases.org_dir."; | |
2d7da676 | 51 | |
636e689e | 52 | char *p = malloc (sizeof (prefix) + local_dir_len); |
c8e82b4a | 53 | if (p == NULL) |
d71b808a UD |
54 | { |
55 | *errnop = errno; | |
56 | return NSS_STATUS_TRYAGAIN; | |
57 | } | |
636e689e UD |
58 | |
59 | memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); | |
60 | ||
61 | tablename_len = sizeof (prefix) - 1 + local_dir_len; | |
62 | ||
63 | atomic_write_barrier (); | |
64 | ||
65 | tablename_val = p; | |
2d7da676 | 66 | } |
636e689e | 67 | |
2d7da676 UD |
68 | return NSS_STATUS_SUCCESS; |
69 | } | |
e61abf83 UD |
70 | |
71 | static int | |
2d7da676 UD |
72 | _nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry, |
73 | struct aliasent *alias, char *buffer, | |
d71b808a | 74 | size_t buflen, int *errnop) |
e61abf83 UD |
75 | { |
76 | if (result == NULL) | |
26dee9c4 | 77 | return 0; |
e61abf83 | 78 | |
d71b808a | 79 | if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) |
3fc044a1 UD |
80 | || __type_of (&NIS_RES_OBJECT (result)[entry]) != NIS_ENTRY_OBJ |
81 | || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type, | |
d71b808a | 82 | "mail_aliases") != 0 |
3fc044a1 | 83 | || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 2) |
26dee9c4 | 84 | return 0; |
636e689e | 85 | |
636e689e | 86 | if (NISENTRYLEN (entry, 1, result) >= buflen) |
0ecb606c | 87 | { |
636e689e UD |
88 | /* The line is too long for our buffer. */ |
89 | no_more_room: | |
90 | *errnop = ERANGE; | |
91 | return -1; | |
92 | } | |
93 | ||
94 | char *cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result), | |
95 | NISENTRYLEN (entry, 1, result)); | |
96 | *cp = '\0'; | |
97 | ||
3fc044a1 UD |
98 | char *first_unused = cp + 1; |
99 | size_t room_left = buflen - (first_unused - buffer); | |
636e689e UD |
100 | |
101 | alias->alias_local = 0; | |
102 | alias->alias_members_len = 0; | |
3fc044a1 UD |
103 | |
104 | if (NISENTRYLEN (entry, 0, result) >= room_left) | |
105 | goto no_more_room; | |
106 | ||
636e689e UD |
107 | cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result), |
108 | NISENTRYLEN (entry, 0, result)); | |
109 | *cp = '\0'; | |
110 | alias->alias_name = first_unused; | |
111 | ||
112 | /* Terminate the line for any case. */ | |
113 | cp = strpbrk (alias->alias_name, "#\n"); | |
114 | if (cp != NULL) | |
115 | *cp = '\0'; | |
116 | ||
3fc044a1 UD |
117 | size_t len = strlen (alias->alias_name) + 1; |
118 | first_unused += len; | |
119 | room_left -= len; | |
120 | ||
636e689e UD |
121 | /* Adjust the pointer so it is aligned for |
122 | storing pointers. */ | |
3fc044a1 UD |
123 | size_t adjust = ((__alignof__ (char *) |
124 | - (first_unused - (char *) 0) % __alignof__ (char *)) | |
125 | % __alignof__ (char *)); | |
126 | if (room_left < adjust) | |
127 | goto no_more_room; | |
128 | first_unused += adjust; | |
129 | room_left -= adjust; | |
130 | ||
636e689e UD |
131 | alias->alias_members = (char **) first_unused; |
132 | ||
133 | char *line = buffer; | |
134 | while (*line != '\0') | |
135 | { | |
136 | /* Skip leading blanks. */ | |
137 | while (isspace (*line)) | |
138 | ++line; | |
139 | ||
140 | if (*line == '\0') | |
141 | break; | |
0ecb606c | 142 | |
636e689e | 143 | if (room_left < sizeof (char *)) |
e61abf83 | 144 | goto no_more_room; |
636e689e UD |
145 | room_left -= sizeof (char *); |
146 | alias->alias_members[alias->alias_members_len] = line; | |
147 | ||
148 | while (*line != '\0' && *line != ',') | |
149 | ++line; | |
e61abf83 | 150 | |
636e689e | 151 | if (line != alias->alias_members[alias->alias_members_len]) |
e61abf83 | 152 | { |
636e689e | 153 | *line++ = '\0'; |
3fc044a1 | 154 | ++alias->alias_members_len; |
e61abf83 | 155 | } |
3fc044a1 UD |
156 | else if (*line == ',') |
157 | ++line; | |
a334319f | 158 | } |
636e689e UD |
159 | |
160 | return alias->alias_members_len == 0 ? 0 : 1; | |
e61abf83 UD |
161 | } |
162 | ||
2d7da676 UD |
163 | static enum nss_status |
164 | internal_setaliasent (void) | |
e61abf83 | 165 | { |
8f2ece69 | 166 | enum nss_status status; |
d71b808a | 167 | int err; |
8f2ece69 | 168 | |
636e689e UD |
169 | if (result != NULL) |
170 | { | |
171 | nis_freeresult (result); | |
172 | result = NULL; | |
173 | } | |
2d7da676 | 174 | |
d71b808a | 175 | if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS) |
2d7da676 UD |
176 | return NSS_STATUS_UNAVAIL; |
177 | ||
178 | next_entry = 0; | |
d71b808a | 179 | result = nis_list (tablename_val, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); |
901956a5 | 180 | if (result == NULL) |
e61abf83 | 181 | { |
901956a5 UD |
182 | status = NSS_STATUS_TRYAGAIN; |
183 | __set_errno (ENOMEM); | |
184 | } | |
185 | else | |
186 | { | |
187 | status = niserr2nss (result->status); | |
188 | if (status != NSS_STATUS_SUCCESS) | |
189 | { | |
190 | nis_freeresult (result); | |
191 | result = NULL; | |
192 | } | |
e61abf83 | 193 | } |
8f2ece69 | 194 | return status; |
2d7da676 UD |
195 | } |
196 | ||
197 | enum nss_status | |
198 | _nss_nisplus_setaliasent (void) | |
199 | { | |
200 | enum nss_status status; | |
201 | ||
202 | __libc_lock_lock (lock); | |
203 | ||
204 | status = internal_setaliasent (); | |
e61abf83 UD |
205 | |
206 | __libc_lock_unlock (lock); | |
207 | ||
2d7da676 | 208 | return status; |
e61abf83 UD |
209 | } |
210 | ||
211 | enum nss_status | |
212 | _nss_nisplus_endaliasent (void) | |
213 | { | |
214 | __libc_lock_lock (lock); | |
215 | ||
636e689e UD |
216 | if (result != NULL) |
217 | { | |
218 | nis_freeresult (result); | |
219 | result = NULL; | |
220 | } | |
2d7da676 | 221 | next_entry = 0; |
e61abf83 UD |
222 | |
223 | __libc_lock_unlock (lock); | |
224 | ||
225 | return NSS_STATUS_SUCCESS; | |
226 | } | |
227 | ||
228 | static enum nss_status | |
229 | internal_nisplus_getaliasent_r (struct aliasent *alias, | |
d71b808a | 230 | char *buffer, size_t buflen, int *errnop) |
e61abf83 UD |
231 | { |
232 | int parse_res; | |
233 | ||
2d7da676 | 234 | if (result == NULL) |
8f2ece69 UD |
235 | { |
236 | enum nss_status status; | |
237 | ||
238 | status = internal_setaliasent (); | |
239 | if (result == NULL || status != NSS_STATUS_SUCCESS) | |
240 | return status; | |
241 | } | |
2d7da676 | 242 | |
e61abf83 UD |
243 | /* Get the next entry until we found a correct one. */ |
244 | do | |
245 | { | |
2d7da676 UD |
246 | if (next_entry >= result->objects.objects_len) |
247 | return NSS_STATUS_NOTFOUND; | |
e61abf83 | 248 | |
d71b808a UD |
249 | parse_res = _nss_nisplus_parse_aliasent (result, next_entry, alias, |
250 | buffer, buflen, errnop); | |
251 | if (parse_res == -1) | |
60c96635 UD |
252 | return NSS_STATUS_TRYAGAIN; |
253 | ||
2d7da676 | 254 | ++next_entry; |
636e689e UD |
255 | } |
256 | while (!parse_res); | |
e61abf83 UD |
257 | |
258 | return NSS_STATUS_SUCCESS; | |
259 | } | |
260 | ||
261 | enum nss_status | |
262 | _nss_nisplus_getaliasent_r (struct aliasent *result, char *buffer, | |
d71b808a | 263 | size_t buflen, int *errnop) |
e61abf83 UD |
264 | { |
265 | int status; | |
266 | ||
267 | __libc_lock_lock (lock); | |
268 | ||
d71b808a | 269 | status = internal_nisplus_getaliasent_r (result, buffer, buflen, errnop); |
e61abf83 UD |
270 | |
271 | __libc_lock_unlock (lock); | |
272 | ||
273 | return status; | |
274 | } | |
275 | ||
276 | enum nss_status | |
277 | _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias, | |
d71b808a | 278 | char *buffer, size_t buflen, int *errnop) |
e61abf83 UD |
279 | { |
280 | int parse_res; | |
281 | ||
2d7da676 | 282 | if (tablename_val == NULL) |
d71b808a | 283 | { |
636e689e UD |
284 | __libc_lock_lock (lock); |
285 | ||
d71b808a | 286 | enum nss_status status = _nss_create_tablename (errnop); |
636e689e UD |
287 | |
288 | __libc_lock_unlock (lock); | |
289 | ||
d71b808a UD |
290 | if (status != NSS_STATUS_SUCCESS) |
291 | return status; | |
292 | } | |
2d7da676 | 293 | |
f88759ea | 294 | if (name == NULL) |
ac9f45cf UD |
295 | { |
296 | *errnop = EINVAL; | |
297 | return NSS_STATUS_UNAVAIL; | |
298 | } | |
e61abf83 | 299 | |
636e689e UD |
300 | char buf[strlen (name) + 9 + tablename_len]; |
301 | int olderr = errno; | |
e61abf83 | 302 | |
636e689e | 303 | snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); |
e61abf83 | 304 | |
636e689e | 305 | nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); |
e61abf83 | 306 | |
636e689e UD |
307 | if (result == NULL) |
308 | { | |
309 | *errnop = ENOMEM; | |
310 | return NSS_STATUS_TRYAGAIN; | |
311 | } | |
34816665 | 312 | |
a1ffb40e | 313 | if (__glibc_unlikely (niserr2nss (result->status) != NSS_STATUS_SUCCESS)) |
0292b0dd UD |
314 | { |
315 | enum nss_status status = niserr2nss (result->status); | |
316 | nis_freeresult (result); | |
317 | return status; | |
318 | } | |
636e689e UD |
319 | |
320 | parse_res = _nss_nisplus_parse_aliasent (result, 0, alias, | |
321 | buffer, buflen, errnop); | |
0292b0dd UD |
322 | |
323 | /* We do not need the lookup result anymore. */ | |
324 | nis_freeresult (result); | |
325 | ||
a1ffb40e | 326 | if (__glibc_unlikely (parse_res < 1)) |
636e689e UD |
327 | { |
328 | __set_errno (olderr); | |
329 | ||
330 | if (parse_res == -1) | |
331 | return NSS_STATUS_TRYAGAIN; | |
332 | else | |
333 | return NSS_STATUS_NOTFOUND; | |
e61abf83 | 334 | } |
636e689e UD |
335 | |
336 | return NSS_STATUS_SUCCESS; | |
e61abf83 | 337 | } |