(getspnam_plususer): Preserve original return value.
[kopensolaris-gnu/glibc.git] / nis / nss_nis / nis-pwd.c
1 /* Copyright (C) 1996-1998, 2001, 2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
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.
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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <nss.h>
21 /* The following is an ugly trick to avoid a prototype declaration for
22    _nss_nis_endpwent.  */
23 #define _nss_nis_endpwent _nss_nis_endpwent_XXX
24 #include <pwd.h>
25 #undef _nss_nis_endpwent
26 #include <ctype.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <bits/libc-lock.h>
30 #include <rpcsvc/yp.h>
31 #include <rpcsvc/ypclnt.h>
32
33 #include "nss-nis.h"
34
35 /* Get the declaration of the parser function.  */
36 #define ENTNAME pwent
37 #define STRUCTURE passwd
38 #define EXTERN_PARSER
39 #include <nss/nss_files/files-parse.c>
40
41 /* Protect global state against multiple changers */
42 __libc_lock_define_initialized (static, lock)
43
44 static bool_t new_start = 1;
45 static char *oldkey;
46 static int oldkeylen;
47
48 enum nss_status
49 _nss_nis_setpwent (int stayopen)
50 {
51   __libc_lock_lock (lock);
52
53   new_start = 1;
54   if (oldkey != NULL)
55     {
56       free (oldkey);
57       oldkey = NULL;
58       oldkeylen = 0;
59     }
60
61   __libc_lock_unlock (lock);
62
63   return NSS_STATUS_SUCCESS;
64 }
65 /* Make _nss_nis_endpwent an alias of _nss_nis_setpwent.  We do this
66    even though the prototypes don't match.  The argument of setpwent
67    is not used so this makes no difference.  */
68 strong_alias (_nss_nis_setpwent, _nss_nis_endpwent)
69
70 static enum nss_status
71 internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
72                          int *errnop)
73 {
74   struct parser_data *data = (void *) buffer;
75   char *domain;
76   int parse_res;
77
78   if (yp_get_default_domain (&domain))
79     return NSS_STATUS_UNAVAIL;
80
81   /* Get the next entry until we found a correct one. */
82   do
83     {
84       enum nss_status retval;
85       char *result, *outkey, *result2, *p;
86       int len, keylen, len2;
87       size_t namelen;
88
89       if (new_start)
90         retval = yperr2nss (yp_first (domain, "passwd.byname",
91                                       &outkey, &keylen, &result, &len));
92       else
93         retval = yperr2nss ( yp_next (domain, "passwd.byname",
94                                       oldkey, oldkeylen,
95                                       &outkey, &keylen, &result, &len));
96
97       if (retval != NSS_STATUS_SUCCESS)
98         {
99           if (retval == NSS_STATUS_TRYAGAIN)
100             *errnop = errno;
101           return retval;
102         }
103
104       /* Check for adjunct style secret passwords.  They can be
105          recognized by a password starting with "##".  */
106       p = strchr (result, ':');
107       if (p != NULL     /* This better should be true in all cases.  */
108           && p[1] == '#' && p[2] == '#'
109           && (namelen = p - result,
110               yp_match (domain, "passwd.adjunct.byname", result, namelen,
111                         &result2, &len2)) == YPERR_SUCCESS)
112         {
113           /* We found a passwd.adjunct entry.  Merge encrypted
114              password therein into original result.  */
115           char *encrypted = strchr (result2, ':');
116           char *endp;
117           size_t restlen;
118
119           if (encrypted == NULL
120               || (endp = strchr (++encrypted, ':')) == NULL
121               || (p = strchr (p + 1, ':')) == NULL)
122             {
123               /* Invalid format of the entry.  This never should happen
124                  unless the data from which the NIS table is generated is
125                  wrong.  We simply ignore it.  */
126               free (result2);
127               goto non_adjunct;
128             }
129
130           restlen = len - (p - result);
131           if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
132             {
133               free (result2);
134               free (result);
135               *errnop = ERANGE;
136               return NSS_STATUS_TRYAGAIN;
137             }
138
139           __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
140                                            ":", 1),
141                                 encrypted, endp - encrypted),
142                      p, restlen + 1);
143           p = buffer;
144
145           free (result2);
146         }
147       else
148         {
149         non_adjunct:
150           if ((size_t) (len + 1) > buflen)
151             {
152               free (result);
153               *errnop = ERANGE;
154               return NSS_STATUS_TRYAGAIN;
155             }
156
157           p = strncpy (buffer, result, len);
158           buffer[len] = '\0';
159         }
160
161       while (isspace (*p))
162         ++p;
163       free (result);
164
165       parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
166       if (parse_res == -1)
167         {
168           free (outkey);
169           *errnop = ERANGE;
170           return NSS_STATUS_TRYAGAIN;
171         }
172
173       free (oldkey);
174       oldkey = outkey;
175       oldkeylen = keylen;
176       new_start = 0;
177     }
178   while (parse_res < 1);
179
180   return NSS_STATUS_SUCCESS;
181 }
182
183 enum nss_status
184 _nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
185                      int *errnop)
186 {
187   int status;
188
189   __libc_lock_lock (lock);
190
191   status = internal_nis_getpwent_r (result, buffer, buflen, errnop);
192
193   __libc_lock_unlock (lock);
194
195   return status;
196 }
197
198 enum nss_status
199 _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
200                      char *buffer, size_t buflen, int *errnop)
201 {
202   struct parser_data *data = (void *) buffer;
203   enum nss_status retval;
204   char *domain, *result, *result2, *p;
205   int len, len2, parse_res;
206   size_t namelen;
207
208   if (name == NULL)
209     {
210       *errnop = EINVAL;
211       return NSS_STATUS_UNAVAIL;
212     }
213
214   if (yp_get_default_domain (&domain))
215     return NSS_STATUS_UNAVAIL;
216
217   namelen = strlen (name);
218
219   retval = yperr2nss (yp_match (domain, "passwd.byname", name,
220                                 namelen, &result, &len));
221
222   if (retval != NSS_STATUS_SUCCESS)
223     {
224       if (retval == NSS_STATUS_TRYAGAIN)
225         *errnop = errno;
226       return retval;
227     }
228
229   /* Check for adjunct style secret passwords.  They can be recognized
230      by a password starting with "##".  */
231   p = strchr (result, ':');
232   if (p != NULL /* This better should be true in all cases.  */
233       && p[1] == '#' && p[2] == '#'
234       && yp_match (domain, "passwd.adjunct.byname", name, namelen,
235                    &result2, &len2) == YPERR_SUCCESS)
236     {
237       /* We found a passwd.adjunct entry.  Merge encrypted password
238          therein into original result.  */
239       char *encrypted = strchr (result2, ':');
240       char *endp;
241       size_t restlen;
242
243       if (encrypted == NULL
244           || (endp = strchr (++encrypted, ':')) == NULL
245           || (p = strchr (p + 1, ':')) == NULL)
246         {
247           /* Invalid format of the entry.  This never should happen
248              unless the data from which the NIS table is generated is
249              wrong.  We simply ignore it.  */
250           free (result2);
251           goto non_adjunct;
252         }
253
254       restlen = len - (p - result);
255       if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
256         {
257           free (result2);
258           free (result);
259           *errnop = ERANGE;
260           return NSS_STATUS_TRYAGAIN;
261         }
262
263       __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, name, namelen),
264                                        ":", 1),
265                             encrypted, endp - encrypted),
266                  p, restlen + 1);
267       p = buffer;
268
269       free (result2);
270     }
271   else
272     {
273     non_adjunct:
274       if ((size_t) (len + 1) > buflen)
275         {
276           free (result);
277           *errnop = ERANGE;
278           return NSS_STATUS_TRYAGAIN;
279         }
280
281       p = strncpy (buffer, result, len);
282       buffer[len] = '\0';
283     }
284
285   while (isspace (*p))
286     ++p;
287   free (result);
288
289   parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
290   if (parse_res < 1)
291     {
292       if (parse_res == -1)
293         return NSS_STATUS_TRYAGAIN;
294       else
295         return NSS_STATUS_NOTFOUND;
296     }
297   else
298     return NSS_STATUS_SUCCESS;
299 }
300
301 enum nss_status
302 _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
303                      char *buffer, size_t buflen, int *errnop)
304 {
305   struct parser_data *data = (void *) buffer;
306   enum nss_status retval;
307   char *domain, *result, *p, *result2;
308   int len, nlen, parse_res, len2;
309   char buf[32];
310   size_t namelen;
311
312   if (yp_get_default_domain (&domain))
313     return NSS_STATUS_UNAVAIL;
314
315   nlen = sprintf (buf, "%lu", (unsigned long int) uid);
316
317   retval = yperr2nss (yp_match (domain, "passwd.byuid", buf,
318                                 nlen, &result, &len));
319
320   if (retval != NSS_STATUS_SUCCESS)
321     {
322       if (retval == NSS_STATUS_TRYAGAIN)
323         *errnop = errno;
324       return retval;
325     }
326
327   /* Check for adjunct style secret passwords.  They can be recognized
328      by a password starting with "##".  */
329   p = strchr (result, ':');
330   if (p != NULL /* This better should be true in all cases.  */
331       && p[1] == '#' && p[2] == '#'
332       && (namelen = p - result,
333           yp_match (domain, "passwd.adjunct.byname", result, namelen,
334                     &result2, &len2)) == YPERR_SUCCESS)
335     {
336       /* We found a passwd.adjunct entry.  Merge encrypted password
337          therein into original result.  */
338       char *encrypted = strchr (result2, ':');
339       char *endp;
340       size_t restlen;
341
342       if (encrypted == NULL
343           || (endp = strchr (++encrypted, ':')) == NULL
344           || (p = strchr (p + 1, ':')) == NULL)
345         {
346           /* Invalid format of the entry.  This never should happen
347              unless the data from which the NIS table is generated is
348              wrong.  We simply ignore it.  */
349           free (result2);
350           goto non_adjunct;
351         }
352
353       restlen = len - (p - result);
354       if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
355         {
356           free (result2);
357           free (result);
358           *errnop = ERANGE;
359           return NSS_STATUS_TRYAGAIN;
360         }
361
362       __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
363                                        ":", 1),
364                             encrypted, endp - encrypted),
365                  p, restlen + 1);
366       p = buffer;
367
368       free (result2);
369     }
370   else
371     {
372     non_adjunct:
373       if ((size_t) (len + 1) > buflen)
374         {
375           free (result);
376           *errnop = ERANGE;
377           return NSS_STATUS_TRYAGAIN;
378         }
379
380       p = strncpy (buffer, result, len);
381       buffer[len] = '\0';
382     }
383
384   while (isspace (*p))
385     ++p;
386   free (result);
387
388   parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
389   if (parse_res < 1)
390     {
391       if (parse_res == -1)
392         return NSS_STATUS_TRYAGAIN;
393      else
394        return NSS_STATUS_NOTFOUND;
395     }
396   else
397     return NSS_STATUS_SUCCESS;
398 }