Back to index

glibc  2.9
nisplus-publickey.c
Go to the documentation of this file.
00001 /* Copyright (c) 1997,1999,2001,2003,2005,2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <nss.h>
00021 #include <ctype.h>
00022 #include <errno.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <libintl.h>
00026 #include <syslog.h>
00027 #include <rpc/rpc.h>
00028 #include <rpcsvc/nis.h>
00029 #include <rpc/key_prot.h>
00030 extern int xdecrypt (char *, char *);
00031 
00032 #include <nss-nisplus.h>
00033 
00034 /* If we haven't found the entry, we give a SUCCESS and an empty key back. */
00035 enum nss_status
00036 _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop)
00037 {
00038   nis_result *res;
00039   enum nss_status retval;
00040   char buf[NIS_MAXNAMELEN + 2];
00041   size_t slen;
00042   char *domain, *cptr;
00043   int len;
00044 
00045   pkey[0] = 0;
00046 
00047   if (netname == NULL)
00048     {
00049       *errnop = EINVAL;
00050       return NSS_STATUS_UNAVAIL;
00051     }
00052 
00053   domain = strchr (netname, '@');
00054   if (!domain)
00055     return NSS_STATUS_UNAVAIL;
00056   domain++;
00057 
00058   slen = snprintf (buf, NIS_MAXNAMELEN,
00059                  "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
00060                  netname, domain);
00061 
00062   if (slen >= NIS_MAXNAMELEN)
00063     {
00064       *errnop = EINVAL;
00065       return NSS_STATUS_UNAVAIL;
00066     }
00067 
00068   if (buf[slen - 1] != '.')
00069     {
00070       buf[slen++] = '.';
00071       buf[slen] = '\0';
00072     }
00073 
00074   res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
00075                 NULL, NULL);
00076 
00077   if (res == NULL)
00078     {
00079       *errnop = ENOMEM;
00080       return NSS_STATUS_TRYAGAIN;
00081     }
00082   retval = niserr2nss (res->status);
00083 
00084   if (retval != NSS_STATUS_SUCCESS)
00085     {
00086       if (retval == NSS_STATUS_TRYAGAIN)
00087        *errnop = errno;
00088       if (res->status == NIS_NOTFOUND)
00089        retval = NSS_STATUS_SUCCESS;
00090       nis_freeresult (res);
00091       return retval;
00092     }
00093 
00094   if (NIS_RES_NUMOBJ (res) > 1)
00095     {
00096       /*
00097        * More than one principal with same uid?
00098        * something wrong with cred table. Should be unique
00099        * Warn user and continue.
00100        */
00101       syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
00102       nis_freeresult (res);
00103       return NSS_STATUS_SUCCESS;
00104     }
00105 
00106   len = ENTRY_LEN (NIS_RES_OBJECT (res), 3);
00107   memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len);
00108   pkey[len] = 0;
00109   cptr = strchr (pkey, ':');
00110   if (cptr)
00111     cptr[0] = '\0';
00112   nis_freeresult (res);
00113 
00114   return NSS_STATUS_SUCCESS;
00115 }
00116 
00117 
00118 enum nss_status
00119 _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
00120                         int *errnop)
00121 {
00122   nis_result *res;
00123   enum nss_status retval;
00124   char buf[NIS_MAXNAMELEN + 2];
00125   size_t slen;
00126   char *domain, *cptr;
00127   int len;
00128 
00129   skey[0] = 0;
00130 
00131   if (netname == NULL)
00132     {
00133       *errnop = EINVAL;
00134       return NSS_STATUS_UNAVAIL;
00135     }
00136 
00137   domain = strchr (netname, '@');
00138   if (!domain)
00139     return NSS_STATUS_UNAVAIL;
00140   domain++;
00141 
00142   slen = snprintf (buf, NIS_MAXNAMELEN,
00143                  "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
00144                  netname, domain);
00145 
00146   if (slen >= NIS_MAXNAMELEN)
00147     {
00148       *errnop = EINVAL;
00149       return NSS_STATUS_UNAVAIL;
00150     }
00151 
00152   if (buf[slen - 1] != '.')
00153     {
00154       buf[slen++] = '.';
00155       buf[slen] = '\0';
00156     }
00157 
00158   res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH,
00159                 NULL, NULL);
00160 
00161   if (res == NULL)
00162     {
00163       *errnop = ENOMEM;
00164       return NSS_STATUS_TRYAGAIN;
00165     }
00166   retval = niserr2nss (res->status);
00167 
00168   if (retval != NSS_STATUS_SUCCESS)
00169     {
00170       if (retval == NSS_STATUS_TRYAGAIN)
00171        *errnop = errno;
00172       nis_freeresult (res);
00173       return retval;
00174     }
00175 
00176   if (NIS_RES_NUMOBJ (res) > 1)
00177     {
00178       /*
00179        * More than one principal with same uid?
00180        * something wrong with cred table. Should be unique
00181        * Warn user and continue.
00182        */
00183       syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
00184       nis_freeresult (res);
00185       return NSS_STATUS_SUCCESS;
00186     }
00187 
00188   len = ENTRY_LEN (NIS_RES_OBJECT (res), 4);
00189   memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len);
00190   buf[len] = '\0';
00191   cptr = strchr (buf, ':');
00192   if (cptr)
00193     cptr[0] = '\0';
00194   nis_freeresult (res);
00195 
00196   if (!xdecrypt (buf, passwd))
00197     return NSS_STATUS_SUCCESS;
00198 
00199   if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
00200     return NSS_STATUS_SUCCESS;
00201 
00202   buf[HEXKEYBYTES] = 0;
00203   strcpy (skey, buf);
00204 
00205   return NSS_STATUS_SUCCESS;
00206 }
00207 
00208 
00209 /* Parse information from the passed string.
00210    The format of the string passed is gid,grp,grp, ...  */
00211 static enum nss_status
00212 parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist,
00213               int *errnop)
00214 {
00215   char *ep;
00216   int gidlen;
00217 
00218   if (!s || (!isdigit (*s)))
00219     {
00220       syslog (LOG_ERR, _("netname2user: missing group id list in `%s'"), s);
00221       return NSS_STATUS_NOTFOUND;
00222     }
00223 
00224   *gidp = strtoul (s, &ep, 10);
00225 
00226   gidlen = 0;
00227 
00228   /* After strtoul() ep should point to the marker ',', which means
00229      here starts a new value.
00230 
00231      The Sun man pages show that GIDLIST should contain at least NGRPS
00232      elements.  Limiting the number written by this value is the best
00233      we can do.  */
00234   while (ep != NULL && *ep == ',' && gidlen < NGRPS)
00235     {
00236       ep++;
00237       s = ep;
00238       gidlist[gidlen++] = strtoul (s, &ep, 10);
00239     }
00240   *gidlenp = gidlen;
00241 
00242   return NSS_STATUS_SUCCESS;
00243 }
00244 
00245 enum nss_status
00246 _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
00247                      gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
00248 {
00249   char *domain;
00250   nis_result *res;
00251   char sname[NIS_MAXNAMELEN + 2]; /*  search criteria + table name */
00252   size_t slen;
00253   char principal[NIS_MAXNAMELEN + 1];
00254   int len;
00255 
00256   /* 1.  Get home domain of user. */
00257   domain = strchr (netname, '@');
00258   if (! domain)
00259     return NSS_STATUS_UNAVAIL;
00260 
00261   ++domain;  /* skip '@' */
00262 
00263   /* 2.  Get user's nisplus principal name.  */
00264   slen = snprintf (sname, NIS_MAXNAMELEN,
00265                  "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
00266                  netname, domain);
00267 
00268   if (slen >= NIS_MAXNAMELEN)
00269     {
00270       *errnop = EINVAL;
00271       return NSS_STATUS_UNAVAIL;
00272     }
00273 
00274   if (sname[slen - 1] != '.')
00275     {
00276       sname[slen++] = '.';
00277       sname[slen] = '\0';
00278     }
00279 
00280   /* must use authenticated call here */
00281   /* XXX but we cant, for now. XXX */
00282   res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
00283                 NULL, NULL);
00284   if (res == NULL)
00285     {
00286       *errnop = ENOMEM;
00287       return NSS_STATUS_TRYAGAIN;
00288     }
00289   switch (res->status)
00290     {
00291     case NIS_SUCCESS:
00292     case NIS_S_SUCCESS:
00293       break;   /* go and do something useful */
00294     case NIS_NOTFOUND:
00295     case NIS_PARTIAL:
00296     case NIS_NOSUCHNAME:
00297     case NIS_NOSUCHTABLE:
00298       nis_freeresult (res);
00299       return NSS_STATUS_NOTFOUND;
00300     case NIS_S_NOTFOUND:
00301     case NIS_TRYAGAIN:
00302       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
00303              nis_sperrno (res->status));
00304       nis_freeresult (res);
00305       *errnop = errno;
00306       return NSS_STATUS_TRYAGAIN;
00307     default:
00308       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
00309              nis_sperrno (res->status));
00310       nis_freeresult (res);
00311       return NSS_STATUS_UNAVAIL;
00312     }
00313 
00314   if (NIS_RES_NUMOBJ (res) > 1)
00315     /*
00316      * A netname belonging to more than one principal?
00317      * Something wrong with cred table. should be unique.
00318      * Warn user and continue.
00319      */
00320     syslog (LOG_ALERT,
00321            _("netname2user: DES entry for %s in directory %s not unique"),
00322            netname, domain);
00323 
00324   len = ENTRY_LEN (NIS_RES_OBJECT (res), 0);
00325   strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len);
00326   principal[len] = '\0';
00327   nis_freeresult (res);
00328 
00329   if (principal[0] == '\0')
00330     return NSS_STATUS_UNAVAIL;
00331 
00332   /*
00333    * 3.  Use principal name to look up uid/gid information in
00334    *     LOCAL entry in **local** cred table.
00335    */
00336   domain = nis_local_directory ();
00337   if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN)
00338     {
00339       syslog (LOG_ERR, _("netname2user: principal name `%s' too long"),
00340              principal);
00341       return NSS_STATUS_UNAVAIL;
00342     }
00343 
00344   slen = snprintf (sname, sizeof  (sname),
00345                  "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
00346                  principal, domain);
00347 
00348   if (sname[slen - 1] != '.')
00349     {
00350       sname[slen++] = '.';
00351       sname[slen] = '\0';
00352     }
00353 
00354   /* must use authenticated call here */
00355   /* XXX but we cant, for now. XXX */
00356   res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
00357                 NULL, NULL);
00358   if (res == NULL)
00359     {
00360       *errnop = ENOMEM;
00361       return NSS_STATUS_TRYAGAIN;
00362     }
00363   switch(res->status)
00364     {
00365     case NIS_NOTFOUND:
00366     case NIS_PARTIAL:
00367     case NIS_NOSUCHNAME:
00368     case NIS_NOSUCHTABLE:
00369       nis_freeresult (res);
00370       return NSS_STATUS_NOTFOUND;
00371     case NIS_S_NOTFOUND:
00372     case NIS_TRYAGAIN:
00373       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
00374              nis_sperrno (res->status));
00375       nis_freeresult (res);
00376       *errnop = errno;
00377       return NSS_STATUS_TRYAGAIN;
00378     case NIS_SUCCESS:
00379     case NIS_S_SUCCESS:
00380       break;   /* go and do something useful */
00381     default:
00382       syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"),
00383              nis_sperrno (res->status));
00384       nis_freeresult (res);
00385       return NSS_STATUS_UNAVAIL;
00386     }
00387 
00388   if (NIS_RES_NUMOBJ (res) > 1)
00389     /*
00390      * A principal can have more than one LOCAL entry?
00391      * Something wrong with cred table.
00392      * Warn user and continue.
00393      */
00394     syslog (LOG_ALERT,
00395            _("netname2user: LOCAL entry for %s in directory %s not unique"),
00396            netname, domain);
00397   /* Fetch the uid */
00398   *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10);
00399 
00400   if (*uidp == 0)
00401     {
00402       syslog (LOG_ERR, _("netname2user: should not have uid 0"));
00403       nis_freeresult (res);
00404       return NSS_STATUS_NOTFOUND;
00405     }
00406 
00407   parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3),
00408                gidp, gidlenp, gidlist, errnop);
00409 
00410   nis_freeresult (res);
00411   return NSS_STATUS_SUCCESS;
00412 }