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

📄 rpasswd.c

📁 pwdutils是一套密码管理工具
💻 C
字号:
/* 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 <assert.h>#include <getopt.h>#include <errno.h>#include <ctype.h>#include <grp.h>#include <pwd.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <termios.h>#include <arpa/inet.h>#include <sys/param.h>#include <sys/poll.h>#include <sys/socket.h>#include <sys/stat.h>#include <syslog.h>#include <signal.h>#include <string.h>#include <security/pam_appl.h>#include <security/pam_misc.h>#ifdef USE_GNUTLS#include <gnutls/gnutls.h>#else#include <openssl/crypto.h>#include <openssl/x509.h>#include <openssl/pem.h>#include <openssl/ssl.h>#include <openssl/err.h>#endif#include "i18n.h"#include "dbg_log.h"#include "rpasswd-client.h"#include "error_codes.h"#ifndef _#define _(String) gettext (String)#endif/* Define verbose output of rpasswd-client functions.  */#define DO_VERBOSE_OUTPUT#define HANDLE#define PRINTF fprintf#define ERR_HANDLE stderr#define STD_HANDLE stdout#define SELECT_SRVURL 1#include "rpasswd-client.c"/* 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){  fprintf (stream,	   _("Usage: %s [-4|-6][-a][-f config-file][-h hostname][-p port][-v][name]\n"),	   program);}static voidprint_help (const char *program){  print_usage (stdout, program);  fprintf (stdout, _("%s - change password information\n\n"), program);  fputs (_("  -4             Use IPv4 only\n"), stdout);  fputs (_("  -6             Use IPv6 only\n"), stdout);  fputs (_	 ("  -a             Admin mode, special admin password is required\n"),	 stdout);  fputs (_("  -f config-file Specify a different config file\n"), stdout);  fputs (_("  -h hostname    Specify the remote server\n"), stdout);  fputs (_("  -p port        Specify port remote server is listening on\n"),	 stdout);  fputs (_("  -r level       Specify level of SSL certificate checks\n"),	 stdout);#ifdef USE_SLP  fputs (_("  --no-slp       Don't use SLP to find a server\n"), stdout);#endif  fputs (_("  -v, --verbose  Be verbose, print SSL connection data\n"),	 stdout);  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);}/* Read a line of input string, giving prompt when appropriate.  */static intread_string (int echo, const char *prompt, char **retstr){  struct termios term_before, term_tmp;  char line[PAM_MAX_MSG_SIZE];  int nc = -1, have_term = 0;  D (("called with echo='%s', prompt='%s'.", echo ? "ON" : "OFF", prompt));  if (isatty (STDIN_FILENO))    {				/* terminal state */      /* is a terminal so record settings and flush it */      if (tcgetattr (STDIN_FILENO, &term_before) != 0)	{	  fprintf (stderr, ("Error: failed to get terminal settings\n"));	  *retstr = NULL;	  return -1;	}      memcpy (&term_tmp, &term_before, sizeof (term_tmp));      if (!echo)	term_tmp.c_lflag &= ~(ECHO);      have_term = 1;    }  else if (!echo)    fprintf (stderr, _("Warning: cannot turn echo off\n"));  /* reading the line */  fprintf (stderr, "%s", prompt);  /* this may, or may not set echo off -- drop pending input */  if (have_term)    (void) tcsetattr (STDIN_FILENO, TCSAFLUSH, &term_tmp);  nc = read (STDIN_FILENO, line, PAM_MAX_MSG_SIZE - 1);  if (have_term)    {      (void) tcsetattr (STDIN_FILENO, TCSADRAIN, &term_before);      if (!echo)		/* do we need a newline? */	fprintf (stderr, "\n");    }  if (nc > 0)			/* We got some user input.  */    {      if (line[nc - 1] == '\n')	/* <NUL> terminate */	line[--nc] = '\0';      else	line[nc] = '\0';      *retstr = x_strdup (line);	/* return malloc()ed string */      _pam_overwrite (line);      return nc;    }  else if (nc == 0)		/* Ctrl-D */    {      D (("user did not want to type anything"));      fprintf (stderr, "\n");    }  /* getting here implies that there was an error or Ctrl-D pressed.  */  if (have_term)    (void) tcsetattr (STDIN_FILENO, TCSADRAIN, &term_before);  memset (line, 0, PAM_MAX_MSG_SIZE);	/* clean up */  *retstr = NULL;  return nc;}#define CONV_ECHO_ON  1		/* types of echo state */#define CONV_ECHO_OFF 0#ifdef USE_GNUTLSstatic inthandle_responses (gnutls_session ssl){  response_header resp;  char retval = E_SUCCESS;  char *buf;  do    {      int ret;      if ((ret = gnutls_record_recv (ssl, &resp, sizeof (resp))) <= 0)	{	  if (ret == 0)	    fprintf (stderr, _("error while reading request: %s"),		     _("Peer has closed the TLS connection"));	  else	    fprintf (stderr, _("error while reading request: %s"),		     gnutls_strerror (ret));	  fputs ("\n", stderr);	  return E_FAILURE;	}      buf = alloca (resp.data_len);      if ((ret = gnutls_record_recv (ssl, buf, resp.data_len)) <= 0)	{	  fprintf (stderr, _("error while reading request data: %s"),		   gnutls_strerror (ret));	  fputs ("\n", stderr);	  return E_FAILURE;	}      switch (resp.type)	{	case TEXT_INFO:	  printf ("%s\n", buf);	  break;	case ERROR_MSG:	  fprintf (stderr, "%s\n", buf);	  break;	case PROMPT_ECHO_OFF:	  {	    char *string = NULL;	    int nc = read_string (CONV_ECHO_OFF, buf, &string);	    if (nc < 0)	      retval = send_string (ssl, PAM_CONV_ERR, string);	    else	      retval = send_string (ssl, PAM_SUCCESS, string);	  }	  break;	case PROMPT_ECHO_ON:	  {	    char *string = NULL;	    int nc = read_string (CONV_ECHO_ON, buf, &string);	    if (nc < 0)	      retval = send_string (ssl, PAM_CONV_ERR, string);	    else	      retval = send_string (ssl, PAM_SUCCESS, string);	  }	  break;	case FINISH:	  retval = buf[0];	  break;	default:	  break;	}      if ((resp.type == PROMPT_ECHO_ON || resp.type == PROMPT_ECHO_OFF) &&	  retval != 0)	{	  char err_buf[256];	  fprintf (stderr, _("Cannot send input back to server: %s\n"),		   strerror_r (errno, err_buf, sizeof (err_buf)));	  return E_FAILURE;	}    }  while (resp.type != FINISH);  return retval;}#elsestatic inthandle_responses (SSL *ssl){  response_header resp;  char retval = E_SUCCESS;  char *buf;  do    {      errno = 0;      if (TEMP_FAILURE_RETRY (SSL_read (ssl, &resp, sizeof (resp)))	  != sizeof (resp))	{	  char err_buf[256];	  if (errno == 0)	    fprintf (stderr, _("error while reading request: %s"),		     _("wrong data received"));	  else	    fprintf (stderr, _("error while reading request: %s"),		     strerror_r (errno, err_buf, sizeof (err_buf)));	  fputs ("\n", stderr);	  return E_FAILURE;	}      buf = alloca (resp.data_len);      if (TEMP_FAILURE_RETRY (SSL_read (ssl, buf, resp.data_len))	  != resp.data_len)	{	  char err_buf[256];	  fprintf (stderr, _("error while reading request data: %s"),		   strerror_r (errno, err_buf, sizeof (err_buf)));	  fputs ("\n", stderr);	  return E_FAILURE;	}      switch (resp.type)	{	case TEXT_INFO:	  printf ("%s\n", buf);	  break;	case ERROR_MSG:	  fprintf (stderr, "%s\n", buf);	  break;	case PROMPT_ECHO_OFF:	  {	    char *string = NULL;	    int nc = read_string (CONV_ECHO_OFF, buf, &string);	    if (nc < 0)	      retval = send_string (ssl, PAM_CONV_ERR, string);	    else	      retval = send_string (ssl, PAM_SUCCESS, string);	  }	  break;	case PROMPT_ECHO_ON:	  {	    char *string = NULL;	    int nc = read_string (CONV_ECHO_ON, buf, &string);	    if (nc < 0)	      retval = send_string (ssl, PAM_CONV_ERR, string);	    else	      retval = send_string (ssl, PAM_SUCCESS, string);	  }	  break;	case FINISH:	  retval = buf[0];	  break;	default:	  break;	}      if ((resp.type == PROMPT_ECHO_ON || resp.type == PROMPT_ECHO_OFF) &&	  retval != 0)	{	  char err_buf[256];	  fprintf (stderr, _("Cannot send input back to server: %s\n"),		   strerror_r (errno, err_buf, sizeof (err_buf)));	  return E_FAILURE;	}    }  while (resp.type != FINISH);  return retval;}#endifintmain (int argc, char **argv){  const char *config_file = _PATH_RPASSWDCONF;  const char *program = "rpasswd";  char *hostp = NULL, *portp = NULL;  int sock = -1, ai_family = PF_UNSPEC;#ifdef USE_SLP  int use_slp = 1;#endif  int verbose = 0;  int admin_mode = 0;  int reqcert = 3;  int retval;  char *username;#ifdef USE_GNUTLS  gnutls_session session;  gnutls_certificate_credentials xcred;#else  SSL_CTX *ctx;  SSL *ssl;#endif  /* Set locale via LC_ALL.  */  setlocale (LC_ALL, "");  /* Set the text message domain.  */  textdomain (PACKAGE);  /* Ignore all signals which can make trouble later.  */  signal (SIGXFSZ, SIG_IGN);  signal (SIGPIPE, SIG_IGN);  /* Parse program arguments */  while (1)    {      int c;      int option_index = 0;      static struct option long_options[] = {	{"admin", no_argument, NULL, 'a'},	{"config-file", required_argument, NULL, 'f'},	{"host", required_argument, NULL, 'h'},	{"ipv4", no_argument, NULL, '4'},	{"ipv6", no_argument, NULL, '6'},	{"port", no_argument, NULL, 'p'},	{"verbose", no_argument, NULL, 'v'},	{"reqcert", required_argument, NULL, 'r'},#ifdef USE_SLP	{"no-slp", no_argument, NULL, '\252'},#endif	{"version", no_argument, NULL, '\255'},	{"usage", no_argument, NULL, '\254'},	{"help", no_argument, NULL, '\253'},	{NULL, 0, NULL, '\0'}      };      c = getopt_long (argc, argv, "af:h:p:r:v46",		       long_options, &option_index);      if (c == EOF)	break;      switch (c)	{	case 'a':	  admin_mode = 1;	  break;	case 'f':	  config_file = optarg;	  break;	case 'h':	  hostp = optarg;	  break;	case '4':	  if (ai_family == PF_INET || ai_family == PF_INET6)	    {	      print_usage (stderr, program);	      return E_USAGE;	    }	  ai_family = PF_INET;	  break;	case '6':	  if (ai_family == PF_INET || ai_family == PF_INET6)	    {	      print_usage (stderr, program);	      return E_USAGE;	    }	  ai_family = PF_INET6;	  break;	case 'p':	  portp = optarg;	  break;	case 'r':	  reqcert = parse_reqcert (optarg);	  break;	case 'v':	  verbose++;	  break;#ifdef USE_SLP	case '\252':	  use_slp = 0;	  break;#endif	case '\253':	  print_help (program);	  return 0;	case '\255':	  print_version (program);	  return 0;	case '\254':	  print_usage (stdout, program);	  return E_USAGE;	default:	  print_error (program);	  return E_BAD_ARG;	}    }  argc -= optind;  argv += optind;  if (argc > 1)    {      fprintf (stderr, _("%s: Too many arguments.\n"), program);      print_error (program);      return E_USAGE;    }  if (hostp)    {      if (portp)	load_config (config_file, NULL, NULL, &reqcert, verbose, 0);      else	load_config (config_file, NULL, &portp, &reqcert, verbose, 0);    }  else if (portp)    load_config (config_file, &hostp, NULL, &reqcert, verbose, 0);  else    load_config (config_file, &hostp, &portp, &reqcert, verbose, 0);#ifdef USE_SLP  if (hostp == NULL && portp == NULL && use_slp == 1)    {      char *descr;      query_slp (&hostp, &portp, &descr);      if (hostp != NULL && portp != NULL)	printf (_("SLP: Found Server on %s, port %s"),		hostp, portp);      else if (hostp != NULL)        printf (_("SLP: Found Server on %s"), hostp);      if (descr)	{	  printf (" (%s)\n", descr);	  free (descr);	}      else	fputs ("\n", stdout);    }#endif  if (portp == NULL)    portp = "rpasswd";  /* Get the login name of the calling user. This could be the one     argument we still have or we use getpwuid/getuid to determine     the login name.  */  if (argc == 1)    username = strdup (argv[0]);  else    {      int pw_buflen = 256;      char *pw_buffer = alloca (pw_buflen);      struct passwd pw_resultbuf;      struct passwd *pw = NULL;      while (getpwuid_r (getuid (), &pw_resultbuf, pw_buffer, pw_buflen,			 &pw) != 0 && errno == ERANGE)	{	  errno = 0;	  pw_buflen += 256;	  pw_buffer = alloca (pw_buflen);	}      if (pw == NULL)	{	  fprintf (stderr, _("Go away, you do not exist!"));	  return E_UNKNOWN_USER;	}      username = strdup (pw->pw_name);    }  if (hostp != NULL)    {      sock = connect_to_server (hostp, portp, ai_family);      if (sock < 0)	return E_FAILURE;    }  else    {      fprintf (stderr, _("No server specified\n"));      return E_USAGE;    }  /* Do SSL */#ifdef USE_GNUTLS  gnutls_global_init ();  /* Initialize TLS session. */  gnutls_init (&session, GNUTLS_CLIENT);  retval = start_ssl (sock, reqcert, verbose, session, &xcred);#else  retval = start_ssl (sock, reqcert, verbose, &ctx, &ssl);#endif  if (retval != 0)    return retval;#ifdef USE_GNUTLS  if ((retval = start_request (session, username, admin_mode)) == 0)    retval = handle_responses (session);  else    retval = E_FAILURE;#else  if ((retval = start_request (ssl, username, admin_mode)) == 0)    retval = handle_responses (ssl);  else    retval = E_FAILURE;#endif  free (username);#ifdef USE_GNUTLS  gnutls_bye (session, GNUTLS_SHUT_RDWR);  close (sock);  gnutls_deinit (session);  gnutls_certificate_free_credentials (xcred);  gnutls_global_deinit ();#else  close (sock);  SSL_free (ssl);  SSL_CTX_free (ctx);#endif  return retval;}

⌨️ 快捷键说明

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