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

📄 rpasswdd.c

📁 pwdutils是一套密码管理工具
💻 C
📖 第 1 页 / 共 3 页
字号:
	     struct pam_response **response, void *appdata_ptr){  int count=0;  struct pam_response *reply;#ifdef USE_GNUTLS  gnutls_session ssl = appdata_ptr;#else  SSL *ssl = appdata_ptr;#endif  if (num_msg <= 0)    return PAM_CONV_ERR;  D(("allocating empty response structure array."));  reply = (struct pam_response *) calloc(num_msg,					 sizeof(struct pam_response));  if (reply == NULL) {    D(("no memory for responses"));    return PAM_CONV_ERR;  }  D(("entering conversation function."));  for (count = 0; count < num_msg; ++count)    {      char *string = NULL;      switch (msgm[count]->msg_style)	{        case PAM_PROMPT_ECHO_OFF:	  D(("PAM_PROMPT_ECHO_OFF"));	  if (send_string (ssl, PROMPT_ECHO_OFF, msgm[count]->msg) != 0)	    goto failed_conversation;	  if (read_string (ssl, &string) != PAM_SUCCESS)	    goto failed_conversation;	  break;        case PAM_PROMPT_ECHO_ON:	  D(("PAM_PROMPT_ECHO_ON"));	  if (send_string (ssl, PROMPT_ECHO_OFF, msgm[count]->msg) != 0)	    goto failed_conversation;	  if (read_string (ssl, &string) != PAM_SUCCESS)	    goto failed_conversation;	  break;        case PAM_ERROR_MSG:	  D(("PAM_ERROR_MSG"));	  if (send_string (ssl, ERROR_MSG, msgm[count]->msg) != 0)	    goto failed_conversation;	  break;        case PAM_TEXT_INFO:	  D(("PAM_TEXT_INFO"));	  if (send_string (ssl, TEXT_INFO, msgm[count]->msg) != 0)	    goto failed_conversation;	  break;        default:	  /* send_string (ssl, TEXT_INFO, _("erroneous conversation (%d)")	     ,msgm[count]->msg_style); */	  goto failed_conversation;        }      if (string) {                         /* must add to reply array */	/* add string to list of responses */	reply[count].resp_retcode = 0;	reply[count].resp = string;	string = NULL;      }    }  /* New (0.59+) behavior is to always have a reply - this is     compatable with the X/Open (March 1997) spec. */  *response = reply;  reply = NULL;  return PAM_SUCCESS;failed_conversation:    if (reply) {        for (count=0; count<num_msg; ++count) {            if (reply[count].resp == NULL) {                continue;            }            switch (msgm[count]->msg_style) {            case PAM_PROMPT_ECHO_ON:            case PAM_PROMPT_ECHO_OFF:                _pam_overwrite(reply[count].resp);                free(reply[count].resp);                break;            case PAM_ERROR_MSG:            case PAM_TEXT_INFO:                /* should not actually be able to get here... */                free(reply[count].resp);            }            reply[count].resp = NULL;        }        /* forget reply too */        free(reply);        reply = NULL;    }    return PAM_CONV_ERR;}/* Sanity check on locale string.   Otherwise local lusers may be tempted to send us   a locale of "../../../../../tmp" and deposit a   message catalog there containing format strings with   lots of %n's in them.  */static intsane_locale (const char *name){  if (!name)    return 0;  if (strchr (name, '/'))    return 0;  if (strstr (name, ".."))    return 0;  /* Any other checks? */  return 1;}/* Handle new request.  */static int#ifdef USE_GNUTLShandle_request (gnutls_session ssl, request_header *req, char *locale,		const char *username, const char * program)#elsehandle_request (SSL *ssl, request_header *req, char *locale,		const char *username, const char *program)#endif{  const struct pam_conv conv = {    rpasswd_conv,    ssl  };  pam_handle_t *pamh = NULL;  int flags = 0, ret;  int retval = E_SUCCESS;  int pw_buflen = 256;  char *pw_buffer = alloca (pw_buflen);  struct passwd pw_resultbuf;  struct passwd *pw = NULL;  if (debug_level > 0)    dbg_log (_("handle_request: request received (Version = %d)"),             req->version);  if (req->version != RPASSWD_VERSION)    {      if (debug_level > 0)        dbg_log (_("\cannot handle request version %d; current version is %d"),                 req->version, RPASSWD_VERSION);      retval = E_WRONG_VERSION;      goto send_finish;    }  if (locale && sane_locale(locale))    setlocale (LC_ALL, locale);  /* Get password file entry... */  while (getpwnam_r (username, &pw_resultbuf, pw_buffer, pw_buflen, &pw) != 0         && errno == ERANGE)    {      errno = 0;      pw_buflen += 256;      pw_buffer = alloca (pw_buflen);    }  if (pw == NULL && req->request != START_ADMIN)    {      dbg_log ("passwd entry for \"%s\" not found", username);      /* Dummy authentication. So the user will not see that this	 account does not exist.  */      ret = pam_start ("rpasswd", username, &conv, &pamh);      if (ret != PAM_SUCCESS)	{	  retval = E_PAM_ERROR;	  goto send_finish;	}      /* We are not interested in the return value, we always assume	 a failed.  */      pam_authenticate (pamh, flags);      pam_end (pamh, PAM_SUCCESS);      /* after using PAM we have to reset openlog data */      openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON);      sleep (getlogindefs_num ("FAIL_DELAY", 1));      send_string (ssl, ERROR_MSG, "Authentication failure");      retval = E_FAILURE;      goto send_finish;    }  /* Do extra authentication if run in admin mode or the passwort     for root should be changed.  */  if (req->request == START_ADMIN || (pw && pw->pw_uid == 0))    {      const char *account;      if (req->request == START_ADMIN)	account = "root";      else	account = username;      /* Do PAM authentification at first.  */      ret = pam_start ("rpasswd", account, &conv, &pamh);      if (ret != PAM_SUCCESS)	{	  /* after using PAM we have to reset openlog data */	  openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON);	  dbg_log ("Couldn't initialize PAM: %s", pam_strerror (pamh, ret));	  retval = E_PAM_ERROR;	  goto send_finish;	}      else if (req->request == START_ADMIN)	{ /* print the message only in admin mode.  */	  char host[MAXHOSTNAMELEN+1];	  char *cp;	  gethostname (host, sizeof (host));	  asprintf (&cp, _("Please authenticate as %s on %s"),		    account, host);	  send_string (ssl, TEXT_INFO, cp);	  free (cp);	}      ret = pam_authenticate (pamh, flags);      if (ret != PAM_SUCCESS)	{	  pam_end (pamh, ret);	  /* after using PAM we have to reset openlog data */	  openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON);	  dbg_log (_("User %s: %s"), account,		   pam_strerror (pamh, ret));	  sleep (getlogindefs_num ("FAIL_DELAY", 1));	  send_string (ssl, ERROR_MSG, pam_strerror (pamh, ret));	  retval = E_FAILURE;	  goto send_finish;	}      pam_end (pamh, PAM_SUCCESS);      /* after using PAM we have to reset openlog data */      openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON);      if (req->request == START_ADMIN)	{ /* In Admin mode send info text what we are now doing.  */	  char *cp;	  if (pw == NULL) /* Now send error message for admin.  */	    {	      dbg_log ("passwd entry for \"%s\" not found", username);	      retval = E_UNKNOWN_USER;	      goto send_finish;	    }	  asprintf (&cp, _("\nNow enter the new password for %s"),		    username);	  send_string (ssl, TEXT_INFO, cp);	  free (cp);	}    }  else /* (req->request != START_ADMIN)  */    {      /* Set the real uid to the one of the user for which we wish to	 change the password and let the effective and saved uid to be	 root. With this, most PAM modules thinks they are called from	 a setuid root passwd program. Not needed if we run in Admin mode.	 In this case, PAM moduls should think passwd is called by root.  */      if (setresuid (pw->pw_uid, 0, 0) == -1)	{	  char *cp;	  if (asprintf (&cp, _("setresuid failed on server: %s"),			strerror (errno)) > 0)	    {	      dbg_log (cp);	      send_string (ssl, ERROR_MSG, cp);	      free (cp);	    }	  retval = E_FAILURE;	  goto send_finish;	}    }  ret = pam_start ("rpasswd", username, &conv, &pamh);  if (ret != PAM_SUCCESS)    {      /* after using PAM we have to reset openlog data */      openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON);      dbg_log ("Couldn't initialize PAM: %s", pam_strerror (pamh, ret));      retval = E_PAM_ERROR;      goto send_finish;    }  ret = pam_chauthtok (pamh, flags);  if (ret != PAM_SUCCESS)    {      pam_end (pamh, ret);      /* after using PAM we have to reset openlog data */      openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON);      dbg_log (_("User %s: %s"), username,	       pam_strerror (pamh, ret));      sleep (getlogindefs_num ("FAIL_DELAY", 1));      send_string (ssl, ERROR_MSG, pam_strerror (pamh, ret));      retval = E_FAILURE;      goto send_finish;    }  pam_end (pamh, PAM_SUCCESS);  /* after using PAM we have to reset openlog data */  openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON);  if (retval)    send_string (ssl, TEXT_INFO, _("Password not changed"));#if 0  else    send_string (ssl, TEXT_INFO, _("Password changed"));#endif send_finish:  {    response_header resp;    resp.type = FINISH;    resp.data_len = 1;#ifdef USE_GNUTLS    gnutls_record_send (ssl, &resp, sizeof (resp));    gnutls_record_send (ssl, &retval, resp.data_len);#else    SSL_write (ssl, &resp, sizeof (resp));    SSL_write (ssl, &retval, resp.data_len);#endif  }  if (debug_level > 0)    dbg_log (_("handle_request: exit (%d)"), retval);  return retval;}#ifdef USE_GNUTLS/* These are global */static gnutls_certificate_credentials x509_cred;static gnutls_sessioninitialize_gnutls_session (const char *certificate, const char *privatekey){  gnutls_session session;  gnutls_certificate_allocate_credentials (&x509_cred);#if 0 /* XXX */  gnutls_certificate_set_x509_trust_file (x509_cred, certificate,					  GNUTLS_X509_FMT_PEM);  gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE,					GNUTLS_X509_FMT_PEM);#endif  gnutls_certificate_set_x509_key_file (x509_cred, certificate, privatekey,					GNUTLS_X509_FMT_PEM);  gnutls_init (&session, GNUTLS_SERVER);  gnutls_set_default_priority (session);  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);  /* XXX gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);     gnutls_dh_set_prime_bits (session, DH_BITS);     generate_dh_params();     gnutls_certificate_set_dh_params( x509_cred, dh_params); */  return session;}#endif/* This is the main loop.  It can be replicated in different threads but the   `poll' call makes sure only one thread handles an incoming connection.  */static void#ifdef USE_GNUTLSserver_run (const char *certificate, const char *privatekey,	    const char *program)#elseserver_run (const char *program)#endif{  int i;  for (i = 0; i < pollfd_cnt; i++)    pollfd_conn[i].events = POLLRDNORM;  while (1)    {      int nr;      nr = poll (pollfd_conn, pollfd_cnt, -1);      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;        }      /* We have a new incoming connection. Look at which socket.  */      for (i = 0; i < pollfd_cnt; i++)	{	  if (pollfd_conn[i].revents & (POLLRDNORM|POLLERR|POLLHUP|POLLNVAL))	    {	      /* Accept the connection.  */	      int ssl_err;	      long fd;	      request_header req;	      char buf[256];	      char *locale, *username;#ifdef USE_GNUTLS	      gnutls_session ssl;#else	      SSL *ssl;#endif	      fd = accept (pollfd_conn[i].fd, NULL, NULL);	      if (fd < 0)		{		  dbg_log (_("while accepting connection: %s"),			   strerror_r (errno, buf, sizeof (buf)));		  continue;		}	      /* TCP connection is ready. Do server side SSL. */#ifdef USE_GNUTLS	      ssl = initialize_gnutls_session (certificate, privatekey);	      gnutls_transport_set_ptr (ssl, (gnutls_transport_ptr)fd);	      ssl_err = gnutls_handshake (ssl);	      if (ssl_err < 0)		{		  close (fd);		  gnutls_deinit (ssl);		  dbg_log (_("Handshake has failed (%s)"),			   gnutls_strerror (ssl_err));		  continue;		}	      /* see the Getting peer's information example */	      /* print_info(session); */	      /* XXX print cipher info and check client		 certificate */	      if ((ssl_err = gnutls_record_recv (ssl, &req, sizeof (req))) <= 0)		{		  if (debug_level > 0)		    {		      if (ssl_err == 0)			dbg_log (_("error while reading request: %s"),				 _("client has closed the GNUTLS connection"));		      else			dbg_log (_("error while reading request: %s"),				 gnutls_strerror (ssl_err));		    }		  gnutls_deinit (ssl);		  close (fd);		  continue;		}#else	      ssl = SSL_new (ctx);	      if (ssl == NULL)		{		  dbg_log (_("cannot enable SSL encryption"));		  close (fd);		  continue;		}	      SSL_set_fd (ssl, fd);	      ssl_err = SSL_accept (ssl);	      if (ssl_err < 1)		{		  dbg_log ("SSL_accept: %s", ERR_error_string (ssl_err, NULL));		  close (fd);		  continue;		}	      /* Get the cipher - opt */	      if (debug_level > 0)

⌨️ 快捷键说明

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