(root)/
Linux-PAM-1.5.3/
libpam/
pam_get_authtok.c
       1  /*
       2   * Redistribution and use in source and binary forms, with or without
       3   * modification, are permitted provided that the following conditions
       4   * are met:
       5   * 1. Redistributions of source code must retain the above copyright
       6   *    notice, and the entire permission notice in its entirety,
       7   *    including the disclaimer of warranties.
       8   * 2. Redistributions in binary form must reproduce the above copyright
       9   *    notice, this list of conditions and the following disclaimer in the
      10   *    documentation and/or other materials provided with the distribution.
      11   * 3. The name of the author may not be used to endorse or promote
      12   *    products derived from this software without specific prior
      13   *    written permission.
      14   *
      15   * ALTERNATIVELY, this product may be distributed under the terms of
      16   * the GNU Public License, in which case the provisions of the GPL are
      17   * required INSTEAD OF the above restrictions.  (This clause is
      18   * necessary due to a potential bad interaction between the GPL and
      19   * the restrictions contained in a BSD-style copyright.)
      20   *
      21   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
      22   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      23   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      24   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      25   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      26   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      27   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      29   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      30   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
      31   * OF THE POSSIBILITY OF SUCH DAMAGE.
      32   */
      33  
      34  #include "config.h"
      35  #include "pam_private.h"
      36  #include "pam_inline.h"
      37  
      38  #include <security/pam_ext.h>
      39  
      40  #define PROMPT _("Password: ")
      41  /* For Translators: "%s" is replaced with "<service>". */
      42  #define PROMPT_CURRENT_ARG _("Current %s password: ")
      43  #define PROMPT_CURRENT_NOARG _("Current password: ")
      44  /* For Translators: "%s" is replaced with "<service>". */
      45  #define PROMPT_NEW_ARG _("New %s password: ")
      46  #define PROMPT_NEW_NOARG _("New password: ")
      47  /* For Translators: "%s" is replaced with "<service>". */
      48  #define PROMPT_RETYPE_ARG _("Retype new %s password: ")
      49  #define PROMPT_RETYPE_NOARG _("Retype new password: ")
      50  #define MISTYPED_PASS _("Sorry, passwords do not match.")
      51  
      52  #define PAM_GETAUTHTOK_NOVERIFY  1
      53  
      54  static const char *
      55  get_option (pam_handle_t *pamh, const char *option)
      56  {
      57    int i;
      58    size_t len;
      59  
      60  
      61    if (option == NULL || pamh == NULL ||
      62        pamh->mod_argc == 0 || pamh->mod_argv == NULL)
      63      return NULL;
      64  
      65    len = strlen (option);
      66  
      67    for (i = 0; i < pamh->mod_argc; i++)
      68      {
      69        if (strncmp (option, pamh->mod_argv[i], len) == 0)
      70          {
      71            if (pamh->mod_argv[i][len] == '=')
      72              return &(pamh->mod_argv[i][len+1]);
      73            else if (pamh->mod_argv[i][len] == '\0')
      74              return "";
      75          }
      76      }
      77    return NULL;
      78  }
      79  
      80  
      81  static int
      82  pam_get_authtok_internal (pam_handle_t *pamh, int item,
      83  			  const char **authtok, const char *prompt,
      84  			  unsigned int flags)
      85  
      86  {
      87    char *resp[2] = {NULL, NULL};
      88    const void *prevauthtok;
      89    const char *authtok_type = "";
      90    int chpass = 0; /* Password change, ask twice for it */
      91    int retval;
      92  
      93    if (authtok == NULL)
      94      return PAM_SYSTEM_ERR;
      95  
      96    /* PAM_AUTHTOK in password stack returns new password,
      97       which needs to be verified. */
      98    if (pamh->choice == PAM_CHAUTHTOK)
      99      {
     100        if (item == PAM_AUTHTOK)
     101  	{
     102  	  chpass = 1;
     103  	  if (!(flags & PAM_GETAUTHTOK_NOVERIFY))
     104  	    ++chpass;
     105  	}
     106        authtok_type = get_option (pamh, "authtok_type");
     107        if (authtok_type == NULL)
     108  	{
     109  	  retval = pam_get_item (pamh, PAM_AUTHTOK_TYPE, (const void **)&authtok_type);
     110  	  if (retval != PAM_SUCCESS || authtok_type == NULL)
     111  	    authtok_type = "";
     112  	}
     113        else
     114          pam_set_item(pamh, PAM_AUTHTOK_TYPE, authtok_type);
     115      }
     116  
     117    retval = pam_get_item (pamh, item, &prevauthtok);
     118    if (retval == PAM_SUCCESS && prevauthtok != NULL)
     119      {
     120        *authtok = prevauthtok;
     121        return PAM_SUCCESS;
     122      }
     123    else if (get_option (pamh, "use_first_pass") ||
     124  	   (chpass && get_option (pamh, "use_authtok")))
     125      {
     126        if (prevauthtok == NULL)
     127  	{
     128  	  if (chpass)
     129  	    return PAM_AUTHTOK_ERR;
     130  	  else
     131  	    return PAM_AUTH_ERR;
     132  	}
     133        else
     134  	return retval;
     135      }
     136  
     137    if (prompt != NULL)
     138      {
     139        retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
     140  			   "%s", prompt);
     141        if (retval == PAM_SUCCESS && chpass > 1 && resp[0] != NULL)
     142  	retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1],
     143  			     _("Retype %s"), prompt);
     144      }
     145    else if (chpass)
     146      {
     147        pamh->authtok_verified = 0;
     148  
     149        retval = *authtok_type ?
     150  	pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
     151  		    PROMPT_NEW_ARG, authtok_type) :
     152  	pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
     153  		    "%s", PROMPT_NEW_NOARG);
     154        if (retval == PAM_SUCCESS && chpass > 1 && resp[0] != NULL)
     155  	{
     156  	  retval = *authtok_type ?
     157  	    pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1],
     158  			PROMPT_RETYPE_ARG, authtok_type) :
     159  	    pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[1],
     160  			"%s", PROMPT_RETYPE_NOARG);
     161  	}
     162      }
     163    else if (item == PAM_OLDAUTHTOK)
     164      {
     165        retval = *authtok_type ?
     166  	pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
     167  		    PROMPT_CURRENT_ARG, authtok_type) :
     168  	pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0],
     169  		    "%s", PROMPT_CURRENT_NOARG);
     170      }
     171    else
     172      retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], "%s", PROMPT);
     173  
     174    if (retval != PAM_SUCCESS || resp[0] == NULL ||
     175        (chpass > 1 && resp[1] == NULL))
     176      {
     177        /* We want to abort */
     178        pam_overwrite_string (resp[0]);
     179        _pam_drop (resp[0]);
     180        pam_overwrite_string (resp[1]);
     181        _pam_drop (resp[1]);
     182        if (chpass)
     183          pam_error (pamh, _("Password change has been aborted."));
     184        return PAM_AUTHTOK_ERR;
     185      }
     186  
     187    if (chpass > 1 && strcmp (resp[0], resp[1]) != 0)
     188      {
     189        pam_error (pamh, MISTYPED_PASS);
     190        pam_overwrite_string (resp[0]);
     191        _pam_drop (resp[0]);
     192        pam_overwrite_string (resp[1]);
     193        _pam_drop (resp[1]);
     194        return PAM_TRY_AGAIN;
     195      }
     196  
     197    pam_overwrite_string (resp[1]);
     198    _pam_drop (resp[1]);
     199  
     200    retval = pam_set_item (pamh, item, resp[0]);
     201    pam_overwrite_string (resp[0]);
     202    _pam_drop (resp[0]);
     203    if (retval != PAM_SUCCESS)
     204      return retval;
     205  
     206    if (chpass > 1)
     207      pamh->authtok_verified = 1;
     208  
     209    return pam_get_item(pamh, item, (const void **)authtok);
     210  }
     211  
     212  int
     213  pam_get_authtok (pam_handle_t *pamh, int item, const char **authtok,
     214  		 const char *prompt)
     215  {
     216    return pam_get_authtok_internal (pamh, item, authtok, prompt, 0);
     217  }
     218  
     219  
     220  int
     221  pam_get_authtok_noverify (pam_handle_t *pamh, const char **authtok,
     222  			  const char *prompt)
     223  {
     224    return pam_get_authtok_internal (pamh, PAM_AUTHTOK, authtok, prompt,
     225  				   PAM_GETAUTHTOK_NOVERIFY);
     226  }
     227  
     228  int
     229  pam_get_authtok_verify (pam_handle_t *pamh, const char **authtok,
     230  			const char *prompt)
     231  {
     232    char *resp = NULL;
     233    const char *authtok_type = "";
     234    int retval;
     235  
     236    if (authtok == NULL || pamh->choice != PAM_CHAUTHTOK)
     237      return PAM_SYSTEM_ERR;
     238  
     239    if (pamh->authtok_verified)
     240      return pam_get_item (pamh, PAM_AUTHTOK, (const void **)authtok);
     241  
     242    if (prompt != NULL)
     243      {
     244        retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
     245  			   _("Retype %s"), prompt);
     246      }
     247    else
     248      {
     249        retval = pam_get_item (pamh, PAM_AUTHTOK_TYPE, (const void **)&authtok_type);
     250        if (retval != PAM_SUCCESS || authtok_type == NULL)
     251          authtok_type = "";
     252        retval = *authtok_type ?
     253  	pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
     254  		    PROMPT_RETYPE_ARG, authtok_type) :
     255  	pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
     256  		    "%s", PROMPT_RETYPE_NOARG);
     257      }
     258  
     259    if (retval != PAM_SUCCESS || resp == NULL)
     260      {
     261        /* We want to abort the password change */
     262        pam_set_item (pamh, PAM_AUTHTOK, NULL);
     263        pam_error (pamh, _("Password change has been aborted."));
     264        return PAM_AUTHTOK_ERR;
     265      }
     266  
     267    if (strcmp (*authtok, resp) != 0)
     268      {
     269        pam_set_item (pamh, PAM_AUTHTOK, NULL);
     270        pam_error (pamh, MISTYPED_PASS);
     271        pam_overwrite_string (resp);
     272        _pam_drop (resp);
     273        return PAM_TRY_AGAIN;
     274      }
     275  
     276    retval = pam_set_item (pamh, PAM_AUTHTOK, resp);
     277    pam_overwrite_string (resp);
     278    _pam_drop (resp);
     279    if (retval != PAM_SUCCESS)
     280      return retval;
     281  
     282    pamh->authtok_verified = 1;
     283  
     284    return pam_get_item(pamh, PAM_AUTHTOK, (const void **)authtok);
     285  }