Back to index

glibc  2.9
nisplus-alias.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <atomic.h>
00022 #include <nss.h>
00023 #include <errno.h>
00024 #include <ctype.h>
00025 #include <string.h>
00026 #include <aliases.h>
00027 #include <bits/libc-lock.h>
00028 #include <rpcsvc/nis.h>
00029 
00030 #include "nss-nisplus.h"
00031 
00032 __libc_lock_define_initialized (static, lock)
00033 
00034 static nis_result *result;
00035 static u_long next_entry;
00036 static nis_name tablename_val;
00037 static size_t tablename_len;
00038 
00039 #define NISENTRYVAL(idx, col, res) \
00040         (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
00041 
00042 #define NISENTRYLEN(idx, col, res) \
00043         (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
00044 
00045 static enum nss_status
00046 _nss_create_tablename (int *errnop)
00047 {
00048   if (tablename_val == NULL)
00049     {
00050       const char *local_dir = nis_local_directory ();
00051       size_t local_dir_len = strlen (local_dir);
00052       static const char prefix[] = "mail_aliases.org_dir.";
00053 
00054       char *p = malloc (sizeof (prefix) + local_dir_len);
00055       if (p == NULL)
00056        {
00057          *errnop = errno;
00058          return NSS_STATUS_TRYAGAIN;
00059        }
00060 
00061       memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
00062 
00063       tablename_len = sizeof (prefix) - 1 + local_dir_len;
00064 
00065       atomic_write_barrier ();
00066 
00067       tablename_val = p;
00068     }
00069 
00070   return NSS_STATUS_SUCCESS;
00071 }
00072 
00073 static int
00074 _nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry,
00075                           struct aliasent *alias, char *buffer,
00076                           size_t buflen, int *errnop)
00077 {
00078   if (result == NULL)
00079     return 0;
00080 
00081   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
00082       || __type_of (&NIS_RES_OBJECT (result)[entry]) != NIS_ENTRY_OBJ
00083       || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type,
00084                "mail_aliases") != 0
00085       || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 2)
00086     return 0;
00087 
00088   if (NISENTRYLEN (entry, 1, result) >= buflen)
00089     {
00090       /* The line is too long for our buffer.  */
00091     no_more_room:
00092       *errnop = ERANGE;
00093       return -1;
00094     }
00095 
00096   char *cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result),
00097                      NISENTRYLEN (entry, 1, result));
00098   *cp = '\0';
00099 
00100   char *first_unused = cp + 1;
00101   size_t room_left = buflen - (first_unused - buffer);
00102 
00103   alias->alias_local = 0;
00104   alias->alias_members_len = 0;
00105 
00106   if (NISENTRYLEN (entry, 0, result) >= room_left)
00107     goto no_more_room;
00108 
00109   cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result),
00110                 NISENTRYLEN (entry, 0, result));
00111   *cp = '\0';
00112   alias->alias_name = first_unused;
00113 
00114   /* Terminate the line for any case.  */
00115   cp = strpbrk (alias->alias_name, "#\n");
00116   if (cp != NULL)
00117     *cp = '\0';
00118 
00119   size_t len = strlen (alias->alias_name) + 1;
00120   first_unused += len;
00121   room_left -= len;
00122 
00123   /* Adjust the pointer so it is aligned for
00124      storing pointers.  */
00125   size_t adjust = ((__alignof__ (char *)
00126                   - (first_unused - (char *) 0) % __alignof__ (char *))
00127                  % __alignof__ (char *));
00128   if (room_left < adjust)
00129     goto no_more_room;
00130   first_unused += adjust;
00131   room_left -= adjust;
00132 
00133   alias->alias_members = (char **) first_unused;
00134 
00135   char *line = buffer;
00136   while (*line != '\0')
00137     {
00138       /* Skip leading blanks.  */
00139       while (isspace (*line))
00140        ++line;
00141 
00142       if (*line == '\0')
00143        break;
00144 
00145       if (room_left < sizeof (char *))
00146        goto no_more_room;
00147       room_left -= sizeof (char *);
00148       alias->alias_members[alias->alias_members_len] = line;
00149 
00150       while (*line != '\0' && *line != ',')
00151        ++line;
00152 
00153       if (line != alias->alias_members[alias->alias_members_len])
00154        {
00155          *line++ = '\0';
00156          ++alias->alias_members_len;
00157        }
00158       else if (*line == ',')
00159        ++line;
00160     }
00161 
00162   return alias->alias_members_len == 0 ? 0 : 1;
00163 }
00164 
00165 static enum nss_status
00166 internal_setaliasent (void)
00167 {
00168   enum nss_status status;
00169   int err;
00170 
00171   if (result !=  NULL)
00172     {
00173       nis_freeresult (result);
00174       result = NULL;
00175     }
00176 
00177   if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
00178     return NSS_STATUS_UNAVAIL;
00179 
00180   next_entry = 0;
00181   result = nis_list (tablename_val, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
00182   if (result == NULL)
00183     {
00184       status = NSS_STATUS_TRYAGAIN;
00185       __set_errno (ENOMEM);
00186     }
00187   else
00188     {
00189       status = niserr2nss (result->status);
00190       if (status != NSS_STATUS_SUCCESS)
00191        {
00192          nis_freeresult (result);
00193          result = NULL;
00194        }
00195     }
00196   return status;
00197 }
00198 
00199 enum nss_status
00200 _nss_nisplus_setaliasent (void)
00201 {
00202   enum nss_status status;
00203 
00204   __libc_lock_lock (lock);
00205 
00206   status = internal_setaliasent ();
00207 
00208   __libc_lock_unlock (lock);
00209 
00210   return status;
00211 }
00212 
00213 enum nss_status
00214 _nss_nisplus_endaliasent (void)
00215 {
00216   __libc_lock_lock (lock);
00217 
00218   if (result != NULL)
00219     {
00220       nis_freeresult (result);
00221       result = NULL;
00222     }
00223   next_entry = 0;
00224 
00225   __libc_lock_unlock (lock);
00226 
00227   return NSS_STATUS_SUCCESS;
00228 }
00229 
00230 static enum nss_status
00231 internal_nisplus_getaliasent_r (struct aliasent *alias,
00232                             char *buffer, size_t buflen, int *errnop)
00233 {
00234   int parse_res;
00235 
00236   if (result == NULL)
00237     {
00238       enum nss_status status;
00239 
00240       status = internal_setaliasent ();
00241       if (result == NULL || status != NSS_STATUS_SUCCESS)
00242        return status;
00243     }
00244 
00245   /* Get the next entry until we found a correct one. */
00246   do
00247     {
00248       if (next_entry >= result->objects.objects_len)
00249        return NSS_STATUS_NOTFOUND;
00250 
00251       parse_res = _nss_nisplus_parse_aliasent (result, next_entry, alias,
00252                                           buffer, buflen, errnop);
00253       if (parse_res == -1)
00254        return NSS_STATUS_TRYAGAIN;
00255 
00256       ++next_entry;
00257     }
00258   while (!parse_res);
00259 
00260   return NSS_STATUS_SUCCESS;
00261 }
00262 
00263 enum nss_status
00264 _nss_nisplus_getaliasent_r (struct aliasent *result, char *buffer,
00265                          size_t buflen, int *errnop)
00266 {
00267   int status;
00268 
00269   __libc_lock_lock (lock);
00270 
00271   status = internal_nisplus_getaliasent_r (result, buffer, buflen, errnop);
00272 
00273   __libc_lock_unlock (lock);
00274 
00275   return status;
00276 }
00277 
00278 enum nss_status
00279 _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias,
00280                          char *buffer, size_t buflen, int *errnop)
00281 {
00282   int parse_res;
00283 
00284   if (tablename_val == NULL)
00285     {
00286       __libc_lock_lock (lock);
00287 
00288       enum nss_status status = _nss_create_tablename (errnop);
00289 
00290       __libc_lock_unlock (lock);
00291 
00292       if (status != NSS_STATUS_SUCCESS)
00293        return status;
00294     }
00295 
00296   if (name != NULL)
00297     {
00298       *errnop = EINVAL;
00299       return NSS_STATUS_UNAVAIL;
00300     }
00301 
00302   char buf[strlen (name) + 9 + tablename_len];
00303   int olderr = errno;
00304 
00305   snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
00306 
00307   nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
00308 
00309   if (result == NULL)
00310     {
00311       *errnop = ENOMEM;
00312       return NSS_STATUS_TRYAGAIN;
00313     }
00314 
00315   if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
00316     {
00317       enum nss_status status = niserr2nss (result->status);
00318       nis_freeresult (result);
00319       return status;
00320     }
00321 
00322   parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
00323                                       buffer, buflen, errnop);
00324 
00325   /* We do not need the lookup result anymore.  */
00326   nis_freeresult (result);
00327 
00328   if (__builtin_expect (parse_res < 1, 0))
00329     {
00330       __set_errno (olderr);
00331 
00332       if (parse_res == -1)
00333        return NSS_STATUS_TRYAGAIN;
00334       else
00335        return NSS_STATUS_NOTFOUND;
00336     }
00337 
00338   return NSS_STATUS_SUCCESS;
00339 }