(internal_nis_getpwent_r): Handle adjunct password scheme.
[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_TRYAGAIN)
110             *errnop = errno;
111           return retval;
112         }
113
114       /* Check for adjunct style secret passwords.  They can be
115          recognized by a password starting with "##".  */
116       p = strchr (result, ':');
117       if (p != NULL     /* This better should be true in all cases.  */
118           && p[1] == '#' && p[2] == '#'
119           && (namelen = p - result,
120               yp_match (domain, "passwd.adjunct.byname", result, namelen,
121                         &result2, &len2)) == YPERR_SUCCESS)
122         {
123           /* We found a passwd.adjunct entry.  Merge encrypted
124              password therein into original result.  */
125           char *encrypted = strchr (result2, ':');
126           char *endp;
127           size_t restlen;
128
129           if (encrypted != NULL
130               || (endp = strchr (++encrypted, ':')) == NULL
131               || (p = strchr (p + 1, ':')) == NULL)
132             {
133               /* Invalid format of the entry.  This never should happen
134                  unless the data from which the NIS table is generated is
135                  wrong.  We simply ignore it.  */
136               free (result2);
137               goto non_adjunct;
138             }
139
140           restlen = len - (p - result);
141           if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
142             {
143               free (result2);
144               free (result);
145               *errnop = ERANGE;
146               return NSS_STATUS_TRYAGAIN;
147             }
148
149           __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
150                                            ":", 1),
151                                 encrypted, endp - encrypted),
152                      p, restlen + 1);
153           p = buffer;
154
155           free (result2);
156         }
157       else
158         {
159         non_adjunct:
160           if ((size_t) (len + 1) > buflen)
161             {
162               free (result);
163               *errnop = ERANGE;
164               return NSS_STATUS_TRYAGAIN;
165             }
166
167           p = strncpy (buffer, result, len);
168           buffer[len] = '\0';
169         }
170
171       while (isspace (*p))
172         ++p;
173       free (result);
174
175       parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
176       if (parse_res == -1)
177         {
178           free (outkey);
179           *errnop = ERANGE;
180           return NSS_STATUS_TRYAGAIN;
181         }
182
183       free (oldkey);
184       oldkey = outkey;
185       oldkeylen = keylen;
186       new_start = 0;
187     }
188   while (parse_res < 1);
189
190   return NSS_STATUS_SUCCESS;
191 }
192
193 enum nss_status
194 _nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
195                      int *errnop)
196 {
197   int status;
198
199   __libc_lock_lock (lock);
200
201   status = internal_nis_getpwent_r (result, buffer, buflen, errnop);
202
203   __libc_lock_unlock (lock);
204
205   return status;
206 }
207
208 enum nss_status
209 _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
210                      char *buffer, size_t buflen, int *errnop)
211 {
212   struct parser_data *data = (void *) buffer;
213   enum nss_status retval;
214   char *domain, *result, *result2, *p;
215   int len, len2, parse_res;
216   size_t namelen;
217
218   if (name == NULL)
219     {
220       *errnop = EINVAL;
221       return NSS_STATUS_UNAVAIL;
222     }
223
224   if (yp_get_default_domain (&domain))
225     return NSS_STATUS_UNAVAIL;
226
227   namelen = strlen (name);
228
229   retval = yperr2nss (yp_match (domain, "passwd.byname", name,
230                                 namelen, &result, &len));
231
232   if (retval != NSS_STATUS_SUCCESS)
233     {
234       if (retval == NSS_STATUS_TRYAGAIN)
235         *errnop = errno;
236       return retval;
237     }
238
239   /* Check for adjunct style secret passwords.  They can be recognized
240      by a password starting with "##".  */
241   p = strchr (result, ':');
242   if (p != NULL /* This better should be true in all cases.  */
243       && p[1] == '#' && p[2] == '#'
244       && yp_match (domain, "passwd.adjunct.byname", name, namelen,
245                    &result2, &len2) == YPERR_SUCCESS)
246     {
247       /* We found a passwd.adjunct entry.  Merge encrypted password
248          therein into original result.  */
249       char *encrypted = strchr (result2, ':');
250       char *endp;
251       size_t restlen;
252
253       if (encrypted != NULL
254           || (endp = strchr (++encrypted, ':')) == NULL
255           || (p = strchr (p + 1, ':')) == NULL)
256         {
257           /* Invalid format of the entry.  This never should happen
258              unless the data from which the NIS table is generated is
259              wrong.  We simply ignore it.  */
260           free (result2);
261           goto non_adjunct;
262         }
263
264       restlen = len - (p - result);
265       if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
266         {
267           free (result2);
268           free (result);
269           *errnop = ERANGE;
270           return NSS_STATUS_TRYAGAIN;
271         }
272
273       __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, name, namelen),
274                                        ":", 1),
275                             encrypted, endp - encrypted),
276                  p, restlen + 1);
277       p = buffer;
278
279       free (result2);
280     }
281   else
282     {
283     non_adjunct:
284       if ((size_t) (len + 1) > buflen)
285         {
286           free (result);
287           *errnop = ERANGE;
288           return NSS_STATUS_TRYAGAIN;
289         }
290
291       p = strncpy (buffer, result, len);
292       buffer[len] = '\0';
293     }
294
295   while (isspace (*p))
296     ++p;
297   free (result);
298
299   parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
300   if (parse_res < 1)
301     {
302       if (parse_res == -1)
303         return NSS_STATUS_TRYAGAIN;
304       else
305         return NSS_STATUS_NOTFOUND;
306     }
307   else
308     return NSS_STATUS_SUCCESS;
309 }
310
311 enum nss_status
312 _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
313                      char *buffer, size_t buflen, int *errnop)
314 {
315   struct parser_data *data = (void *) buffer;
316   enum nss_status retval;
317   char *domain, *result, *p, *result2;
318   int len, nlen, parse_res, len2;
319   char buf[32];
320   size_t namelen;
321
322   if (yp_get_default_domain (&domain))
323     return NSS_STATUS_UNAVAIL;
324
325   nlen = sprintf (buf, "%d", uid);
326
327   retval = yperr2nss (yp_match (domain, "passwd.byuid", buf,
328                                 nlen, &result, &len));
329
330   if (retval != NSS_STATUS_SUCCESS)
331     {
332       if (retval == NSS_STATUS_TRYAGAIN)
333         *errnop = errno;
334       return retval;
335     }
336
337   /* Check for adjunct style secret passwords.  They can be recognized
338      by a password starting with "##".  */
339   p = strchr (result, ':');
340   if (p != NULL /* This better should be true in all cases.  */
341       && p[1] == '#' && p[2] == '#'
342       && (namelen = p - result,
343           yp_match (domain, "passwd.adjunct.byname", result, namelen,
344                     &result2, &len2)) == YPERR_SUCCESS)
345     {
346       /* We found a passwd.adjunct entry.  Merge encrypted password
347          therein into original result.  */
348       char *encrypted = strchr (result2, ':');
349       char *endp;
350       size_t restlen;
351
352       if (encrypted != NULL
353           || (endp = strchr (++encrypted, ':')) == NULL
354           || (p = strchr (p + 1, ':')) == NULL)
355         {
356           /* Invalid format of the entry.  This never should happen
357              unless the data from which the NIS table is generated is
358              wrong.  We simply ignore it.  */
359           free (result2);
360           goto non_adjunct;
361         }
362
363       restlen = len - (p - result);
364       if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
365         {
366           free (result2);
367           free (result);
368           *errnop = ERANGE;
369           return NSS_STATUS_TRYAGAIN;
370         }
371
372       __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
373                                        ":", 1),
374                             encrypted, endp - encrypted),
375                  p, restlen + 1);
376       p = buffer;
377
378       free (result2);
379     }
380   else
381     {
382     non_adjunct:
383       if ((size_t) (len + 1) > buflen)
384         {
385           free (result);
386           *errnop = ERANGE;
387           return NSS_STATUS_TRYAGAIN;
388         }
389
390       p = strncpy (buffer, result, len);
391       buffer[len] = '\0';
392     }
393
394   while (isspace (*p))
395     ++p;
396   free (result);
397
398   parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
399   if (parse_res < 1)
400     {
401       if (parse_res == -1)
402         return NSS_STATUS_TRYAGAIN;
403       else
404         return NSS_STATUS_NOTFOUND;
405     }
406   else
407     return NSS_STATUS_SUCCESS;
408 }