about summary refs log tree commit diff
path: root/nscd/connections.c
diff options
context:
space:
mode:
Diffstat (limited to 'nscd/connections.c')
-rw-r--r--nscd/connections.c78
1 files changed, 67 insertions, 11 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index 53e258b498..552d554295 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -80,7 +80,10 @@ const char *serv2str[LASTREQ] =
   [GETHOSTBYADDRv6] = "GETHOSTBYADDRv6",
   [SHUTDOWN] = "SHUTDOWN",
   [GETSTAT] = "GETSTAT",
-  [INVALIDATE] = "INVALIDATE"
+  [INVALIDATE] = "INVALIDATE",
+  [GETFDPW] = "GETFDPW",
+  [GETFDGR] = "GETFDGR",
+  [GETFDHST] = "GETFDHST"
 };
 
 /* The control data structures for the services.  */
@@ -91,6 +94,7 @@ struct database_dyn dbs[lastdb] =
     .enabled = 0,
     .check_file = 1,
     .persistent = 0,
+    .shared = 0,
     .filename = "/etc/passwd",
     .db_filename = _PATH_NSCD_PASSWD_DB,
     .disabled_iov = &pwd_iov_disabled,
@@ -105,6 +109,7 @@ struct database_dyn dbs[lastdb] =
     .enabled = 0,
     .check_file = 1,
     .persistent = 0,
+    .shared = 0,
     .filename = "/etc/group",
     .db_filename = _PATH_NSCD_GROUP_DB,
     .disabled_iov = &grp_iov_disabled,
@@ -119,6 +124,7 @@ struct database_dyn dbs[lastdb] =
     .enabled = 0,
     .check_file = 1,
     .persistent = 0,
+    .shared = 0,
     .filename = "/etc/hosts",
     .db_filename = _PATH_NSCD_HOSTS_DB,
     .disabled_iov = &hst_iov_disabled,
@@ -132,7 +138,7 @@ struct database_dyn dbs[lastdb] =
 
 
 /* Mapping of request type to database.  */
-static struct database_dyn *const serv2db[LASTDBREQ + 1] =
+static struct database_dyn *const serv2db[LASTREQ] =
 {
   [GETPWBYNAME] = &dbs[pwddb],
   [GETPWBYUID] = &dbs[pwddb],
@@ -141,7 +147,10 @@ static struct database_dyn *const serv2db[LASTDBREQ + 1] =
   [GETHOSTBYNAME] = &dbs[hstdb],
   [GETHOSTBYNAMEv6] = &dbs[hstdb],
   [GETHOSTBYADDR] = &dbs[hstdb],
-  [GETHOSTBYADDRv6] = &dbs[hstdb]
+  [GETHOSTBYADDRv6] = &dbs[hstdb],
+  [GETFDPW] = &dbs[pwddb],
+  [GETFDGR] = &dbs[grpdb],
+  [GETFDHST] = &dbs[hstdb],
 };
 
 
@@ -158,9 +167,6 @@ static int sock;
 /* Number of times clients had to wait.  */
 unsigned long int client_queued;
 
-/* Alignment requirement of the beginning of the data region.  */
-#define ALIGN 16
-
 
 /* Initialize database information structures.  */
 void
@@ -224,11 +230,10 @@ nscd_init (void)
 		    dbs[cnt].persistent = 0;
 		  }
 		else if ((total = (sizeof (head)
-				   + roundup (head.module
-					      * sizeof (struct hashentry),
+				   + roundup (head.module * sizeof (ref_t),
 					      ALIGN)
 				   + head.data_size))
-			 < st.st_size)
+			 > st.st_size)
 		  {
 		    dbg_log (_("invalid persistent database file \"%s\": %s"),
 			     dbs[cnt].db_filename,
@@ -253,6 +258,7 @@ nscd_init (void)
 			       dbnames[cnt]);
 
 		    dbs[cnt].wr_fd = fd;
+		    dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
 		    fd = -1;
 		    /* We also need a read-only descriptor.  */
 		    dbs[cnt].ro_fd = open (dbs[cnt].db_filename, O_RDONLY);
@@ -439,6 +445,9 @@ cannot create read-only descriptor for \"%s\"; no mmap"),
 					* dbs[cnt].head->module);
 	    dbs[cnt].data = xmalloc (dbs[cnt].head->data_size);
 	    dbs[cnt].head->first_free = 0;
+
+	    dbs[cnt].shared = 0;
+	    assert (dbs[cnt].ro_fd == -1);
 	  }
 
 	if (dbs[cnt].check_file)
@@ -529,6 +538,43 @@ invalidate_cache (char *key)
 }
 
 
+#ifdef SCM_RIGHTS
+static void
+send_ro_fd (struct database_dyn *db, char *key, int fd)
+{
+  /* If we do not have an read-only file descriptor do nothing.  */
+  if (db->ro_fd == -1)
+    return;
+
+  /* We need to send some data along with the descriptor.  */
+  struct iovec iov[1];
+  iov[0].iov_base = key;
+  iov[0].iov_len = strlen (key) + 1;
+
+  /* Prepare the control message to transfer the descriptor.  */
+  char buf[CMSG_SPACE (sizeof (int))];
+  struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
+			.msg_control = buf, .msg_controllen = sizeof (buf) };
+  struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
+
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN (sizeof (int));
+
+  *(int *) CMSG_DATA (cmsg) = db->ro_fd;
+
+  msg.msg_controllen = cmsg->cmsg_len;
+
+  /* Send the control message.  We repeat when we are interrupted but
+     everything else is ignored.  */
+  (void) TEMP_FAILURE_RETRY (sendmsg (fd, &msg, 0));
+
+  if (__builtin_expect (debug_level > 0, 0))
+    dbg_log (_("provide access to FD %d, for %s"), db->ro_fd, key);
+}
+#endif	/* SCM_RIGHTS */
+
+
 /* Handle new request.  */
 static void
 handle_request (int fd, request_header *req, void *key, uid_t uid)
@@ -614,7 +660,7 @@ cannot handle old request version %d; current version is %d"),
   else if (__builtin_expect (debug_level, 0) > 0)
     {
       if (req->type == INVALIDATE)
-	dbg_log ("\t%s (%s)", serv2str[req->type], (char *)key);
+	dbg_log ("\t%s (%s)", serv2str[req->type], (char *) key);
       else
 	dbg_log ("\t%s", serv2str[req->type]);
     }
@@ -697,6 +743,14 @@ cannot handle old request version %d; current version is %d"),
 	}
       break;
 
+    case GETFDPW:
+    case GETFDGR:
+    case GETFDHST:
+#ifdef SCM_RIGHTS
+      send_ro_fd (serv2db[req->type], key, fd);
+#endif
+      break;
+
     default:
       /* Ignore the command, it's nothing we know.  */
       break;
@@ -733,7 +787,9 @@ nscd_run (void *p)
 	  int timeout = -1;
 	  if (run_prune)
 	    {
-	      now = time (NULL);
+	      /* NB: we do not flush the timestamp update using msync since
+		 this value doesnot matter on disk.  */
+	      dbs[my_number].head->timestamp = now = time (NULL);
 	      timeout = now < next_prune ? 1000 * (next_prune - now) : 0;
 	    }