diff options
Diffstat (limited to 'nis/nss_compat/compat-pwd.c')
-rw-r--r-- | nis/nss_compat/compat-pwd.c | 406 |
1 files changed, 344 insertions, 62 deletions
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; |