]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_nisplus/nisplus-publickey.c
.
[thirdparty/glibc.git] / nis / nss_nisplus / nisplus-publickey.c
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.
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 <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 *);
31
32 #include <nss-nisplus.h>
33
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)
37 {
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;
44
45 pkey[0] = 0;
46
47 if (netname == NULL)
48 {
49 *errnop = EINVAL;
50 return NSS_STATUS_UNAVAIL;
51 }
52
53 domain = strchr (netname, '@');
54 if (!domain)
55 return NSS_STATUS_UNAVAIL;
56 domain++;
57
58 slen = snprintf (buf, NIS_MAXNAMELEN,
59 "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
60 netname, domain);
61
62 if (slen >= NIS_MAXNAMELEN)
63 {
64 *errnop = EINVAL;
65 return NSS_STATUS_UNAVAIL;
66 }
67
68 if (buf[slen - 1] != '.')
69 {
70 buf[slen++] = '.';
71 buf[slen] = '\0';
72 }
73
74 res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
75 NULL, NULL);
76
77 if (res == NULL)
78 {
79 *errnop = ENOMEM;
80 return NSS_STATUS_TRYAGAIN;
81 }
82 retval = niserr2nss (res->status);
83
84 if (retval != NSS_STATUS_SUCCESS)
85 {
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;
92 }
93
94 if (NIS_RES_NUMOBJ (res) > 1)
95 {
96 /*
97 * More than one principal with same uid?
98 * something wrong with cred table. Should be unique
99 * Warn user and continue.
100 */
101 syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
102 nis_freeresult (res);
103 return NSS_STATUS_SUCCESS;
104 }
105
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);
113
114 return NSS_STATUS_SUCCESS;
115 }
116
117
118 enum nss_status
119 _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
120 int *errnop)
121 {
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;
128
129 skey[0] = 0;
130
131 if (netname == NULL)
132 {
133 *errnop = EINVAL;
134 return NSS_STATUS_UNAVAIL;
135 }
136
137 domain = strchr (netname, '@');
138 if (!domain)
139 return NSS_STATUS_UNAVAIL;
140 domain++;
141
142 slen = snprintf (buf, NIS_MAXNAMELEN,
143 "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
144 netname, domain);
145
146 if (slen >= NIS_MAXNAMELEN)
147 {
148 *errnop = EINVAL;
149 return NSS_STATUS_UNAVAIL;
150 }
151
152 if (buf[slen - 1] != '.')
153 {
154 buf[slen++] = '.';
155 buf[slen] = '\0';
156 }
157
158 res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH,
159 NULL, NULL);
160
161 if (res == NULL)
162 {
163 *errnop = ENOMEM;
164 return NSS_STATUS_TRYAGAIN;
165 }
166 retval = niserr2nss (res->status);
167
168 if (retval != NSS_STATUS_SUCCESS)
169 {
170 if (retval == NSS_STATUS_TRYAGAIN)
171 *errnop = errno;
172 nis_freeresult (res);
173 return retval;
174 }
175
176 if (NIS_RES_NUMOBJ (res) > 1)
177 {
178 /*
179 * More than one principal with same uid?
180 * something wrong with cred table. Should be unique
181 * Warn user and continue.
182 */
183 syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
184 nis_freeresult (res);
185 return NSS_STATUS_SUCCESS;
186 }
187
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);
195
196 if (!xdecrypt (buf, passwd))
197 return NSS_STATUS_SUCCESS;
198
199 if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
200 return NSS_STATUS_SUCCESS;
201
202 buf[HEXKEYBYTES] = 0;
203 strcpy (skey, buf);
204
205 return NSS_STATUS_SUCCESS;
206 }
207
208
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)
214 {
215 char *ep;
216 int gidlen;
217
218 if (!s || (!isdigit (*s)))
219 {
220 syslog (LOG_ERR, _("netname2user: missing group id list in `%s'."), s);
221 return NSS_STATUS_NOTFOUND;
222 }
223
224 *gidp = strtoul (s, &ep, 10);
225
226 gidlen = 0;
227
228 /* After strtoul() ep should point to the marker ',', which means
229 here starts a new value.
230
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)
235 {
236 ep++;
237 s = ep;
238 gidlist[gidlen++] = strtoul (s, &ep, 10);
239 }
240 *gidlenp = gidlen;
241
242 return NSS_STATUS_SUCCESS;
243 }
244
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)
248 {
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;
255
256 /* 1. Get home domain of user. */
257 domain = strchr (netname, '@');
258 if (! domain)
259 return NSS_STATUS_UNAVAIL;
260
261 ++domain; /* skip '@' */
262
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);
267
268 if (slen >= NIS_MAXNAMELEN)
269 {
270 *errnop = EINVAL;
271 return NSS_STATUS_UNAVAIL;
272 }
273
274 if (sname[slen - 1] != '.')
275 {
276 sname[slen++] = '.';
277 sname[slen] = '\0';
278 }
279
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)
285 {
286 *errnop = ENOMEM;
287 return NSS_STATUS_TRYAGAIN;
288 }
289 switch (res->status)
290 {
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;
312 }
313
314 if (NIS_RES_NUMOBJ (res) > 1)
315 /*
316 * A netname belonging to more than one principal?
317 * Something wrong with cred table. should be unique.
318 * Warn user and continue.
319 */
320 syslog (LOG_ALERT,
321 _("netname2user: DES entry for %s in directory %s not unique"),
322 netname, domain);
323
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);
328
329 if (principal[0] == '\0')
330 return NSS_STATUS_UNAVAIL;
331
332 /*
333 * 3. Use principal name to look up uid/gid information in
334 * LOCAL entry in **local** cred table.
335 */
336 domain = nis_local_directory ();
337 if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN)
338 {
339 syslog (LOG_ERR, _("netname2user: principal name `%s' too long"),
340 principal);
341 return NSS_STATUS_UNAVAIL;
342 }
343
344 slen = snprintf (sname, sizeof (sname),
345 "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
346 principal, domain);
347
348 if (sname[slen - 1] != '.')
349 {
350 sname[slen++] = '.';
351 sname[slen] = '\0';
352 }
353
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)
359 {
360 *errnop = ENOMEM;
361 return NSS_STATUS_TRYAGAIN;
362 }
363 switch(res->status)
364 {
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;
386 }
387
388 if (NIS_RES_NUMOBJ (res) > 1)
389 /*
390 * A principal can have more than one LOCAL entry?
391 * Something wrong with cred table.
392 * Warn user and continue.
393 */
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);
399
400 if (*uidp == 0)
401 {
402 syslog (LOG_ERR, _("netname2user: should not have uid 0"));
403 nis_freeresult (res);
404 return NSS_STATUS_NOTFOUND;
405 }
406
407 parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3),
408 gidp, gidlenp, gidlist, errnop);
409
410 nis_freeresult (res);
411 return NSS_STATUS_SUCCESS;
412 }