Update NIS+.
[kopensolaris-gnu/glibc.git] / nis / nss_nisplus / nisplus-publickey.c
1 /* Copyright (c) 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 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 <syslog.h>
26 #include <rpc/rpc.h>
27 #include <rpcsvc/nis.h>
28 #include <rpc/key_prot.h>
29 extern int xdecrypt (char *, char *);
30
31 #include <nss-nisplus.h>
32
33 /* If we haven't found the entry, we give a SUCCESS and an empty key back. */
34 enum nss_status
35 _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop)
36 {
37   nis_result *res;
38   enum nss_status retval;
39   char buf[NIS_MAXNAMELEN+2];
40   size_t slen;
41   char *domain, *cptr;
42   int len;
43
44   pkey[0] = 0;
45
46   if (netname == NULL)
47     {
48       *errnop = EINVAL;
49       return NSS_STATUS_UNAVAIL;
50     }
51
52   domain = strchr (netname, '@');
53   if (!domain)
54     return NSS_STATUS_UNAVAIL;
55   domain++;
56
57   slen = snprintf (buf, NIS_MAXNAMELEN,
58                    "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
59                    netname, domain);
60
61   if (buf[slen - 1] != '.')
62     {
63       buf[slen++] = '.';
64       buf[slen] = '\0';
65     }
66
67   res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
68                   NULL, NULL);
69
70   retval = niserr2nss (res->status);
71
72   if (retval != NSS_STATUS_SUCCESS)
73     {
74       if (retval == NSS_STATUS_TRYAGAIN)
75         *errnop = errno;
76       if (res->status == NIS_NOTFOUND)
77         retval = NSS_STATUS_SUCCESS;
78       nis_freeresult (res);
79       return retval;
80     }
81
82   if (res->objects.objects_len > 1)
83     {
84       /*
85        * More than one principal with same uid?
86        * something wrong with cred table. Should be unique
87        * Warn user and continue.
88        */
89       printf (_("DES entry for netname %s not unique\n"), netname);
90       nis_freeresult (res);
91       return NSS_STATUS_SUCCESS;
92     }
93
94   len = ENTRY_LEN (res->objects.objects_val, 3);
95   memcpy (pkey, ENTRY_VAL (res->objects.objects_val,3), len);
96   pkey[len] = 0;
97   cptr = strchr (pkey, ':');
98   if (cptr)
99     cptr[0] = '\0';
100   nis_freeresult (res);
101
102   return NSS_STATUS_SUCCESS;
103 }
104
105 enum nss_status
106 _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
107                            int *errnop)
108 {
109   nis_result *res;
110   enum nss_status retval;
111   char buf[NIS_MAXNAMELEN+2];
112   size_t slen;
113   char *domain, *cptr;
114   int len;
115
116   skey[0] = 0;
117
118   if (netname == NULL)
119     {
120       *errnop = EINVAL;
121       return NSS_STATUS_UNAVAIL;
122     }
123
124   domain = strchr (netname, '@');
125   if (!domain)
126     return NSS_STATUS_UNAVAIL;
127   domain++;
128
129   slen = snprintf (buf, NIS_MAXNAMELEN,
130                    "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
131                    netname, domain);
132
133   if (buf[slen - 1] != '.')
134     {
135       buf[slen++] = '.';
136       buf[slen] = '\0';
137     }
138
139   res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
140                   NULL, NULL);
141
142   retval = niserr2nss (res->status);
143
144   if (retval != NSS_STATUS_SUCCESS)
145     {
146       if (retval == NSS_STATUS_TRYAGAIN)
147         *errnop = errno;
148       nis_freeresult (res);
149       return retval;
150     }
151
152   if (res->objects.objects_len > 1)
153     {
154       /*
155        * More than one principal with same uid?
156        * something wrong with cred table. Should be unique
157        * Warn user and continue.
158        */
159       printf (_("DES entry for netname %s not unique\n"), netname);
160       nis_freeresult (res);
161       return NSS_STATUS_SUCCESS;
162     }
163
164   len = ENTRY_LEN (res->objects.objects_val, 4);
165   memcpy (buf, ENTRY_VAL (res->objects.objects_val,4), len);
166   buf[len] = '\0';
167   cptr = strchr (buf, ':');
168   if (cptr)
169     cptr[0] = '\0';
170   nis_freeresult (res);
171
172   if (!xdecrypt (buf, passwd))
173     return NSS_STATUS_SUCCESS;
174
175   if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
176     return NSS_STATUS_SUCCESS;
177
178   buf[HEXKEYBYTES] = 0;
179   strcpy (skey, buf);
180
181   return NSS_STATUS_SUCCESS;
182 }
183
184 /* Parse information from the passed string.
185    The format of the string passed is gid,grp,grp, ...  */
186 static enum nss_status
187 parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist,
188                int *errnop)
189 {
190   int gidlen;
191
192   if (!s || (!isdigit (*s)))
193     {
194       syslog (LOG_ERR, _("netname2user: missing group id list in '%s'."), s);
195       return NSS_STATUS_NOTFOUND;
196     }
197
198   *gidp = atoi (s);
199
200   gidlen = 0;
201
202   while ((s = strchr (s, ',')) != NULL)
203     {
204       s++;
205       gidlist[gidlen++] = atoi (s);
206     }
207   *gidlenp = gidlen;
208
209   return NSS_STATUS_SUCCESS;
210 }
211
212 enum nss_status
213 _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
214                        gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
215 {
216   char *domain;
217   nis_result *res;
218   char sname[NIS_MAXNAMELEN+1]; /*  search criteria + table name */
219   size_t slen;
220   char principal[NIS_MAXNAMELEN+1];
221   int len;
222
223   /* 1.  Get home domain of user. */
224   domain = strchr (netname, '@');
225   if (! domain)
226     return NSS_STATUS_UNAVAIL;
227
228   ++domain;  /* skip '@' */
229
230   /* 2.  Get user's nisplus principal name.  */
231   if ((strlen (netname) + strlen (domain)+45) >
232       (size_t) NIS_MAXNAMELEN)
233     return NSS_STATUS_UNAVAIL;
234
235   slen = snprintf (sname, NIS_MAXNAMELEN,
236                    "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
237                    netname, domain);
238
239   if (sname[slen - 1] != '.')
240     {
241       sname[slen++] = '.';
242       sname[slen] = '\0';
243     }
244
245   /* must use authenticated call here */
246   /* XXX but we cant, for now. XXX */
247   res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
248                   NULL, NULL);
249   switch (res->status)
250     {
251     case NIS_SUCCESS:
252     case NIS_S_SUCCESS:
253       break;   /* go and do something useful */
254     case NIS_NOTFOUND:
255     case NIS_PARTIAL:
256     case NIS_NOSUCHNAME:
257     case NIS_NOSUCHTABLE:
258       nis_freeresult (res);
259       return NSS_STATUS_NOTFOUND;
260     case NIS_S_NOTFOUND:
261     case NIS_TRYAGAIN:
262       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
263               nis_sperrno (res->status));
264       nis_freeresult (res);
265       *errnop = errno;
266       return NSS_STATUS_TRYAGAIN;
267     default:
268       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
269               nis_sperrno (res->status));
270       nis_freeresult (res);
271       return NSS_STATUS_UNAVAIL;
272     }
273
274   if (res->objects.objects_len > 1)
275     /*
276      * A netname belonging to more than one principal?
277      * Something wrong with cred table. should be unique.
278      * Warn user and continue.
279      */
280     syslog (LOG_ALERT,
281             _("netname2user: DES entry for %s in directory %s not unique"),
282             netname, domain);
283
284   len = ENTRY_LEN (res->objects.objects_val, 0);
285   strncpy (principal, ENTRY_VAL (res->objects.objects_val, 0), len);
286   principal[len] = '\0';
287   nis_freeresult (res);
288
289   if (principal[0] == '\0')
290     return NSS_STATUS_UNAVAIL;
291
292   /*
293    * 3.  Use principal name to look up uid/gid information in
294    *     LOCAL entry in **local** cred table.
295    */
296   domain = nis_local_directory ();
297   if ((strlen (principal) + strlen (domain) + 45) > (size_t) NIS_MAXNAMELEN)
298     {
299       syslog (LOG_ERR, _("netname2user: principal name '%s' too long"),
300               principal);
301       return NSS_STATUS_UNAVAIL;
302     }
303
304   slen = sprintf (sname, "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
305                   principal, domain);
306
307   if (sname[slen - 1] != '.')
308     {
309       sname[slen++] = '.';
310       sname[slen] = '\0';
311     }
312
313   /* must use authenticated call here */
314   /* XXX but we cant, for now. XXX */
315   res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
316                   NULL, NULL);
317   switch(res->status)
318     {
319     case NIS_NOTFOUND:
320     case NIS_PARTIAL:
321     case NIS_NOSUCHNAME:
322     case NIS_NOSUCHTABLE:
323       nis_freeresult (res);
324       return NSS_STATUS_NOTFOUND;
325     case NIS_S_NOTFOUND:
326     case NIS_TRYAGAIN:
327       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
328               nis_sperrno (res->status));
329       nis_freeresult (res);
330       *errnop = errno;
331       return NSS_STATUS_TRYAGAIN;
332     case NIS_SUCCESS:
333     case NIS_S_SUCCESS:
334       break;   /* go and do something useful */
335     default:
336       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
337               nis_sperrno (res->status));
338       nis_freeresult (res);
339       return NSS_STATUS_UNAVAIL;
340     }
341
342   if (res->objects.objects_len > 1)
343     /*
344      * A principal can have more than one LOCAL entry?
345      * Something wrong with cred table.
346      * Warn user and continue.
347      */
348     syslog (LOG_ALERT,
349             _("netname2user: LOCAL entry for %s in directory %s not unique"),
350             netname, domain);
351   /* Fetch the uid */
352   *uidp = atoi (ENTRY_VAL (res->objects.objects_val, 2));
353
354   if (*uidp == 0)
355     {
356       syslog (LOG_ERR, _("netname2user: should not have uid 0"));
357       return NSS_STATUS_NOTFOUND;
358     }
359
360   parse_grp_str (ENTRY_VAL (res->objects.objects_val, 3),
361                  gidp, gidlenp, gidlist, errnop);
362
363   nis_freeresult (res);
364   return NSS_STATUS_SUCCESS;
365 }