Update NIS+.
[kopensolaris-gnu/glibc.git] / nis / nss_nisplus / nisplus-alias.c
1 /* Copyright (C) 1997 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <nss.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <aliases.h>
25 #include <bits/libc-lock.h>
26 #include <rpcsvc/nis.h>
27
28 #include "nss-nisplus.h"
29
30 __libc_lock_define_initialized (static, lock)
31
32 static nis_result *result = NULL;
33 static u_long next_entry = 0;
34 static nis_name tablename_val = NULL;
35 static u_long tablename_len = 0;
36
37 #define NISENTRYVAL(idx,col,res) \
38         ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
39
40 #define NISENTRYLEN(idx,col,res) \
41         ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
42
43 static enum nss_status
44 _nss_create_tablename (int *errnop)
45 {
46   if (tablename_val == NULL)
47     {
48       char buf [40 + strlen (nis_local_directory ())];
49       char *p;
50
51       p = __stpcpy (buf, "mail_aliases.org_dir.");
52       p = __stpcpy (p, nis_local_directory ());
53       tablename_val = __strdup (buf);
54       if (tablename_val == NULL)
55         {
56           *errnop = errno;
57           return NSS_STATUS_TRYAGAIN;
58         }
59       tablename_len = strlen (tablename_val);
60     }
61   return NSS_STATUS_SUCCESS;
62 }
63
64 static int
65 _nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry,
66                              struct aliasent *alias, char *buffer,
67                              size_t buflen, int *errnop)
68 {
69   if (result == NULL)
70     return 0;
71
72   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
73       || __type_of (&result->objects.objects_val[entry]) != NIS_ENTRY_OBJ
74       || strcmp (result->objects.objects_val[entry].EN_data.en_type,
75                  "mail_aliases") != 0
76       || result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 2)
77     return 0;
78   else
79     {
80       char *first_unused = buffer + NISENTRYLEN (0, 1, result) + 1;
81       size_t room_left =
82         buflen - (buflen % __alignof__ (char *)) -
83         NISENTRYLEN (0, 1, result) - 2;
84       char *line;
85       char *cp;
86
87       if (NISENTRYLEN (entry, 1, result) >= buflen)
88         {
89           /* The line is too long for our buffer.  */
90         no_more_room:
91           *errnop = ERANGE;
92           return -1;
93         }
94       else
95         {
96           strncpy (buffer, NISENTRYVAL (entry, 1, result),
97                    NISENTRYLEN (entry, 1, result));
98           buffer[NISENTRYLEN (entry, 1, result)] = '\0';
99         }
100
101       if (NISENTRYLEN(entry, 0, result) >= room_left)
102         goto no_more_room;
103
104       alias->alias_local = 0;
105       alias->alias_members_len = 0;
106       *first_unused = '\0';
107       ++first_unused;
108       strcpy (first_unused, NISENTRYVAL (entry, 0, result));
109       first_unused[NISENTRYLEN (entry, 0, result)] = '\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
117       first_unused += strlen (alias->alias_name) +1;
118       /* Adjust the pointer so it is aligned for
119          storing pointers.  */
120       first_unused += __alignof__ (char *) - 1;
121       first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
122       alias->alias_members = (char **) first_unused;
123
124       line = buffer;
125
126       while (*line != '\0')
127         {
128           /* Skip leading blanks.  */
129           while (isspace (*line))
130             ++line;
131
132           if (*line == '\0')
133             break;
134
135           if (room_left < sizeof (char *))
136             goto no_more_room;
137           room_left -= sizeof (char *);
138           alias->alias_members[alias->alias_members_len] = line;
139
140           while (*line != '\0' && *line != ',')
141             ++line;
142
143           if (line != alias->alias_members[alias->alias_members_len])
144             {
145               *line++ = '\0';
146               alias->alias_members_len++;
147             }
148         }
149
150       return alias->alias_members_len == 0 ? 0 : 1;
151     }
152 }
153
154 static enum nss_status
155 internal_setaliasent (void)
156 {
157   enum nss_status status;
158   int err;
159
160   if (result)
161     nis_freeresult (result);
162   result = NULL;
163
164   if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
165     return NSS_STATUS_UNAVAIL;
166
167   next_entry = 0;
168   result = nis_list (tablename_val, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
169   status = niserr2nss (result->status);
170   if (status != NSS_STATUS_SUCCESS)
171     {
172       nis_freeresult (result);
173       result = NULL;
174     }
175   return status;
176 }
177
178 enum nss_status
179 _nss_nisplus_setaliasent (void)
180 {
181   enum nss_status status;
182
183   __libc_lock_lock (lock);
184
185   status = internal_setaliasent ();
186
187   __libc_lock_unlock (lock);
188
189   return status;
190 }
191
192 enum nss_status
193 _nss_nisplus_endaliasent (void)
194 {
195   __libc_lock_lock (lock);
196
197   if (result)
198     nis_freeresult (result);
199   result = NULL;
200   next_entry = 0;
201
202   __libc_lock_unlock (lock);
203
204   return NSS_STATUS_SUCCESS;
205 }
206
207 static enum nss_status
208 internal_nisplus_getaliasent_r (struct aliasent *alias,
209                                 char *buffer, size_t buflen, int *errnop)
210 {
211   int parse_res;
212
213   if (result == NULL)
214     {
215       enum nss_status status;
216
217       status = internal_setaliasent ();
218       if (result == NULL || status != NSS_STATUS_SUCCESS)
219         return status;
220     }
221
222   /* Get the next entry until we found a correct one. */
223   do
224     {
225       if (next_entry >= result->objects.objects_len)
226         return NSS_STATUS_NOTFOUND;
227
228       parse_res = _nss_nisplus_parse_aliasent (result, next_entry, alias,
229                                                buffer, buflen, errnop);
230       if (parse_res == -1)
231         return NSS_STATUS_TRYAGAIN;
232
233       ++next_entry;
234     } while (!parse_res);
235
236   return NSS_STATUS_SUCCESS;
237 }
238
239 enum nss_status
240 _nss_nisplus_getaliasent_r (struct aliasent *result, char *buffer,
241                             size_t buflen, int *errnop)
242 {
243   int status;
244
245   __libc_lock_lock (lock);
246
247   status = internal_nisplus_getaliasent_r (result, buffer, buflen, errnop);
248
249   __libc_lock_unlock (lock);
250
251   return status;
252 }
253
254 enum nss_status
255 _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
256                             char *buffer, size_t buflen, int *errnop)
257 {
258   int parse_res;
259
260   if (tablename_val == NULL)
261     {
262       enum nss_status status = _nss_create_tablename (errnop);
263       if (status != NSS_STATUS_SUCCESS)
264         return status;
265     }
266
267   if (name != NULL)
268     {
269       *errnop = EINVAL;
270       return NSS_STATUS_UNAVAIL;
271     }
272   else
273     {
274       nis_result *result;
275       char buf[strlen (name) + 30 + tablename_len];
276
277       sprintf (buf, "[name=%s],%s", name, tablename_val);
278
279       result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
280
281       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
282         return niserr2nss (result->status);
283
284       parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
285                                                buffer, buflen, errnop);
286       if (parse_res < 1)
287         {
288           if (parse_res == -1)
289             return NSS_STATUS_TRYAGAIN;
290           else
291             return NSS_STATUS_NOTFOUND;
292         }
293       return NSS_STATUS_SUCCESS;
294     }
295 }