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