⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rpasswdd.c

📁 pwdutils是一套密码管理工具
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Copyright (C) 2002, 2003, 2004, 2005 Thorsten Kukuk   Author: Thorsten Kukuk <kukuk@suse.de>   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License version 2 as   published by the Free Software Foundation.   This program 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 General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software Foundation,   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#ifdef HAVE_CONFIG_H#include "config.h"#endif#define _GNU_SOURCE#include <getopt.h>#include <error.h>#include <errno.h>#include <grp.h>#include <pwd.h>#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/param.h>#include <sys/poll.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/resource.h>#include <syslog.h>#include <signal.h>#include <string.h>#ifdef USE_GNUTLS#include <gnutls/gnutls.h>#else#include <openssl/rsa.h>       /* SSLeay stuff */#include <openssl/crypto.h>#include <openssl/x509.h>#include <openssl/pem.h>#include <openssl/ssl.h>#include <openssl/err.h>#endif#include <security/pam_appl.h>#include <security/pam_misc.h>#include "i18n.h"#include "dbg_log.h"#include "use_slp.h"#include "logindefs.h"#include "error_codes.h"#include "rpasswd-client.h"#if !defined(IPV6_V6ONLY) && defined(__linux__)#define IPV6_V6ONLY   26#endif/* Path of the file where the PID of the running system is stored.  */#define _PATH_RPASSWDDPID    "/var/run/rpasswdd.pid"extern int setresuid(uid_t ruid, uid_t euid, uid_t suid);/* XXX This variable should not be global.  */#ifdef USE_GNUTLS/* XXX */#elsestatic SSL_CTX *ctx;#endif/* Socket for incoming connections.  */static struct pollfd pollfd_conn[10];static int pollfd_cnt = 0;#ifdef USE_SLP/* register/deregister at SLP server.  */static int use_slp = 0;#endif/* Print the version information.  */static voidprint_version (const char *program){  fprintf (stdout, "%s (%s) %s\n", program, PACKAGE, VERSION);  fprintf (stdout, gettext ("\Copyright (C) %s Thorsten Kukuk.\n\This is free software; see the source for copying conditions.  There is NO\n\warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\"), "2005");  /* fprintf (stdout, _("Written by %s.\n"), "Thorsten Kukuk"); */}static voidprint_usage (FILE *stream, const char *program){#ifdef USE_SLP  fprintf (stream, _("Usage: %s [-4] [-6] [-d] [-c certificate] [-k privatekey] [-p port]\n       [--slp [--slp-timeout timeout] [--slp-descr description]]\n"),	   program);#else  fprintf (stream, _("Usage: %s [-4] [-6] [-d] [-c certificate] [-k privatekey] [-p port]\n"),	   program);#endif}static voidprint_help (const char *program){  print_usage (stdout, program);  fprintf (stdout, _("%s - change password information\n\n"), program);  fputs (_("  -4             Use IPv4\n"), stdout);  fputs (_("  -6             Use IPv6\n"), stdout);  fputs (_("  -c certificate Specify alternate certificate file\n"), stdout);  fputs (_("  -k privatekey  Specify alternate file with private key\n"),	 stdout);  fputs (_("  -d             Run in debug mode\n"), stdout);  fputs (_("  -p port        Port on which the server should listen\n"),	 stdout);#ifdef USE_SLP  fputs (_("  --slp          Register at local SLP server\n"), stdout);  fputs (_("  --slp-timeout  Set timeout for re-registration\n"), stdout);  fputs (_("  --slp-descr    Set a description shown to SLP clients\n"),	 stdout);#endif  fputs (_("  --help         Give this help list\n"), stdout);  fputs (_("  --usage        Give a short usage message\n"), stdout);  fputs (_("  --version      Print program version\n"), stdout);}static voidprint_error (const char *program){  fprintf (stderr,           _("Try `%s --help' or `%s --usage' for more information.\n"),           program, program);}/* Returns 1 if the process in pid file FILE is running, 0 if not.  */static intcheck_pid (const char *file){  FILE *fp;  fp = fopen (file, "r");  if (fp)    {      pid_t pid;      int n;      n = fscanf (fp, "%d", &pid);      fclose (fp);      if (n != 1 || kill (pid, 0) == 0)        return 1;    }  return 0;}/* Write the current process id to the pid file.   Returns 0 if successful, -1 if not.  */static intwrite_pid (const char *file){  FILE *fp;  fp = fopen (file, "w");  if (fp == NULL)    return -1;  fprintf (fp, "%d\n", getpid ());  if (fflush (fp) || ferror (fp))    return -1;  fclose (fp);  return 0;}/****************************************************************************************************************************************************                                                                   ****** Here is now the connection handling part                          ******                                                                   ****************************************************************************************************************************************************//* Initialize database information structures.  */static voidserver_init (int port, int ipv4, int ipv6){  int have_usagi = 1; /* Assume we have a USAGI patched kernel.  */  /* The Linux kernel without USAGI patch will handle IPv4 connections     over an existing IPv6 binding. So we cannot bind explicit a IPv6     and a IPv4 socket. We use only a IPv6 socket in this case.  */  if (ipv6)    {      struct sockaddr_in6 sock_addr;      int on = 1;      /* Create the socket.  */      pollfd_conn[pollfd_cnt].fd = socket (AF_INET6, SOCK_STREAM, 0);      if (pollfd_conn[pollfd_cnt].fd < 0)	{	  dbg_log (_("cannot open socket: %s"), strerror (errno));	  exit (1);	}#ifdef IPV6_V6ONLY      /* we try to bind to IPv6 only and to bind a second socket	 for IPv4. If the IPV6_V6ONLY option failed, we assume IPv6	 will also handle IPv4 addresses.  */      if (setsockopt (pollfd_conn[pollfd_cnt].fd, IPPROTO_IPV6, IPV6_V6ONLY,		      (char *)&on, sizeof (on)) <0)	{	  if (errno != ENOPROTOOPT)	    dbg_log ("setsockopt (IPPROTO_IPV6, IPV6_V6ONLY): %m");	  have_usagi = 0;	}#endif      memset (&sock_addr, '\0', sizeof (sock_addr));      sock_addr.sin6_family = AF_INET6;      sock_addr.sin6_addr = in6addr_any;      sock_addr.sin6_port = port;      if (bind (pollfd_conn[pollfd_cnt].fd, (struct sockaddr *) &sock_addr,		sizeof (sock_addr)) < 0)	{	  dbg_log ("bind: %s", strerror (errno));	  exit (1);	}      /* Set the socket up to accept connections.  */      if (listen (pollfd_conn[pollfd_cnt].fd, SOMAXCONN) < 0)	{	  dbg_log (_("cannot enable socket to accept connections: %s"),		   strerror (errno));	  exit (1);	}      ++pollfd_cnt;    }  if (ipv4 && (!ipv6 || have_usagi))    {      struct sockaddr_in sock_addr;      /* Create the socket.  */      pollfd_conn[pollfd_cnt].fd = socket (AF_INET, SOCK_STREAM, 0);      if (pollfd_conn[pollfd_cnt].fd < 0)	{	  dbg_log (_("cannot open socket: %s"), strerror (errno));	  exit (1);	}      memset (&sock_addr, '\0', sizeof (sock_addr));      sock_addr.sin_family = AF_INET;      sock_addr.sin_addr.s_addr = INADDR_ANY;      sock_addr.sin_port = port;      if (bind (pollfd_conn[pollfd_cnt].fd, (struct sockaddr *) &sock_addr,		sizeof (sock_addr)) < 0)	{	  dbg_log ("bind: %s", strerror (errno));	  exit (1);	}      /* Set the socket up to accept connections.  */      if (listen (pollfd_conn[pollfd_cnt].fd, SOMAXCONN) < 0)	{	  dbg_log (_("cannot enable socket to accept connections: %s"),		   strerror (errno));	  exit (1);	}      ++pollfd_cnt;    }}/* Close the connections.  */static voidclose_sockets (void){  int i;  for (i = 0; i < pollfd_cnt; i++)    if (pollfd_conn[i].fd >= 0)      close (pollfd_conn[i].fd);}#ifdef USE_GNUTLSstatic intsend_string (gnutls_session ssl, response_type type, const char *str){  response_header resp;  resp.type = type;  resp.data_len = strlen (str) + 1;  if (gnutls_record_send (ssl, &resp, sizeof (resp)) <= 0)    return -1;  if (gnutls_record_send (ssl, str, resp.data_len) <= 0)    return -1;  return 0;}static ssize_tsafe_read (gnutls_session ssl, void *data, size_t count, int timeout){  struct pollfd conn;  void *sock;  sock = gnutls_transport_get_ptr (ssl);  conn.fd = (long) sock;  conn.events = POLLRDNORM;  errno = 0;  while (1)    {      int nr = poll (&conn, 1, timeout * 1000);      if (nr < 0)        {	  /* Don't print error messages if poll is only interupted	     by a signal.  */	  if (errno != EINTR)	    dbg_log ("poll() failed: %s", strerror (errno));          continue;        }      else if (nr == 0)	{	  /* XXX TIMEOUT */	  errno = ETIME;	  return -1;	}      else	break;    }  /* We have new incoming data.  */  if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))    {      if (gnutls_record_recv (ssl, data, count) <= 0)	return -1;      else	return count;    }  else    {      /* I don't know if this can ever happen.  */      errno = EAGAIN;      return -1;    }}#elsestatic intsend_string (SSL *ssl, response_type type, const char *str){  response_header resp;  resp.type = type;  resp.data_len = strlen (str) + 1;  if (TEMP_FAILURE_RETRY(SSL_write (ssl, &resp, sizeof (resp)))      != sizeof (resp))    return -1;  if (TEMP_FAILURE_RETRY(SSL_write (ssl, str, resp.data_len))      != resp.data_len)    return -1;  return 0;}static ssize_tsafe_read (SSL *ssl, void *data, size_t count, int timeout){  struct pollfd conn;  conn.fd = SSL_get_fd (ssl);  conn.events = POLLRDNORM;  errno = 0;  while (1)    {      int nr = poll (&conn, 1, timeout * 1000);      if (nr < 0)        {	  /* Don't print error messages if poll is only interupted	     by a signal.  */	  if (errno != EINTR)	    dbg_log ("poll() failed: %s", strerror (errno));          continue;        }      else if (nr == 0)	{	  /* XXX TIMEOUT */	  errno = ETIME;	  return -1;	}      else	break;    }  /* We have new incoming data.  */  if (conn.revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))    return TEMP_FAILURE_RETRY (SSL_read (ssl, data, count));  else    {      /* I don't know if this can ever happen.  */      errno = EAGAIN;      return -1;    }}#endifstatic int#ifdef USE_GNUTLSread_string (gnutls_session ssl, char **retstr)#elseread_string (SSL *ssl, char **retstr)#endif{  conv_header resp;  *retstr = NULL;  errno = 0;  if (safe_read (ssl, &resp, sizeof (resp), 120) != sizeof (resp))    {      char err_buf[256];      if (errno == 0)	dbg_log (_("error while reading request: %s"),		 _("wrong data received"));      else	dbg_log (_("error while reading request: %s"),		 strerror_r (errno, err_buf, sizeof (err_buf)));      return PAM_CONV_ERR;    }  /* 1024 bytes data should be enough. Don't allow more to avoid     DOS attacks.  */  if (resp.data_len > 0 && resp.data_len <= 1024)    {      char *buf = alloca (resp.data_len + 1);      if (safe_read (ssl, buf, resp.data_len, 120) != resp.data_len)	{	  char err_buf[256];	  if (errno == 0)	    dbg_log (_("error while reading request data: %s"),		     _("wrong data received"));	  else	    dbg_log (_("error while reading request data: %s"),		     strerror_r (errno, err_buf, sizeof (err_buf)));	  return PAM_CONV_ERR;	}      buf[resp.data_len] = '\0';      *retstr = strdup (buf);    }  else    return PAM_CONV_ERR;  return resp.retval;}static intrpasswd_conv(int num_msg, const struct pam_message **msgm,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -