(root)/
Linux-PAM-1.5.3/
modules/
pam_stress/
pam_stress.c
       1  /*
       2   * pam_stress module
       3   *
       4   * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12
       5   */
       6  
       7  #include "config.h"
       8  
       9  #include <stdlib.h>
      10  #include <stdio.h>
      11  
      12  #include <syslog.h>
      13  
      14  #include <stdarg.h>
      15  #include <string.h>
      16  #include <unistd.h>
      17  
      18  #include <security/pam_modules.h>
      19  #include <security/_pam_macros.h>
      20  #include <security/pam_ext.h>
      21  #include "pam_inline.h"
      22  
      23  /* ---------- */
      24  
      25  /* an internal function to turn all possible test arguments into bits
      26     of a ctrl number */
      27  
      28  /* generic options */
      29  
      30  #define PAM_ST_DEBUG         01
      31  #define PAM_ST_NO_WARN       02
      32  #define PAM_ST_USE_PASS1     04
      33  #define PAM_ST_TRY_PASS1    010
      34  #define PAM_ST_ROOTOK       020
      35  
      36  /* simulation options */
      37  
      38  #define PAM_ST_EXPIRED       040
      39  #define PAM_ST_FAIL_1       0100
      40  #define PAM_ST_FAIL_2       0200
      41  #define PAM_ST_PRELIM       0400
      42  #define PAM_ST_REQUIRE_PWD 01000
      43  
      44  /* some syslogging */
      45  
      46  static void
      47  _pam_report (const pam_handle_t *pamh, int ctrl, const char *name,
      48  	     int flags, int argc, const char **argv)
      49  {
      50       if (ctrl & PAM_ST_DEBUG) {
      51  	  pam_syslog(pamh, LOG_DEBUG, "CALLED: %s", name);
      52  	  pam_syslog(pamh, LOG_DEBUG, "FLAGS : 0%o%s",
      53  		     flags, (flags & PAM_SILENT) ? " (silent)":"");
      54  	  pam_syslog(pamh, LOG_DEBUG, "CTRL  = 0%o", ctrl);
      55  	  pam_syslog(pamh, LOG_DEBUG, "ARGV  :");
      56  	  while (argc--) {
      57  	       pam_syslog(pamh, LOG_DEBUG, " \"%s\"", *argv++);
      58  	  }
      59       }
      60  }
      61  
      62  static int
      63  _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
      64  {
      65       int ctrl=0;
      66  
      67       /* step through arguments */
      68       for (ctrl=0; argc-- > 0; ++argv) {
      69  
      70  	  /* generic options */
      71  
      72  	  if (!strcmp(*argv,"debug"))
      73  	       ctrl |= PAM_ST_DEBUG;
      74  	  else if (!strcmp(*argv,"no_warn"))
      75  	       ctrl |= PAM_ST_NO_WARN;
      76  	  else if (!strcmp(*argv,"use_first_pass"))
      77  	       ctrl |= PAM_ST_USE_PASS1;
      78  	  else if (!strcmp(*argv,"try_first_pass"))
      79  	       ctrl |= PAM_ST_TRY_PASS1;
      80  	  else if (!strcmp(*argv,"rootok"))
      81  	       ctrl |= PAM_ST_ROOTOK;
      82  
      83  	  /* simulation options */
      84  
      85  	  else if (!strcmp(*argv,"expired"))   /* signal password needs
      86  						  renewal */
      87  	       ctrl |= PAM_ST_EXPIRED;
      88  	  else if (!strcmp(*argv,"fail_1"))    /* instruct fn 1 to fail */
      89  	       ctrl |= PAM_ST_FAIL_1;
      90  	  else if (!strcmp(*argv,"fail_2"))    /* instruct fn 2 to fail */
      91  	       ctrl |= PAM_ST_FAIL_2;
      92  	  else if (!strcmp(*argv,"prelim"))    /* instruct pam_sm_setcred
      93  						  to fail on first call */
      94  	       ctrl |= PAM_ST_PRELIM;
      95  	  else if (!strcmp(*argv,"required"))  /* module is fussy about the
      96  						  user being authenticated */
      97  	       ctrl |= PAM_ST_REQUIRE_PWD;
      98  
      99  	  else {
     100  	       pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
     101  	  }
     102       }
     103  
     104       return ctrl;
     105  }
     106  
     107  static int converse(pam_handle_t *pamh, int nargs
     108  		    , const struct pam_message **message
     109  		    , struct pam_response **response)
     110  {
     111       int retval;
     112       const void *void_conv;
     113       const struct pam_conv *conv;
     114  
     115       retval = pam_get_item(pamh,PAM_CONV,&void_conv);
     116       conv = void_conv;
     117       if (retval == PAM_SUCCESS && conv) {
     118  	  retval = conv->conv(nargs, message, response, conv->appdata_ptr);
     119  	  if (retval != PAM_SUCCESS) {
     120  	       pam_syslog(pamh, LOG_ERR, "converse returned %d: %s",
     121  			retval, pam_strerror(pamh, retval));
     122  	  }
     123       } else {
     124  	  pam_syslog(pamh, LOG_ERR, "converse failed to get pam_conv");
     125           if (retval == PAM_SUCCESS)
     126               retval = PAM_BAD_ITEM; /* conv was null */
     127       }
     128  
     129       return retval;
     130  }
     131  
     132  /* authentication management functions */
     133  
     134  static int stress_get_password(pam_handle_t *pamh, int flags
     135  			       , int ctrl, char **password)
     136  {
     137       const void *pam_pass;
     138       char *pass;
     139  
     140       if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
     141  	 && (pam_get_item(pamh,PAM_AUTHTOK,&pam_pass)
     142  	     == PAM_SUCCESS)
     143  	 && (pam_pass != NULL) ) {
     144  	  if ((pass = strdup(pam_pass)) == NULL)
     145  	       return PAM_BUF_ERR;
     146       } else if ((ctrl & PAM_ST_USE_PASS1)) {
     147  	  pam_syslog(pamh, LOG_WARNING, "no forwarded password");
     148  	  return PAM_PERM_DENIED;
     149       } else {                                /* we will have to get one */
     150  	  struct pam_message msg[1];
     151  	  const struct pam_message *pmsg[1];
     152  	  struct pam_response *resp;
     153  	  int retval;
     154  
     155  	  /* set up conversation call */
     156  
     157  	  pmsg[0] = &msg[0];
     158  	  msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
     159  	  msg[0].msg = "STRESS Password: ";
     160  	  resp = NULL;
     161  
     162  	  if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
     163  	       return retval;
     164  	  }
     165  
     166  	  if (resp) {
     167  	       if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
     168  		    pam_syslog(pamh, LOG_DEBUG,
     169  			       "pam_sm_authenticate: NULL authtok given");
     170  	       }
     171  	       if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
     172  		   && resp[0].resp == NULL) {
     173  		    free(resp);
     174  		    return PAM_AUTH_ERR;
     175  	       }
     176  
     177  	       pass = resp[0].resp;          /* remember this! */
     178  
     179  	       resp[0].resp = NULL;
     180  	  } else {
     181                 if (ctrl & PAM_ST_DEBUG) {
     182  	          pam_syslog(pamh, LOG_DEBUG,
     183  			     "pam_sm_authenticate: no error reported");
     184  	          pam_syslog(pamh, LOG_DEBUG,
     185  			     "getting password, but NULL returned!?");
     186                 }
     187  	       return PAM_CONV_ERR;
     188  	  }
     189  	  free(resp);
     190       }
     191  
     192       *password = pass;             /* this *MUST* be free()'d by this module */
     193  
     194       return PAM_SUCCESS;
     195  }
     196  
     197  /* function to clean up data items */
     198  
     199  static void
     200  wipe_up (pam_handle_t *pamh UNUSED, void *data, int error UNUSED)
     201  {
     202       free(data);
     203  }
     204  
     205  int pam_sm_authenticate(pam_handle_t *pamh, int flags,
     206  			int argc, const char **argv)
     207  {
     208       const char *username;
     209       int retval=PAM_SUCCESS;
     210       char *pass;
     211       int ctrl;
     212  
     213       D(("called."));
     214  
     215       ctrl = _pam_parse(pamh, argc, argv);
     216       _pam_report(pamh, ctrl, "pam_sm_authenticate", flags, argc, argv);
     217  
     218       /* try to get the username */
     219  
     220       retval = pam_get_user(pamh, &username, "username: ");
     221       if (retval != PAM_SUCCESS) {
     222  	  pam_syslog(pamh, LOG_NOTICE,
     223  		     "pam_sm_authenticate: cannot determine user name: %s",
     224  		     pam_strerror(pamh, retval));
     225  	  return retval;
     226       }
     227       else if (ctrl & PAM_ST_DEBUG) {
     228  	  pam_syslog(pamh, LOG_DEBUG,
     229  		     "pam_sm_authenticate: username = %s", username);
     230       }
     231  
     232       /* now get the password */
     233  
     234       retval = stress_get_password(pamh,flags,ctrl,&pass);
     235       if (retval != PAM_SUCCESS) {
     236  	  pam_syslog(pamh, LOG_WARNING,
     237  		     "pam_sm_authenticate: failed to get a password");
     238  	  return retval;
     239       }
     240  
     241       /* try to set password item */
     242  
     243       retval = pam_set_item(pamh,PAM_AUTHTOK,pass);
     244       pam_overwrite_string(pass); /* clean up local copy of password */
     245       free(pass);
     246       pass = NULL;
     247       if (retval != PAM_SUCCESS) {
     248  	  pam_syslog(pamh, LOG_WARNING,
     249  		     "pam_sm_authenticate: failed to store new password");
     250  	  return retval;
     251       }
     252  
     253       /* if we are debugging then we print the password */
     254  
     255       if (ctrl & PAM_ST_DEBUG) {
     256            const void *pam_pass;
     257  	  (void) pam_get_item(pamh,PAM_AUTHTOK,&pam_pass);
     258  	  pam_syslog(pamh, LOG_DEBUG,
     259  		     "pam_st_authenticate: password entered is: [%s]",
     260  		     (const char *)pam_pass);
     261       }
     262  
     263       /* if we signal a fail for this function then fail */
     264  
     265       if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
     266  	  return PAM_PERM_DENIED;
     267  
     268       return retval;
     269  }
     270  
     271  int pam_sm_setcred(pam_handle_t *pamh, int flags,
     272  		   int argc, const char **argv)
     273  {
     274       int ctrl = _pam_parse(pamh, argc, argv);
     275  
     276       D(("called. [post parsing]"));
     277  
     278       _pam_report(pamh, ctrl, "pam_sm_setcred", flags, argc, argv);
     279  
     280       if (ctrl & PAM_ST_FAIL_2)
     281  	  return PAM_CRED_ERR;
     282  
     283       return PAM_SUCCESS;
     284  }
     285  
     286  /* account management functions */
     287  
     288  int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
     289  		     int argc, const char **argv)
     290  {
     291       int ctrl = _pam_parse(pamh, argc, argv);
     292  
     293       D(("called. [post parsing]"));
     294  
     295       _pam_report(pamh, ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
     296  
     297       if (ctrl & PAM_ST_FAIL_1)
     298  	  return PAM_PERM_DENIED;
     299       else if (ctrl & PAM_ST_EXPIRED) {
     300  	  int retval;
     301  	  void *text = strdup("yes");
     302  	  if (!text)
     303  	        return PAM_BUF_ERR;
     304  	  retval = pam_set_data(pamh,"stress_new_pwd",text,wipe_up);
     305  	  if (retval != PAM_SUCCESS) {
     306  	        pam_syslog(pamh, LOG_DEBUG,
     307  			   "pam_sm_acct_mgmt: failed setting stress_new_pwd");
     308  	        free(text);
     309  	        return retval;
     310  	  }
     311  
     312  	  if (ctrl & PAM_ST_DEBUG) {
     313  	       pam_syslog(pamh, LOG_DEBUG,
     314  			  "pam_sm_acct_mgmt: need a new password");
     315  	  }
     316  	  return PAM_NEW_AUTHTOK_REQD;
     317       }
     318  
     319       return PAM_SUCCESS;
     320  }
     321  
     322  int pam_sm_open_session(pam_handle_t *pamh, int flags,
     323  			int argc, const char **argv)
     324  {
     325       const void *username, *service;
     326       int ctrl = _pam_parse(pamh, argc, argv);
     327  
     328       D(("called. [post parsing]"));
     329  
     330       _pam_report(pamh, ctrl,"pam_sm_open_session", flags, argc, argv);
     331  
     332       if ((pam_get_item(pamh, PAM_USER, &username)
     333  	  != PAM_SUCCESS || !username)
     334  	 || (pam_get_item(pamh, PAM_SERVICE, &service)
     335  	     != PAM_SUCCESS || !service)) {
     336  	  pam_syslog(pamh, LOG_WARNING, "pam_sm_open_session: for whom?");
     337  	  return PAM_SESSION_ERR;
     338       }
     339  
     340       pam_syslog(pamh, LOG_NOTICE, "opened [%s] session for user [%s]",
     341  	        (const char *)service, (const char *)username);
     342  
     343       if (ctrl & PAM_ST_FAIL_1)
     344  	  return PAM_SESSION_ERR;
     345  
     346       return PAM_SUCCESS;
     347  }
     348  
     349  int pam_sm_close_session(pam_handle_t *pamh, int flags,
     350  			 int argc, const char **argv)
     351  {
     352       const void *username, *service;
     353       int ctrl = _pam_parse(pamh, argc, argv);
     354  
     355       D(("called. [post parsing]"));
     356  
     357       _pam_report(pamh, ctrl,"pam_sm_close_session", flags, argc, argv);
     358  
     359       if ((pam_get_item(pamh, PAM_USER, &username)
     360  	  != PAM_SUCCESS || !username)
     361  	 || (pam_get_item(pamh, PAM_SERVICE, &service)
     362  	     != PAM_SUCCESS || !service)) {
     363  	  pam_syslog(pamh, LOG_WARNING, "pam_sm_close_session: for whom?");
     364  	  return PAM_SESSION_ERR;
     365       }
     366  
     367       pam_syslog(pamh, LOG_NOTICE, "closed [%s] session for user [%s]",
     368  	      (const char *)service, (const char *)username);
     369  
     370       if (ctrl & PAM_ST_FAIL_2)
     371  	  return PAM_SESSION_ERR;
     372  
     373       return PAM_SUCCESS;
     374  }
     375  
     376  int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
     377  		     int argc, const char **argv)
     378  {
     379       int retval;
     380       int ctrl = _pam_parse(pamh, argc, argv);
     381  
     382       D(("called. [post parsing]"));
     383  
     384       _pam_report(pamh, ctrl,"pam_sm_chauthtok", flags, argc, argv);
     385  
     386       /* this function should be called twice by the Linux-PAM library */
     387  
     388       if (flags & PAM_PRELIM_CHECK) {           /* first call */
     389  	  if (ctrl & PAM_ST_DEBUG) {
     390  	       pam_syslog(pamh, LOG_DEBUG, "pam_sm_chauthtok: prelim check");
     391  	  }
     392  	  if (ctrl & PAM_ST_PRELIM)
     393  	       return PAM_TRY_AGAIN;
     394  
     395  	  return PAM_SUCCESS;
     396       } else if (flags & PAM_UPDATE_AUTHTOK) {  /* second call */
     397  	  struct pam_message msg[3];
     398  	  const struct pam_message *pmsg[3];
     399  	  struct pam_response *resp;
     400  	  const void *text;
     401  	  char *txt=NULL;
     402  	  int i;
     403  
     404  	  if (ctrl & PAM_ST_DEBUG) {
     405  	       pam_syslog(pamh, LOG_DEBUG, "pam_sm_chauthtok: alter password");
     406  	  }
     407  
     408  	  if (ctrl & PAM_ST_FAIL_1)
     409  	       return PAM_AUTHTOK_LOCK_BUSY;
     410  
     411  	  if ( !(ctrl & PAM_ST_EXPIRED)
     412  	       && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
     413  	       && (pam_get_data(pamh,"stress_new_pwd", &text)
     414  		      != PAM_SUCCESS || strcmp(text,"yes"))) {
     415  	       return PAM_SUCCESS;          /* the token has not expired */
     416  	  }
     417  
     418  	  /* the password should be changed */
     419  
     420  	  if ((ctrl & PAM_ST_REQUIRE_PWD)
     421  	      && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
     422  	       ) {                       /* first get old one? */
     423  	       char *pass;
     424  
     425  	       if (ctrl & PAM_ST_DEBUG) {
     426  		    pam_syslog(pamh, LOG_DEBUG,
     427  			       "pam_sm_chauthtok: getting old password");
     428  	       }
     429  	       retval = stress_get_password(pamh,flags,ctrl,&pass);
     430  	       if (retval != PAM_SUCCESS) {
     431  		    pam_syslog(pamh, LOG_DEBUG,
     432  			       "pam_sm_chauthtok: no password obtained");
     433  		    return retval;
     434  	       }
     435  	       retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
     436  	       pam_overwrite_string(pass);
     437  	       free(pass);
     438  	       pass = NULL;
     439  	       if (retval != PAM_SUCCESS) {
     440  		    pam_syslog(pamh, LOG_DEBUG,
     441  			       "pam_sm_chauthtok: could not set OLDAUTHTOK");
     442  		    return retval;
     443  	       }
     444  	  }
     445  
     446  	  /* set up for conversation */
     447  
     448  	  if (!(flags & PAM_SILENT)) {
     449  	       const void *username;
     450  
     451  	       if ( pam_get_item(pamh, PAM_USER, &username)
     452  		    || username == NULL ) {
     453  		    pam_syslog(pamh, LOG_ERR, "no username set");
     454  		    return PAM_USER_UNKNOWN;
     455  	       }
     456  	       pmsg[0] = &msg[0];
     457  	       msg[0].msg_style = PAM_TEXT_INFO;
     458  	       if (asprintf(&txt, "Changing STRESS password for %s.",
     459  			    (const char *)username) < 0) {
     460  		    pam_syslog(pamh, LOG_CRIT, "out of memory");
     461  		    return PAM_BUF_ERR;
     462  	       }
     463  
     464  	       msg[0].msg = txt;
     465  	       i = 1;
     466  	  } else {
     467  	       i = 0;
     468  	  }
     469  
     470  	  pmsg[i] = &msg[i];
     471  	  msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
     472  	  msg[i++].msg = "Enter new STRESS password: ";
     473  	  pmsg[i] = &msg[i];
     474  	  msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
     475  	  msg[i++].msg = "Retype new STRESS password: ";
     476  	  resp = NULL;
     477  
     478  	  retval = converse(pamh,i,pmsg,&resp);
     479  	  if (txt) {
     480  	       free(txt);
     481  	       txt = NULL;               /* clean up */
     482  	  }
     483  	  if (retval != PAM_SUCCESS) {
     484  	       return retval;
     485  	  }
     486  
     487  	  if (resp == NULL) {
     488  	       pam_syslog(pamh, LOG_ERR,
     489  			  "pam_sm_chauthtok: no response from conv");
     490  	       return PAM_CONV_ERR;
     491  	  }
     492  
     493  	  /* store the password */
     494  
     495  	  if (resp[i-2].resp && resp[i-1].resp) {
     496  	       if (strcmp(resp[i-2].resp,resp[i-1].resp)) {
     497  		    /* passwords are not the same; forget and return error */
     498  
     499  		    pam_drop_response(resp, i);
     500  
     501  		    if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
     502  			 pmsg[0] = &msg[0];
     503  			 msg[0].msg_style = PAM_ERROR_MSG;
     504  			 msg[0].msg = "Verification mis-typed; "
     505  				      "password unchanged";
     506  			 resp = NULL;
     507  			 (void) converse(pamh,1,pmsg,&resp);
     508  			 if (resp) {
     509  			     pam_drop_response(resp, 1);
     510  			 }
     511  		    }
     512  		    return PAM_AUTHTOK_ERR;
     513  	       }
     514  
     515  	       if (pam_get_item(pamh,PAM_AUTHTOK,&text)
     516  		   == PAM_SUCCESS) {
     517  		    (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
     518  		    text = NULL;
     519  	       }
     520  	       (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
     521  	  } else {
     522  	       pam_syslog(pamh, LOG_DEBUG,
     523  			  "pam_sm_chauthtok: problem with resp");
     524  	       retval = PAM_SYSTEM_ERR;
     525  	  }
     526  
     527  	  pam_drop_response(resp, i);      /* clean up the passwords */
     528       } else {
     529  	  pam_syslog(pamh, LOG_ERR,
     530  		     "pam_sm_chauthtok: this must be a Linux-PAM error");
     531  	  return PAM_SYSTEM_ERR;
     532       }
     533  
     534       return retval;
     535  }