Fix "buffer to small" problems and memory leaks.
[kopensolaris-gnu/glibc.git] / nis / nss_nisplus / nisplus-pwd.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 <pwd.h>
23 #include <string.h>
24 #include <bits/libc-lock.h>
25 #include <rpcsvc/nis.h>
26 #include <rpcsvc/nislib.h>
27
28 #include "nss-nisplus.h"
29
30 __libc_lock_define_initialized (static, lock)
31
32 static nis_result *result = NULL;
33 static nis_name tablename_val = NULL;
34 static u_long tablename_len = 0;
35
36 extern int _nss_nisplus_parse_pwent (nis_result *res, struct passwd *pw,
37                                      char *buffer, size_t buflen);
38
39 static enum nss_status
40 _nss_create_tablename (void)
41 {
42   if (tablename_val == NULL)
43     {
44       char buf [40 + strlen (nis_local_directory ())];
45       char *p;
46
47       p = stpcpy (buf, "passwd.org_dir.");
48       p = stpcpy (p, nis_local_directory ());
49       tablename_val = strdup (buf);
50       if (tablename_val == NULL)
51         return NSS_STATUS_TRYAGAIN;
52       tablename_len = strlen (tablename_val);
53     }
54   return NSS_STATUS_SUCCESS;
55 }
56
57
58 enum nss_status
59 _nss_nisplus_setpwent (void)
60 {
61   enum nss_status status = NSS_STATUS_SUCCESS;
62
63   __libc_lock_lock (lock);
64
65   if (result)
66     nis_freeresult (result);
67   result = NULL;
68
69   if (tablename_val == NULL)
70     status = _nss_create_tablename ();
71
72   __libc_lock_unlock (lock);
73
74   return status;
75 }
76
77 enum nss_status
78 _nss_nisplus_endpwent (void)
79 {
80   __libc_lock_lock (lock);
81
82   if (result)
83     nis_freeresult (result);
84   result = NULL;
85
86   __libc_lock_unlock (lock);
87
88   return NSS_STATUS_SUCCESS;
89 }
90
91 static enum nss_status
92 internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen)
93 {
94   int parse_res;
95
96   /* Get the next entry until we found a correct one. */
97   do
98     {
99       nis_result *saved_res;
100       
101       if (result == NULL)
102         {
103           saved_res = NULL;
104           if (tablename_val == NULL)
105             if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
106               return NSS_STATUS_UNAVAIL;
107
108           result = nis_first_entry(tablename_val);
109           if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
110             return niserr2nss (result->status);
111         }
112       else
113         {
114           nis_result *res;
115
116           saved_res = result;
117           res = nis_next_entry(tablename_val, &result->cookie);
118           result = res;
119           if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
120             {
121               nis_freeresult (saved_res);
122               return niserr2nss (result->status);
123             }
124         }
125
126       if ((parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, 
127                                                  buflen)) == -1)
128         {
129           nis_freeresult (result);
130           result = saved_res;
131           return NSS_STATUS_TRYAGAIN;
132         }
133       else
134         {
135           if (saved_res)
136             nis_freeresult (saved_res);
137         }
138     } while (!parse_res);
139
140   return NSS_STATUS_SUCCESS;
141 }
142
143 enum nss_status
144 _nss_nisplus_getpwent_r (struct passwd *result, char *buffer, size_t buflen)
145 {
146   int status;
147
148   __libc_lock_lock (lock);
149
150   status = internal_nisplus_getpwent_r (result, buffer, buflen);
151
152   __libc_lock_unlock (lock);
153
154   return status;
155 }
156
157 enum nss_status
158 _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw,
159                      char *buffer, size_t buflen)
160 {
161   int parse_res;
162
163   if (tablename_val == NULL)
164     if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
165       return NSS_STATUS_UNAVAIL;
166
167   if (name == NULL || strlen (name) > 8)
168     return NSS_STATUS_NOTFOUND;
169   else
170     {
171       nis_result *result;
172       char buf[strlen (name) + 24 + tablename_len];
173
174       sprintf(buf, "[name=%s],%s", name, tablename_val);
175
176       result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
177
178       if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
179         {
180           enum nss_status status =  niserr2nss (result->status);
181
182           nis_freeresult (result);
183           return status;
184         }
185
186       parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen);
187
188       nis_freeresult (result);
189
190       if (parse_res == -1)
191         return NSS_STATUS_TRYAGAIN;
192
193       if (parse_res)
194         return NSS_STATUS_SUCCESS;
195       
196       return NSS_STATUS_NOTFOUND;
197     }
198 }
199
200 enum nss_status
201 _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw,
202                      char *buffer, size_t buflen)
203 {
204   if (tablename_val == NULL)
205     if (_nss_create_tablename () != NSS_STATUS_SUCCESS)
206       return NSS_STATUS_UNAVAIL;
207   {
208     int parse_res;
209     nis_result *result;
210     char buf[100 + tablename_len];
211
212     sprintf(buf, "[uid=%d],%s", uid, tablename_val);
213
214     result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
215
216     if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
217       {
218         enum nss_status status = niserr2nss (result->status);
219
220         nis_freeresult (result);
221         return status;
222       }
223
224     parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen);
225
226     nis_freeresult (result);
227
228     if (parse_res == -1)
229       return NSS_STATUS_TRYAGAIN;
230     
231     if (parse_res)
232       return NSS_STATUS_SUCCESS;
233
234     return NSS_STATUS_NOTFOUND;
235   }
236 }