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