2.9
[glibc/nacl-glibc.git] / nis / nss_nisplus / nisplus-publickey.c
blob14e7d41dbe6106070b4ff0838a631de0948a2599
1 /* Copyright (c) 1997,1999,2001,2003,2005,2006 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
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.
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.
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. */
20 #include <nss.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <libintl.h>
26 #include <syslog.h>
27 #include <rpc/rpc.h>
28 #include <rpcsvc/nis.h>
29 #include <rpc/key_prot.h>
30 extern int xdecrypt (char *, char *);
32 #include <nss-nisplus.h>
34 /* If we haven't found the entry, we give a SUCCESS and an empty key back. */
35 enum nss_status
36 _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop)
38 nis_result *res;
39 enum nss_status retval;
40 char buf[NIS_MAXNAMELEN + 2];
41 size_t slen;
42 char *domain, *cptr;
43 int len;
45 pkey[0] = 0;
47 if (netname == NULL)
49 *errnop = EINVAL;
50 return NSS_STATUS_UNAVAIL;
53 domain = strchr (netname, '@');
54 if (!domain)
55 return NSS_STATUS_UNAVAIL;
56 domain++;
58 slen = snprintf (buf, NIS_MAXNAMELEN,
59 "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
60 netname, domain);
62 if (slen >= NIS_MAXNAMELEN)
64 *errnop = EINVAL;
65 return NSS_STATUS_UNAVAIL;
68 if (buf[slen - 1] != '.')
70 buf[slen++] = '.';
71 buf[slen] = '\0';
74 res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
75 NULL, NULL);
77 if (res == NULL)
79 *errnop = ENOMEM;
80 return NSS_STATUS_TRYAGAIN;
82 retval = niserr2nss (res->status);
84 if (retval != NSS_STATUS_SUCCESS)
86 if (retval == NSS_STATUS_TRYAGAIN)
87 *errnop = errno;
88 if (res->status == NIS_NOTFOUND)
89 retval = NSS_STATUS_SUCCESS;
90 nis_freeresult (res);
91 return retval;
94 if (NIS_RES_NUMOBJ (res) > 1)
97 * More than one principal with same uid?
98 * something wrong with cred table. Should be unique
99 * Warn user and continue.
101 syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
102 nis_freeresult (res);
103 return NSS_STATUS_SUCCESS;
106 len = ENTRY_LEN (NIS_RES_OBJECT (res), 3);
107 memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len);
108 pkey[len] = 0;
109 cptr = strchr (pkey, ':');
110 if (cptr)
111 cptr[0] = '\0';
112 nis_freeresult (res);
114 return NSS_STATUS_SUCCESS;
118 enum nss_status
119 _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
120 int *errnop)
122 nis_result *res;
123 enum nss_status retval;
124 char buf[NIS_MAXNAMELEN + 2];
125 size_t slen;
126 char *domain, *cptr;
127 int len;
129 skey[0] = 0;
131 if (netname == NULL)
133 *errnop = EINVAL;
134 return NSS_STATUS_UNAVAIL;
137 domain = strchr (netname, '@');
138 if (!domain)
139 return NSS_STATUS_UNAVAIL;
140 domain++;
142 slen = snprintf (buf, NIS_MAXNAMELEN,
143 "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
144 netname, domain);
146 if (slen >= NIS_MAXNAMELEN)
148 *errnop = EINVAL;
149 return NSS_STATUS_UNAVAIL;
152 if (buf[slen - 1] != '.')
154 buf[slen++] = '.';
155 buf[slen] = '\0';
158 res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH,
159 NULL, NULL);
161 if (res == NULL)
163 *errnop = ENOMEM;
164 return NSS_STATUS_TRYAGAIN;
166 retval = niserr2nss (res->status);
168 if (retval != NSS_STATUS_SUCCESS)
170 if (retval == NSS_STATUS_TRYAGAIN)
171 *errnop = errno;
172 nis_freeresult (res);
173 return retval;
176 if (NIS_RES_NUMOBJ (res) > 1)
179 * More than one principal with same uid?
180 * something wrong with cred table. Should be unique
181 * Warn user and continue.
183 syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
184 nis_freeresult (res);
185 return NSS_STATUS_SUCCESS;
188 len = ENTRY_LEN (NIS_RES_OBJECT (res), 4);
189 memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len);
190 buf[len] = '\0';
191 cptr = strchr (buf, ':');
192 if (cptr)
193 cptr[0] = '\0';
194 nis_freeresult (res);
196 if (!xdecrypt (buf, passwd))
197 return NSS_STATUS_SUCCESS;
199 if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
200 return NSS_STATUS_SUCCESS;
202 buf[HEXKEYBYTES] = 0;
203 strcpy (skey, buf);
205 return NSS_STATUS_SUCCESS;
209 /* Parse information from the passed string.
210 The format of the string passed is gid,grp,grp, ... */
211 static enum nss_status
212 parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist,
213 int *errnop)
215 char *ep;
216 int gidlen;
218 if (!s || (!isdigit (*s)))
220 syslog (LOG_ERR, _("netname2user: missing group id list in `%s'"), s);
221 return NSS_STATUS_NOTFOUND;
224 *gidp = strtoul (s, &ep, 10);
226 gidlen = 0;
228 /* After strtoul() ep should point to the marker ',', which means
229 here starts a new value.
231 The Sun man pages show that GIDLIST should contain at least NGRPS
232 elements. Limiting the number written by this value is the best
233 we can do. */
234 while (ep != NULL && *ep == ',' && gidlen < NGRPS)
236 ep++;
237 s = ep;
238 gidlist[gidlen++] = strtoul (s, &ep, 10);
240 *gidlenp = gidlen;
242 return NSS_STATUS_SUCCESS;
245 enum nss_status
246 _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
247 gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
249 char *domain;
250 nis_result *res;
251 char sname[NIS_MAXNAMELEN + 2]; /* search criteria + table name */
252 size_t slen;
253 char principal[NIS_MAXNAMELEN + 1];
254 int len;
256 /* 1. Get home domain of user. */
257 domain = strchr (netname, '@');
258 if (! domain)
259 return NSS_STATUS_UNAVAIL;
261 ++domain; /* skip '@' */
263 /* 2. Get user's nisplus principal name. */
264 slen = snprintf (sname, NIS_MAXNAMELEN,
265 "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
266 netname, domain);
268 if (slen >= NIS_MAXNAMELEN)
270 *errnop = EINVAL;
271 return NSS_STATUS_UNAVAIL;
274 if (sname[slen - 1] != '.')
276 sname[slen++] = '.';
277 sname[slen] = '\0';
280 /* must use authenticated call here */
281 /* XXX but we cant, for now. XXX */
282 res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
283 NULL, NULL);
284 if (res == NULL)
286 *errnop = ENOMEM;
287 return NSS_STATUS_TRYAGAIN;
289 switch (res->status)
291 case NIS_SUCCESS:
292 case NIS_S_SUCCESS:
293 break; /* go and do something useful */
294 case NIS_NOTFOUND:
295 case NIS_PARTIAL:
296 case NIS_NOSUCHNAME:
297 case NIS_NOSUCHTABLE:
298 nis_freeresult (res);
299 return NSS_STATUS_NOTFOUND;
300 case NIS_S_NOTFOUND:
301 case NIS_TRYAGAIN:
302 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
303 nis_sperrno (res->status));
304 nis_freeresult (res);
305 *errnop = errno;
306 return NSS_STATUS_TRYAGAIN;
307 default:
308 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
309 nis_sperrno (res->status));
310 nis_freeresult (res);
311 return NSS_STATUS_UNAVAIL;
314 if (NIS_RES_NUMOBJ (res) > 1)
316 * A netname belonging to more than one principal?
317 * Something wrong with cred table. should be unique.
318 * Warn user and continue.
320 syslog (LOG_ALERT,
321 _("netname2user: DES entry for %s in directory %s not unique"),
322 netname, domain);
324 len = ENTRY_LEN (NIS_RES_OBJECT (res), 0);
325 strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len);
326 principal[len] = '\0';
327 nis_freeresult (res);
329 if (principal[0] == '\0')
330 return NSS_STATUS_UNAVAIL;
333 * 3. Use principal name to look up uid/gid information in
334 * LOCAL entry in **local** cred table.
336 domain = nis_local_directory ();
337 if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN)
339 syslog (LOG_ERR, _("netname2user: principal name `%s' too long"),
340 principal);
341 return NSS_STATUS_UNAVAIL;
344 slen = snprintf (sname, sizeof (sname),
345 "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
346 principal, domain);
348 if (sname[slen - 1] != '.')
350 sname[slen++] = '.';
351 sname[slen] = '\0';
354 /* must use authenticated call here */
355 /* XXX but we cant, for now. XXX */
356 res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
357 NULL, NULL);
358 if (res == NULL)
360 *errnop = ENOMEM;
361 return NSS_STATUS_TRYAGAIN;
363 switch(res->status)
365 case NIS_NOTFOUND:
366 case NIS_PARTIAL:
367 case NIS_NOSUCHNAME:
368 case NIS_NOSUCHTABLE:
369 nis_freeresult (res);
370 return NSS_STATUS_NOTFOUND;
371 case NIS_S_NOTFOUND:
372 case NIS_TRYAGAIN:
373 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
374 nis_sperrno (res->status));
375 nis_freeresult (res);
376 *errnop = errno;
377 return NSS_STATUS_TRYAGAIN;
378 case NIS_SUCCESS:
379 case NIS_S_SUCCESS:
380 break; /* go and do something useful */
381 default:
382 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
383 nis_sperrno (res->status));
384 nis_freeresult (res);
385 return NSS_STATUS_UNAVAIL;
388 if (NIS_RES_NUMOBJ (res) > 1)
390 * A principal can have more than one LOCAL entry?
391 * Something wrong with cred table.
392 * Warn user and continue.
394 syslog (LOG_ALERT,
395 _("netname2user: LOCAL entry for %s in directory %s not unique"),
396 netname, domain);
397 /* Fetch the uid */
398 *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10);
400 if (*uidp == 0)
402 syslog (LOG_ERR, _("netname2user: should not have uid 0"));
403 nis_freeresult (res);
404 return NSS_STATUS_NOTFOUND;
407 parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3),
408 gidp, gidlenp, gidlist, errnop);
410 nis_freeresult (res);
411 return NSS_STATUS_SUCCESS;