+++ /dev/null
-/* Handle locking of NIS+ cache file.
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
- This file is part of the GNU C Library and based on shadow/lckfile.c.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-#include <fcntl.h>
-#include <bits/libc-lock.h>
-#include <shadow.h>
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/file.h>
-#include <rpcsvc/nis.h>
-#include <rpcsvc/nislib.h>
-#include <rpcsvc/nis_cache.h>
-
-/* How long to wait for getting the lock before returning with an
- error. */
-#define TIMEOUT 5 /* sec */
-
-
-/* File descriptor for lock file. */
-static int lock_fd = -1;
-
-/* Prevent problems in multithreaded program by using mutex. */
-__libc_lock_define_initialized (static, lock)
-
-
-/* Prototypes for local functions. */
-static void noop_handler __P ((int __sig));
-
-
-/* We cannot simply return in error cases. We have to close the file
- and perhaps restore the signal handler. */
-#define RETURN_CLOSE_FD(code) \
- do { \
- if ((code) < 0 && lock_fd >= 0) \
- { \
- close (lock_fd); \
- lock_fd = -1; \
- } \
- __libc_lock_unlock (lock); \
- return (code); \
- } while (0)
-
-#define RETURN_RESTORE_HANDLER(code) \
- do { \
- /* Restore old action handler for alarm. We don't need to know \
- about the current one. */ \
- sigaction (SIGALRM, &saved_act, NULL); \
- RETURN_CLOSE_FD (code); \
- } while (0)
-
-#define RETURN_CLEAR_ALARM(code) \
- do { \
- /* Clear alarm. */ \
- alarm (0); \
- /* Restore old set of handled signals. We don't need to know \
- about the current one.*/ \
- sigprocmask (SIG_SETMASK, &saved_set, NULL); \
- RETURN_RESTORE_HANDLER (code); \
- } while (0)
-
-
-int
-__nis_lock_cache (void)
-{
- int flags;
- sigset_t saved_set; /* Saved set of caught signals. */
- struct sigaction saved_act; /* Saved signal action. */
- sigset_t new_set; /* New set of caught signals. */
- struct sigaction new_act; /* New signal action. */
- struct flock fl; /* Information struct for locking. */
- int result;
-
- if (lock_fd != -1)
- /* Still locked by own process. */
- return -1;
-
- /* Prevent problems caused by multiple threads. */
- __libc_lock_lock (lock);
-
- lock_fd = open (CACHELOCK, O_RDONLY|O_CREAT, 0666);
- if (lock_fd == -1)
- /* Cannot create lock file. */
- RETURN_CLOSE_FD (-1);
-
- /* Make sure file gets correctly closed when process finished. */
- flags = fcntl (lock_fd, F_GETFD, 0);
- if (flags == -1)
- /* Cannot get file flags. */
- RETURN_CLOSE_FD (-1);
- flags |= FD_CLOEXEC; /* Close on exit. */
- if (fcntl (lock_fd, F_SETFD, flags) < 0)
- /* Cannot set new flags. */
- RETURN_CLOSE_FD (-1);
-
- /* Now we have to get exclusive write access. Since multiple
- process could try this we won't stop when it first fails.
- Instead we set a timeout for the system call. Once the timer
- expires it is likely that there are some problems which cannot be
- resolved by waiting.
-
- It is important that we don't change the signal state. We must
- restore the old signal behaviour. */
- memset (&new_act, '\0', sizeof (struct sigaction));
- new_act.sa_handler = noop_handler;
- sigfillset (&new_act.sa_mask);
- new_act.sa_flags = 0ul;
-
- /* Install new action handler for alarm and save old. */
- if (sigaction (SIGALRM, &new_act, &saved_act) < 0)
- /* Cannot install signal handler. */
- RETURN_CLOSE_FD (-1);
-
- /* Now make sure the alarm signal is not blocked. */
- sigemptyset (&new_set);
- sigaddset (&new_set, SIGALRM);
- if (sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
- RETURN_RESTORE_HANDLER (-1);
-
- /* Start timer. If we cannot get the lock in the specified time we
- get a signal. */
- alarm (TIMEOUT);
-
- /* Try to get the lock. */
- memset (&fl, '\0', sizeof (struct flock));
- fl.l_type = F_RDLCK;
- fl.l_whence = SEEK_SET;
- result = fcntl (lock_fd, F_SETLKW, &fl);
-
- RETURN_CLEAR_ALARM (result);
-}
-
-
-int
-__nis_unlock_cache ()
-{
- int result;
-
- if (lock_fd == -1)
- /* There is no lock set. */
- result = -1;
- else
- {
- /* Prevent problems caused by multiple threads. */
- __libc_lock_lock (lock);
-
- result = close (lock_fd);
-
- /* Mark descriptor as unused. */
- lock_fd = -1;
-
- /* Clear mutex. */
- __libc_lock_unlock (lock);
- }
-
- return result;
-}
-
-
-static void
-noop_handler (sig)
- int sig;
-{
- /* We simply return which makes the `fcntl' call return with an error. */
-}
+++ /dev/null
-/* Copyright (C) 1997 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <rpcsvc/nis.h>
-#include <rpcsvc/nis_cache.h>
-#include <bits/libc-lock.h>
-
-#include "nis_intern.h"
-
-static struct timeval TIMEOUT = {10, 0};
-
-#define HEADER_MAGIC 0x07021971
-#define SPACER_MAGIC 0x07654321
-
-#define CACHE_VERSION 0x00000001
-
-struct cache_header
-{
- u_long magic; /* Magic number */
- u_long vers; /* Cache file format version */
- u_short tcp_port; /* tcp port of nis_cachemgr */
- u_short udp_port; /* udp port of nis_cachemgr */
- u_long entries; /* Number of cached objs. */
- off_t used; /* How many space are used ? */
-};
-typedef struct cache_header cache_header;
-
-struct cache_spacer
-{
- u_long magic; /* Magic number */
- u_long hashval;
- time_t ctime; /* time we have created this object */
- time_t ttl; /* time to life of this object */
- off_t next_offset;
-};
-typedef struct cache_spacer cache_spacer;
-
-static int cache_fd = -1;
-static int clnt_sock;
-static caddr_t maddr = NULL;
-static size_t msize;
-static CLIENT *cache_clnt = NULL;
-
-/* If there is no cachemgr, we shouldn't use NIS_SHARED_DIRCACHE, if
- there is no NIS_SHARED_DIRCACHE, we couldn't use nis_cachemgr.
- So, if the clnt_call to nis_cachemgr fails, we also close the cache file.
- But another thread could read the cache => lock the cache_fd and cache_clnt
- variables with the same lock */
-__libc_lock_define_initialized (static, mgrlock)
-
-/* close file handles and nis_cachemgr connection */
-static void
-__cache_close (void)
-{
- if (cache_fd != -1)
- {
- close (cache_fd);
- cache_fd = -1;
- }
- if (cache_clnt != NULL)
- {
- clnt_destroy (cache_clnt);
- close (clnt_sock);
- cache_clnt = NULL;
- }
-}
-
-/* open the cache file and connect to nis_cachemgr */
-static bool_t
-__cache_open (void)
-{
- struct sockaddr_in sin;
- cache_header hptr;
-
- if ((cache_fd = open (CACHEFILE, O_RDONLY)) == -1)
- return FALSE;
-
- if (read (cache_fd, &hptr, sizeof (cache_header)) == -1
- || lseek (cache_fd, 0, SEEK_SET) < 0)
- {
- close (cache_fd);
- cache_fd = -1;
- return FALSE;
- }
- if (hptr.magic != HEADER_MAGIC)
- {
- close (cache_fd);
- cache_fd = -1;
- syslog (LOG_ERR, _("NIS+: cache file is corrupt!"));
- return FALSE;
- }
-
- memset (&sin, '\0', sizeof (sin));
- sin.sin_family = AF_INET;
- clnt_sock = RPC_ANYSOCK;
- sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- sin.sin_port = htons (hptr.tcp_port);
- cache_clnt = clnttcp_create (&sin, CACHEPROG, CACHE_VER_1, &clnt_sock, 0, 0);
- if (cache_clnt == NULL)
- {
- close (cache_fd);
- cache_fd = -1;
- return FALSE;
- }
- /* If the program exists, close the socket */
- if (fcntl (clnt_sock, F_SETFD, FD_CLOEXEC) == -1)
- perror (_("fcntl: F_SETFD"));
- return TRUE;
-}
-
-/* Ask the cache manager to update directory 'name'
- for us (because the ttl has expired). */
-static nis_error
-__cache_refresh (nis_name name)
-{
- char clnt_res = 0;
- nis_error result = NIS_SUCCESS;
-
- __libc_lock_lock (mgrlock);
-
- if (cache_clnt == NULL)
- result = NIS_FAIL;
- else if (clnt_call (cache_clnt, NIS_CACHE_REFRESH_ENTRY,
- (xdrproc_t) xdr_wrapstring, (caddr_t) &name,
- (xdrproc_t) xdr_void, &clnt_res, TIMEOUT)
- != RPC_SUCCESS)
- {
- __cache_close ();
- result = NIS_FAIL;
- }
-
- __libc_lock_unlock (mgrlock);
-
- return result;
-}
-
-static nis_error
-__cache_find (const_nis_name name, directory_obj **obj)
-{
- unsigned long hash;
- struct cache_header *hptr;
- struct cache_spacer *cs;
- struct directory_obj *dir;
- XDR xdrs;
- caddr_t addr, ptr;
- time_t now = time (NULL);
-
- if (maddr == NULL)
- return NIS_FAIL;
-
- hash = __nis_hash (name, strlen(name));
- hptr = (cache_header *)maddr;
- if ((hptr->magic != HEADER_MAGIC) || (hptr->vers != CACHE_VERSION))
- {
- syslog (LOG_ERR, _("NIS+: cache file is corrupt!"));
- return NIS_SYSTEMERROR;
- }
- cs = (cache_spacer *)(maddr + sizeof (cache_header));
- while (cs->next_offset)
- {
- if (cs->magic != SPACER_MAGIC)
- {
- syslog (LOG_ERR, _("NIS+: cache file is corrupt!"));
- return NIS_SYSTEMERROR;
- }
- if (cs->hashval == hash)
- {
- if ((now - cs->ctime) > cs->ttl)
- return NIS_CACHEEXPIRED;
- dir = calloc (1, sizeof (directory_obj));
- addr = (caddr_t)cs + sizeof (cache_spacer);
- xdrmem_create (&xdrs, addr, cs->next_offset, XDR_DECODE);
- xdr_directory_obj (&xdrs, dir);
- xdr_destroy (&xdrs);
- *obj = dir;
- return NIS_SUCCESS;
- }
- ptr = (caddr_t)cs;
- ptr += cs->next_offset + sizeof (struct cache_spacer);
- cs = (struct cache_spacer *)ptr;
- }
- return NIS_NOTFOUND;
-}
-
-static directory_obj *
-internal_cache_search (const_nis_name name)
-{
- directory_obj *dir;
- nis_error res;
- int second_refresh = 0;
- struct stat s;
-
- if (cache_fd == -1)
- if (__cache_open () == FALSE)
- return NULL;
-
- again:
- /* This lock is for nis_cachemgr, so it couldn't write a new cache
- file if we reading it */
- if (__nis_lock_cache () == -1)
- return NULL;
-
- if (maddr != NULL)
- munmap (maddr, msize);
- if (fstat (cache_fd, &s) < 0)
- maddr = MAP_FAILED;
- else
- {
- msize = s.st_size;
- maddr = mmap (0, msize, PROT_READ, MAP_SHARED, cache_fd, 0);
- }
- if (maddr == MAP_FAILED)
- {
- __nis_unlock_cache ();
- return NULL;
- }
-
- res = __cache_find (name, &dir);
-
- munmap (maddr, msize);
- maddr = NULL;
- /* Allow nis_cachemgr to write a new cachefile */
- __nis_unlock_cache ();
-
- switch(res)
- {
- case NIS_CACHEEXPIRED:
- if (second_refresh)
- {
- __cache_close ();
- syslog (LOG_WARNING,
- _("NIS+: nis_cachemgr failed to refresh object for us"));
- return NULL;
- }
- ++second_refresh;
- if (__cache_refresh ((char *) name) != NIS_SUCCESS)
- return NULL;
- goto again;
- break;
- case NIS_SUCCESS:
- return dir;
- default:
- return NULL;
- }
-}
-
-directory_obj *
-__cache_search (const_nis_name name)
-{
- directory_obj *dir;
-
- __libc_lock_lock (mgrlock);
-
- dir = internal_cache_search (name);
-
- __libc_lock_unlock (mgrlock);
-
- return dir;
-}
-
-nis_error
-__cache_add (fd_result *fd)
-{
- char clnt_res = 0;
- nis_error result = NIS_SUCCESS;
-
- __libc_lock_lock (mgrlock);
-
- if (cache_clnt == NULL)
- if (__cache_open () == FALSE)
- result = NIS_FAIL;
-
- if (cache_clnt != NULL &&
- (clnt_call (cache_clnt, NIS_CACHE_ADD_ENTRY, (xdrproc_t) xdr_fd_result,
- (caddr_t)fd, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT)
- != RPC_SUCCESS))
- {
- __cache_close ();
- result = NIS_RPCERROR;
- }
-
- __libc_lock_unlock (mgrlock);
-
- return result;
-}