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