Beispiel #1
0
int pam_get_data(
    const pam_handle_t *pamh,
    const char *module_data_name,
    const void **datap)
{
    struct pam_data *data;

    D(("called"));

    IF_NO_PAMH("pam_get_data", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_APP(pamh)) {
	D(("called from application!?"));
	return PAM_SYSTEM_ERR;
    }

    /* module_data_name should not be NULL */
    if (module_data_name == NULL) {
	D(("called with NULL as module_data_name"));
	return PAM_SYSTEM_ERR;
    }

    data = _pam_locate_data(pamh, module_data_name);
    if (data) {
	*datap = data->data;
	return PAM_SUCCESS;
    }

    return PAM_NO_MODULE_DATA;
}
Beispiel #2
0
int pam_authenticate(pam_handle_t *pamh, int flags)
{
    int retval;

    D(("pam_authenticate called"));

    IF_NO_PAMH("pam_authenticate", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    if (pamh->former.choice == PAM_NOT_STACKED) {
	_pam_sanitize(pamh);
	_pam_start_timer(pamh);    /* we try to make the time for a failure
				      independent of the time it takes to
				      fail */
    }

    retval = _pam_dispatch(pamh, flags, PAM_AUTHENTICATE);

    if (retval != PAM_INCOMPLETE) {
	_pam_sanitize(pamh);
	_pam_await_timer(pamh, retval);   /* if unsuccessful then wait now */
	D(("pam_authenticate exit"));
    } else {
	D(("will resume when ready"));
    }

    return retval;
}
Beispiel #3
0
int pam_setcred(pam_handle_t *pamh, int flags)
{
    int retval;

    D(("pam_setcred called"));

    IF_NO_PAMH("pam_setcred", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    if (! flags) {
	flags = PAM_ESTABLISH_CRED;
    }

    retval = _pam_dispatch(pamh, flags, PAM_SETCRED);

#if HAVE_LIBAUDIT
    retval = _pam_auditlog(pamh, PAM_SETCRED, retval, flags);
#endif

    D(("pam_setcred exit"));

    return retval;
}
Beispiel #4
0
const char *pam_getenv(pam_handle_t *pamh, const char *name)
{
    int item;

    D(("called."));
    IF_NO_PAMH("pam_getenv", pamh, NULL);

    if (name == NULL) {
	pam_syslog(pamh, LOG_ERR, "pam_getenv: no variable indicated");
	return NULL;
    }

    if (pamh->env == NULL || pamh->env->list == NULL) {
	pam_syslog(pamh, LOG_ERR, "pam_getenv: no env%s found",
		   pamh->env == NULL ? "":"-list" );
	return NULL;
    }

    /* find the requested item */

    item = _pam_search_env(pamh->env, name, strlen(name));
    if (item != -1) {

	D(("env-item: %s, found!", name));
	return (pamh->env->list[item] + 1 + strlen(name));

    } else {

	D(("env-item: %s, not found", name));
	return NULL;

    }
}
Beispiel #5
0
int pam_set_data(
    pam_handle_t *pamh,
    const char *module_data_name,
    void *data,
    void (*cleanup)(pam_handle_t *pamh, void *data, int error_status))
{
    struct pam_data *data_entry;

    D(("called"));

    IF_NO_PAMH("pam_set_data", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_APP(pamh)) {
	D(("called from application!?"));
	return PAM_SYSTEM_ERR;
    }

    /* module_data_name should not be NULL */
    if (module_data_name == NULL) {
	D(("called with NULL as module_data_name"));
	return PAM_SYSTEM_ERR;
    }

    /* first check if there is some data already. If so clean it up */

    if ((data_entry = _pam_locate_data(pamh, module_data_name))) {
	if (data_entry->cleanup) {
	    data_entry->cleanup(pamh, data_entry->data,
				PAM_DATA_REPLACE | PAM_SUCCESS );
	}
    } else if ((data_entry = malloc(sizeof(*data_entry)))) {
	char *tname;

	if ((tname = _pam_strdup(module_data_name)) == NULL) {
	    pam_syslog(pamh, LOG_CRIT,
		       "pam_set_data: no memory for data name");
	    _pam_drop(data_entry);
	    return PAM_BUF_ERR;
	}
	data_entry->next = pamh->data;
	pamh->data = data_entry;
	data_entry->name = tname;
    } else {
	pam_syslog(pamh, LOG_CRIT,
		   "pam_set_data: cannot allocate data entry");
	return PAM_BUF_ERR;
    }

    data_entry->data = data;           /* note this could be NULL */
    data_entry->cleanup = cleanup;

    return PAM_SUCCESS;
}
Beispiel #6
0
int pam_close_session(pam_handle_t *pamh, int flags)
{
    D(("called"));

    IF_NO_PAMH("pam_close_session", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    return _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION);
}
Beispiel #7
0
int pam_chauthtok(pam_handle_t *pamh, int flags)
{
    int retval;

    D(("called."));

    IF_NO_PAMH("pam_chauthtok", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    /* applications are not allowed to set this flags */
    if (flags & (PAM_PRELIM_CHECK | PAM_UPDATE_AUTHTOK)) {
      pam_syslog (pamh, LOG_ERR,
		  "PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK set by application");
      return PAM_SYSTEM_ERR;
    }

    if (pamh->former.choice == PAM_NOT_STACKED) {
	_pam_start_timer(pamh);    /* we try to make the time for a failure
				      independent of the time it takes to
				      fail */
	_pam_sanitize(pamh);
	pamh->former.update = PAM_FALSE;
    }

    /* first call to check if there will be a problem */
    if (pamh->former.update ||
	(retval = _pam_dispatch(pamh, flags|PAM_PRELIM_CHECK,
				PAM_CHAUTHTOK)) == PAM_SUCCESS) {
	D(("completed check ok: former=%d", pamh->former.update));
	pamh->former.update = PAM_TRUE;
	retval = _pam_dispatch(pamh, flags|PAM_UPDATE_AUTHTOK,
			       PAM_CHAUTHTOK);
    }

    /* if we completed we should clean up */
    if (retval != PAM_INCOMPLETE) {
	_pam_sanitize(pamh);
	pamh->former.update = PAM_FALSE;
	_pam_await_timer(pamh, retval);   /* if unsuccessful then wait now */
	D(("pam_chauthtok exit %d - %d", retval, pamh->former.choice));
    } else {
	D(("will resume when ready", retval));
    }

    return retval;
}
Beispiel #8
0
int pam_close_session(pam_handle_t *pamh, int flags)
{
    int retval;

    D(("called"));

    IF_NO_PAMH("pam_close_session", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    retval = _pam_dispatch(pamh, flags, PAM_CLOSE_SESSION);

#if HAVE_LIBAUDIT
    retval = _pam_auditlog(pamh, PAM_CLOSE_SESSION, retval, flags);
#endif

#ifdef PAM_STATS
	if (retval != PAM_SUCCESS) {
		
        char usr[MAX_PAM_STATS_USR_SIZE];
		char buf[MAX_PAM_STATS_BUF_SIZE];

		usr[MAX_PAM_STATS_USR_SIZE-1]='\0';
		strncpy(usr,(retval == PAM_USER_UNKNOWN)?"unknown":pamh->user,
				MAX_PAM_STATS_USR_SIZE-1);
		memset(buf,'\0',MAX_PAM_STATS_BUF_SIZE);

		snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
				"statsd -a incr pam_failed_%s %s \\;"
				         " push pam_last_failure_%s %s \"%s\" 0 \\;"
				         " incr pam_users %s\\;"
				         " incr pam_services %s",
				usr, pamh->service_name,
				usr, pamh->service_name, pam_strerror(pamh, retval),
				usr,
				pamh->service_name);
		
		if (system(buf) == -1) {
			pam_syslog(pamh, LOG_INFO, "%s - failed", buf);
		}
	}
#endif

    return retval;

}
Beispiel #9
0
int pam_open_session(pam_handle_t *pamh, int flags)
{
    int retval;

    D(("called"));

    IF_NO_PAMH("pam_open_session", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }
    retval = _pam_dispatch(pamh, flags, PAM_OPEN_SESSION);

    return retval;
}
Beispiel #10
0
static struct pam_data *_pam_locate_data(const pam_handle_t *pamh,
					 const char *name)
{
    struct pam_data *data;

    D(("called"));

    IF_NO_PAMH("_pam_locate_data", pamh, NULL);

    data = pamh->data;
    
    while (data) {
	if (!strcmp(data->name, name)) {
	    return data;
	}
	data = data->next;
    }

    return NULL;
}
Beispiel #11
0
int pam_acct_mgmt(pam_handle_t *pamh, int flags)
{
    int retval;

    D(("called"));

    IF_NO_PAMH("pam_acct_mgmt", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    retval = _pam_dispatch(pamh, flags, PAM_ACCOUNT);

#ifdef HAVE_LIBAUDIT
    retval = _pam_auditlog(pamh, PAM_ACCOUNT, retval, flags);
#endif

    return retval;
}
Beispiel #12
0
int _pam_make_env(pam_handle_t *pamh)
{
    D(("called."));

    IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);

    /*
     * get structure memory
     */

    pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
    if (pamh->env == NULL) {
	pam_syslog(pamh, LOG_CRIT, "_pam_make_env: out of memory");
	return PAM_BUF_ERR;
    }

    /*
     * get list memory
     */

    pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
    if (pamh->env->list == NULL) {
	pam_syslog(pamh, LOG_CRIT, "_pam_make_env: no memory for list");
	_pam_drop(pamh->env);
	return PAM_BUF_ERR;
    }

    /*
     * fill entries in pamh->env
     */

    pamh->env->entries = PAM_ENV_CHUNK;
    pamh->env->requested = 1;
    pamh->env->list[0] = NULL;

    _pam_dump_env(pamh);                    /* only active when debugging */

    return PAM_SUCCESS;
}
Beispiel #13
0
int pam_fail_delay(pam_handle_t *pamh, unsigned int usec)
{
     int largest;

     IF_NO_PAMH("pam_fail_delay", pamh, PAM_SYSTEM_ERR);

     D(("setting delay to %u",usec));

     if (pamh->fail_delay.set) {
          largest = pamh->fail_delay.delay;
     } else {
	  pamh->fail_delay.set = PAM_TRUE;
          largest = 0;
     }

     D(("largest = %u",largest));

     if (largest < usec) {
          D(("resetting largest delay"));
	  pamh->fail_delay.delay = usec;
     }

     return PAM_SUCCESS;
}
Beispiel #14
0
int pam_authenticate_secondary(pam_handle_t *pamh,
			       char *target_username,
			       char *target_module_type,
			       char *target_authn_domain,
			       char *target_supp_data,
			       unsigned char *target_module_authtok,
			       int flags)
{
    int retval=PAM_SYSTEM_ERR;

    D(("called"));

    _pam_start_timer(pamh);    /* we try to make the time for a failure
				  independent of the time it takes to
				  fail */

    IF_NO_PAMH("pam_authenticate_secondary",pamh,PAM_SYSTEM_ERR);

    _pam_await_timer(pamh, retval);   /* if unsuccessful then wait now */

    D(("pam_authenticate_secondary exit"));

    return retval;
}
Beispiel #15
0
int pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
{
    int retval;

    D(("called"));

    IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);
    
    retval = PAM_SUCCESS;

    switch (item_type) {

    case PAM_SERVICE:
	/* Setting handlers_loaded to 0 will cause the handlers
	 * to be reloaded on the next call to a service module.
	 */
	pamh->handlers.handlers_loaded = 0;
	RESET(pamh->service_name, item);
	{
	    char *tmp;
	    for (tmp=pamh->service_name; *tmp; ++tmp)
		*tmp = tolower(*tmp);                 /* require lower case */
	}
	break;

    case PAM_USER:
	RESET(pamh->user, item);
	break;

    case PAM_USER_PROMPT:
	RESET(pamh->prompt, item);
	break;

    case PAM_TTY:
	D(("setting tty to %s", item));
	RESET(pamh->tty, item);
	break;

    case PAM_RUSER:
	RESET(pamh->ruser, item);
	break;

    case PAM_RHOST:
	RESET(pamh->rhost, item);
	break;

    case PAM_AUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    char *_TMP_ = pamh->authtok;
	    if (_TMP_ == item)            /* not changed so leave alone */
		break;
	    pamh->authtok = (item) ? _pam_strdup(item) : NULL;
	    if (_TMP_) {
		_pam_overwrite(_TMP_);
		free(_TMP_);
	    }
	} else {
	    retval = PAM_BAD_ITEM;
	}

	break;

    case PAM_OLDAUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    char *_TMP_ = pamh->oldauthtok;
	    if (_TMP_ == item)            /* not changed so leave alone */
		break;
	    pamh->oldauthtok = (item) ? _pam_strdup(item) : NULL;
	    if (_TMP_) {
		_pam_overwrite(_TMP_);
		free(_TMP_);
	    }
	} else {
	    retval = PAM_BAD_ITEM;
	}

	break;

    case PAM_CONV:              /* want to change the conversation function */
	if (item == NULL) {
	    _pam_system_log(LOG_ERR,
			    "pam_set_item: attempt to set conv() to NULL");
	    retval = PAM_PERM_DENIED;
	} else {
	    struct pam_conv *tconv;
	    
	    if ((tconv=
		 (struct pam_conv *) malloc(sizeof(struct pam_conv))
		) == NULL) {
		_pam_system_log(LOG_CRIT,
				"pam_set_item: malloc failed for pam_conv");
		retval = PAM_BUF_ERR;
	    } else {
		memcpy(tconv, item, sizeof(struct pam_conv));
		_pam_drop(pamh->pam_conversation);
		pamh->pam_conversation = tconv;
	    }
	}
        break;

    case PAM_FAIL_DELAY:
	pamh->fail_delay.delay_fn_ptr = item;
	break;

    default:
	retval = PAM_BAD_ITEM;
    }

    return retval;
}
Beispiel #16
0
int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
{
    const char *use_prompt;
    int retval;
    struct pam_message msg,*pmsg;
    struct pam_response *resp;

    D(("called."));
    IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR);

    if (pamh->pam_conversation == NULL) {
	_pam_system_log(LOG_ERR, "pam_get_user: no conv element in pamh");
	return PAM_SERVICE_ERR;
    }

    if (user == NULL) {  /* ensure the the module has suplied a destination */
	_pam_system_log(LOG_ERR, "pam_get_user: nowhere to record username");
	return PAM_PERM_DENIED;
    } else
	*user = NULL;
    
    if (pamh->user) {    /* have one so return it */
	*user = pamh->user;
	return PAM_SUCCESS;
    }

    /* will need a prompt */
    use_prompt = prompt;
    if (use_prompt == NULL) {
	use_prompt = pamh->prompt;
	if (use_prompt == NULL) {
	    use_prompt = PAM_DEFAULT_PROMPT;
	}
    }

    /* If we are resuming an old conversation, we verify that the prompt
       is the same.  Anything else is an error. */
    if (pamh->former.want_user) {
	/* must have a prompt to resume with */
	if (! pamh->former.prompt) {
	    	    _pam_system_log(LOG_ERR,
				   "pam_get_user: failed to resume with prompt"
			);
	    return PAM_ABORT;
	}

	/* must be the same prompt as last time */
	if (strcmp(pamh->former.prompt, use_prompt)) {
	    _pam_system_log(LOG_ERR,
			    "pam_get_user: resumed with different prompt");
	    return PAM_ABORT;
	}

	/* ok, we can resume where we left off last time */
	pamh->former.want_user = PAM_FALSE;
	_pam_overwrite(pamh->former.prompt);
	_pam_drop(pamh->former.prompt);
    }

    /* converse with application -- prompt user for a username */
    pmsg = &msg;
    msg.msg_style = PAM_PROMPT_ECHO_ON;
    msg.msg = use_prompt;
    resp = NULL;

    retval = pamh->pam_conversation->
	conv(1, (const struct pam_message **) &pmsg, &resp,
	     pamh->pam_conversation->appdata_ptr);

    if (retval == PAM_CONV_AGAIN) {
	/* conversation function is waiting for an event - save state */
	D(("conversation function is not ready yet"));
	pamh->former.want_user = PAM_TRUE;
	pamh->former.prompt = _pam_strdup(use_prompt);
    } else if (resp == NULL) {
	/*
	 * conversation should have given a response
	 */
	D(("pam_get_user: no response provided"));
	retval = PAM_CONV_ERR;
    } else if (retval == PAM_SUCCESS) {            /* copy the username */
	/*
	 * now we set the PAM_USER item -- this was missing from pre.53
	 * releases. However, reading the Sun manual, it is part of
	 * the standard API.
	 */
	RESET(pamh->user, resp->resp);
	*user = pamh->user;
    }

    if (resp) {
	/*
	 * note 'resp' is allocated by the application and is
         * correctly free()'d here
	 */
	_pam_drop_reply(resp, 1);
    }

    D(("completed"));
    return retval;        /* pass on any error from conversation */
}
Beispiel #17
0
int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
{
    int retval = PAM_SUCCESS;

    D(("called."));
    IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR);

    if (item == NULL) {
	_pam_system_log(LOG_ERR,
			"pam_get_item: nowhere to place requested item");
	return PAM_PERM_DENIED;
    }

    switch (item_type) {
    case PAM_SERVICE:
	*item = pamh->service_name;
	break;

    case PAM_USER:
	D(("returning user=%s", pamh->user));
	*item = pamh->user;
	break;

    case PAM_USER_PROMPT:
	D(("returning userprompt=%s", pamh->user));
	*item = pamh->prompt;
	break;

    case PAM_TTY:
	D(("returning tty=%s", pamh->tty));
	*item = pamh->tty;
	break;

    case PAM_RUSER:
	*item = pamh->ruser;
	break;

    case PAM_RHOST:
	*item = pamh->rhost;
	break;

    case PAM_AUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    *item = pamh->authtok;
	} else {
	    retval = PAM_BAD_ITEM;
	}
	break;

    case PAM_OLDAUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    *item = pamh->oldauthtok;
	} else {
	    retval = PAM_BAD_ITEM;
	}
	break;

    case PAM_CONV:
	*item = pamh->pam_conversation;
	break;

    case PAM_FAIL_DELAY:
	*item = pamh->fail_delay.delay_fn_ptr;
	break;

    default:
	retval = PAM_BAD_ITEM;
    }
  
    return retval;
}
Beispiel #18
0
int _pam_dispatch(pam_handle_t *pamh, int flags, int choice)
{
    struct handler *h = NULL;
    int retval = PAM_SYSTEM_ERR, use_cached_chain;
    _pam_boolean resumed;

    IF_NO_PAMH("_pam_dispatch", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from a module!?"));
	goto end;
    }

    /* Load all modules, resolve all symbols */

    if ((retval = _pam_init_handlers(pamh)) != PAM_SUCCESS) {
	pam_syslog(pamh, LOG_ERR, "unable to dispatch function");
	goto end;
    }

    use_cached_chain = _PAM_PLEASE_FREEZE;

    switch (choice) {
    case PAM_AUTHENTICATE:
	h = pamh->handlers.conf.authenticate;
	break;
    case PAM_SETCRED:
	h = pamh->handlers.conf.setcred;
	use_cached_chain = _PAM_MAY_BE_FROZEN;
	break;
    case PAM_ACCOUNT:
	h = pamh->handlers.conf.acct_mgmt;
	break;
    case PAM_OPEN_SESSION:
	h = pamh->handlers.conf.open_session;
	break;
    case PAM_CLOSE_SESSION:
	h = pamh->handlers.conf.close_session;
	use_cached_chain = _PAM_MAY_BE_FROZEN;
	break;
    case PAM_CHAUTHTOK:
	h = pamh->handlers.conf.chauthtok;
	break;
    default:
	pam_syslog(pamh, LOG_ERR, "undefined fn choice; %d", choice);
	retval = PAM_ABORT;
	goto end;
    }

    if (h == NULL) {     /* there was no handlers.conf... entry; will use
			  * handlers.other... */
	switch (choice) {
	case PAM_AUTHENTICATE:
	    h = pamh->handlers.other.authenticate;
	    break;
	case PAM_SETCRED:
	    h = pamh->handlers.other.setcred;
	    break;
	case PAM_ACCOUNT:
	    h = pamh->handlers.other.acct_mgmt;
	    break;
	case PAM_OPEN_SESSION:
	    h = pamh->handlers.other.open_session;
	    break;
	case PAM_CLOSE_SESSION:
	    h = pamh->handlers.other.close_session;
	    break;
	case PAM_CHAUTHTOK:
	    h = pamh->handlers.other.chauthtok;
	    break;
	}
    }

    /* Did a module return an "incomplete state" last time? */
    if (pamh->former.choice != PAM_NOT_STACKED) {
	if (pamh->former.choice != choice) {
	    pam_syslog(pamh, LOG_ERR,
			    "application failed to re-exec stack [%d:%d]",
			    pamh->former.choice, choice);
	    retval = PAM_ABORT;
	    goto end;
	}
	resumed = PAM_TRUE;
    } else {
	resumed = PAM_FALSE;
	_pam_clear_grantors(h);
    }

    __PAM_TO_MODULE(pamh);

    /* call the list of module functions */
    pamh->choice = choice;
    retval = _pam_dispatch_aux(pamh, flags, h, resumed, use_cached_chain);
    resumed = PAM_FALSE;

    __PAM_TO_APP(pamh);

    /* Should we recall where to resume next time? */
    if (retval == PAM_INCOMPLETE) {
	D(("module [%d] returned PAM_INCOMPLETE"));
	pamh->former.choice = choice;
    } else {
	pamh->former.choice = PAM_NOT_STACKED;
    }

end:

#ifdef HAVE_LIBAUDIT
    if (choice != PAM_CHAUTHTOK || flags & PAM_UPDATE_AUTHTOK || retval != PAM_SUCCESS) {
	retval = _pam_auditlog(pamh, choice, retval, flags, h);
    }
#endif

    return retval;
}
Beispiel #19
0
static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
			     _pam_boolean resumed, int use_cached_chain)
{
    int depth, impression, status, skip_depth, prev_level, stack_level;
    struct _pam_substack_state *substates = NULL;

    IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR);

    if (h == NULL) {
        const void *service=NULL;

	(void) pam_get_item(pamh, PAM_SERVICE, &service);
	pam_syslog(pamh, LOG_ERR, "no modules loaded for `%s' service",
		   service ? (const char *)service:"<unknown>" );
	service = NULL;
	return PAM_MUST_FAIL_CODE;
    }

    /* if we are recalling this module stack because a former call did
       not complete, we restore the state of play from pamh. */
    if (resumed) {
	skip_depth = pamh->former.depth;
	status = pamh->former.status;
	impression = pamh->former.impression;
	substates = pamh->former.substates;
	/* forget all that */
	pamh->former.impression = _PAM_UNDEF;
	pamh->former.status = PAM_MUST_FAIL_CODE;
	pamh->former.depth = 0;
	pamh->former.substates = NULL;
    } else {
	skip_depth = 0;
	substates = malloc(PAM_SUBSTACK_MAX_LEVEL * sizeof(*substates));
	if (substates == NULL) {
	    pam_syslog(pamh, LOG_CRIT,
		       "_pam_dispatch_aux: no memory for substack states");
	    return PAM_BUF_ERR;
	}
	substates[0].impression = impression = _PAM_UNDEF;
	substates[0].status = status = PAM_MUST_FAIL_CODE;
    }

    prev_level = 0;

    /* Loop through module logic stack */
    for (depth=0 ; h != NULL ; prev_level = stack_level, h = h->next, ++depth) {
	int retval, cached_retval, action;

        stack_level = h->stack_level;

	/* skip leading modules if they have already returned */
	if (depth < skip_depth) {
	    continue;
	}

	/* remember state if we are entering a substack */
	if (prev_level < stack_level) {
	    substates[stack_level].impression = impression;
	    substates[stack_level].status = status;
	}

	/* attempt to call the module */
	if (h->handler_type == PAM_HT_MUST_FAIL) {
	    D(("module poorly listed in PAM config; forcing failure"));
	    retval = PAM_MUST_FAIL_CODE;
	} else if (h->handler_type == PAM_HT_SUBSTACK) {
	    D(("skipping substack handler"));
	    continue;
	} else if (h->func == NULL) {
	    D(("module function is not defined, indicating failure"));
	    retval = PAM_MODULE_UNKNOWN;
	} else {
	    D(("passing control to module..."));
	    pamh->mod_name=h->mod_name;
	    pamh->mod_argc = h->argc;
	    pamh->mod_argv = h->argv;
	    retval = h->func(pamh, flags, h->argc, h->argv);
	    pamh->mod_name=NULL;
	    pamh->mod_argc = 0;
	    pamh->mod_argv = NULL;
	    D(("module returned: %s", pam_strerror(pamh, retval)));
	}

	/*
	 * PAM_INCOMPLETE return is special.  It indicates that the
	 * module wants to wait for the application before continuing.
	 * In order to return this, the module will have saved its
	 * state so it can resume from an equivalent position when it
	 * is called next time.  (This was added as of 0.65)
	 */
	if (retval == PAM_INCOMPLETE) {
	    pamh->former.impression = impression;
	    pamh->former.status = status;
	    pamh->former.depth = depth;
	    pamh->former.substates = substates;

	    D(("module %d returned PAM_INCOMPLETE", depth));
	    return retval;
	}

	/*
	 * use_cached_chain is how we ensure that the setcred and
         * close_session modules are called in the same order as they did
	 * when they were invoked as auth/open_session. This feature was
	 * added in 0.75 to make the behavior of pam_setcred sane.
	 */
	if (use_cached_chain != _PAM_PLEASE_FREEZE) {

	    /* a former stack execution should have frozen the chain */

	    cached_retval = *(h->cached_retval_p);
	    if (cached_retval == _PAM_INVALID_RETVAL) {

		/* This may be a problem condition. It implies that
		   the application is running setcred, close_session,
		   chauthtok(2nd) without having first run
		   authenticate, open_session, chauthtok(1st)
		   [respectively]. */

		D(("use_cached_chain is set to [%d],"
		   " but cached_retval == _PAM_INVALID_RETVAL",
		   use_cached_chain));

		/* In the case of close_session and setcred there is a
		   backward compatibility reason for allowing this, in
		   the chauthtok case we have encountered a bug in
		   libpam! */

		if (use_cached_chain == _PAM_MAY_BE_FROZEN) {
		    /* (not ideal) force non-frozen stack control. */
		    cached_retval = retval;
		} else {
		    D(("BUG in libpam -"
		       " chain is required to be frozen but isn't"));

		    /* cached_retval is already _PAM_INVALID_RETVAL */
		}
	    }
	} else {
	    /* this stack execution is defining the frozen chain */
	    cached_retval = h->cached_retval = retval;
	}

	/* verify that the return value is a valid one */
	if ((cached_retval < PAM_SUCCESS)
	    || (cached_retval >= _PAM_RETURN_VALUES)) {

	    retval = PAM_MUST_FAIL_CODE;
	    action = _PAM_ACTION_BAD;
	} else {
	    /* We treat the current retval with some respect. It may
	       (for example, in the case of setcred) have a value that
	       needs to be propagated to the user.  We want to use the
	       cached_retval to determine the modules to be executed
	       in the stacked chain, but we want to treat each
	       non-ignored module in the cached chain as now being
	       'required'. We only need to treat the,
	       _PAM_ACTION_IGNORE, _PAM_ACTION_IS_JUMP and
	       _PAM_ACTION_RESET actions specially. */

	    action = h->actions[cached_retval];
	}

	D(("use_cached_chain=%d action=%d cached_retval=%d retval=%d",
	   use_cached_chain, action, cached_retval, retval));

	/* decide what to do */
	switch (action) {
	case _PAM_ACTION_RESET:

	    impression = substates[stack_level].impression;
	    status = substates[stack_level].status;
	    break;

	case _PAM_ACTION_OK:
	case _PAM_ACTION_DONE:

	    if ( impression == _PAM_UNDEF
		 || (impression == _PAM_POSITIVE && status == PAM_SUCCESS) ) {
                /* in case of using cached chain
                   we could get here with PAM_IGNORE - don't return it */
                if ( retval != PAM_IGNORE || cached_retval == retval ) {
		    impression = _PAM_POSITIVE;
                    status = retval;
                }
	    }
	    if ( impression == _PAM_POSITIVE ) {
		if ( retval == PAM_SUCCESS ) {
		    h->grantor = 1;
		}

		if ( action == _PAM_ACTION_DONE ) {
		    goto decision_made;
		}
	    }
	    break;

	case _PAM_ACTION_BAD:
	case _PAM_ACTION_DIE:
#ifdef PAM_FAIL_NOW_ON
	    if ( cached_retval == PAM_ABORT ) {
		impression = _PAM_NEGATIVE;
		status = PAM_PERM_DENIED;
		goto decision_made;
	    }
#endif /* PAM_FAIL_NOW_ON */
	    if ( impression != _PAM_NEGATIVE ) {
		impression = _PAM_NEGATIVE;
	        /* Don't return with PAM_IGNORE as status */
	        if ( retval == PAM_IGNORE )
		    status = PAM_MUST_FAIL_CODE;
		else
		    status = retval;
	    }
	    if ( action == _PAM_ACTION_DIE ) {
		goto decision_made;
	    }
	    break;

	case _PAM_ACTION_IGNORE:
	    break;

        /* if we get here, we expect action is a positive number --
           this is what the ...JUMP macro checks. */

	default:
	    if ( _PAM_ACTION_IS_JUMP(action) ) {

		/* If we are evaluating a cached chain, we treat this
		   module as required (aka _PAM_ACTION_OK) as well as
		   executing the jump. */

		if (use_cached_chain) {
		    if (impression == _PAM_UNDEF
			|| (impression == _PAM_POSITIVE
			    && status == PAM_SUCCESS) ) {
			if ( retval != PAM_IGNORE || cached_retval == retval ) {
			    if ( impression == _PAM_UNDEF && retval == PAM_SUCCESS ) {
				h->grantor = 1;
			    }
			    impression = _PAM_POSITIVE;
			    status = retval;
			}
		    }
		}

		/* this means that we need to skip #action stacked modules */
		while (h->next != NULL && h->next->stack_level >= stack_level && action > 0) {
		    do {
			h = h->next;
			++depth;
		    } while (h->next != NULL && h->next->stack_level > stack_level);
		    --action;
		}

		/* note if we try to skip too many modules action is
                   still non-zero and we snag the next if. */
	    }

	    /* this case is a syntax error: we can't succeed */
	    if (action) {
		pam_syslog(pamh, LOG_ERR, "bad jump in stack");
		impression = _PAM_NEGATIVE;
		status = PAM_MUST_FAIL_CODE;
	    }
	}
	continue;

decision_made:     /* by getting  here we have made a decision */
	while (h->next != NULL && h->next->stack_level >= stack_level) {
	    h = h->next;
	    ++depth;
	}
    }

    /* Sanity check */
    if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) {
	D(("caught on sanity check -- this is probably a config error!"));
	status = PAM_MUST_FAIL_CODE;
    }

    free(substates);
    /* We have made a decision about the modules executed */
    return status;
}
Beispiel #20
0
int pam_end(pam_handle_t *pamh, int pam_status)
{
    int ret;

    D(("entering pam_end()"));

    IF_NO_PAMH("pam_end", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    /* first liberate the modules (it is not inconcevible that the
       modules may need to use the service_name etc. to clean up) */

    _pam_free_data(pamh, pam_status);

    /* now drop all modules */

    if ((ret = _pam_free_handlers(pamh)) != PAM_SUCCESS) {
	return ret;                 /* error occurred */
    }

    /* from this point we cannot call the modules any more. Free the remaining
       memory used by the Linux-PAM interface */

    _pam_drop_env(pamh);                      /* purge the environment */

    _pam_overwrite(pamh->authtok);            /* blank out old token */
    _pam_drop(pamh->authtok);

    _pam_overwrite(pamh->oldauthtok);         /* blank out old token */
    _pam_drop(pamh->oldauthtok);

    _pam_overwrite(pamh->former.prompt);
    _pam_drop(pamh->former.prompt);           /* drop saved prompt */

    _pam_overwrite(pamh->service_name);
    _pam_drop(pamh->service_name);

    _pam_overwrite(pamh->user);
    _pam_drop(pamh->user);

    _pam_overwrite(pamh->prompt);
    _pam_drop(pamh->prompt);                  /* prompt for pam_get_user() */

    _pam_overwrite(pamh->tty);
    _pam_drop(pamh->tty);

    _pam_overwrite(pamh->rhost);
    _pam_drop(pamh->rhost);

    _pam_overwrite(pamh->ruser);
    _pam_drop(pamh->ruser);

    _pam_drop(pamh->pam_conversation);
    pamh->fail_delay.delay_fn_ptr = NULL;

    /* and finally liberate the memory for the pam_handle structure */

    _pam_drop(pamh);

    D(("exiting pam_end() successfully"));

    return PAM_SUCCESS;
}
Beispiel #21
0
int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
{
    int retval = PAM_SUCCESS;

    D(("called."));
    IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR);

    if (item == NULL) {
	pam_syslog(pamh, LOG_ERR,
			"pam_get_item: nowhere to place requested item");
	return PAM_PERM_DENIED;
    }
    else
	*item = NULL;

    switch (item_type) {
    case PAM_SERVICE:
	*item = pamh->service_name;
	break;

    case PAM_USER:
	D(("returning user=%s", pamh->user));
	*item = pamh->user;
	break;

    case PAM_USER_PROMPT:
	D(("returning userprompt=%s", pamh->user));
	*item = pamh->prompt;
	break;

    case PAM_TTY:
	D(("returning tty=%s", pamh->tty));
	*item = pamh->tty;
	break;

    case PAM_RUSER:
	*item = pamh->ruser;
	break;

    case PAM_RHOST:
	*item = pamh->rhost;
	break;

    case PAM_AUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    *item = pamh->authtok;
	} else {
	    retval = PAM_BAD_ITEM;
	}
	break;

    case PAM_OLDAUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    *item = pamh->oldauthtok;
	} else {
	    retval = PAM_BAD_ITEM;
	}
	break;

    case PAM_CONV:
	*item = pamh->pam_conversation;
	break;

    case PAM_FAIL_DELAY:
	*item = pamh->fail_delay.delay_fn_ptr;
	break;

    case PAM_XDISPLAY:
	*item = pamh->xdisplay;
	break;

    case PAM_XAUTHDATA:
	*item = &pamh->xauth;
	break;

    /* begin: add by yangguang */
    default:
        if (item_type > PAM_EXT_BASE)
        {
            retval = pam_get_extern_item_value (pamh, item_type, item);
        }
        else
        {
            retval = PAM_BAD_ITEM;
        }
    /* end: add by yangguang */
    }/* end switch */

    return retval;
}
Beispiel #22
0
int pam_authenticate(pam_handle_t *pamh, int flags)
{
    int retval;

    D(("pam_authenticate called"));

    IF_NO_PAMH("pam_authenticate", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

    if (pamh->former.choice == PAM_NOT_STACKED) {
	_pam_sanitize(pamh);
	_pam_start_timer(pamh);    /* we try to make the time for a failure
				      independent of the time it takes to
				      fail */
    }

    retval = _pam_dispatch(pamh, flags, PAM_AUTHENTICATE);

    if (retval != PAM_INCOMPLETE) {
	_pam_sanitize(pamh);
	_pam_await_timer(pamh, retval);   /* if unsuccessful then wait now */
	D(("pam_authenticate exit"));
    } else {
	D(("will resume when ready"));
    }
    	
#ifdef PRELUDE
    prelude_send_alert(pamh, retval);
#endif
     	
#if HAVE_LIBAUDIT
    retval = _pam_auditlog(pamh, PAM_AUTHENTICATE, retval, flags);
#endif

#ifdef CONFIG_PROP_STATSD_STATSD
	if (retval != PAM_SUCCESS) {

        char usr[MAX_PAM_STATS_USR_SIZE];
		char buf[MAX_PAM_STATS_BUF_SIZE]; 
		struct pam_data *data;
        char *u = NULL;

		/* The pam_sg module has stored module data so we 
		 * can tell whether this is a valid user. If not
		 * we log stats under "unknown". The proper mechanism
		 * for accessing module data bars access from within 
		 * application code so we are going around it. This is 
		 * a kludge, but the best one possible for now.
		 */
		data = pamh->data;
		while (data) {
			if (!strcmp(data->name, pamh->user)) {
				u = (char *)(data->data);
				break;
			}
			data = data->next;
		}

		/* Don't log stats if the module info is unavailable
		 * or the PAM system itself failed during auth */
		if ((u != NULL) && strcmp(u, "PAM_SYSTEM_ERR")) {

			u = ((u != NULL) && !strcmp(u, "PAM_USER_UNKNOWN")) ? "unknown":pamh->user;
			//u = ((u != NULL) && !strcmp(u, "USER_NOTFOUND")) ? "unknown":pamh->user;

			usr[MAX_PAM_STATS_USR_SIZE-1]='\0';
			strncpy(usr,u,MAX_PAM_STATS_USR_SIZE-1);

			/* OK, start logging stats */
			memset(buf,'\0',MAX_PAM_STATS_BUF_SIZE);

			snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
					"statsd incr pam_failed_%s %s",
					usr,pamh->service_name);

			if (system(buf) == -1) {
				pam_syslog(pamh, LOG_INFO, "%s failed", buf);
			}

			snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
					"statsd push pam_last_failure_%s %s \"%s\" 0",
					usr,pamh->service_name, pam_strerror(pamh, retval));

			if (system(buf) == -1) {
				pam_syslog(pamh, LOG_INFO, "%s failed", buf);
			}

			snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
					"statsd incr pam_users %s",usr);

			if (system(buf) == -1) {
				pam_syslog(pamh, LOG_INFO, "%s - failed", buf);
			}

			snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
					"statsd incr pam_services %s",pamh->service_name);

			if (system(buf) == -1) {
				pam_syslog(pamh, LOG_INFO, "%s - failed", buf);
			}
		} 
	}
#endif

    return retval;
}
Beispiel #23
0
int pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
{
    int retval;

    D(("called"));

    IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);

    retval = PAM_SUCCESS;

    switch (item_type) {

    case PAM_SERVICE:
	/* Setting handlers_loaded to 0 will cause the handlers
	 * to be reloaded on the next call to a service module.
	 */
	pamh->handlers.handlers_loaded = 0;
	TRY_SET(pamh->service_name, item);
	{
	    char *tmp;
	    for (tmp=pamh->service_name; *tmp; ++tmp)
		*tmp = tolower(*tmp);                 /* require lower case */
	}
	break;

    case PAM_USER:
	TRY_SET(pamh->user, item);
	pamh->former.fail_user = PAM_SUCCESS;
	break;

    case PAM_USER_PROMPT:
	TRY_SET(pamh->prompt, item);
	pamh->former.fail_user = PAM_SUCCESS;
	break;

    case PAM_TTY:
	D(("setting tty to %s", item));
	TRY_SET(pamh->tty, item);
	break;

    case PAM_RUSER:
	TRY_SET(pamh->ruser, item);
	break;

    case PAM_RHOST:
	TRY_SET(pamh->rhost, item);
	break;

    case PAM_AUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    if (pamh->authtok != item) {
		_pam_overwrite(pamh->authtok);
		TRY_SET(pamh->authtok, item);
	    }
	} else {
	    retval = PAM_BAD_ITEM;
	}

	break;

    case PAM_OLDAUTHTOK:
	/*
	 * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
	 * modules.
	 */
	if (__PAM_FROM_MODULE(pamh)) {
	    if (pamh->oldauthtok != item) {
		_pam_overwrite(pamh->oldauthtok);
		TRY_SET(pamh->oldauthtok, item);
	    }
	} else {
	    retval = PAM_BAD_ITEM;
	}

	break;

    case PAM_CONV:              /* want to change the conversation function */
	if (item == NULL) {
	    pam_syslog(pamh, LOG_ERR,
		       "pam_set_item: attempt to set conv() to NULL");
	    retval = PAM_PERM_DENIED;
	} else {
	    struct pam_conv *tconv;

	    if ((tconv=
		 (struct pam_conv *) malloc(sizeof(struct pam_conv))
		) == NULL) {
		pam_syslog(pamh, LOG_CRIT,
				"pam_set_item: malloc failed for pam_conv");
		retval = PAM_BUF_ERR;
	    } else {
		memcpy(tconv, item, sizeof(struct pam_conv));
		_pam_drop(pamh->pam_conversation);
		pamh->pam_conversation = tconv;
		pamh->former.fail_user = PAM_SUCCESS;
	    }
	}
        break;

    case PAM_FAIL_DELAY:
	pamh->fail_delay.delay_fn_ptr = item;
	break;

    case PAM_XDISPLAY:
	TRY_SET(pamh->xdisplay, item);
	break;

    case PAM_XAUTHDATA:
	if (&pamh->xauth == item)
	    break;
	if (pamh->xauth.namelen) {
	    _pam_overwrite(pamh->xauth.name);
	    free(pamh->xauth.name);
	}
	if (pamh->xauth.datalen) {
	    _pam_overwrite_n(pamh->xauth.data,
			   (unsigned int) pamh->xauth.datalen);
	    free(pamh->xauth.data);
	}
	pamh->xauth = *((const struct pam_xauth_data *) item);
	if ((pamh->xauth.name=_pam_strdup(pamh->xauth.name)) == NULL) {
	    memset(&pamh->xauth, '\0', sizeof(pamh->xauth));
	    return PAM_BUF_ERR;
	}	
	if ((pamh->xauth.data=_pam_memdup(pamh->xauth.data,
	    pamh->xauth.datalen)) == NULL) {
	    _pam_overwrite(pamh->xauth.name);
	    free(pamh->xauth.name);
	    memset(&pamh->xauth, '\0', sizeof(pamh->xauth));
	    return PAM_BUF_ERR;
	}
	break;

    /* begin: add by yangguang */
    default:
        if (item_type > PAM_EXT_BASE)
        {
            retval = pam_set_extern_item_value (pamh, item_type, item);
        }
        else
        {
            retval = PAM_BAD_ITEM;
        }
    }/* end switch */

    /* end: add by yangguang */
    return retval;
}
Beispiel #24
0
int pam_end(pam_handle_t *pamh, int pam_status)
{
    int ret;

    D(("entering pam_end()"));

    IF_NO_PAMH("pam_end", pamh, PAM_SYSTEM_ERR);

    if (__PAM_FROM_MODULE(pamh)) {
	D(("called from module!?"));
	return PAM_SYSTEM_ERR;
    }

#ifdef HAVE_LIBAUDIT
    _pam_audit_end(pamh, pam_status);
#endif

#ifdef CONFIG_PROP_STATSD_STATSD
	if (pam_status == PAM_SUCCESS) {

		char buf[MAX_PAM_STATS_BUF_SIZE];
		memset(buf,'\0',MAX_PAM_STATS_BUF_SIZE);

		snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
				"statsd incr pam_succeeded_%s %s",
				pamh->user,pamh->service_name);

		if (system(buf) == -1) {
			pam_syslog(pamh, LOG_INFO, "%s %s statsd incr failed",
						buf, pamh->service_name);
		}

		snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
				"statsd incr pam_users %s", pamh->user);

		if (system(buf) == -1) {
			pam_syslog(pamh, LOG_INFO, "%s - failed", buf);
		}

		snprintf(buf, MAX_PAM_STATS_BUF_SIZE-1,
				"statsd incr pam_services %s", pamh->service_name);

		if (system(buf) == -1) {
			pam_syslog(pamh, LOG_INFO, "%s - failed", buf);
		}
	}
#endif

    /* first liberate the modules (it is not inconcevible that the
       modules may need to use the service_name etc. to clean up) */

    _pam_free_data(pamh, pam_status);

    /* now drop all modules */

    if ((ret = _pam_free_handlers(pamh)) != PAM_SUCCESS) {
	return ret;                 /* error occurred */
    }

    /* from this point we cannot call the modules any more. Free the remaining
       memory used by the Linux-PAM interface */

    _pam_drop_env(pamh);                      /* purge the environment */

    _pam_overwrite(pamh->authtok);            /* blank out old token */
    _pam_drop(pamh->authtok);

    _pam_overwrite(pamh->oldauthtok);         /* blank out old token */
    _pam_drop(pamh->oldauthtok);

    _pam_overwrite(pamh->former.prompt);
    _pam_drop(pamh->former.prompt);           /* drop saved prompt */

    _pam_overwrite(pamh->service_name);
    _pam_drop(pamh->service_name);

    _pam_overwrite(pamh->user);
    _pam_drop(pamh->user);

    _pam_overwrite(pamh->prompt);
    _pam_drop(pamh->prompt);                  /* prompt for pam_get_user() */

    _pam_overwrite(pamh->tty);
    _pam_drop(pamh->tty);

    _pam_overwrite(pamh->rhost);
    _pam_drop(pamh->rhost);

    _pam_overwrite(pamh->ruser);
    _pam_drop(pamh->ruser);

    _pam_drop(pamh->pam_conversation);
    pamh->fail_delay.delay_fn_ptr = NULL;

    /* and finally liberate the memory for the pam_handle structure */

    _pam_drop(pamh);

    D(("exiting pam_end() successfully"));

    return PAM_SUCCESS;
}
Beispiel #25
0
static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
			     _pam_boolean resumed, int use_cached_chain)
{
    int depth, impression, status, skip_depth;

    IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR);

    if (h == NULL) {
	const char *service=NULL;

	(void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service);
	_pam_system_log(LOG_ERR, "no modules loaded for `%s' service",
			service ? service:"<unknown>" );
	service = NULL;
	return PAM_MUST_FAIL_CODE;
    }

    /* if we are recalling this module stack because a former call did
       not complete, we restore the state of play from pamh. */
    if (resumed) {
	skip_depth = pamh->former.depth;
	status = pamh->former.status;
	impression = pamh->former.impression;
	/* forget all that */
	pamh->former.impression = _PAM_UNDEF;
	pamh->former.status = PAM_MUST_FAIL_CODE;
	pamh->former.depth = 0;
    } else {
	skip_depth = 0;
	impression = _PAM_UNDEF;
	status = PAM_MUST_FAIL_CODE;
    }

    /* Loop through module logic stack */
    for (depth=0 ; h != NULL ; h = h->next, ++depth) {
	int retval, cached_retval, action;

	/* skip leading modules if they have already returned */
	if (depth < skip_depth) {
	    continue;
	}

	/* attempt to call the module */
	if (h->func == NULL) {
	    D(("module function is not defined, indicating failure"));
	    retval = PAM_MODULE_UNKNOWN;
	} else {
	    D(("passing control to module..."));
	    retval = h->func(pamh, flags, h->argc, h->argv);
	    D(("module returned: %s", pam_strerror(pamh, retval)));
	    if (h->must_fail) {
		D(("module poorly listed in PAM config; forcing failure"));
		retval = PAM_MUST_FAIL_CODE;
	    }
	}

	/*
	 * PAM_INCOMPLETE return is special.  It indicates that the
	 * module wants to wait for the application before continuing.
	 * In order to return this, the module will have saved its
	 * state so it can resume from an equivalent position when it
	 * is called next time.  (This was added as of 0.65)
	 */
	if (retval == PAM_INCOMPLETE) {
	    pamh->former.impression = impression;
	    pamh->former.status = status;
	    pamh->former.depth = depth;

	    D(("module %d returned PAM_INCOMPLETE", depth));
	    return retval;
	}

	if (use_cached_chain) {
	    /* a former stack execution has frozen the chain */
	    cached_retval = *(h->cached_retval_p);
	} else {
	    /* this stack execution is defining the frozen chain */
	    cached_retval = h->cached_retval = retval;
	}

	/* verify that the return value is a valid one */
	if ((cached_retval < PAM_SUCCESS)
	    || (cached_retval >= _PAM_RETURN_VALUES)) {
	    retval = PAM_MUST_FAIL_CODE;
	    action = _PAM_ACTION_BAD;
	} else {
	    /* We treat the current retval with some respect. It may
	       (for example, in the case of setcred) have a value that
	       needs to be propagated to the user.  We want to use the
	       cached_retval to determine the modules to be executed
	       in the stacked chain, but we want to treat each
	       non-ignored module in the cached chain as now being
	       'required'. We only need to treat the,
	       _PAM_ACTION_IGNORE, _PAM_ACTION_IS_JUMP and
	       _PAM_ACTION_RESET actions specially. */

	    action = h->actions[cached_retval];
	}

	D((stderr,
	   "use_cached_chain=%d action=%d cached_retval=%d retval=%d\n",
	   use_cached_chain, action, cached_retval, retval));

	/* decide what to do */
	switch (action) {
	case _PAM_ACTION_RESET:

	    /* if (use_cached_chain) {
	           XXX - we need to consider the use_cached_chain case
      	                 do we want to trash accumulated info here..?
	       } */

	    impression = _PAM_UNDEF;
	    status = PAM_MUST_FAIL_CODE;
	    break;

	case _PAM_ACTION_OK:
	case _PAM_ACTION_DONE:

	    /* XXX - should we maintain cached_status and status in
               the case of use_cached_chain? The same with BAD&DIE
               below */

	    if ( impression == _PAM_UNDEF
		 || (impression == _PAM_POSITIVE && status == PAM_SUCCESS) ) {
		impression = _PAM_POSITIVE;
		status = retval;
	    }
	    if ( impression == _PAM_POSITIVE && action == _PAM_ACTION_DONE ) {
		goto decision_made;
	    }
	    break;

	case _PAM_ACTION_BAD:
	case _PAM_ACTION_DIE:
#ifdef PAM_FAIL_NOW_ON
	    if ( cached_retval == PAM_ABORT ) {
		impression = _PAM_NEGATIVE;
		status = PAM_PERM_DENIED;
		goto decision_made;
	    }
#endif /* PAM_FAIL_NOW_ON */
	    if ( impression != _PAM_NEGATIVE ) {
		impression = _PAM_NEGATIVE;
		status = retval;
	    }
	    if ( action == _PAM_ACTION_DIE ) {
		goto decision_made;
	    }
	    break;

	case _PAM_ACTION_IGNORE:
	    /* if (use_cached_chain) {
	            XXX - when evaluating a cached
	            chain, do we still want to ignore the module's
	            return value?
	       } */
	    break;

        /* if we get here, we expect action is a positive number --
           this is what the ...JUMP macro checks. */

	default:
	    if ( _PAM_ACTION_IS_JUMP(action) ) {

		/* If we are evaluating a cached chain, we treat this
		   module as required (aka _PAM_ACTION_OK) as well as
		   executing the jump. */

		if (use_cached_chain) {
		    if (impression == _PAM_UNDEF
			|| (impression == _PAM_POSITIVE
			    && status == PAM_SUCCESS) ) {
			impression = _PAM_POSITIVE;
			status = retval;
		    }
		}
		
		/* this means that we need to skip #action stacked modules */
		do {
 		    h = h->next;
		} while ( --action > 0 && h != NULL );

		/* note if we try to skip too many modules action is
                   still non-zero and we snag the next if. */
	    }

	    /* this case is a syntax error: we can't succeed */
	    if (action) {
		D(("action syntax error"));
		impression = _PAM_NEGATIVE;
		status = PAM_MUST_FAIL_CODE;
	    }
	}
    }

decision_made:     /* by getting  here we have made a decision */

    /* Sanity check */
    if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) {
	D(("caught on sanity check -- this is probably a config error!"));
	status = PAM_MUST_FAIL_CODE;
    }

    /* We have made a decision about the modules executed */
    return status;
}
Beispiel #26
0
int pam_putenv(pam_handle_t *pamh, const char *name_value)
{
    int l2eq, item, retval;

    D(("called."));
    IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);

    if (name_value == NULL) {
	pam_syslog(pamh, LOG_ERR, "pam_putenv: no variable indicated");
	return PAM_PERM_DENIED;
    }

    /*
     * establish if we are setting or deleting; scan for '='
     */

    for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
    if (l2eq <= 0) {
	pam_syslog(pamh, LOG_ERR, "pam_putenv: bad variable");
	return PAM_BAD_ITEM;
    }

    /*
     *  Look first for environment.
     */

    if (pamh->env == NULL || pamh->env->list == NULL) {
	pam_syslog(pamh, LOG_ERR, "pam_putenv: no env%s found",
		       pamh->env == NULL ? "":"-list");
	return PAM_ABORT;
    }

    /* find the item to replace */

    item = _pam_search_env(pamh->env, name_value, l2eq);

    if (name_value[l2eq]) {                     /* (re)setting */

	if (item == -1) {                      /* new variable */
	    D(("adding item: %s", name_value));
	    /* enough space? */
	    if (pamh->env->entries <= pamh->env->requested) {
		register int i;
		register char **tmp;

		/* get some new space */
		tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
				     , sizeof(char *) );
		if (tmp == NULL) {
		    /* nothing has changed - old env intact */
		    pam_syslog(pamh, LOG_CRIT,
			       "pam_putenv: cannot grow environment");
		    return PAM_BUF_ERR;
		}

		/* copy old env-item pointers/forget old */
		for (i=0; i<pamh->env->requested; ++i) {
		    tmp[i] = pamh->env->list[i];
		    pamh->env->list[i] = NULL;
		}

		/* drop old list and replace with new */
		_pam_drop(pamh->env->list);
		pamh->env->list = tmp;
		pamh->env->entries += PAM_ENV_CHUNK;

		D(("resized env list"));
		_pam_dump_env(pamh);              /* only when debugging */
	    }

	    item = pamh->env->requested-1;        /* old last item (NULL) */

	    /* add a new NULL entry at end; increase counter */
	    pamh->env->list[pamh->env->requested++] = NULL;

	} else {                                /* replace old */
	    D(("replacing item: %s\n          with: %s"
	       , pamh->env->list[item], name_value));
	    _pam_overwrite(pamh->env->list[item]);
	    _pam_drop(pamh->env->list[item]);
	}

	/*
	 * now we have a place to put the new env-item, insert at 'item'
	 */

	pamh->env->list[item] = _pam_strdup(name_value);
	if (pamh->env->list[item] != NULL) {
	    _pam_dump_env(pamh);                   /* only when debugging */
	    return PAM_SUCCESS;
	}

	/* something went wrong; we should delete the item - fall through */

	retval = PAM_BUF_ERR;                        /* an error occurred */
    } else {
	retval = PAM_SUCCESS;                      /* we requested delete */
    }

    /* getting to here implies we are deleting an item */

    if (item < 0) {
	pam_syslog(pamh, LOG_ERR,
		   "pam_putenv: delete non-existent entry; %s", name_value);
	return PAM_BAD_ITEM;
    }

    /*
     * remove item: purge memory; reset counter; resize [; display-env]
     */

    D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
    _pam_overwrite(pamh->env->list[item]);
    _pam_drop(pamh->env->list[item]);
    --(pamh->env->requested);
    D(("mmove: item[%d]+%d -> item[%d]"
       , item+1, ( pamh->env->requested - item ), item));
    (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
		   , ( pamh->env->requested - item )*sizeof(char *) );

    _pam_dump_env(pamh);                   /* only when debugging */

    /*
     * deleted.
     */

    return retval;
}