(root)/
Linux-PAM-1.5.3/
libpam/
pam_item.c
       1  /* pam_item.c */
       2  
       3  /*
       4   * $Id$
       5   */
       6  
       7  #include "pam_private.h"
       8  #include "pam_inline.h"
       9  
      10  #include <ctype.h>
      11  #include <stdlib.h>
      12  #include <string.h>
      13  #include <syslog.h>
      14  
      15  #define TRY_SET(X, Y)                      \
      16  {                                          \
      17      if ((X) != (Y)) {		           \
      18  	char *_TMP_ = _pam_strdup(Y);      \
      19  	if (_TMP_ == NULL && (Y) != NULL)  \
      20  	    return PAM_BUF_ERR;            \
      21  	free(X);                           \
      22  	(X) = _TMP_;                       \
      23      }					   \
      24  }
      25  
      26  /* functions */
      27  
      28  int pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
      29  {
      30      int retval;
      31  
      32      D(("called"));
      33  
      34      IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);
      35  
      36      retval = PAM_SUCCESS;
      37  
      38      switch (item_type) {
      39  
      40      case PAM_SERVICE:
      41  	/* Setting handlers_loaded to 0 will cause the handlers
      42  	 * to be reloaded on the next call to a service module.
      43  	 */
      44  	pamh->handlers.handlers_loaded = 0;
      45  	TRY_SET(pamh->service_name, item);
      46  	{
      47  	    char *tmp;
      48  	    for (tmp=pamh->service_name; *tmp; ++tmp)
      49  		*tmp = tolower(*tmp);                 /* require lower case */
      50  	}
      51  	break;
      52  
      53      case PAM_USER:
      54  	TRY_SET(pamh->user, item);
      55  	pamh->former.fail_user = PAM_SUCCESS;
      56  	break;
      57  
      58      case PAM_USER_PROMPT:
      59  	TRY_SET(pamh->prompt, item);
      60  	pamh->former.fail_user = PAM_SUCCESS;
      61  	break;
      62  
      63      case PAM_TTY:
      64  	D(("setting tty to %s", item));
      65  	TRY_SET(pamh->tty, item);
      66  	break;
      67  
      68      case PAM_RUSER:
      69  	TRY_SET(pamh->ruser, item);
      70  	break;
      71  
      72      case PAM_RHOST:
      73  	TRY_SET(pamh->rhost, item);
      74  	break;
      75  
      76      case PAM_AUTHTOK:
      77  	/*
      78  	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
      79  	 * modules.
      80  	 */
      81  	if (__PAM_FROM_MODULE(pamh)) {
      82  	    if (pamh->authtok != item) {
      83  		pam_overwrite_string(pamh->authtok);
      84  		TRY_SET(pamh->authtok, item);
      85  	    }
      86  	} else {
      87  	    retval = PAM_BAD_ITEM;
      88  	}
      89  
      90  	break;
      91  
      92      case PAM_OLDAUTHTOK:
      93  	/*
      94  	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
      95  	 * modules.
      96  	 */
      97  	if (__PAM_FROM_MODULE(pamh)) {
      98  	    if (pamh->oldauthtok != item) {
      99  		pam_overwrite_string(pamh->oldauthtok);
     100  		TRY_SET(pamh->oldauthtok, item);
     101  	    }
     102  	} else {
     103  	    retval = PAM_BAD_ITEM;
     104  	}
     105  
     106  	break;
     107  
     108      case PAM_CONV:              /* want to change the conversation function */
     109  	if (item == NULL) {
     110  	    pam_syslog(pamh, LOG_ERR,
     111  		       "pam_set_item: attempt to set conv() to NULL");
     112  	    retval = PAM_PERM_DENIED;
     113  	} else {
     114  	    struct pam_conv *tconv;
     115  
     116  	    if ((tconv=
     117  		 (struct pam_conv *) malloc(sizeof(struct pam_conv))
     118  		) == NULL) {
     119  		pam_syslog(pamh, LOG_CRIT,
     120  				"pam_set_item: malloc failed for pam_conv");
     121  		retval = PAM_BUF_ERR;
     122  	    } else {
     123  		memcpy(tconv, item, sizeof(struct pam_conv));
     124  		_pam_drop(pamh->pam_conversation);
     125  		pamh->pam_conversation = tconv;
     126  		pamh->former.fail_user = PAM_SUCCESS;
     127  	    }
     128  	}
     129          break;
     130  
     131      case PAM_FAIL_DELAY:
     132  	pamh->fail_delay.delay_fn_ptr = item;
     133  	break;
     134  
     135      case PAM_XDISPLAY:
     136  	TRY_SET(pamh->xdisplay, item);
     137  	break;
     138  
     139      case PAM_XAUTHDATA:
     140  	if (&pamh->xauth == item)
     141  	    break;
     142  	if (pamh->xauth.namelen) {
     143  	    pam_overwrite_string(pamh->xauth.name);
     144  	    free(pamh->xauth.name);
     145  	}
     146  	if (pamh->xauth.datalen) {
     147  	    pam_overwrite_n(pamh->xauth.data, (unsigned int) pamh->xauth.datalen);
     148  	    free(pamh->xauth.data);
     149  	}
     150  	pamh->xauth = *((const struct pam_xauth_data *) item);
     151  	if ((pamh->xauth.name=_pam_strdup(pamh->xauth.name)) == NULL) {
     152  	    pam_overwrite_object(&pamh->xauth);
     153  	    return PAM_BUF_ERR;
     154  	}
     155  	if ((pamh->xauth.data=_pam_memdup(pamh->xauth.data,
     156  	    pamh->xauth.datalen)) == NULL) {
     157  	    pam_overwrite_string(pamh->xauth.name);
     158  	    free(pamh->xauth.name);
     159  	    pam_overwrite_object(&pamh->xauth);
     160  	    return PAM_BUF_ERR;
     161  	}
     162  	break;
     163  
     164      case PAM_AUTHTOK_TYPE:
     165  	TRY_SET(pamh->authtok_type, item);
     166  	break;
     167  
     168      default:
     169  	retval = PAM_BAD_ITEM;
     170      }
     171  
     172      return retval;
     173  }
     174  
     175  int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
     176  {
     177      int retval = PAM_SUCCESS;
     178  
     179      D(("called."));
     180      IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR);
     181  
     182      if (item == NULL) {
     183  	pam_syslog(pamh, LOG_ERR,
     184  			"pam_get_item: nowhere to place requested item");
     185  	return PAM_PERM_DENIED;
     186      }
     187      else
     188  	*item = NULL;
     189  
     190      switch (item_type) {
     191      case PAM_SERVICE:
     192  	*item = pamh->service_name;
     193  	break;
     194  
     195      case PAM_USER:
     196  	D(("returning user=%s", pamh->user));
     197  	*item = pamh->user;
     198  	break;
     199  
     200      case PAM_USER_PROMPT:
     201  	D(("returning userprompt=%s", pamh->user));
     202  	*item = pamh->prompt;
     203  	break;
     204  
     205      case PAM_TTY:
     206  	D(("returning tty=%s", pamh->tty));
     207  	*item = pamh->tty;
     208  	break;
     209  
     210      case PAM_RUSER:
     211  	*item = pamh->ruser;
     212  	break;
     213  
     214      case PAM_RHOST:
     215  	*item = pamh->rhost;
     216  	break;
     217  
     218      case PAM_AUTHTOK:
     219  	/*
     220  	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
     221  	 * modules.
     222  	 */
     223  	if (__PAM_FROM_MODULE(pamh)) {
     224  	    *item = pamh->authtok;
     225  	} else {
     226  	    retval = PAM_BAD_ITEM;
     227  	}
     228  	break;
     229  
     230      case PAM_OLDAUTHTOK:
     231  	/*
     232  	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
     233  	 * modules.
     234  	 */
     235  	if (__PAM_FROM_MODULE(pamh)) {
     236  	    *item = pamh->oldauthtok;
     237  	} else {
     238  	    retval = PAM_BAD_ITEM;
     239  	}
     240  	break;
     241  
     242      case PAM_CONV:
     243  	*item = pamh->pam_conversation;
     244  	break;
     245  
     246      case PAM_FAIL_DELAY:
     247  	*item = pamh->fail_delay.delay_fn_ptr;
     248  	break;
     249  
     250      case PAM_XDISPLAY:
     251  	*item = pamh->xdisplay;
     252  	break;
     253  
     254      case PAM_XAUTHDATA:
     255  	*item = &pamh->xauth;
     256  	break;
     257  
     258      case PAM_AUTHTOK_TYPE:
     259  	*item = pamh->authtok_type;
     260  	break;
     261  
     262      default:
     263  	retval = PAM_BAD_ITEM;
     264      }
     265  
     266      return retval;
     267  }
     268  
     269  /*
     270   * This function is the 'preferred method to obtain the username'.
     271   */
     272  
     273  int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
     274  {
     275      const char *use_prompt;
     276      int retval;
     277      struct pam_message msg;
     278      const struct pam_message *pmsg;
     279      struct pam_response *resp;
     280  
     281      D(("called."));
     282  
     283      IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR);
     284  
     285      if (user == NULL) {
     286          /* ensure that the module has supplied a destination */
     287  	pam_syslog(pamh, LOG_ERR, "pam_get_user: nowhere to record username");
     288  	return PAM_SYSTEM_ERR;
     289      } else
     290  	*user = NULL;
     291  
     292      if (pamh->pam_conversation == NULL) {
     293  	pam_syslog(pamh, LOG_ERR, "pam_get_user: no conv element in pamh");
     294  	return PAM_SYSTEM_ERR;
     295      }
     296  
     297      if (pamh->user) {    /* have one so return it */
     298  	*user = pamh->user;
     299  	return PAM_SUCCESS;
     300      }
     301  
     302      if (pamh->former.fail_user != PAM_SUCCESS)
     303  	return pamh->former.fail_user;
     304  
     305      /* will need a prompt */
     306      if (prompt != NULL)
     307        use_prompt = prompt;
     308      else if (pamh->prompt != NULL)
     309        use_prompt = pamh->prompt;
     310      else
     311        use_prompt = _("login:");
     312  
     313      /* If we are resuming an old conversation, we verify that the prompt
     314         is the same.  Anything else is an error. */
     315      if (pamh->former.want_user) {
     316  	/* must have a prompt to resume with */
     317  	if (! pamh->former.prompt) {
     318  	    pam_syslog(pamh, LOG_ERR,
     319  		       "pam_get_user: failed to resume with prompt"
     320  			);
     321  	    return PAM_ABORT;
     322  	}
     323  
     324  	/* must be the same prompt as last time */
     325  	if (strcmp(pamh->former.prompt, use_prompt)) {
     326  	    pam_syslog(pamh, LOG_ERR,
     327  		       "pam_get_user: resumed with different prompt");
     328  	    return PAM_ABORT;
     329  	}
     330  
     331  	/* ok, we can resume where we left off last time */
     332  	pamh->former.want_user = PAM_FALSE;
     333  	pam_overwrite_string(pamh->former.prompt);
     334  	_pam_drop(pamh->former.prompt);
     335      }
     336  
     337      /* converse with application -- prompt user for a username */
     338      pmsg = &msg;
     339      msg.msg_style = PAM_PROMPT_ECHO_ON;
     340      msg.msg = use_prompt;
     341      resp = NULL;
     342  
     343      retval = pamh->pam_conversation->
     344  	conv(1, &pmsg, &resp, pamh->pam_conversation->appdata_ptr);
     345  
     346      switch (retval) {
     347  	case PAM_SUCCESS:
     348  	case PAM_BUF_ERR:
     349  	case PAM_CONV_AGAIN:
     350  	case PAM_CONV_ERR:
     351  	    break;
     352  	default:
     353  	    retval = PAM_CONV_ERR;
     354      }
     355  
     356      switch (retval) {
     357  	case PAM_CONV_AGAIN:
     358  	    /* conversation function is waiting for an event - save state */
     359  	    D(("conversation function is not ready yet"));
     360  	    pamh->former.want_user = PAM_TRUE;
     361  	    pamh->former.prompt = _pam_strdup(use_prompt);
     362  	    break;
     363  	case PAM_SUCCESS:
     364  	    if (resp != NULL && resp->resp != NULL) {
     365  		/*
     366  		 * now we set the PAM_USER item -- this was missing from pre.53
     367  		 * releases. However, reading the Sun manual, it is part of
     368  		 * the standard API.
     369  		 */
     370  		retval = pam_set_item(pamh, PAM_USER, resp->resp);
     371  		*user = pamh->user;
     372  		break;
     373  	    } else {
     374  		/* conversation should have given a response */
     375  		D(("pam_get_user: no response provided"));
     376  		retval = PAM_CONV_ERR;
     377  	    }
     378  	    /* fallthrough */
     379  	default:
     380  	    pamh->former.fail_user = retval;
     381      }
     382  
     383      if (resp) {
     384  	if (retval != PAM_SUCCESS)
     385  	    pam_syslog(pamh, LOG_WARNING,
     386  		       "unexpected response from failed conversation function");
     387  	/*
     388  	 * note 'resp' is allocated by the application and is
     389           * correctly free()'d here
     390  	 */
     391  	pam_drop_response(resp, 1);
     392      }
     393  
     394      D(("completed"));
     395      return retval;        /* pass on any error from conversation */
     396  }