Back to index

glibc  2.9
compat-grp.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
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 <ctype.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <grp.h>
00024 #include <nss.h>
00025 #include <nsswitch.h>
00026 #include <stdio_ext.h>
00027 #include <string.h>
00028 #include <rpc/types.h>
00029 #include <bits/libc-lock.h>
00030 #include <kernel-features.h>
00031 
00032 static service_user *ni;
00033 static enum nss_status (*nss_setgrent) (int stayopen);
00034 static enum nss_status (*nss_getgrnam_r) (const char *name,
00035                                      struct group * grp, char *buffer,
00036                                      size_t buflen, int *errnop);
00037 static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp,
00038                                      char *buffer, size_t buflen,
00039                                      int *errnop);
00040 static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer,
00041                                      size_t buflen, int *errnop);
00042 static enum nss_status (*nss_endgrent) (void);
00043 
00044 /* Get the declaration of the parser function.  */
00045 #define ENTNAME grent
00046 #define STRUCTURE group
00047 #define EXTERN_PARSER
00048 #include <nss/nss_files/files-parse.c>
00049 
00050 /* Structure for remembering -group members ... */
00051 #define BLACKLIST_INITIAL_SIZE 512
00052 #define BLACKLIST_INCREMENT 256
00053 struct blacklist_t
00054 {
00055   char *data;
00056   int current;
00057   int size;
00058 };
00059 
00060 struct ent_t
00061 {
00062   bool_t files;
00063   enum nss_status setent_status;
00064   FILE *stream;
00065   struct blacklist_t blacklist;
00066 };
00067 typedef struct ent_t ent_t;
00068 
00069 static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
00070 
00071 /* Protect global state against multiple changers.  */
00072 __libc_lock_define_initialized (static, lock)
00073 
00074 /* Positive if O_CLOEXEC is supported, negative if it is not supported,
00075    zero if it is still undecided.  This variable is shared with the
00076    other compat functions.  */
00077 #ifdef __ASSUME_O_CLOEXEC
00078 # define __compat_have_cloexec 1
00079 #else
00080 # ifdef O_CLOEXEC
00081 int __compat_have_cloexec;
00082 # else
00083 #  define __compat_have_cloexec -1
00084 # endif
00085 #endif
00086 
00087 /* Prototypes for local functions.  */
00088 static void blacklist_store_name (const char *, ent_t *);
00089 static int in_blacklist (const char *, int, ent_t *);
00090 
00091 /* Initialize the NSS interface/functions. The calling function must
00092    hold the lock.  */
00093 static void
00094 init_nss_interface (void)
00095 {
00096   if (__nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0)
00097     {
00098       nss_setgrent = __nss_lookup_function (ni, "setgrent");
00099       nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r");
00100       nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r");
00101       nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r");
00102       nss_endgrent = __nss_lookup_function (ni, "endgrent");
00103     }
00104 }
00105 
00106 static enum nss_status
00107 internal_setgrent (ent_t *ent, int stayopen, int needent)
00108 {
00109   enum nss_status status = NSS_STATUS_SUCCESS;
00110 
00111   ent->files = TRUE;
00112 
00113   if (ent->blacklist.data != NULL)
00114     {
00115       ent->blacklist.current = 1;
00116       ent->blacklist.data[0] = '|';
00117       ent->blacklist.data[1] = '\0';
00118     }
00119   else
00120     ent->blacklist.current = 0;
00121 
00122   if (ent->stream == NULL)
00123     {
00124       ent->stream = fopen ("/etc/group", "rme");
00125 
00126       if (ent->stream == NULL)
00127        status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
00128       else
00129        {
00130          /* We have to make sure the file is  `closed on exec'.  */
00131          int result = 0;
00132 
00133          if (__compat_have_cloexec <= 0)
00134            {
00135              int flags;
00136              result = flags = fcntl (fileno_unlocked (ent->stream), F_GETFD,
00137                                   0);
00138              if (result >= 0)
00139               {
00140 #if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC
00141                 if (__compat_have_cloexec == 0)
00142                   __compat_have_cloexec = (flags & FD_CLOEXEC) ? 1 : -1;
00143 
00144                 if (__compat_have_cloexec < 0)
00145 #endif
00146                   {
00147                     flags |= FD_CLOEXEC;
00148                     result = fcntl (fileno_unlocked (ent->stream), F_SETFD,
00149                                   flags);
00150                   }
00151               }
00152            }
00153 
00154          if (result < 0)
00155            {
00156              /* Something went wrong.  Close the stream and return a
00157                 failure.  */
00158              fclose (ent->stream);
00159              ent->stream = NULL;
00160              status = NSS_STATUS_UNAVAIL;
00161            }
00162          else
00163            /* We take care of locking ourself.  */
00164            __fsetlocking (ent->stream, FSETLOCKING_BYCALLER);
00165        }
00166     }
00167   else
00168     rewind (ent->stream);
00169 
00170   if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent)
00171     ent->setent_status = nss_setgrent (stayopen);
00172 
00173   return status;
00174 }
00175 
00176 
00177 enum nss_status
00178 _nss_compat_setgrent (int stayopen)
00179 {
00180   enum nss_status result;
00181 
00182   __libc_lock_lock (lock);
00183 
00184   if (ni == NULL)
00185     init_nss_interface ();
00186 
00187   result = internal_setgrent (&ext_ent, stayopen, 1);
00188 
00189   __libc_lock_unlock (lock);
00190 
00191   return result;
00192 }
00193 
00194 
00195 static enum nss_status
00196 internal_endgrent (ent_t *ent)
00197 {
00198   if (nss_endgrent)
00199     nss_endgrent ();
00200 
00201   if (ent->stream != NULL)
00202     {
00203       fclose (ent->stream);
00204       ent->stream = NULL;
00205     }
00206 
00207   if (ent->blacklist.data != NULL)
00208     {
00209       ent->blacklist.current = 1;
00210       ent->blacklist.data[0] = '|';
00211       ent->blacklist.data[1] = '\0';
00212     }
00213   else
00214     ent->blacklist.current = 0;
00215 
00216   return NSS_STATUS_SUCCESS;
00217 }
00218 
00219 enum nss_status
00220 _nss_compat_endgrent (void)
00221 {
00222   enum nss_status result;
00223 
00224   __libc_lock_lock (lock);
00225 
00226   result = internal_endgrent (&ext_ent);
00227 
00228   __libc_lock_unlock (lock);
00229 
00230   return result;
00231 }
00232 
00233 /* get the next group from NSS  (+ entry) */
00234 static enum nss_status
00235 getgrent_next_nss (struct group *result, ent_t *ent, char *buffer,
00236                  size_t buflen, int *errnop)
00237 {
00238   if (!nss_getgrent_r)
00239     return NSS_STATUS_UNAVAIL;
00240 
00241   /* If the setgrent call failed, say so.  */
00242   if (ent->setent_status != NSS_STATUS_SUCCESS)
00243     return ent->setent_status;
00244 
00245   do
00246     {
00247       enum nss_status status;
00248 
00249       if ((status = nss_getgrent_r (result, buffer, buflen, errnop)) !=
00250          NSS_STATUS_SUCCESS)
00251        return status;
00252     }
00253   while (in_blacklist (result->gr_name, strlen (result->gr_name), ent));
00254 
00255   return NSS_STATUS_SUCCESS;
00256 }
00257 
00258 /* This function handle the +group entrys in /etc/group */
00259 static enum nss_status
00260 getgrnam_plusgroup (const char *name, struct group *result, ent_t *ent,
00261                   char *buffer, size_t buflen, int *errnop)
00262 {
00263   if (!nss_getgrnam_r)
00264     return NSS_STATUS_UNAVAIL;
00265 
00266   enum nss_status status = nss_getgrnam_r (name, result, buffer, buflen,
00267                                       errnop);
00268   if (status != NSS_STATUS_SUCCESS)
00269     return status;
00270 
00271   if (in_blacklist (result->gr_name, strlen (result->gr_name), ent))
00272     return NSS_STATUS_NOTFOUND;
00273 
00274   /* We found the entry.  */
00275   return NSS_STATUS_SUCCESS;
00276 }
00277 
00278 static enum nss_status
00279 getgrent_next_file (struct group *result, ent_t *ent,
00280                   char *buffer, size_t buflen, int *errnop)
00281 {
00282   struct parser_data *data = (void *) buffer;
00283   while (1)
00284     {
00285       fpos_t pos;
00286       int parse_res = 0;
00287       char *p;
00288 
00289       do
00290        {
00291          /* We need at least 3 characters for one line.  */
00292          if (__builtin_expect (buflen < 3, 0))
00293            {
00294            erange:
00295              *errnop = ERANGE;
00296              return NSS_STATUS_TRYAGAIN;
00297            }
00298 
00299          fgetpos (ent->stream, &pos);
00300          buffer[buflen - 1] = '\xff';
00301          p = fgets_unlocked (buffer, buflen, ent->stream);
00302          if (p == NULL && feof_unlocked (ent->stream))
00303            return NSS_STATUS_NOTFOUND;
00304 
00305          if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0))
00306            {
00307            erange_reset:
00308              fsetpos (ent->stream, &pos);
00309              goto erange;
00310            }
00311 
00312          /* Terminate the line for any case.  */
00313          buffer[buflen - 1] = '\0';
00314 
00315          /* Skip leading blanks.  */
00316          while (isspace (*p))
00317            ++p;
00318        }
00319       while (*p == '\0' || *p == '#' ||   /* Ignore empty and comment lines. */
00320             /* Parse the line.  If it is invalid, loop to
00321                get the next line of the file to parse.  */
00322             !(parse_res = _nss_files_parse_grent (p, result, data, buflen,
00323                                              errnop)));
00324 
00325       if (__builtin_expect (parse_res == -1, 0))
00326        /* The parser ran out of space.  */
00327        goto erange_reset;
00328 
00329       if (result->gr_name[0] != '+' && result->gr_name[0] != '-')
00330        /* This is a real entry.  */
00331        break;
00332 
00333       /* -group */
00334       if (result->gr_name[0] == '-' && result->gr_name[1] != '\0'
00335          && result->gr_name[1] != '@')
00336        {
00337          blacklist_store_name (&result->gr_name[1], ent);
00338          continue;
00339        }
00340 
00341       /* +group */
00342       if (result->gr_name[0] == '+' && result->gr_name[1] != '\0'
00343          && result->gr_name[1] != '@')
00344        {
00345          size_t len = strlen (result->gr_name);
00346          char buf[len];
00347          enum nss_status status;
00348 
00349          /* Store the group in the blacklist for the "+" at the end of
00350             /etc/group */
00351          memcpy (buf, &result->gr_name[1], len);
00352          status = getgrnam_plusgroup (&result->gr_name[1], result, ent,
00353                                    buffer, buflen, errnop);
00354          blacklist_store_name (buf, ent);
00355          if (status == NSS_STATUS_SUCCESS)       /* We found the entry. */
00356            break;
00357          else if (status == NSS_STATUS_RETURN /* We couldn't parse the entry*/
00358                  || status == NSS_STATUS_NOTFOUND)      /* No group in NIS */
00359            continue;
00360          else
00361            {
00362              if (status == NSS_STATUS_TRYAGAIN)
00363               /* The parser ran out of space.  */
00364               goto erange_reset;
00365 
00366              return status;
00367            }
00368        }
00369 
00370       /* +:... */
00371       if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
00372        {
00373          ent->files = FALSE;
00374 
00375          return getgrent_next_nss (result, ent, buffer, buflen, errnop);
00376        }
00377     }
00378 
00379   return NSS_STATUS_SUCCESS;
00380 }
00381 
00382 
00383 enum nss_status
00384 _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen,
00385                      int *errnop)
00386 {
00387   enum nss_status result = NSS_STATUS_SUCCESS;
00388 
00389   __libc_lock_lock (lock);
00390 
00391   /* Be prepared that the setgrent function was not called before.  */
00392   if (ni == NULL)
00393     init_nss_interface ();
00394 
00395   if (ext_ent.stream == NULL)
00396     result = internal_setgrent (&ext_ent, 1, 1);
00397 
00398   if (result == NSS_STATUS_SUCCESS)
00399     {
00400       if (ext_ent.files)
00401        result = getgrent_next_file (grp, &ext_ent, buffer, buflen, errnop);
00402       else
00403        result = getgrent_next_nss (grp, &ext_ent, buffer, buflen, errnop);
00404     }
00405   __libc_lock_unlock (lock);
00406 
00407   return result;
00408 }
00409 
00410 /* Searches in /etc/group and the NIS/NIS+ map for a special group */
00411 static enum nss_status
00412 internal_getgrnam_r (const char *name, struct group *result, ent_t *ent,
00413                    char *buffer, size_t buflen, int *errnop)
00414 {
00415   struct parser_data *data = (void *) buffer;
00416   while (1)
00417     {
00418       fpos_t pos;
00419       int parse_res = 0;
00420       char *p;
00421 
00422       do
00423        {
00424          /* We need at least 3 characters for one line.  */
00425          if (__builtin_expect (buflen < 3, 0))
00426            {
00427            erange:
00428              *errnop = ERANGE;
00429              return NSS_STATUS_TRYAGAIN;
00430            }
00431 
00432          fgetpos (ent->stream, &pos);
00433          buffer[buflen - 1] = '\xff';
00434          p = fgets_unlocked (buffer, buflen, ent->stream);
00435          if (p == NULL && feof_unlocked (ent->stream))
00436            return NSS_STATUS_NOTFOUND;
00437 
00438          if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0))
00439            {
00440            erange_reset:
00441              fsetpos (ent->stream, &pos);
00442              goto erange;
00443            }
00444 
00445          /* Terminate the line for any case.  */
00446          buffer[buflen - 1] = '\0';
00447 
00448          /* Skip leading blanks.  */
00449          while (isspace (*p))
00450            ++p;
00451        }
00452       while (*p == '\0' || *p == '#' ||   /* Ignore empty and comment lines. */
00453             /* Parse the line.  If it is invalid, loop to
00454                get the next line of the file to parse.  */
00455             !(parse_res = _nss_files_parse_grent (p, result, data, buflen,
00456                                              errnop)));
00457 
00458       if (__builtin_expect (parse_res == -1, 0))
00459        /* The parser ran out of space.  */
00460        goto erange_reset;
00461 
00462       /* This is a real entry.  */
00463       if (result->gr_name[0] != '+' && result->gr_name[0] != '-')
00464        {
00465          if (strcmp (result->gr_name, name) == 0)
00466            return NSS_STATUS_SUCCESS;
00467          else
00468            continue;
00469        }
00470 
00471       /* -group */
00472       if (result->gr_name[0] == '-' && result->gr_name[1] != '\0')
00473        {
00474          if (strcmp (&result->gr_name[1], name) == 0)
00475            return NSS_STATUS_NOTFOUND;
00476          else
00477            continue;
00478        }
00479 
00480       /* +group */
00481       if (result->gr_name[0] == '+' && result->gr_name[1] != '\0')
00482        {
00483          if (strcmp (name, &result->gr_name[1]) == 0)
00484            {
00485              enum nss_status status;
00486 
00487              status = getgrnam_plusgroup (name, result, ent,
00488                                       buffer, buflen, errnop);
00489              if (status == NSS_STATUS_RETURN)
00490               /* We couldn't parse the entry */
00491               continue;
00492              else
00493               return status;
00494            }
00495        }
00496       /* +:... */
00497       if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
00498        {
00499          enum nss_status status;
00500 
00501          status = getgrnam_plusgroup (name, result, ent,
00502                                    buffer, buflen, errnop);
00503          if (status == NSS_STATUS_RETURN)
00504            /* We couldn't parse the entry */
00505            continue;
00506          else
00507            return status;
00508        }
00509     }
00510 
00511   return NSS_STATUS_SUCCESS;
00512 }
00513 
00514 enum nss_status
00515 _nss_compat_getgrnam_r (const char *name, struct group *grp,
00516                      char *buffer, size_t buflen, int *errnop)
00517 {
00518   ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
00519   enum nss_status result;
00520 
00521   if (name[0] == '-' || name[0] == '+')
00522     return NSS_STATUS_NOTFOUND;
00523 
00524   __libc_lock_lock (lock);
00525 
00526   if (ni == NULL)
00527     init_nss_interface ();
00528 
00529   __libc_lock_unlock (lock);
00530 
00531   result = internal_setgrent (&ent, 0, 0);
00532 
00533   if (result == NSS_STATUS_SUCCESS)
00534     result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
00535 
00536   internal_endgrent (&ent);
00537 
00538   return result;
00539 }
00540 
00541 /* Searches in /etc/group and the NIS/NIS+ map for a special group id */
00542 static enum nss_status
00543 internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent,
00544                    char *buffer, size_t buflen, int *errnop)
00545 {
00546   struct parser_data *data = (void *) buffer;
00547   while (1)
00548     {
00549       fpos_t pos;
00550       int parse_res = 0;
00551       char *p;
00552 
00553       do
00554        {
00555          /* We need at least 3 characters for one line.  */
00556          if (__builtin_expect (buflen < 3, 0))
00557            {
00558            erange:
00559              *errnop = ERANGE;
00560              return NSS_STATUS_TRYAGAIN;
00561            }
00562 
00563          fgetpos (ent->stream, &pos);
00564          buffer[buflen - 1] = '\xff';
00565          p = fgets_unlocked (buffer, buflen, ent->stream);
00566          if (p == NULL && feof_unlocked (ent->stream))
00567            return NSS_STATUS_NOTFOUND;
00568 
00569          if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0))
00570            {
00571            erange_reset:
00572              fsetpos (ent->stream, &pos);
00573              goto erange;
00574            }
00575 
00576          /* Terminate the line for any case.  */
00577          buffer[buflen - 1] = '\0';
00578 
00579          /* Skip leading blanks.  */
00580          while (isspace (*p))
00581            ++p;
00582        }
00583       while (*p == '\0' || *p == '#' ||   /* Ignore empty and comment lines. */
00584             /* Parse the line.  If it is invalid, loop to
00585                get the next line of the file to parse.  */
00586             !(parse_res = _nss_files_parse_grent (p, result, data, buflen,
00587                                              errnop)));
00588 
00589       if (__builtin_expect (parse_res == -1, 0))
00590        /* The parser ran out of space.  */
00591        goto erange_reset;
00592 
00593       /* This is a real entry.  */
00594       if (result->gr_name[0] != '+' && result->gr_name[0] != '-')
00595        {
00596          if (result->gr_gid == gid)
00597            return NSS_STATUS_SUCCESS;
00598          else
00599            continue;
00600        }
00601 
00602       /* -group */
00603       if (result->gr_name[0] == '-' && result->gr_name[1] != '\0')
00604        {
00605          blacklist_store_name (&result->gr_name[1], ent);
00606          continue;
00607        }
00608 
00609       /* +group */
00610       if (result->gr_name[0] == '+' && result->gr_name[1] != '\0')
00611        {
00612          /* Yes, no +1, see the memcpy call below.  */
00613          size_t len = strlen (result->gr_name);
00614          char buf[len];
00615          enum nss_status status;
00616 
00617          /* Store the group in the blacklist for the "+" at the end of
00618             /etc/group */
00619          memcpy (buf, &result->gr_name[1], len);
00620          status = getgrnam_plusgroup (&result->gr_name[1], result, ent,
00621                                    buffer, buflen, errnop);
00622          blacklist_store_name (buf, ent);
00623          if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid)
00624            break;
00625          else
00626            continue;
00627        }
00628       /* +:... */
00629       if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
00630        {
00631          if (!nss_getgrgid_r)
00632            return NSS_STATUS_UNAVAIL;
00633 
00634          enum nss_status status = nss_getgrgid_r (gid, result, buffer, buflen,
00635                                              errnop);
00636          if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
00637            return NSS_STATUS_NOTFOUND;
00638          else
00639            return status;
00640        }
00641     }
00642 
00643   return NSS_STATUS_SUCCESS;
00644 }
00645 
00646 enum nss_status
00647 _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
00648                      char *buffer, size_t buflen, int *errnop)
00649 {
00650   ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
00651   enum nss_status result;
00652 
00653   __libc_lock_lock (lock);
00654 
00655   if (ni == NULL)
00656     init_nss_interface ();
00657 
00658   __libc_lock_unlock (lock);
00659 
00660   result = internal_setgrent (&ent, 0, 0);
00661 
00662   if (result == NSS_STATUS_SUCCESS)
00663     result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
00664 
00665   internal_endgrent (&ent);
00666 
00667   return result;
00668 }
00669 
00670 
00671 /* Support routines for remembering -@netgroup and -user entries.
00672    The names are stored in a single string with `|' as separator. */
00673 static void
00674 blacklist_store_name (const char *name, ent_t *ent)
00675 {
00676   int namelen = strlen (name);
00677   char *tmp;
00678 
00679   /* first call, setup cache */
00680   if (ent->blacklist.size == 0)
00681     {
00682       ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
00683       ent->blacklist.data = malloc (ent->blacklist.size);
00684       if (ent->blacklist.data == NULL)
00685        return;
00686       ent->blacklist.data[0] = '|';
00687       ent->blacklist.data[1] = '\0';
00688       ent->blacklist.current = 1;
00689     }
00690   else
00691     {
00692       if (in_blacklist (name, namelen, ent))
00693        return;                     /* no duplicates */
00694 
00695       if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
00696        {
00697          ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
00698          tmp = realloc (ent->blacklist.data, ent->blacklist.size);
00699          if (tmp == NULL)
00700            {
00701              free (ent->blacklist.data);
00702              ent->blacklist.size = 0;
00703              return;
00704            }
00705          ent->blacklist.data = tmp;
00706        }
00707     }
00708 
00709   tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
00710   *tmp++ = '|';
00711   *tmp = '\0';
00712   ent->blacklist.current += namelen + 1;
00713 
00714   return;
00715 }
00716 
00717 /* returns TRUE if ent->blacklist contains name, else FALSE */
00718 static bool_t
00719 in_blacklist (const char *name, int namelen, ent_t *ent)
00720 {
00721   char buf[namelen + 3];
00722   char *cp;
00723 
00724   if (ent->blacklist.data == NULL)
00725     return FALSE;
00726 
00727   buf[0] = '|';
00728   cp = stpcpy (&buf[1], name);
00729   *cp++ = '|';
00730   *cp = '\0';
00731   return strstr (ent->blacklist.data, buf) != NULL;
00732 }