diff options
Diffstat (limited to 'nis/nss_compat')
-rw-r--r-- | nis/nss_compat/compat-grp.c | 255 | ||||
-rw-r--r-- | nis/nss_compat/compat-pwd.c | 406 | ||||
-rw-r--r-- | nis/nss_compat/compat-spwd.c | 408 |
3 files changed, 910 insertions, 159 deletions
diff --git a/nis/nss_compat/compat-grp.c b/nis/nss_compat/compat-grp.c index de96dbbeb6..6231a1e911 100644 --- a/nis/nss_compat/compat-grp.c +++ b/nis/nss_compat/compat-grp.c @@ -25,6 +25,14 @@ #include <string.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> +#include <rpcsvc/nis.h> +#include <rpcsvc/nislib.h> +#include <nsswitch.h> + +#include "nss-nisplus.h" + +static service_user *ni = NULL; +static bool_t use_nisplus = FALSE; /* default: group_compat: nis */ /* Get the declaration of the parser function. */ #define ENTNAME grent @@ -32,7 +40,7 @@ #define EXTERN_PARSER #include "../../nss/nss_files/files-parse.c" -/* Structure for remembering -@netgroup and -user members ... */ +/* Structure for remembering -group members ... */ #define BLACKLIST_INITIAL_SIZE 512 #define BLACKLIST_INCREMENT 256 struct blacklist_t @@ -48,12 +56,15 @@ struct ent_t bool_t nis_first; char *oldkey; int oldkeylen; + nis_result *result; + nis_name *names; + u_long names_nr; FILE *stream; struct blacklist_t blacklist; - }; +}; typedef struct ent_t ent_t; -static ent_t ext_ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; +static ent_t ext_ent = {0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}}; /* Protect global state against multiple changers. */ __libc_lock_define_initialized (static, lock) @@ -61,6 +72,8 @@ __libc_lock_define_initialized (static, lock) /* Prototypes for local functions. */ static void blacklist_store_name (const char *, ent_t *); static int in_blacklist (const char *, int, ent_t *); +extern int _nss_nisplus_parse_grent (nis_result *, struct group *, + char *, size_t); static enum nss_status internal_setgrent (ent_t *ent) @@ -75,15 +88,27 @@ internal_setgrent (ent_t *ent) ent->oldkey = NULL; ent->oldkeylen = 0; } - + + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + + if (ent->names != NULL) + { + nis_freenames (ent->names); + ent->names = NULL; + } + ent->names_nr = 0; ent->blacklist.current = 0; if (ent->blacklist.data != NULL) ent->blacklist.data[0] = '\0'; - + if (ent->stream == NULL) { ent->stream = fopen ("/etc/group", "r"); - + if (ent->stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; } @@ -101,6 +126,12 @@ _nss_compat_setgrent (void) __libc_lock_lock (lock); + if (ni == NULL) + { + __nss_database_lookup ("group_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + result = internal_setgrent (&ext_ent); __libc_lock_unlock (lock); @@ -127,6 +158,18 @@ internal_endgrent (ent_t *ent) ent->oldkeylen = 0; } + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + + if (ent->names != NULL) + { + nis_freenames (ent->names); + ent->names = NULL; + } + ent->names_nr = 0; ent->blacklist.current = 0; if (ent->blacklist.data != NULL) ent->blacklist.data[0] = '\0'; @@ -155,7 +198,7 @@ getgrent_next_nis (struct group *result, ent_t *ent, char *buffer, struct parser_data *data = (void *) buffer; char *domain; char *outkey, *outval; - int outkeylen, outvallen; + int outkeylen, outvallen, parse_res; char *p; if (yp_get_default_domain (&domain) != YPERR_SUCCESS) @@ -202,13 +245,133 @@ getgrent_next_nis (struct group *result, ent_t *ent, char *buffer, while (isspace (*p)) ++p; + + parse_res = _nss_files_parse_grent (p, result, data, buflen); + + if (parse_res && + in_blacklist (result->gr_name, strlen (result->gr_name), ent)) + parse_res = 0; /* if result->gr_name in blacklist,search next entry */ + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer, + size_t buflen) +{ + int parse_res; + + if (ent->names == NULL) + { + ent->names = nis_getnames ("group.org_dir"); + if (ent->names == NULL || ent->names[0] == NULL) + { + ent->nis = 0; + return NSS_STATUS_UNAVAIL; + } } - while (!_nss_files_parse_grent (p, result, data, buflen)); + + do + { + if (ent->nis_first) + { + next_name: + ent->result = nis_first_entry(ent->names[ent->names_nr]); + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + ent->nis = 0; + return niserr2nss (ent->result->status); + } + ent->nis_first = FALSE; + } + else + { + nis_result *res; + + res = nis_next_entry(ent->names[ent->names_nr], + &ent->result->cookie); + nis_freeresult (ent->result); + ent->result = res; + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + if ((ent->result->status == NIS_NOTFOUND) && + ent->names[ent->names_nr + 1] != NULL) + { + nis_freeresult (ent->result); + ent->names_nr += 1; + goto next_name; + } + else + { + ent->nis = 0; + return niserr2nss (ent->result->status); + } + } + } + parse_res = _nss_nisplus_parse_grent (ent->result, result, buffer, + buflen); + if (parse_res && + in_blacklist (result->gr_name, strlen (result->gr_name), ent)) + parse_res = 0; /* if result->gr_name in blacklist,search next entry */ + } + while (!parse_res); + + return NSS_STATUS_SUCCESS; +} - if (!in_blacklist (result->gr_name, strlen (result->gr_name), ent)) +/* This function handle the +group entrys in /etc/group */ +static enum nss_status +getgrent_next_file_plusgroup (struct group *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + int parse_res; + + if (use_nisplus) /* Do the NIS+ query here */ + { + nis_result *res; + char buf[strlen (result->gr_name) + 24]; + + sprintf(buf, "[name=%s],group.org_dir", + &result->gr_name[1]); + res = nis_list(buf, EXPAND_NAME, NULL, NULL); + if (niserr2nss (res->status) != NSS_STATUS_SUCCESS) + { + enum nss_status status = niserr2nss (res->status); + + nis_freeresult (res); + return status; + } + parse_res = _nss_nisplus_parse_grent (res, result, buffer, buflen); + nis_freeresult (res); + } + else /* Use NIS */ + { + char *domain, *outval, *p; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + + if (yp_match (domain, "group.byname", &result->gr_name[1], + strlen (result->gr_name) - 1, &outval, &outvallen) + != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + p = strncpy (buffer, outval, + buflen < outvallen ? buflen : outvallen); + free (outval); + while (isspace (*p)) + p++; + parse_res = _nss_files_parse_grent (p, result, data, buflen); + } + + if (parse_res) + /* We found the entry. */ return NSS_STATUS_SUCCESS; else - return NSS_STATUS_NOTFOUND; + return NSS_STATUS_RETURN; } @@ -256,27 +419,16 @@ getgrent_next_file (struct group *result, ent_t *ent, if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' && result->gr_name[1] != '@') { - char *domain; - char *outval; - int outvallen; - - if (yp_get_default_domain (&domain) != YPERR_SUCCESS) - /* XXX Should we regard this as an fatal error? I don't - think so. Just continue working. --drepper@gnu */ - continue; - - if (yp_match (domain, "group.byname", &result->gr_name[1], - strlen (result->gr_name) - 1, &outval, &outvallen) - != YPERR_SUCCESS) - continue; - - p = strncpy (buffer, outval, buflen); - while (isspace (*p)) - p++; - free (outval); - if (_nss_files_parse_grent (p, result, data, buflen)) - /* We found the entry. */ - break; + enum nss_status status; + + status = getgrent_next_file_plusgroup (result, buffer, buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + continue; + else + return status; } /* +:... */ @@ -285,7 +437,10 @@ getgrent_next_file (struct group *result, ent_t *ent, ent->nis = TRUE; ent->nis_first = TRUE; - return getgrent_next_nis (result, ent, buffer, buflen); + if (use_nisplus) + return getgrent_next_nisplus (result, ent, buffer, buflen); + else + return getgrent_next_nis (result, ent, buffer, buflen); } } @@ -298,7 +453,12 @@ internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer, size_t buflen) { if (ent->nis) - return getgrent_next_nis (gr, ent, buffer, buflen); + { + if (use_nisplus) + return getgrent_next_nisplus (gr, ent, buffer, buflen); + else + return getgrent_next_nis (gr, ent, buffer, buflen); + } else return getgrent_next_file (gr, ent, buffer, buflen); } @@ -310,6 +470,12 @@ _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen) __libc_lock_lock (lock); + if (ni == NULL) + { + __nss_database_lookup ("group_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + /* Be prepared that the setgrent function was not called before. */ if (ext_ent.stream == NULL) status = internal_setgrent (&ext_ent); @@ -327,12 +493,21 @@ enum nss_status _nss_compat_getgrnam_r (const char *name, struct group *grp, char *buffer, size_t buflen) { - ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + ent_t ent = {0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}}; enum nss_status status; if (name[0] == '-' || name[0] == '+') return NSS_STATUS_NOTFOUND; + __libc_lock_lock (lock); + + if (ni == NULL) + { + __nss_database_lookup ("group_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + + __libc_lock_unlock (lock); status = internal_setgrent (&ent); if (status != NSS_STATUS_SUCCESS) @@ -352,9 +527,19 @@ enum nss_status _nss_compat_getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t buflen) { - ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}}; + ent_t ent = {0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}}; enum nss_status status; + __libc_lock_lock (lock); + + if (ni == NULL) + { + __nss_database_lookup ("group_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + + __libc_lock_unlock (lock); + status = internal_setgrent (&ent); if (status != NSS_STATUS_SUCCESS) return status; diff --git a/nis/nss_compat/compat-pwd.c b/nis/nss_compat/compat-pwd.c index 56659e9ed5..317e2d18bf 100644 --- a/nis/nss_compat/compat-pwd.c +++ b/nis/nss_compat/compat-pwd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -26,8 +26,15 @@ #include <libc-lock.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> +#include <rpcsvc/nis.h> +#include <rpcsvc/nislib.h> +#include <nsswitch.h> #include "netgroup.h" +#include "nss-nisplus.h" + +static service_user *ni = NULL; +static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */ /* Get the declaration of the parser function. */ #define ENTNAME pwent @@ -52,6 +59,9 @@ struct ent_t bool_t first; char *oldkey; int oldkeylen; + nis_result *result; + nis_name *names; + u_long names_nr; FILE *stream; struct blacklist_t blacklist; struct passwd pwd; @@ -59,7 +69,7 @@ struct ent_t }; typedef struct ent_t ent_t; -static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, +static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}, {NULL, NULL, 0, 0, NULL, NULL, NULL}}; /* Protect global state against multiple changers. */ @@ -68,7 +78,8 @@ __libc_lock_define_initialized (static, lock) /* Prototypes for local functions. */ static void blacklist_store_name (const char *, ent_t *); static int in_blacklist (const char *, int, ent_t *); - +extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *, + char *, size_t); static void give_pwd_free (struct passwd *pwd) { @@ -192,6 +203,18 @@ internal_setpwent (ent_t *ent) ent->oldkeylen = 0; } + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + + if (ent->names != NULL) + { + nis_freenames (ent->names); + ent->names = NULL; + } + ent->names_nr = 0; ent->blacklist.current = 0; if (ent->blacklist.data != NULL) ent->blacklist.data[0] = '\0'; @@ -219,6 +242,12 @@ _nss_compat_setpwent (void) __libc_lock_lock (lock); + if (ni == NULL) + { + __nss_database_lookup ("passwd_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + result = internal_setpwent (&ext_ent); __libc_lock_unlock (lock); @@ -245,6 +274,19 @@ internal_endpwent (ent_t *ent) ent->oldkeylen = 0; } + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + + if (ent->names != NULL) + { + nis_freenames (ent->names); + ent->names = NULL; + } + ent->names_nr = 0; + ent->blacklist.current = 0; if (ent->blacklist.data != NULL) ent->blacklist.data[0] = '\0'; @@ -272,14 +314,14 @@ _nss_compat_endpwent (void) } static enum nss_status -getpwent_next_netgr (struct passwd *result, ent_t *ent, char *group, - char *buffer, size_t buflen) +getpwent_next_nis_netgr (struct passwd *result, ent_t *ent, char *group, + char *buffer, size_t buflen) { struct parser_data *data = (void *) buffer; char *ypdomain, *host, *user, *domain, *outval, *p, *p2; int status, outvallen; size_t p2len; - + if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS) { ent->netgroup = 0; @@ -341,12 +383,175 @@ getpwent_next_netgr (struct passwd *result, ent_t *ent, char *group, } static enum nss_status +getpwent_next_nisplus_netgr (struct passwd *result, ent_t *ent, char *group, + char *buffer, size_t buflen) +{ + char *ypdomain, *host, *user, *domain, *p2; + int status, parse_res; + size_t p2len; + nis_result *nisres; + + /* Maybe we should use domainname here ? We need the current + domainname for the domain field in netgroups */ + if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS) + { + ent->netgroup = 0; + ent->first = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + if (ent->first == TRUE) + { + bzero (&ent->netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = FALSE; + } + + while (1) + { + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen); + if (status != 1) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = 0; + give_pwd_free (&ent->pwd); + return NSS_STATUS_RETURN; + } + + if (user == NULL || user[0] == '-') + continue; + + if (domain != NULL && strcmp (ypdomain, domain) != 0) + continue; + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + { + char buf[strlen (user) + 30]; + sprintf(buf, "[name=%s],passwd.org_dir", user); + nisres = nis_list(buf, EXPAND_NAME, NULL, NULL); + } + if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (nisres); + continue; + } + parse_res = _nss_nisplus_parse_pwent (nisres, result, buffer, buflen); + nis_freeresult (nisres); + + if (parse_res) + { + copy_pwd_changes (result, &ent->pwd, p2, p2len); + break; + } + } + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getpwent_next_netgr (struct passwd *result, ent_t *ent, char *group, + char *buffer, size_t buflen) +{ + if (use_nisplus) + return getpwent_next_nisplus_netgr (result, ent, group, buffer, buflen); + else + return getpwent_next_nis_netgr (result, ent, group, buffer, buflen); +} + +static enum nss_status +getpwent_next_nisplus (struct passwd *result, ent_t *ent, char *buffer, + size_t buflen) +{ + int parse_res; + size_t p2len; + char *p2; + + if (ent->names == NULL) + { + ent->names = nis_getnames ("passwd.org_dir"); + if (ent->names == NULL || ent->names[0] == NULL) + { + ent->nis = 0; + return NSS_STATUS_UNAVAIL; + } + } + + p2len = pwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + do + { + if (ent->first) + { + next_name: + ent->result = nis_first_entry(ent->names[ent->names_nr]); + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return niserr2nss (ent->result->status); + } + ent->first = FALSE; + } + else + { + nis_result *res; + + res = nis_next_entry(ent->names[ent->names_nr], + &ent->result->cookie); + nis_freeresult (ent->result); + ent->result = res; + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + if ((ent->result->status == NIS_NOTFOUND) && + ent->names[ent->names_nr + 1] != NULL) + { + nis_freeresult (ent->result); + ent->names_nr += 1; + goto next_name; + } + else + { + ent->nis = 0; + give_pwd_free (&ent->pwd); + return niserr2nss (ent->result->status); + } + } + } + parse_res = _nss_nisplus_parse_pwent (ent->result, result, buffer, + buflen); + if (parse_res && + in_blacklist (result->pw_name, strlen (result->pw_name), ent)) + parse_res = 0; /* if result->pw_name in blacklist,search next entry */ + } + while (!parse_res); + + copy_pwd_changes (result, &ent->pwd, p2, p2len); + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer, size_t buflen) { struct parser_data *data = (void *) buffer; char *domain, *outkey, *outval, *p, *p2; - int outkeylen, outvallen; + int outkeylen, outvallen, parse_res; size_t p2len; if (yp_get_default_domain (&domain) != YPERR_SUCCESS) @@ -404,17 +609,96 @@ getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer, while (isspace (*p)) ++p; + parse_res = _nss_files_parse_pwent (p, result, data, buflen); + if (parse_res && + in_blacklist (result->pw_name, strlen (result->pw_name), ent)) + parse_res = 0; } - while (!_nss_files_parse_pwent (p, result, data, buflen)); + while (!parse_res); copy_pwd_changes (result, &ent->pwd, p2, p2len); - if (!in_blacklist (result->pw_name, strlen (result->pw_name), ent)) - return NSS_STATUS_SUCCESS; - else - return NSS_STATUS_NOTFOUND; + return NSS_STATUS_SUCCESS; } +/* This function handle the +user entrys in /etc/passwd */ +static enum nss_status +getpwent_next_file_plususer (struct passwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct passwd pwd; + int parse_res; + char *p; + size_t plen; + + memset (&pwd, '\0', sizeof (struct passwd)); + + copy_pwd_changes (&pwd, result, NULL, 0); + + plen = pwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + if (use_nisplus) /* Do the NIS+ query here */ + { + nis_result *res; + char buf[strlen (result->pw_name) + 24]; + + sprintf(buf, "[name=%s],passwd.org_dir", + &result->pw_name[1]); + res = nis_list(buf, EXPAND_NAME, NULL, NULL); + if (niserr2nss (res->status) != NSS_STATUS_SUCCESS) + { + enum nss_status status = niserr2nss (res->status); + + nis_freeresult (res); + return status; + } + parse_res = _nss_nisplus_parse_pwent (res, result, buffer, buflen); + nis_freeresult (res); + } + else /* Use NIS */ + { + char *domain; + char *outval; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + + if (yp_match (domain, "passwd.byname", &result->pw_name[1], + strlen (result->pw_name) - 1, &outval, &outvallen) + != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + p = strncpy (buffer, outval, + buflen < outvallen ? buflen : outvallen); + free (outval); + while (isspace (*p)) + p++; + parse_res = _nss_files_parse_pwent (p, result, data, buflen); + } + + if (parse_res) + { + copy_pwd_changes (result, &pwd, p, plen); + give_pwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_pwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} static enum nss_status getpwent_next_file (struct passwd *result, ent_t *ent, @@ -423,8 +707,7 @@ getpwent_next_file (struct passwd *result, ent_t *ent, struct parser_data *data = (void *) buffer; while (1) { - char *p, *p2; - size_t p2len; + char *p; do { @@ -494,50 +777,16 @@ getpwent_next_file (struct passwd *result, ent_t *ent, if (result->pw_name[0] == '+' && result->pw_name[1] != '\0' && result->pw_name[1] != '@') { - char *domain; - char *outval; - int outvallen; - struct passwd pwd; - - memset (&pwd, '\0', sizeof (struct passwd)); - - if (yp_get_default_domain (&domain) != YPERR_SUCCESS) - /* XXX Should we regard this as an fatal error? I don't - think so. Just continue working. --drepper@gnu */ - continue; - - if (yp_match (domain, "passwd.byname", &result->pw_name[1], - strlen (result->pw_name) - 1, &outval, &outvallen) - != YPERR_SUCCESS) - continue; - - copy_pwd_changes (&pwd, result, NULL, 0); - - p2len = pwd_need_buflen (&pwd); - if (p2len > buflen) - { - __set_errno (ERANGE); - return NSS_STATUS_TRYAGAIN; - } - p2 = buffer + (buflen - p2len); - buflen -= p2len; - p = strncpy (buffer, outval, buflen); - while (isspace (*p)) - p++; - free (outval); - if (_nss_files_parse_pwent (p, result, data, buflen)) - { - copy_pwd_changes (result, &pwd, p2, p2len); - give_pwd_free (&pwd); - /* We found the entry. */ - break; - } + enum nss_status status; + + status = getpwent_next_file_plususer (result, buffer, buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; else - { - /* Give buffer the old len back */ - buflen += p2len; - give_pwd_free (&pwd); - } + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + continue; + else + return status; } /* +:... */ @@ -547,7 +796,10 @@ getpwent_next_file (struct passwd *result, ent_t *ent, ent->first = TRUE; copy_pwd_changes (&ent->pwd, result, NULL, 0); - return getpwent_next_nis (result, ent, buffer, buflen); + if (use_nisplus) + return getpwent_next_nisplus (result, ent, buffer, buflen); + else + return getpwent_next_nis (result, ent, buffer, buflen); } } @@ -572,7 +824,12 @@ internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer, return status; } else if (ent->nis) - return getpwent_next_nis (pw, ent, buffer, buflen); + { + if (use_nisplus) + return getpwent_next_nisplus (pw, ent, buffer, buflen); + else + return getpwent_next_nis (pw, ent, buffer, buflen); + } else return getpwent_next_file (pw, ent, buffer, buflen); } @@ -585,6 +842,12 @@ _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, __libc_lock_lock (lock); + if (ni == NULL) + { + __nss_database_lookup ("passwd_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + /* Be prepared that the setpwent function was not called before. */ if (ext_ent.stream == NULL) status = internal_setpwent (&ext_ent); @@ -602,13 +865,22 @@ enum nss_status _nss_compat_getpwnam_r (const char *name, struct passwd *pwd, char *buffer, size_t buflen) { - ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}, {NULL, NULL, 0, 0, NULL, NULL, NULL}}; enum nss_status status; if (name[0] == '-' || name[0] == '+') return NSS_STATUS_NOTFOUND; + __libc_lock_lock (lock); + + if (ni == NULL) + { + __nss_database_lookup ("passwd_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + + __libc_lock_unlock (lock); status = internal_setpwent (&ent); if (status != NSS_STATUS_SUCCESS) @@ -628,10 +900,20 @@ enum nss_status _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t buflen) { - ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}, {NULL, NULL, 0, 0, NULL, NULL, NULL}}; enum nss_status status; - + + __libc_lock_lock (lock); + + if (ni == NULL) + { + __nss_database_lookup ("passwd_compat", NULL, "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + + __libc_lock_unlock (lock); + status = internal_setpwent (&ent); if (status != NSS_STATUS_SUCCESS) return status; diff --git a/nis/nss_compat/compat-spwd.c b/nis/nss_compat/compat-spwd.c index 47dd22970a..7c0eb24fc1 100644 --- a/nis/nss_compat/compat-spwd.c +++ b/nis/nss_compat/compat-spwd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -26,6 +26,15 @@ #include <libc-lock.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> +#include <rpcsvc/nis.h> +#include <rpcsvc/nislib.h> +#include <nsswitch.h> + +#include "netgroup.h" +#include "nss-nisplus.h" + +static service_user *ni = NULL; +static bool_t use_nisplus = FALSE; /* default: passwd_compat: nis */ /* Get the declaration of the parser function. */ #define ENTNAME spent @@ -50,13 +59,17 @@ struct ent_t bool_t first; char *oldkey; int oldkeylen; + nis_result *result; + nis_name *names; + u_long names_nr; FILE *stream; struct blacklist_t blacklist; struct spwd pwd; + struct __netgrent netgrdata; }; typedef struct ent_t ent_t; -static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, +static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}, {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; /* Protect global state against multiple changers. */ @@ -65,7 +78,8 @@ __libc_lock_define_initialized (static, lock) /* Prototypes for local functions. */ static void blacklist_store_name (const char *, ent_t *); static int in_blacklist (const char *, int, ent_t *); - +extern int _nss_nisplus_parse_spent (nis_result *, struct spwd *, + char *, size_t); static void give_spwd_free (struct spwd *pwd) { @@ -130,6 +144,10 @@ internal_setspent (ent_t *ent) ent->nis = ent->first = ent->netgroup = 0; + /* If something was left over free it. */ + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + if (ent->oldkey != NULL) { free (ent->oldkey); @@ -137,6 +155,18 @@ internal_setspent (ent_t *ent) ent->oldkeylen = 0; } + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + if (ent->names != NULL) + { + nis_freenames (ent->names); + ent->names = NULL; + } + ent->names_nr = 0; + ent->blacklist.current = 0; if (ent->blacklist.data != NULL) ent->blacklist.data[0] = '\0'; @@ -164,6 +194,12 @@ _nss_compat_setspent (void) __libc_lock_lock (lock); + if (ni == NULL) + { + __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + result = internal_setspent (&ext_ent); __libc_lock_unlock (lock); @@ -181,6 +217,9 @@ internal_endspent (ent_t *ent) ent->stream = NULL; } + if (ent->netgroup) + __internal_endnetgrent (&ent->netgrdata); + ent->nis = ent->first = ent->netgroup = 0; if (ent->oldkey != NULL) @@ -190,10 +229,22 @@ internal_endspent (ent_t *ent) ent->oldkeylen = 0; } + if (ent->result != NULL) + { + nis_freeresult (ent->result); + ent->result = NULL; + } + if (ent->names != NULL) + { + nis_freenames (ent->names); + ent->names = NULL; + } + ent->names_nr = 0; + ent->blacklist.current = 0; if (ent->blacklist.data != NULL) ent->blacklist.data[0] = '\0'; - + give_spwd_free (&ent->pwd); return NSS_STATUS_SUCCESS; @@ -215,8 +266,8 @@ _nss_compat_endspent (void) static enum nss_status -getspent_next_netgr (struct spwd *result, ent_t *ent, char *group, - char *buffer, size_t buflen) +getspent_next_nis_netgr (struct spwd *result, ent_t *ent, char *group, + char *buffer, size_t buflen) { struct parser_data *data = (void *) buffer; char *ypdomain, *host, *user, *domain, *outval, *p, *p2; @@ -233,15 +284,18 @@ getspent_next_netgr (struct spwd *result, ent_t *ent, char *group, if (ent->first == TRUE) { - setnetgrent (group); + bzero (&ent->netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); ent->first = FALSE; } while (1) { - if ((status = getnetgrent (&host, &user, &domain)) != 1) + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen); + if (status != 1) { - endnetgrent (); + __internal_endnetgrent (&ent->netgrdata); ent->netgroup = 0; give_spwd_free (&ent->pwd); return NSS_STATUS_RETURN; @@ -281,12 +335,176 @@ getspent_next_netgr (struct spwd *result, ent_t *ent, char *group, } static enum nss_status +getspent_next_nisplus_netgr (struct spwd *result, ent_t *ent, char *group, + char *buffer, size_t buflen) +{ + char *ypdomain, *host, *user, *domain, *p2; + int status, parse_res; + size_t p2len; + nis_result *nisres; + + /* Maybe we should use domainname here ? We need the current + domainname for the domain field in netgroups */ + if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS) + { + ent->netgroup = 0; + ent->first = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_UNAVAIL; + } + + if (ent->first == TRUE) + { + bzero (&ent->netgrdata, sizeof (struct __netgrent)); + __internal_setnetgrent (group, &ent->netgrdata); + ent->first = FALSE; + } + + while (1) + { + status = __internal_getnetgrent_r (&host, &user, &domain, + &ent->netgrdata, buffer, buflen); + if (status != 1) + { + __internal_endnetgrent (&ent->netgrdata); + ent->netgroup = 0; + give_spwd_free (&ent->pwd); + return NSS_STATUS_RETURN; + } + + if (user == NULL || user[0] == '-') + continue; + + if (domain != NULL && strcmp (ypdomain, domain) != 0) + continue; + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + { + char buf[strlen (user) + 30]; + sprintf(buf, "[name=%s],passwd.org_dir", user); + nisres = nis_list(buf, EXPAND_NAME, NULL, NULL); + } + if (niserr2nss (nisres->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (nisres); + continue; + } + parse_res = _nss_nisplus_parse_spent (nisres, result, buffer, buflen); + nis_freeresult (nisres); + + if (parse_res) + { + copy_spwd_changes (result, &ent->pwd, p2, p2len); + break; + } + } + + return NSS_STATUS_SUCCESS; +} + +static enum nss_status +getspent_next_netgr (struct spwd *result, ent_t *ent, char *group, + char *buffer, size_t buflen) +{ + if (use_nisplus) + return getpwent_next_nisplus_netgr (result, ent, group, buffer, buflen); + else + return getpwent_next_nis_netgr (result, ent, group, buffer, buflen); +} + +static enum nss_status +getspent_next_nisplus (struct spwd *result, ent_t *ent, char *buffer, + size_t buflen) +{ + int parse_res; + size_t p2len; + char *p2; + + if (ent->names == NULL) + { + ent->names = nis_getnames ("passwd.org_dir"); + if (ent->names == NULL || ent->names[0] == NULL) + { + ent->nis = 0; + return NSS_STATUS_UNAVAIL; + } + } + + p2len = spwd_need_buflen (&ent->pwd); + if (p2len > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p2 = buffer + (buflen - p2len); + buflen -= p2len; + do + { + if (ent->first) + { + next_name: + ent->result = nis_first_entry(ent->names[ent->names_nr]); + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return niserr2nss (ent->result->status); + } + ent->first = FALSE; + } + else + { + nis_result *res; + + res = nis_next_entry(ent->names[ent->names_nr], + &ent->result->cookie); + nis_freeresult (ent->result); + ent->result = res; + if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) + { + if ((ent->result->status == NIS_NOTFOUND) && + ent->names[ent->names_nr + 1] != NULL) + { + nis_freeresult (ent->result); + ent->names_nr += 1; + goto next_name; + } + else + { + ent->nis = 0; + give_spwd_free (&ent->pwd); + return niserr2nss (ent->result->status); + } + } + } + parse_res = _nss_nisplus_parse_spent (ent->result, result, buffer, + buflen); + if (parse_res && + in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) + parse_res = 0; /* if result->pw_name in blacklist,search next entry */ + } + while (!parse_res); + + copy_spwd_changes (result, &ent->pwd, p2, p2len); + + return NSS_STATUS_SUCCESS; +} + + +static enum nss_status getspent_next_nis (struct spwd *result, ent_t *ent, char *buffer, size_t buflen) { struct parser_data *data = (void *) buffer; char *domain, *outkey, *outval, *p, *p2; - int outkeylen, outvallen; + int outkeylen, outvallen, parse_res; size_t p2len; if (yp_get_default_domain (&domain) != YPERR_SUCCESS) @@ -344,17 +562,96 @@ getspent_next_nis (struct spwd *result, ent_t *ent, while (isspace (*p)) ++p; + parse_res = _nss_files_parse_spent (p, result, data, buflen); + if (parse_res && + in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) + parse_res = 0; } - while (!_nss_files_parse_spent (p, result, data, buflen)); + while (!parse_res); copy_spwd_changes (result, &ent->pwd, p2, p2len); - if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) - return NSS_STATUS_SUCCESS; - else - return NSS_STATUS_NOTFOUND; + return NSS_STATUS_SUCCESS; } +/* This function handle the +user entrys in /etc/shadow */ +static enum nss_status +getspent_next_file_plususer (struct spwd *result, char *buffer, + size_t buflen) +{ + struct parser_data *data = (void *) buffer; + struct spwd pwd; + int parse_res; + char *p; + size_t plen; + + memset (&pwd, '\0', sizeof (struct spwd)); + + copy_spwd_changes (&pwd, result, NULL, 0); + + plen = spwd_need_buflen (&pwd); + if (plen > buflen) + { + __set_errno (ERANGE); + return NSS_STATUS_TRYAGAIN; + } + p = buffer + (buflen - plen); + buflen -= plen; + + if (use_nisplus) /* Do the NIS+ query here */ + { + nis_result *res; + char buf[strlen (result->sp_namp) + 24]; + + sprintf(buf, "[name=%s],passwd.org_dir", + &result->sp_namp[1]); + res = nis_list(buf, EXPAND_NAME, NULL, NULL); + if (niserr2nss (res->status) != NSS_STATUS_SUCCESS) + { + enum nss_status status = niserr2nss (res->status); + + nis_freeresult (res); + return status; + } + parse_res = _nss_nisplus_parse_spent (res, result, buffer, buflen); + nis_freeresult (res); + } + else /* Use NIS */ + { + char *domain; + char *outval; + int outvallen; + + if (yp_get_default_domain (&domain) != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + + if (yp_match (domain, "passwd.byname", &result->sp_namp[1], + strlen (result->sp_namp) - 1, &outval, &outvallen) + != YPERR_SUCCESS) + return NSS_STATUS_TRYAGAIN; + p = strncpy (buffer, outval, + buflen < outvallen ? buflen : outvallen); + free (outval); + while (isspace (*p)) + p++; + parse_res = _nss_files_parse_spent (p, result, data, buflen); + } + + if (parse_res) + { + copy_spwd_changes (result, &pwd, p, plen); + give_spwd_free (&pwd); + /* We found the entry. */ + return NSS_STATUS_SUCCESS; + } + else + { + /* Give buffer the old len back */ + buflen += plen; + give_spwd_free (&pwd); + } + return NSS_STATUS_RETURN; +} static enum nss_status getspent_next_file (struct spwd *result, ent_t *ent, @@ -434,50 +731,16 @@ getspent_next_file (struct spwd *result, ent_t *ent, if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0' && result->sp_namp[1] != '@') { - char *domain; - char *outval; - int outvallen; - struct spwd pwd; - - memset (&pwd, '\0', sizeof (struct spwd)); - - if (yp_get_default_domain (&domain) != YPERR_SUCCESS) - /* XXX Should we regard this as an fatal error? I don't - think so. Just continue working. --drepper@gnu */ - continue; - - if (yp_match (domain, "shadow.byname", &result->sp_namp[1], - strlen (result->sp_namp) - 1, &outval, &outvallen) - != YPERR_SUCCESS) - continue; - - copy_spwd_changes (&pwd, result, NULL, 0); - - p2len = spwd_need_buflen (&pwd); - if (p2len > buflen) - { - __set_errno (ERANGE); - return NSS_STATUS_TRYAGAIN; - } - p2 = buffer + (buflen - p2len); - buflen -= p2len; - p = strncpy (buffer, outval, buflen); - while (isspace (*p)) - p++; - free (outval); - if (_nss_files_parse_spent (p, result, data, buflen)) - { - copy_spwd_changes (result, &pwd, p2, p2len); - give_spwd_free (&pwd); - /* We found the entry. */ - break; - } - else - { - /* Give buffer the old len back */ - buflen += p2len; - give_spwd_free (&pwd); - } + enum nss_status status; + + status = getspent_next_file_plususer (result, buffer, buflen); + if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ + break; + else + if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ + continue; + else + return status; } /* +:... */ @@ -487,7 +750,10 @@ getspent_next_file (struct spwd *result, ent_t *ent, ent->first = TRUE; copy_spwd_changes (&ent->pwd, result, NULL, 0); - return getspent_next_nis (result, ent, buffer, buflen); + if (use_nisplus) + return getspent_next_nisplus (result, ent, buffer, buflen); + else + return getspent_next_nis (result, ent, buffer, buflen); } } @@ -512,7 +778,12 @@ internal_getspent_r (struct spwd *pw, ent_t *ent, return status; } else if (ent->nis) - return getspent_next_nis (pw, ent, buffer, buflen); + { + if (use_nisplus) + return getspent_next_nisplus (pw, ent, buffer, buflen); + else + return getspent_next_nis (pw, ent, buffer, buflen); + } else return getspent_next_file (pw, ent, buffer, buflen); } @@ -524,6 +795,12 @@ _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen) __libc_lock_lock (lock); + if (ni == NULL) + { + __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + /* Be prepared that the setspent function was not called before. */ if (ext_ent.stream == NULL) status = internal_setspent (&ext_ent); @@ -541,13 +818,19 @@ enum nss_status _nss_compat_getspnam_r (const char *name, struct spwd *pwd, char *buffer, size_t buflen) { - ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0}, + ent_t ent = {0, 0, 0, NULL, 0, NULL, NULL, 0, NULL, {NULL, 0, 0}, {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; enum nss_status status; if (name[0] == '-' || name[0] == '+') return NSS_STATUS_NOTFOUND; + if (ni == NULL) + { + __nss_database_lookup ("shadow_compat", "passwd_compat", "nis", &ni); + use_nisplus = (strcmp (ni->name, "nisplus") == 0); + } + status = internal_setspent (&ent); if (status != NSS_STATUS_SUCCESS) return status; @@ -619,3 +902,4 @@ in_blacklist (const char *name, int namelen, ent_t *ent) stpcpy (stpcpy (stpcpy (buf, "|"), name), "|"); return strstr (ent->blacklist.data, buf) != NULL; } + |