Update.
[glibc.git] / nis / nss_nisplus / nisplus-publickey.c
blob58ae7012afae377a13926870d37178e173474931
1 /* Copyright (c) 1997, 1999, 2001, 2003 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 (res->objects.objects_len > 1)
97 * More than one principal with same uid?
98 * something wrong with cred table. Should be unique
99 * Warn user and continue.
101 printf (_("DES entry for netname %s not unique\n"), netname);
102 nis_freeresult (res);
103 return NSS_STATUS_SUCCESS;
106 len = ENTRY_LEN (res->objects.objects_val, 3);
107 memcpy (pkey, ENTRY_VAL (res->objects.objects_val,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;
117 enum nss_status
118 _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
119 int *errnop)
121 nis_result *res;
122 enum nss_status retval;
123 char buf[NIS_MAXNAMELEN+2];
124 size_t slen;
125 char *domain, *cptr;
126 int len;
128 skey[0] = 0;
130 if (netname == NULL)
132 *errnop = EINVAL;
133 return NSS_STATUS_UNAVAIL;
136 domain = strchr (netname, '@');
137 if (!domain)
138 return NSS_STATUS_UNAVAIL;
139 domain++;
141 slen = snprintf (buf, NIS_MAXNAMELEN,
142 "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
143 netname, domain);
145 if (slen >= NIS_MAXNAMELEN)
147 *errnop = EINVAL;
148 return NSS_STATUS_UNAVAIL;
151 if (buf[slen - 1] != '.')
153 buf[slen++] = '.';
154 buf[slen] = '\0';
157 res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
158 NULL, NULL);
160 if (res == NULL)
162 *errnop = ENOMEM;
163 return NSS_STATUS_TRYAGAIN;
165 retval = niserr2nss (res->status);
167 if (retval != NSS_STATUS_SUCCESS)
169 if (retval == NSS_STATUS_TRYAGAIN)
170 *errnop = errno;
171 nis_freeresult (res);
172 return retval;
175 if (res->objects.objects_len > 1)
178 * More than one principal with same uid?
179 * something wrong with cred table. Should be unique
180 * Warn user and continue.
182 printf (_("DES entry for netname %s not unique\n"), netname);
183 nis_freeresult (res);
184 return NSS_STATUS_SUCCESS;
187 len = ENTRY_LEN (res->objects.objects_val, 4);
188 memcpy (buf, ENTRY_VAL (res->objects.objects_val,4), len);
189 buf[len] = '\0';
190 cptr = strchr (buf, ':');
191 if (cptr)
192 cptr[0] = '\0';
193 nis_freeresult (res);
195 if (!xdecrypt (buf, passwd))
196 return NSS_STATUS_SUCCESS;
198 if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
199 return NSS_STATUS_SUCCESS;
201 buf[HEXKEYBYTES] = 0;
202 strcpy (skey, buf);
204 return NSS_STATUS_SUCCESS;
207 /* Parse information from the passed string.
208 The format of the string passed is gid,grp,grp, ... */
209 static enum nss_status
210 parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist,
211 int *errnop)
213 char *ep;
214 int gidlen;
216 if (!s || (!isdigit (*s)))
218 syslog (LOG_ERR, _("netname2user: missing group id list in `%s'."), s);
219 return NSS_STATUS_NOTFOUND;
222 *gidp = strtoul (s, &ep, 10);
224 gidlen = 0;
226 /* After strtoul() ep should point to the marker ',', which means
227 here starts a new value. */
228 while (ep != NULL && *ep == ',')
230 ep++;
231 s = ep;
232 gidlist[gidlen++] = strtoul (s, &ep, 10);
234 *gidlenp = gidlen;
236 return NSS_STATUS_SUCCESS;
239 enum nss_status
240 _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
241 gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
243 char *domain;
244 nis_result *res;
245 char sname[NIS_MAXNAMELEN+2]; /* search criteria + table name */
246 size_t slen;
247 char principal[NIS_MAXNAMELEN+1];
248 int len;
250 /* 1. Get home domain of user. */
251 domain = strchr (netname, '@');
252 if (! domain)
253 return NSS_STATUS_UNAVAIL;
255 ++domain; /* skip '@' */
257 /* 2. Get user's nisplus principal name. */
258 if ((strlen (netname) + strlen (domain)+45) >
259 (size_t) NIS_MAXNAMELEN)
260 return NSS_STATUS_UNAVAIL;
262 slen = snprintf (sname, NIS_MAXNAMELEN,
263 "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
264 netname, domain);
266 if (slen >= NIS_MAXNAMELEN)
268 *errnop = EINVAL;
269 return NSS_STATUS_UNAVAIL;
272 if (sname[slen - 1] != '.')
274 sname[slen++] = '.';
275 sname[slen] = '\0';
278 /* must use authenticated call here */
279 /* XXX but we cant, for now. XXX */
280 res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
281 NULL, NULL);
282 if (res == NULL)
284 *errnop = ENOMEM;
285 return NSS_STATUS_TRYAGAIN;
287 switch (res->status)
289 case NIS_SUCCESS:
290 case NIS_S_SUCCESS:
291 break; /* go and do something useful */
292 case NIS_NOTFOUND:
293 case NIS_PARTIAL:
294 case NIS_NOSUCHNAME:
295 case NIS_NOSUCHTABLE:
296 nis_freeresult (res);
297 return NSS_STATUS_NOTFOUND;
298 case NIS_S_NOTFOUND:
299 case NIS_TRYAGAIN:
300 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
301 nis_sperrno (res->status));
302 nis_freeresult (res);
303 *errnop = errno;
304 return NSS_STATUS_TRYAGAIN;
305 default:
306 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
307 nis_sperrno (res->status));
308 nis_freeresult (res);
309 return NSS_STATUS_UNAVAIL;
312 if (res->objects.objects_len > 1)
314 * A netname belonging to more than one principal?
315 * Something wrong with cred table. should be unique.
316 * Warn user and continue.
318 syslog (LOG_ALERT,
319 _("netname2user: DES entry for %s in directory %s not unique"),
320 netname, domain);
322 len = ENTRY_LEN (res->objects.objects_val, 0);
323 strncpy (principal, ENTRY_VAL (res->objects.objects_val, 0), len);
324 principal[len] = '\0';
325 nis_freeresult (res);
327 if (principal[0] == '\0')
328 return NSS_STATUS_UNAVAIL;
331 * 3. Use principal name to look up uid/gid information in
332 * LOCAL entry in **local** cred table.
334 domain = nis_local_directory ();
335 if ((strlen (principal) + strlen (domain) + 45) > (size_t) NIS_MAXNAMELEN)
337 syslog (LOG_ERR, _("netname2user: principal name `%s' too long"),
338 principal);
339 return NSS_STATUS_UNAVAIL;
342 slen = sprintf (sname, "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
343 principal, domain);
345 if (sname[slen - 1] != '.')
347 sname[slen++] = '.';
348 sname[slen] = '\0';
351 /* must use authenticated call here */
352 /* XXX but we cant, for now. XXX */
353 res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
354 NULL, NULL);
355 if (res == NULL)
357 *errnop = ENOMEM;
358 return NSS_STATUS_TRYAGAIN;
360 switch(res->status)
362 case NIS_NOTFOUND:
363 case NIS_PARTIAL:
364 case NIS_NOSUCHNAME:
365 case NIS_NOSUCHTABLE:
366 nis_freeresult (res);
367 return NSS_STATUS_NOTFOUND;
368 case NIS_S_NOTFOUND:
369 case NIS_TRYAGAIN:
370 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
371 nis_sperrno (res->status));
372 nis_freeresult (res);
373 *errnop = errno;
374 return NSS_STATUS_TRYAGAIN;
375 case NIS_SUCCESS:
376 case NIS_S_SUCCESS:
377 break; /* go and do something useful */
378 default:
379 syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
380 nis_sperrno (res->status));
381 nis_freeresult (res);
382 return NSS_STATUS_UNAVAIL;
385 if (res->objects.objects_len > 1)
387 * A principal can have more than one LOCAL entry?
388 * Something wrong with cred table.
389 * Warn user and continue.
391 syslog (LOG_ALERT,
392 _("netname2user: LOCAL entry for %s in directory %s not unique"),
393 netname, domain);
394 /* Fetch the uid */
395 *uidp = strtoul (ENTRY_VAL (res->objects.objects_val, 2), NULL, 10);
397 if (*uidp == 0)
399 syslog (LOG_ERR, _("netname2user: should not have uid 0"));
400 return NSS_STATUS_NOTFOUND;
403 parse_grp_str (ENTRY_VAL (res->objects.objects_val, 3),
404 gidp, gidlenp, gidlist, errnop);
406 nis_freeresult (res);
407 return NSS_STATUS_SUCCESS;