(getspnam_plususer): Preserve original return value.
[kopensolaris-gnu/glibc.git] / nis / nss_nis / nis-publickey.c
1 /* Copyright (C) 1996,1997,1998,1999,2001,2002 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.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 #include <ctype.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <syslog.h>
25 #include <rpc/rpc.h>
26 #include <rpcsvc/yp.h>
27 #include <rpcsvc/ypclnt.h>
28 #include <rpc/key_prot.h>
29 extern int xdecrypt (char *, char *);
30
31 #include "nss-nis.h"
32
33 /* If we haven't found the entry, we give a SUCCESS and an empty key back.
34    Solaris docu says: sizeof (pkey) == HEXKEYBYTES + 1.
35 */
36 enum nss_status
37 _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop)
38 {
39   enum nss_status retval;
40   char *domain, *result;
41   int len;
42
43   pkey[0] = 0;
44
45   if (netname == NULL)
46     {
47       *errnop = EINVAL;
48       return NSS_STATUS_UNAVAIL;
49     }
50
51   domain = strchr (netname, '@');
52   if (!domain)
53     {
54       *errnop = EINVAL;
55       return NSS_STATUS_UNAVAIL;
56     }
57   ++domain;
58
59   retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
60                                 strlen (netname), &result, &len));
61
62   if (retval != NSS_STATUS_SUCCESS)
63     {
64       if (retval == NSS_STATUS_TRYAGAIN)
65         *errnop = errno;
66       return retval;
67     }
68
69   if (result != NULL)
70     {
71       char *p = strchr (result, ':');
72       if (p != NULL)
73         *p = 0;
74       strncpy (pkey, result, HEXKEYBYTES + 1);
75       pkey[HEXKEYBYTES] = '\0';
76     }
77   return NSS_STATUS_SUCCESS;
78 }
79
80 enum nss_status
81 _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd,
82                        int *errnop)
83 {
84   enum nss_status retval;
85   char buf[2 * (HEXKEYBYTES + 1)];
86   char *domain, *result;
87   int len;
88
89   skey[0] = 0;
90
91   if (netname == NULL || passwd == NULL)
92     {
93       *errnop = EINVAL;
94       return NSS_STATUS_UNAVAIL;
95     }
96
97   domain = strchr (netname, '@');
98   if (!domain)
99     {
100       *errnop = EINVAL;
101       return NSS_STATUS_UNAVAIL;
102     }
103   ++domain;
104
105   retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
106                                 strlen (netname), &result, &len));
107
108   if (retval != NSS_STATUS_SUCCESS)
109     {
110       if (retval == NSS_STATUS_TRYAGAIN)
111         *errnop = errno;
112       return retval;
113     }
114
115   if (result != NULL)
116     {
117       char *p = strchr (result, ':');
118       if (p == NULL)
119         return NSS_STATUS_SUCCESS;
120
121       ++p;
122       strncpy (buf, p, 2 * (HEXKEYBYTES + 1));
123       buf[2 * (HEXKEYBYTES + 1)] = '\0';
124       if (!xdecrypt (buf, passwd))
125         return NSS_STATUS_SUCCESS;
126
127       if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
128         return NSS_STATUS_SUCCESS;
129
130       buf[HEXKEYBYTES] = '\0';
131       strcpy (skey, buf);
132     }
133   return NSS_STATUS_SUCCESS;
134 }
135
136 /* Parse uid and group information from the passed string.
137    The format of the string passed is uid:gid,grp,grp, ...  */
138 static enum nss_status
139 parse_netid_str (const char *s, uid_t *uidp, gid_t *gidp, int *gidlenp,
140                  gid_t *gidlist)
141 {
142   char *p, *ep;
143   int gidlen;
144
145   if (!s || !isdigit (*s))
146     {
147       syslog (LOG_ERR, "netname2user: expecting uid '%s'", s);
148       return NSS_STATUS_NOTFOUND;       /* XXX need a better error */
149     }
150
151   /* Fetch the uid */
152   *uidp = strtoul (s, NULL, 10);
153
154   if (*uidp == 0)
155     {
156       syslog (LOG_ERR, "netname2user: should not have uid 0");
157       return NSS_STATUS_NOTFOUND;
158     }
159
160   /* Now get the group list */
161   p = strchr (s, ':');
162   if (!p)
163     {
164       syslog (LOG_ERR, "netname2user: missing group id list in '%s'", s);
165       return NSS_STATUS_NOTFOUND;
166     }
167   ++p;                          /* skip ':' */
168   if (!p || (!isdigit (*p)))
169     {
170       syslog (LOG_ERR, "netname2user: missing group id list in '%s'.", p);
171       return NSS_STATUS_NOTFOUND;
172     }
173
174   *gidp = strtoul (p, &ep, 10);
175
176   gidlen = 0;
177
178   /* After strtoul() ep should point to the first invalid character.
179      This is the marker "," we search for the next value.  */
180   while (ep != NULL && *ep == ',')
181     {
182       ep++;
183       p = ep;
184       gidlist[gidlen++] = strtoul (p, &ep, 10);
185     }
186
187   *gidlenp = gidlen;
188
189   return NSS_STATUS_SUCCESS;
190 }
191
192
193 enum nss_status
194 _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
195                        gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
196 {
197   char *domain;
198   int yperr;
199   char *lookup;
200   int len;
201
202   domain = strchr (netname, '@');
203   if (!domain)
204     {
205       *errnop = EINVAL;
206       return NSS_STATUS_UNAVAIL;
207     }
208
209   /* Point past the '@' character */
210   ++domain;
211   lookup = NULL;
212   yperr = yp_match (domain, "netid.byname", netname, strlen (netname),
213                     &lookup, &len);
214   switch (yperr)
215     {
216     case YPERR_SUCCESS:
217       break;                    /* the successful case */
218     case YPERR_DOMAIN:
219     case YPERR_KEY:
220       return NSS_STATUS_NOTFOUND;
221     case YPERR_MAP:
222     default:
223       return NSS_STATUS_UNAVAIL;
224     }
225
226   if (lookup)
227     {
228       enum nss_status err;
229
230       lookup[len] = '\0';
231       err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist);
232       free (lookup);
233       return err;
234     }
235   else
236     return NSS_STATUS_NOTFOUND;
237
238   return NSS_STATUS_SUCCESS;
239 }