Rewrite parser for fixing errors and speedup.
[kopensolaris-gnu/glibc.git] / nis / nss_nisplus / nisplus-grp.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 <grp.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <libc-lock.h>
26 #include <rpcsvc/nis.h>
27 #include <rpcsvc/nislib.h>
28
29 #include "nss-nisplus.h"
30
31 __libc_lock_define_initialized (static, lock);
32
33 static nis_result *result = NULL;
34 static nis_name *names = NULL;
35
36 #define NISENTRYVAL(idx,col,res) \
37 ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
38
39 #define NISENTRYLEN(idx,col,res) \
40   ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
41
42 int
43 _nss_nisplus_parse_grent (nis_result * result, struct group *gr,
44                           char *buffer, size_t buflen)
45 {
46   char *first_unused = buffer;
47   size_t room_left = buflen;
48   char *line;
49   int count;
50   
51   if (result == NULL)
52     return 0;
53   
54   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
55       result->objects.objects_len != 1 ||
56       result->objects.objects_val[0].zo_data.zo_type != ENTRY_OBJ ||
57       strcmp (result->objects.objects_val[0].zo_data.objdata_u.en_data.en_type,
58               "group_tbl") != 0 ||
59       result->objects.objects_val[0].zo_data.objdata_u.en_data.en_cols.en_cols_len < 4)
60     return 0;
61
62   if (NISENTRYLEN (0, 0, result) >= room_left)
63     {
64       /* The line is too long for our buffer.  */
65     no_more_room:
66       __set_errno (ERANGE);
67       return 0;
68     }
69   
70   strncpy (first_unused, NISENTRYVAL (0, 0, result),
71            NISENTRYLEN (0, 0, result));
72   first_unused[NISENTRYLEN (0, 0, result)] = '\0';
73   gr->gr_name = first_unused;
74   room_left -= (strlen (first_unused) + 1);
75   first_unused += strlen (first_unused) + 1;
76
77   if (NISENTRYLEN (0, 1, result) >= room_left)
78     goto no_more_room;
79
80   strncpy (first_unused, NISENTRYVAL (0, 1, result),
81            NISENTRYLEN (0, 1, result));
82   first_unused[NISENTRYLEN (0, 1, result)] = '\0';
83   gr->gr_passwd = first_unused;
84   room_left -= (strlen (first_unused) + 1);
85   first_unused += strlen (first_unused) + 1;
86
87   if (NISENTRYLEN (0, 2, result) >= room_left)
88     goto no_more_room;
89
90   strncpy (first_unused, NISENTRYVAL (0, 2, result),
91            NISENTRYLEN (0, 2, result));
92   first_unused[NISENTRYLEN (0, 2, result)] = '\0';
93   gr->gr_gid = atoi (first_unused);
94   room_left -= (strlen (first_unused) + 1);
95   first_unused += strlen (first_unused) + 1;
96
97   if (NISENTRYLEN (0, 3, result) >= room_left)
98     goto no_more_room;
99
100   strncpy (first_unused, NISENTRYVAL (0, 3, result),
101            NISENTRYLEN (0, 3, result));
102   first_unused[NISENTRYLEN (0, 3, result)] = '\0';
103   line = first_unused;
104   room_left -= (strlen (line) + 1);
105   first_unused += strlen (line) + 1;
106   /* Adjust the pointer so it is aligned for
107      storing pointers.  */
108   first_unused += __alignof__ (char *) - 1;
109   first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
110   gr->gr_mem = (char **) first_unused;
111
112   count = 0;
113   while (*line != '\0')
114     {
115       /* Skip leading blanks.  */
116       while (isspace (*line))
117         ++line;
118
119       if (*line == '\0')
120         break;
121
122       if (room_left < sizeof (char *))
123           goto no_more_room;
124       room_left -= sizeof (char *);
125       gr->gr_mem[count] = line;
126
127       while (*line != '\0' && *line != ',' && !isspace(*line))
128         ++line;
129
130       if (line != gr->gr_mem[count])
131         {
132           if (*line != '\0')
133             {
134               *line = '\0';
135               ++line;
136             }
137           ++count;
138         }
139       else
140         gr->gr_mem[count] = NULL;
141     }
142   if (room_left < sizeof (char *))
143       goto no_more_room;
144   room_left -= sizeof (char *);
145   gr->gr_mem[count] = NULL;
146
147   return 1;
148 }
149
150 enum nss_status
151 _nss_nisplus_setgrent (void)
152 {
153   __libc_lock_lock (lock);
154
155   if (result)
156     nis_freeresult (result);
157   result = NULL;
158   if (names)
159     {
160       nis_freenames (names);
161       names = NULL;
162     }
163
164   __libc_lock_unlock (lock);
165
166   return NSS_STATUS_SUCCESS;
167 }
168
169 enum nss_status
170 _nss_nisplus_endgrent (void)
171 {
172   __libc_lock_lock (lock);
173
174   if (result)
175     nis_freeresult (result);
176   result = NULL;
177   if (names)
178     {
179       nis_freenames (names);
180       names = NULL;
181     }
182
183   __libc_lock_unlock (lock);
184
185   return NSS_STATUS_SUCCESS;
186 }
187
188 static enum nss_status
189 internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen)
190 {
191   int parse_res;
192
193   /* Get the next entry until we found a correct one. */
194   do
195     {
196       if (result == NULL)
197         {
198           names = nis_getnames ("group.org_dir");
199           if (names == NULL || names[0] == NULL)
200             return NSS_STATUS_UNAVAIL;
201
202           result = nis_first_entry (names[0]);
203           if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
204             return niserr2nss (result->status);
205         }
206       else
207         {
208           nis_result *res;
209
210           res = nis_next_entry (names[0], &result->cookie);
211           nis_freeresult (result);
212           result = res;
213           if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
214             return niserr2nss (result->status);
215         }
216
217       parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen);
218     }
219   while (!parse_res);
220
221   return NSS_STATUS_SUCCESS;
222 }
223
224 enum nss_status
225 _nss_nisplus_getgrent_r (struct group *result, char *buffer, size_t buflen)
226 {
227   int status;
228
229   __libc_lock_lock (lock);
230
231   status = internal_nisplus_getgrent_r (result, buffer, buflen);
232
233   __libc_lock_unlock (lock);
234
235   return status;
236 }
237
238 enum nss_status
239 _nss_nisplus_getgrnam_r (const char *name, struct group *gr,
240                          char *buffer, size_t buflen)
241 {
242   int parse_res;
243
244   if (name == NULL || strlen (name) > 8)
245     return NSS_STATUS_NOTFOUND;
246   else
247     {
248       nis_result *result;
249       char buf[strlen (name) + 24];
250
251       sprintf (buf, "[name=%s],group.org_dir", name);
252
253       result = nis_list (buf, EXPAND_NAME, NULL, NULL);
254
255       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
256         {
257           enum nss_status status = niserr2nss (result->status);
258
259           nis_freeresult (result);
260           return status;
261         }
262
263       parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen);
264
265       nis_freeresult (result);
266
267       if (parse_res)
268         return NSS_STATUS_SUCCESS;
269
270       if (!parse_res && errno == ERANGE)
271         return NSS_STATUS_TRYAGAIN;
272       else
273         return NSS_STATUS_NOTFOUND;
274     }
275 }
276
277 enum nss_status
278 _nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr,
279                          char *buffer, size_t buflen)
280 {
281   int parse_res;
282   nis_result *result;
283   char buf[36];
284
285   sprintf (buf, "[gid=%d],group.org_dir", gid);
286
287   result = nis_list (buf, EXPAND_NAME, NULL, NULL);
288
289   if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
290     {
291       enum nss_status status = niserr2nss (result->status);
292
293       nis_freeresult (result);
294       return status;
295     }
296
297   parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen);
298
299   nis_freeresult (result);
300
301   if (parse_res)
302     return NSS_STATUS_SUCCESS;
303
304   if (!parse_res && errno == ERANGE)
305     return NSS_STATUS_TRYAGAIN;
306   else
307     return NSS_STATUS_NOTFOUND;
308 }