Don't include <rpcsvc/nislib.h>.
[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 (void)
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         return NSS_STATUS_TRYAGAIN;
56       tablename_len = strlen (tablename_val);
57     }
58   return NSS_STATUS_SUCCESS;
59 }
60
61 static int
62 _nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry,
63                              struct aliasent *alias, char *buffer,
64                              size_t buflen)
65 {
66   if (result == NULL)
67     return 0;
68
69   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
70       __type_of (&result->objects.objects_val[entry]) != ENTRY_OBJ ||
71       strcmp(result->objects.objects_val[entry].EN_data.en_type,
72              "mail_aliases") != 0 ||
73       result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 2)
74     return 0;
75   else
76     {
77       char *first_unused = buffer + NISENTRYLEN(0, 1, result) + 1;
78       size_t room_left =
79         buflen - (buflen % __alignof__ (char *)) -
80         NISENTRYLEN(0, 1, result) - 2;
81       char *line;
82       char *cp;
83
84       if (NISENTRYLEN(entry, 1, result) >= buflen)
85         {
86           /* The line is too long for our buffer.  */
87         no_more_room:
88           __set_errno (ERANGE);
89           return -1;
90         }
91       else
92         {
93           strncpy (buffer, NISENTRYVAL(entry, 1, result),
94                    NISENTRYLEN(entry, 1, result));
95           buffer[NISENTRYLEN(entry, 1, result)] = '\0';
96         }
97
98       if (NISENTRYLEN(entry, 0, result) >= room_left)
99         goto no_more_room;
100
101       alias->alias_local = 0;
102       alias->alias_members_len = 0;
103       *first_unused = '\0';
104       ++first_unused;
105       strcpy (first_unused, NISENTRYVAL(entry, 0, result));
106       first_unused[NISENTRYLEN(entry, 0, result)] = '\0';
107       alias->alias_name = first_unused;
108
109       /* Terminate the line for any case.  */
110       cp = strpbrk (alias->alias_name, "#\n");
111       if (cp != NULL)
112         *cp = '\0';
113
114       first_unused += strlen (alias->alias_name) +1;
115       /* Adjust the pointer so it is aligned for
116          storing pointers.  */
117       first_unused += __alignof__ (char *) - 1;
118       first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
119       alias->alias_members = (char **) first_unused;
120
121       line = buffer;
122
123       while (*line != '\0')
124         {
125           /* Skip leading blanks.  */
126           while (isspace (*line))
127             line++;
128
129           if (*line == '\0')
130             break;
131
132           if (room_left < sizeof (char *))
133             goto no_more_room;
134           room_left -= sizeof (char *);
135           alias->alias_members[alias->alias_members_len] = line;
136
137           while (*line != '\0' && *line != ',')
138             line++;
139
140           if (line != alias->alias_members[alias->alias_members_len])
141             {
142               *line = '\0';
143               line++;
144               alias->alias_members_len++;
145             }
146         }
147
148       return alias->alias_members_len == 0 ? 0 : 1;
149     }
150 }
151
152 static enum nss_status
153 internal_setaliasent (void)
154 {
155   enum nss_status status;
156
157   if (result)
158     nis_freeresult (result);
159   result = NULL;
160
161   if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
162     return NSS_STATUS_UNAVAIL;
163
164   next_entry = 0;
165   result = nis_list(tablename_val, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
166   status = niserr2nss (result->status);
167   if (status != NSS_STATUS_SUCCESS)
168     {
169       nis_freeresult (result);
170       result = NULL;
171     }
172   return status;
173 }
174
175 enum nss_status
176 _nss_nisplus_setaliasent (void)
177 {
178   enum nss_status status;
179
180   __libc_lock_lock (lock);
181
182   status = internal_setaliasent ();
183
184   __libc_lock_unlock (lock);
185
186   return status;
187 }
188
189 enum nss_status
190 _nss_nisplus_endaliasent (void)
191 {
192   __libc_lock_lock (lock);
193
194   if (result)
195     nis_freeresult (result);
196   result = NULL;
197   next_entry = 0;
198
199   __libc_lock_unlock (lock);
200
201   return NSS_STATUS_SUCCESS;
202 }
203
204 static enum nss_status
205 internal_nisplus_getaliasent_r (struct aliasent *alias,
206                                 char *buffer, size_t buflen)
207 {
208   int parse_res;
209
210   if (result == NULL)
211     {
212       enum nss_status status;
213
214       status = internal_setaliasent ();
215       if (result == NULL || status != NSS_STATUS_SUCCESS)
216         return status;
217     }
218
219   /* Get the next entry until we found a correct one. */
220   do
221     {
222       if (next_entry >= result->objects.objects_len)
223         return NSS_STATUS_NOTFOUND;
224
225       if ((parse_res = _nss_nisplus_parse_aliasent (result, next_entry, alias,
226                                                     buffer, buflen)) == -1)
227         return NSS_STATUS_TRYAGAIN;
228
229       ++next_entry;
230     } while (!parse_res);
231
232   return NSS_STATUS_SUCCESS;
233 }
234
235 enum nss_status
236 _nss_nisplus_getaliasent_r (struct aliasent *result, char *buffer,
237                             size_t buflen)
238 {
239   int status;
240
241   __libc_lock_lock (lock);
242
243   status = internal_nisplus_getaliasent_r (result, buffer, buflen);
244
245   __libc_lock_unlock (lock);
246
247   return status;
248 }
249
250 enum nss_status
251 _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
252                             char *buffer, size_t buflen)
253 {
254   int parse_res;
255
256   if (tablename_val == NULL)
257     if (_nss_create_tablename() != NSS_STATUS_SUCCESS)
258       return NSS_STATUS_UNAVAIL;
259
260   if (name != NULL || strlen(name) <= 8)
261     {
262       nis_result *result;
263       char buf[strlen (name) + 30 + tablename_len];
264
265       sprintf(buf, "[name=%s],%s", name, tablename_val);
266
267       result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
268
269       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
270         return niserr2nss (result->status);
271
272       if ((parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
273                                                     buffer, buflen)) == -1)
274         return NSS_STATUS_TRYAGAIN;
275
276       if (parse_res)
277         return NSS_STATUS_SUCCESS;
278     }
279   return NSS_STATUS_NOTFOUND;
280 }