/* Copyright (c) 1997,1999,2001,2003,2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk , 1997. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #include #include #include extern int xdecrypt (char *, char *); #include /* If we haven't found the entry, we give a SUCCESS and an empty key back. */ enum nss_status _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop) { nis_result *res; enum nss_status retval; char buf[NIS_MAXNAMELEN + 2]; size_t slen; char *domain, *cptr; int len; pkey[0] = 0; if (netname == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } domain = strchr (netname, '@'); if (!domain) return NSS_STATUS_UNAVAIL; domain++; slen = snprintf (buf, NIS_MAXNAMELEN, "[auth_name=%s,auth_type=DES],cred.org_dir.%s", netname, domain); if (slen >= NIS_MAXNAMELEN) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } if (buf[slen - 1] != '.') { buf[slen++] = '.'; buf[slen] = '\0'; } res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH, NULL, NULL); if (res == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } retval = niserr2nss (res->status); if (retval != NSS_STATUS_SUCCESS) { if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; if (res->status == NIS_NOTFOUND) retval = NSS_STATUS_SUCCESS; nis_freeresult (res); return retval; } if (NIS_RES_NUMOBJ (res) > 1) { /* * More than one principal with same uid? * something wrong with cred table. Should be unique * Warn user and continue. */ syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname); nis_freeresult (res); return NSS_STATUS_SUCCESS; } len = ENTRY_LEN (NIS_RES_OBJECT (res), 3); memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len); pkey[len] = 0; cptr = strchr (pkey, ':'); if (cptr) cptr[0] = '\0'; nis_freeresult (res); return NSS_STATUS_SUCCESS; } enum nss_status _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd, int *errnop) { nis_result *res; enum nss_status retval; char buf[NIS_MAXNAMELEN + 2]; size_t slen; char *domain, *cptr; int len; skey[0] = 0; if (netname == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } domain = strchr (netname, '@'); if (!domain) return NSS_STATUS_UNAVAIL; domain++; slen = snprintf (buf, NIS_MAXNAMELEN, "[auth_name=%s,auth_type=DES],cred.org_dir.%s", netname, domain); if (slen >= NIS_MAXNAMELEN) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } if (buf[slen - 1] != '.') { buf[slen++] = '.'; buf[slen] = '\0'; } res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); if (res == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } retval = niserr2nss (res->status); if (retval != NSS_STATUS_SUCCESS) { if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; nis_freeresult (res); return retval; } if (NIS_RES_NUMOBJ (res) > 1) { /* * More than one principal with same uid? * something wrong with cred table. Should be unique * Warn user and continue. */ syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname); nis_freeresult (res); return NSS_STATUS_SUCCESS; } len = ENTRY_LEN (NIS_RES_OBJECT (res), 4); memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len); buf[len] = '\0'; cptr = strchr (buf, ':'); if (cptr) cptr[0] = '\0'; nis_freeresult (res); if (!xdecrypt (buf, passwd)) return NSS_STATUS_SUCCESS; if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0) return NSS_STATUS_SUCCESS; buf[HEXKEYBYTES] = 0; strcpy (skey, buf); return NSS_STATUS_SUCCESS; } /* Parse information from the passed string. The format of the string passed is gid,grp,grp, ... */ static enum nss_status parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop) { char *ep; int gidlen; if (!s || (!isdigit (*s))) { syslog (LOG_ERR, _("netname2user: missing group id list in `%s'"), s); return NSS_STATUS_NOTFOUND; } *gidp = strtoul (s, &ep, 10); gidlen = 0; /* After strtoul() ep should point to the marker ',', which means here starts a new value. The Sun man pages show that GIDLIST should contain at least NGRPS elements. Limiting the number written by this value is the best we can do. */ while (ep != NULL && *ep == ',' && gidlen < NGRPS) { ep++; s = ep; gidlist[gidlen++] = strtoul (s, &ep, 10); } *gidlenp = gidlen; return NSS_STATUS_SUCCESS; } enum nss_status _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop) { char *domain; nis_result *res; char sname[NIS_MAXNAMELEN + 2]; /* search criteria + table name */ size_t slen; char principal[NIS_MAXNAMELEN + 1]; int len; /* 1. Get home domain of user. */ domain = strchr (netname, '@'); if (! domain) return NSS_STATUS_UNAVAIL; ++domain; /* skip '@' */ /* 2. Get user's nisplus principal name. */ slen = snprintf (sname, NIS_MAXNAMELEN, "[auth_name=%s,auth_type=DES],cred.org_dir.%s", netname, domain); if (slen >= NIS_MAXNAMELEN) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } if (sname[slen - 1] != '.') { sname[slen++] = '.'; sname[slen] = '\0'; } /* must use authenticated call here */ /* XXX but we cant, for now. XXX */ res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH, NULL, NULL); if (res == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } switch (res->status) { case NIS_SUCCESS: case NIS_S_SUCCESS: break; /* go and do something useful */ case NIS_NOTFOUND: case NIS_PARTIAL: case NIS_NOSUCHNAME: case NIS_NOSUCHTABLE: nis_freeresult (res); return NSS_STATUS_NOTFOUND; case NIS_S_NOTFOUND: case NIS_TRYAGAIN: syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), nis_sperrno (res->status)); nis_freeresult (res); *errnop = errno; return NSS_STATUS_TRYAGAIN; default: syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), nis_sperrno (res->status)); nis_freeresult (res); return NSS_STATUS_UNAVAIL; } if (NIS_RES_NUMOBJ (res) > 1) /* * A netname belonging to more than one principal? * Something wrong with cred table. should be unique. * Warn user and continue. */ syslog (LOG_ALERT, _("netname2user: DES entry for %s in directory %s not unique"), netname, domain); len = ENTRY_LEN (NIS_RES_OBJECT (res), 0); strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len); principal[len] = '\0'; nis_freeresult (res); if (principal[0] == '\0') return NSS_STATUS_UNAVAIL; /* * 3. Use principal name to look up uid/gid information in * LOCAL entry in **local** cred table. */ domain = nis_local_directory (); if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN) { syslog (LOG_ERR, _("netname2user: principal name `%s' too long"), principal); return NSS_STATUS_UNAVAIL; } slen = snprintf (sname, sizeof (sname), "[cname=%s,auth_type=LOCAL],cred.org_dir.%s", principal, domain); if (sname[slen - 1] != '.') { sname[slen++] = '.'; sname[slen] = '\0'; } /* must use authenticated call here */ /* XXX but we cant, for now. XXX */ res = nis_list (sname, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH, NULL, NULL); if (res == NULL) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; } switch(res->status) { case NIS_NOTFOUND: case NIS_PARTIAL: case NIS_NOSUCHNAME: case NIS_NOSUCHTABLE: nis_freeresult (res); return NSS_STATUS_NOTFOUND; case NIS_S_NOTFOUND: case NIS_TRYAGAIN: syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), nis_sperrno (res->status)); nis_freeresult (res); *errnop = errno; return NSS_STATUS_TRYAGAIN; case NIS_SUCCESS: case NIS_S_SUCCESS: break; /* go and do something useful */ default: syslog (LOG_ERR, _("netname2user: (nis+ lookup): %s\n"), nis_sperrno (res->status)); nis_freeresult (res); return NSS_STATUS_UNAVAIL; } if (NIS_RES_NUMOBJ (res) > 1) /* * A principal can have more than one LOCAL entry? * Something wrong with cred table. * Warn user and continue. */ syslog (LOG_ALERT, _("netname2user: LOCAL entry for %s in directory %s not unique"), netname, domain); /* Fetch the uid */ *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10); if (*uidp == 0) { syslog (LOG_ERR, _("netname2user: should not have uid 0")); nis_freeresult (res); return NSS_STATUS_NOTFOUND; } parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3), gidp, gidlenp, gidlist, errnop); nis_freeresult (res); return NSS_STATUS_SUCCESS; }