Exemplo n.º 1
0
void _whawty_cleanup(whawty_ctx_t* ctx)
{
  _pam_overwrite(ctx->password_);
  _pam_drop(ctx->password_);

  _pam_drop(ctx->sockpath_);

  if(ctx->sock_ >= 0) {
    close(ctx->sock_);
  }

  _whawty_logf(ctx, LOG_DEBUG, "done cleaning up");
}
Exemplo n.º 2
0
/*
 * Conversation function to obtain the user's password
 */
static int
obtain_authtok(pam_handle_t *pamh)
{
    char *resp;
    const void *item;
    int retval;

    retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &resp, _("Password: "));

    if (retval != PAM_SUCCESS)
	return retval;

    if (resp == NULL)
	return PAM_CONV_ERR;

    /* set the auth token */
    retval = pam_set_item(pamh, PAM_AUTHTOK, resp);

    /* clean it up */
    _pam_overwrite(resp);
    _pam_drop(resp);

    if ( (retval != PAM_SUCCESS) ||
	 (retval = pam_get_item(pamh, PAM_AUTHTOK, &item))
	 != PAM_SUCCESS ) {
	return retval;
    }

    return retval;
}
Exemplo n.º 3
0
int
helper_verify_password(const char *name, const char *p, int nullok)
{
	struct passwd *pwd = NULL;
	char *salt = NULL;
	int retval;

	retval = get_pwd_hash(name, &pwd, &salt);

	if (pwd == NULL || salt == NULL) {
		helper_log_err(LOG_WARNING, "check pass; user unknown");
		retval = PAM_USER_UNKNOWN;
	} else {
		retval = verify_pwd_hash(p, salt, nullok);
	}

	if (salt) {
		_pam_overwrite(salt);
		_pam_drop(salt);
	}

	p = NULL;		/* no longer needed here */

	return retval;
}
Exemplo n.º 4
0
void _pam_free_data(pam_handle_t *pamh, int status)
{
    struct pam_data *last;
    struct pam_data *data;

    D(("called"));

    IF_NO_PAMH("_pam_free_data", pamh, /* no return value for void fn */);
    data = pamh->data;

    while (data) {
	last = data;
	data = data->next;
	if (last->cleanup) {
	    last->cleanup(pamh, last->data, status);
	}
	_pam_drop(last->name);
	_pam_drop(last);
    }
}
Exemplo n.º 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;
}
Exemplo n.º 6
0
void _pam_drop_env(pam_handle_t *pamh)
{
    D(("called."));
    IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);

    if (pamh->env != NULL) {
	int i;
	/* we will only purge the pamh->env->requested number of elements */

	for (i=pamh->env->requested-1; i-- > 0; ) {
	    D(("dropping #%3d>%s<", i, pamh->env->list[i]));
	    _pam_overwrite(pamh->env->list[i]);          /* clean */
	    _pam_drop(pamh->env->list[i]);              /* forget */
	}
	pamh->env->requested = 0;
	pamh->env->entries = 0;
	_pam_drop(pamh->env->list);                     /* forget */
	_pam_drop(pamh->env);                           /* forget */
    } else {
	D(("no environment present in pamh?"));
    }
}
Exemplo n.º 7
0
Arquivo: pam_mail.c Projeto: aosm/pam
static int report_mail(pam_handle_t *pamh, int ctrl
		       , const char *type, const char *folder)
{
    int retval;

    if (!(ctrl & PAM_MAIL_SILENT) || ((ctrl & PAM_QUIET_MAIL) && strcmp(type, "new"))) {
	char *remark;

	if (ctrl & PAM_STANDARD_MAIL)
	    if (!strcmp(type, "no"))
		remark = malloc(strlen(NO_MAIL_STANDARD_FORMAT)+1);
	    else
		remark = malloc(strlen(YOUR_MAIL_STANDARD_FORMAT)+strlen(type)+1);
	else
	    remark = malloc(strlen(YOUR_MAIL_VERBOSE_FORMAT)+strlen(type)+strlen(folder)+1);
	if (remark == NULL) {
	    retval = PAM_BUF_ERR;
	} else {
	    struct pam_message msg[1], *mesg[1];
	    struct pam_response *resp=NULL;

	    if (ctrl & PAM_STANDARD_MAIL)
		if (!strcmp(type, "no"))
		    sprintf(remark, NO_MAIL_STANDARD_FORMAT);
		else
		    sprintf(remark, YOUR_MAIL_STANDARD_FORMAT, type);
	    else
		sprintf(remark, YOUR_MAIL_VERBOSE_FORMAT, type, folder);

	    mesg[0] = &msg[0];
	    msg[0].msg_style = PAM_TEXT_INFO;
	    msg[0].msg = remark;

	    retval = converse(pamh, ctrl, 1, mesg, &resp);

	    _pam_overwrite(remark);
	    _pam_drop(remark);
	    if (resp)
		_pam_drop_reply(resp, 1);
	}
    } else {
	D(("keeping quiet"));
	retval = PAM_SUCCESS;
    }

    D(("returning %s", pam_strerror(pamh, retval)));
    return retval;
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
0
static int parse_credentials_buffer(const char *creds,
                                     size_t len,
                                     char **username,
                                     char **password)
{
    char *domain;
    int user_len, pass_len;

    if (len < sizeof(int)) {
        return -1;
    }

    user_len = ntohl(*((int *)creds));
    *username = strndup(creds + sizeof(int), user_len);
    if (*username == NULL) {
            return -1;
    }

    pass_len = len - sizeof(int) - user_len;
    *password = strndup(creds + sizeof(int) + user_len, pass_len);
    if (*password == NULL) {
            _pam_drop(*username);
            return -1;
    }
    
    domain = strchr(*username, '@');
    if (domain != NULL) {
        *domain = '\0';
        /* local/nis users doesn't have a domain. */
        if (getpwnam(*username) == NULL) {
            *domain = '@';
        } else {
            domain += 1;
        }
    }

    return 0;
}
Exemplo n.º 10
0
static int lookup(const char *name, const char *list, const char **_user)
{
    int anon = 0;

    *_user = name;                 /* this is the default */
    if (list && *list) {
	const char *l;
	char *list_copy, *x;
	char *sptr = NULL;

	list_copy = strdup(list);
	x = list_copy;
	while (list_copy && (l = strtok_r(x, ",", &sptr))) {
	    x = NULL;
	    if (!strcmp(name, l)) {
		*_user = list;
		anon = 1;
	    }
	}
	_pam_overwrite(list_copy);
	_pam_drop(list_copy);
    } else {
#define MAX_L 2
	static const char *l[MAX_L] = { "ftp", "anonymous" };
	int i;

	for (i=0; i<MAX_L; ++i) {
	    if (!strcmp(l[i], name)) {
		*_user = l[0];
		anon = 1;
		break;
	    }
	}
    }

    return anon;
}
Exemplo n.º 11
0
Arquivo: pam_time.c Projeto: aosm/pam
static int read_field(int fd, char **buf, int *from, int *to)
{
    /* is buf set ? */

    if (! *buf) {
	*buf = (char *) malloc(PAM_TIME_BUFLEN);
	if (! *buf) {
	    _log_err("out of memory");
	    D(("no memory"));
	    return -1;
	}
	*from = *to = 0;
	fd = open(PAM_TIME_CONF, O_RDONLY);
    }

    /* do we have a file open ? return error */

    if (fd < 0 && *to <= 0) {
	_log_err( PAM_TIME_CONF " not opened");
	memset(*buf, 0, PAM_TIME_BUFLEN);
	_pam_drop(*buf);
	return -1;
    }

    /* check if there was a newline last time */

    if ((*to > *from) && (*to > 0)
	&& ((*buf)[*from] == '\0')) { /* previous line ended */
	(*from)++;
	(*buf)[0] = '\0';
	return fd;
    }

    /* ready for more data: first shift the buffer's remaining data */

    *to -= *from;
    shift_bytes(*buf, *from, *to);
    *from = 0;
    (*buf)[*to] = '\0';

    while (fd >= 0 && *to < PAM_TIME_BUFLEN) {
	int i;

	/* now try to fill the remainder of the buffer */

	i = read(fd, *to + *buf, PAM_TIME_BUFLEN - *to);
	if (i < 0) {
	    _log_err("error reading " PAM_TIME_CONF);
	    return -1;
	} else if (!i) {
	    close(fd);
	    fd = -1;          /* end of file reached */
	} else
	    *to += i;
    
	/*
	 * contract the buffer. Delete any comments, and replace all
	 * multiple spaces with single commas
	 */

	i = 0;
#ifdef DEBUG_DUMP
	D(("buffer=<%s>",*buf));
#endif
	while (i < *to) {
	    if ((*buf)[i] == ',') {
		int j;

		for (j=++i; j<*to && (*buf)[j] == ','; ++j);
		if (j!=i) {
		    shift_bytes(i + (*buf), j-i, (*to) - j);
		    *to -= j-i;
		}
	    }
	    switch ((*buf)[i]) {
		int j,c;
	    case '#':
		for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j);
		if (j >= *to) {
		    (*buf)[*to = ++i] = '\0';
		} else if (c == '\n') {
		    shift_bytes(i + (*buf), j-i, (*to) - j);
		    *to -= j-i;
		    ++i;
		} else {
		    _log_err("internal error in " __FILE__
			     " at line %d", __LINE__ );
		    return -1;
		}
		break;
	    case '\\':
		if ((*buf)[i+1] == '\n') {
		    shift_bytes(i + *buf, 2, *to - (i+2));
		    *to -= 2;
		} else {
		    ++i;   /* we don't escape non-newline characters */
		}
		break;
	    case '!':
	    case ' ':
	    case '\t':
		if ((*buf)[i] != '!')
		    (*buf)[i] = ',';
		/* delete any trailing spaces */
		for (j=++i; j < *to && ( (c = (*buf)[j]) == ' '
					 || c == '\t' ); ++j);
		shift_bytes(i + *buf, j-i, (*to)-j );
		*to -= j-i;
		break;
	    default:
		++i;
	    }
	}
    }

    (*buf)[*to] = '\0';

    /* now return the next field (set the from/to markers) */
    {
	int i;

	for (i=0; i<*to; ++i) {
	    switch ((*buf)[i]) {
	    case '#':
	    case '\n':               /* end of the line/file */
		(*buf)[i] = '\0';
		*from = i;
		return fd;
	    case FIELD_SEPARATOR:    /* end of the field */
		(*buf)[i] = '\0';
	    *from = ++i;
	    return fd;
	    }
	}
	*from = i;
	(*buf)[*from] = '\0';
    }

    if (*to <= 0) {
	D(("[end of text]"));
	*buf = NULL;
    }

    return fd;
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
0
int
pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
		     int argc, const char **argv)
{
    int retval, anon=0, ctrl;
    const char *user;
    const char *users = NULL;

    /*
     * this module checks if the user name is ftp or annonymous. If
     * this is the case, it can set the PAM_RUSER to the entered email
     * address and SUCCEEDS, otherwise it FAILS.
     */

    ctrl = _pam_parse(pamh, argc, argv, &users);

    retval = pam_get_user(pamh, &user, NULL);
    if (retval != PAM_SUCCESS || user == NULL) {
	pam_syslog(pamh, LOG_ERR, "no user specified");
	return PAM_USER_UNKNOWN;
    }

    if (!(ctrl & PAM_NO_ANON)) {
	anon = lookup(user, users, &user);
    }

    if (anon) {
	retval = pam_set_item(pamh, PAM_USER, (const void *)user);
	if (retval != PAM_SUCCESS || user == NULL) {
	    pam_syslog(pamh, LOG_ERR, "user resetting failed");
	    return PAM_USER_UNKNOWN;
	}
    }

    /*
     * OK. we require an email address for user or the user's password.
     * - build conversation and get their input.
     */

    {
	char *resp = NULL;
	const char *token;

	if (!anon)
	  retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
			       PLEASE_ENTER_PASSWORD, user);
	else
	  retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
			       GUEST_LOGIN_PROMPT);

	if (retval != PAM_SUCCESS) {
	    _pam_overwrite (resp);
	    _pam_drop (resp);
	    return ((retval == PAM_CONV_AGAIN)
		    ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
	}

	if (anon) {
	  /* XXX: Some effort should be made to verify this email address! */

	    if (!(ctrl & PAM_IGNORE_EMAIL)) {
		char *sptr = NULL;
		token = strtok_r(resp, "@", &sptr);
		retval = pam_set_item(pamh, PAM_RUSER, token);

		if ((token) && (retval == PAM_SUCCESS)) {
		    token = strtok_r(NULL, "@", &sptr);
		    retval = pam_set_item(pamh, PAM_RHOST, token);
		}
	    }

	    /* we are happy to grant annonymous access to the user */
	    retval = PAM_SUCCESS;

	} else {
	    /*
	     * we have a password so set AUTHTOK
	     */

	    pam_set_item(pamh, PAM_AUTHTOK, resp);

	    /*
	     * this module failed, but the next one might succeed with
	     * this password.
	     */

	    retval = PAM_AUTH_ERR;
	}

	/* clean up */
	_pam_overwrite(resp);
	_pam_drop(resp);

	/* success or failure */

	return retval;
    }
}
Exemplo n.º 14
0
static int
last_login_failed(pam_handle_t *pamh, int announce, const char *user, time_t lltime)
{
    int retval;
    int fd;
    struct utmp ut;
    struct utmp utuser;
    int failed = 0;
    char the_time[256];
    char *date = NULL;
    char *host = NULL;
    char *line = NULL;

    if (strlen(user) > UT_NAMESIZE) {
	pam_syslog(pamh, LOG_WARNING, "username too long, output might be inaccurate");
    }

    /* obtain the failed login attempt records from btmp */
    fd = open(_PATH_BTMP, O_RDONLY);
    if (fd < 0) {
        int save_errno = errno;
	pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_BTMP);
	D(("unable to open %s file", _PATH_BTMP));
        if (save_errno == ENOENT)
	  return PAM_SUCCESS;
	else
	  return PAM_SERVICE_ERR;
    }

    while ((retval=pam_modutil_read(fd, (void *)&ut,
			 sizeof(ut))) == sizeof(ut)) {
	if (ut.ut_tv.tv_sec >= lltime && strncmp(ut.ut_user, user, UT_NAMESIZE) == 0) {
	    memcpy(&utuser, &ut, sizeof(utuser));
	    failed++;
	}
    }

    if (failed) {
	/* we want the date? */
	if (announce & LASTLOG_DATE) {
	    struct tm *tm, tm_buf;
	    time_t lf_time;

	    lf_time = utuser.ut_tv.tv_sec;
	    tm = localtime_r (&lf_time, &tm_buf);
	    strftime (the_time, sizeof (the_time),
	        /* TRANSLATORS: "strftime options for date of last login" */
		_(" %a %b %e %H:%M:%S %Z %Y"), tm);

	    date = the_time;
	}

	/* we want & have the host? */
	if ((announce & LASTLOG_HOST)
		&& (utuser.ut_host[0] != '\0')) {
	    /* TRANSLATORS: " from <host>" */
	    if (asprintf(&host, _(" from %.*s"), UT_HOSTSIZE,
		    utuser.ut_host) < 0) {
		pam_syslog(pamh, LOG_ERR, "out of memory");
		retval = PAM_BUF_ERR;
		goto cleanup;
	    }
	}

	/* we want and have the terminal? */
	if ((announce & LASTLOG_LINE)
		&& (utuser.ut_line[0] != '\0')) {
	    /* TRANSLATORS: " on <terminal>" */
	    if (asprintf(&line, _(" on %.*s"), UT_LINESIZE,
			utuser.ut_line) < 0) {
		pam_syslog(pamh, LOG_ERR, "out of memory");
		retval = PAM_BUF_ERR;
		goto cleanup;
	    }
	}

	if (line != NULL || date != NULL || host != NULL) {
	    /* TRANSLATORS: "Last failed login: <date> from <host> on <terminal>" */
	    pam_info(pamh, _("Last failed login:%s%s%s"),
			      date ? date : "",
			      host ? host : "",
			      line ? line : "");
	}

	_pam_drop(line);
#if defined HAVE_DNGETTEXT && defined ENABLE_NLS
        retval = asprintf (&line, dngettext(PACKAGE,
		"There was %d failed login attempt since the last successful login.",
		"There were %d failed login attempts since the last successful login.",
		failed),
	    failed);
#else
	if (failed == 1)
	    retval = asprintf(&line,
		_("There was %d failed login attempt since the last successful login."),
		failed);
	else
	    retval = asprintf(&line,
		/* TRANSLATORS: only used if dngettext is not supported */
		_("There were %d failed login attempts since the last successful login."),
		failed);
#endif
	if (retval >= 0)
		retval = pam_info(pamh, "%s", line);
	else {
		retval = PAM_BUF_ERR;
		line = NULL;
	}
    }

cleanup:
    free(host);
    free(line);
    close(fd);
    D(("all done with btmp"));

    return retval;
}
Exemplo n.º 15
0
Arquivo: pam_end.c Projeto: dgeo96/src
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;
}
Exemplo n.º 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 */
}
Exemplo n.º 17
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;
}
Exemplo n.º 18
0
static security_context_t
config_context (pam_handle_t *pamh, security_context_t defaultcon, int use_current_range, int debug)
{
  security_context_t newcon=NULL;
  context_t new_context;
  int mls_enabled = is_selinux_mls_enabled();
  char *response=NULL;
  char *type=NULL;
  char resp_val = 0;

  pam_prompt (pamh, PAM_TEXT_INFO, NULL, _("Default Security Context %s\n"), defaultcon);

  while (1) {
    if (query_response(pamh,
		   _("Would you like to enter a different role or level?"), "n", 
		   &response, debug) == PAM_SUCCESS) {
	resp_val = response[0];
	_pam_drop(response);
    } else {
	resp_val = 'N';
    }
    if ((resp_val == 'y') || (resp_val == 'Y'))
      {
        if ((new_context = context_new(defaultcon)) == NULL)
    	    goto fail_set;

	/* Allow the user to enter role and level individually */
	if (query_response(pamh, _("role:"), context_role_get(new_context), 
		       &response, debug) == PAM_SUCCESS && response[0]) {
	  if (get_default_type(response, &type)) {
	    pam_prompt (pamh, PAM_ERROR_MSG, NULL, _("No default type for role %s\n"), response);
	    _pam_drop(response);
	    continue;
	  } else {
	    if (context_role_set(new_context, response)) 
	      goto fail_set;
	    if (context_type_set (new_context, type))
	      goto fail_set;
	  } 
	}
	_pam_drop(response);

	if (mls_enabled)
	  {
	    if (use_current_range) {
	        security_context_t mycon = NULL;
	        context_t my_context;

		if (getcon(&mycon) != 0)
		    goto fail_set;
    		my_context = context_new(mycon);
	        if (my_context == NULL) {
    		    freecon(mycon);
		    goto fail_set;
		}
		freecon(mycon);
		if (context_range_set(new_context, context_range_get(my_context))) {
		    context_free(my_context);
		    goto fail_set;
		}
		context_free(my_context);
	    } else if (query_response(pamh, _("level:"), context_range_get(new_context), 
			   &response, debug) == PAM_SUCCESS && response[0]) {
		if (context_range_set(new_context, response))
		    goto fail_set;
	    } 
	    _pam_drop(response);
	  }

	if (debug)
	  pam_syslog(pamh, LOG_NOTICE, "Selected Security Context %s", context_str(new_context));

        /* Get the string value of the context and see if it is valid. */
        if (!security_check_context(context_str(new_context))) {
	  newcon = strdup(context_str(new_context));
	  if (newcon == NULL)
	    goto fail_set;
	  context_free(new_context);

          /* we have to check that this user is allowed to go into the
             range they have specified ... role is tied to an seuser, so that'll
             be checked at setexeccon time */
          if (mls_enabled && !mls_range_allowed(pamh, defaultcon, newcon, debug)) {
	    pam_syslog(pamh, LOG_NOTICE, "Security context %s is not allowed for %s", defaultcon, newcon);

    	    send_audit_message(pamh, 0, defaultcon, newcon);

	    free(newcon);
            goto fail_range;
	  }
	  return newcon;
	}
	else {
	  send_audit_message(pamh, 0, defaultcon, context_str(new_context));
	  send_text(pamh,_("Not a valid security context"),debug);
	}
        context_free(new_context); /* next time around allocates another */
      }
    else
      return strdup(defaultcon);
  } /* end while */

  return NULL;

 fail_set:
  free(type);
  _pam_drop(response);
  context_free (new_context);
  send_audit_message(pamh, 0, defaultcon, NULL);
 fail_range:
  return NULL;  
}
Exemplo n.º 19
0
static security_context_t
manual_context (pam_handle_t *pamh, const char *user, int debug)
{
  security_context_t newcon=NULL;
  context_t new_context;
  int mls_enabled = is_selinux_mls_enabled();
  char *type=NULL;
  char *response=NULL;

  while (1) {
    if (query_response(pamh,
		   _("Would you like to enter a security context? [N] "), NULL,
		   &response, debug) != PAM_SUCCESS)
	return NULL;

    if ((response[0] == 'y') || (response[0] == 'Y'))
      {
	if (mls_enabled)
	  new_context = context_new ("user:role:type:level");
	else
	  new_context = context_new ("user:role:type");

	if (!new_context)
              goto fail_set;

	if (context_user_set (new_context, user))
              goto fail_set;

	_pam_drop(response);
	/* Allow the user to enter each field of the context individually */
	if (query_response(pamh, _("role:"), NULL, &response, debug) == PAM_SUCCESS &&
	    response[0] != '\0') {
	   if (context_role_set (new_context, response)) 
              goto fail_set;
	   if (get_default_type(response, &type)) 
              goto fail_set;
	   if (context_type_set (new_context, type)) 
              goto fail_set;
	}
	_pam_drop(response);

	if (mls_enabled)
	  {
	    if (query_response(pamh, _("level:"), NULL, &response, debug) == PAM_SUCCESS &&
		response[0] != '\0') {
	      if (context_range_set (new_context, response))
		goto fail_set;
	    }
	    _pam_drop(response);
	  }

	/* Get the string value of the context and see if it is valid. */
	if (!security_check_context(context_str(new_context))) {
	  newcon = strdup(context_str(new_context));
	  context_free (new_context);
	  return newcon;
	}
	else
	  send_text(pamh,_("Not a valid security context"),debug);

        context_free (new_context);
      }
    else {
      _pam_drop(response);
      return NULL;
    }
  } /* end while */
 fail_set:
  free(type);
  _pam_drop(response);
  context_free (new_context);
  return NULL;
}
Exemplo n.º 20
0
static int check_account(const char *service, const char *tty
     , const char *user)
{
    int from=0,to=0,fd=-1;
    char *buffer=NULL;
    int count=0;
    TIME here_and_now;
    int retval=PAM_SUCCESS;
    gid_t *grps;
    int no_grps;

    /*
     * first we get the current list of groups - the application
     * will have previously done an initgroups(), or equivalent.
     */

    D(("counting supplementary groups"));
    no_grps = getgroups(0, NULL);      /* find the current number of groups */
    if (no_grps > 0) {
	grps = calloc( blk_size(no_grps) , sizeof(gid_t) );
	D(("copying current list into grps [%d big]",blk_size(no_grps)));
	(void) getgroups(no_grps, grps);
#ifdef DEBUG
	{
	    int z;
	    for (z=0; z<no_grps; ++z) {
		D(("gid[%d]=%d", z, grps[z]));
	    }
	}
#endif
    } else {
	D(("no supplementary groups known"));
	no_grps = 0;
	grps = NULL;
    }

    here_and_now = time_now();                         /* find current time */

    /* parse the rules in the configuration file */
    do {
	int good=TRUE;

	/* here we get the service name field */

	fd = read_field(fd,&buffer,&from,&to);
	if (!buffer || !buffer[0]) {
	    /* empty line .. ? */
	    continue;
	}
	++count;
	D(("working on rule #%d",count));

	good = logic_field(service, buffer, count, is_same);
	D(("with service: %s", good ? "passes":"fails" ));

	/* here we get the terminal name field */

	fd = read_field(fd,&buffer,&from,&to);
	if (!buffer || !buffer[0]) {
	    _log_err(PAM_GROUP_CONF "; no tty entry #%d", count);
	    continue;
	}
	good &= logic_field(tty, buffer, count, is_same);
	D(("with tty: %s", good ? "passes":"fails" ));

	/* here we get the username field */

	fd = read_field(fd,&buffer,&from,&to);
	if (!buffer || !buffer[0]) {
	    _log_err(PAM_GROUP_CONF "; no user entry #%d", count);
	    continue;
	}
	good &= logic_field(user, buffer, count, is_same);
	D(("with user: %s", good ? "passes":"fails" ));

	/* here we get the time field */

	fd = read_field(fd,&buffer,&from,&to);
	if (!buffer || !buffer[0]) {
	    _log_err(PAM_GROUP_CONF "; no time entry #%d", count);
	    continue;
	}

	good &= logic_field(&here_and_now, buffer, count, check_time);
	D(("with time: %s", good ? "passes":"fails" ));

	fd = read_field(fd,&buffer,&from,&to);
	if (!buffer || !buffer[0]) {
	    _log_err(PAM_GROUP_CONF "; no listed groups for rule #%d"
		     , count);
	    continue;
	}

	/*
	 * so we have a list of groups, we need to turn it into
	 * something to send to setgroups(2)
	 */

	if (good) {
	    D(("adding %s to gid list", buffer));
	    good = mkgrplist(buffer, &grps, no_grps);
	    if (good < 0) {
		no_grps = 0;
	    } else {
		no_grps = good;
	    }
	}

	/* check the line is terminated correctly */

	fd = read_field(fd,&buffer,&from,&to);
	if (buffer && buffer[0]) {
	    _log_err(PAM_GROUP_CONF "; poorly terminated rule #%d", count);
	}

	if (good > 0) {
	    D(("rule #%d passed, added %d groups", count, good));
	} else if (good < 0) {
	    retval = PAM_BUF_ERR;
	} else {
	    D(("rule #%d failed", count));
	}

    } while (buffer);

    /* now set the groups for the user */

    if (no_grps > 0) {
	int err;
	D(("trying to set %d groups", no_grps));
#ifdef DEBUG
	for (err=0; err<no_grps; ++err) {
	    D(("gid[%d]=%d", err, grps[err]));
	}
#endif
	if ((err = setgroups(no_grps, grps))) {
	    D(("but couldn't set groups %d", err));
	    _log_err("unable to set the group membership for user (err=%d)"
		     , err);
	    retval = PAM_CRED_ERR;
	}
    }

    if (grps) {                                          /* tidy up */
	memset(grps, 0, sizeof(gid_t) * blk_size(no_grps));
	_pam_drop(grps);
	no_grps = 0;
    }

    return retval;
}
Exemplo n.º 21
0
/**
 * Overwrite possibly sensitive memory before free-ing it.
 *
 * @param  xx String containing possibly sensitive information
 * @retval Always NULL (useful for reseting pointer in the same line)
 */
static char * _pam_delete( register char * xx )
{
   _pam_overwrite( xx );
   _pam_drop( xx );
   return NULL;
}
Exemplo n.º 22
0
static int
get_mail_status(pam_handle_t *pamh, int ctrl, const char *folder)
{
    int type = 0;
    struct stat mail_st;

    if (stat(folder, &mail_st) < 0)
	return 0;

    if (S_ISDIR(mail_st.st_mode)) {	/* Assume Maildir format */
	int i, save_errno;
	char *dir;
	struct dirent **namelist;

	if (asprintf(&dir, "%s/new", folder) < 0) {
	    pam_syslog(pamh, LOG_CRIT, "out of memory");
	    goto get_mail_status_cleanup;
	}
	i = scandir(dir, &namelist, 0, alphasort);
	save_errno = errno;
	_pam_overwrite(dir);
	_pam_drop(dir);
	if (i < 0) {
	    type = 0;
	    namelist = NULL;
	    if (save_errno == ENOMEM) {
		pam_syslog(pamh, LOG_CRIT, "out of memory");
		goto get_mail_status_cleanup;
	    }
	}
	type = (i > 2) ? HAVE_NEW_MAIL : 0;
	while (--i >= 0)
	    _pam_drop(namelist[i]);
	_pam_drop(namelist);
	if (type == 0) {
	    if (asprintf(&dir, "%s/cur", folder) < 0) {
		pam_syslog(pamh, LOG_CRIT, "out of memory");
		goto get_mail_status_cleanup;
	    }
	    i = scandir(dir, &namelist, 0, alphasort);
	    save_errno = errno;
	    _pam_overwrite(dir);
	    _pam_drop(dir);
	    if (i < 0) {
		type = 0;
		namelist = NULL;
		if (save_errno == ENOMEM) {
		    pam_syslog(pamh, LOG_CRIT, "out of memory");
		    goto get_mail_status_cleanup;
		}
	    }
	    if (i > 2)
	        type = HAVE_OLD_MAIL;
	    else
	        type = (ctrl & PAM_EMPTY_TOO) ? HAVE_NO_MAIL : 0;
	    while (--i >= 0)
		_pam_drop(namelist[i]);
	    _pam_drop(namelist);
	}
    } else {
	if (mail_st.st_size > 0) {
	    if (mail_st.st_atime < mail_st.st_mtime)	/* new */
	        type = HAVE_NEW_MAIL;
	    else		/* old */
	        type = (ctrl & PAM_STANDARD_MAIL) ? HAVE_MAIL : HAVE_OLD_MAIL;
	} else if (ctrl & PAM_EMPTY_TOO) {
	    type = HAVE_NO_MAIL;
	} else {
	    type = 0;
	}
    }

  get_mail_status_cleanup:
    memset(&mail_st, 0, sizeof(mail_st));
    D(("user has %d mail in %s folder", type, folder));
    return type;
}
Exemplo n.º 23
0
Arquivo: pam_mail.c Projeto: aosm/pam
static int get_folder(pam_handle_t *pamh, int ctrl,
		      char **path_mail, char **folder_p, int hashcount)
{
    int retval;
    const char *user, *path;
    char *folder;
    const struct passwd *pwd=NULL;

    retval = pam_get_user(pamh, &user, NULL);
    if (retval != PAM_SUCCESS || user == NULL) {
	_log_err(LOG_ERR, "no user specified");
	return PAM_USER_UNKNOWN;
    }

    if (ctrl & PAM_NEW_MAIL_DIR) {
	path = *path_mail;
	if (*path == '~') {       /* support for $HOME delivery */
	    pwd = getpwnam(user);
	    if (pwd == NULL) {
		_log_err(LOG_ERR, "user [%s] unknown", user);
		_pam_overwrite(*path_mail);
		_pam_drop(*path_mail);
		return PAM_USER_UNKNOWN;
	    }
	    /*
	     * "~/xxx" and "~xxx" are treated as same
	     */
	    if (!*++path || (*path == '/' && !*++path)) {
		_log_err(LOG_ALERT, "badly formed mail path [%s]", *path_mail);
		_pam_overwrite(*path_mail);
		_pam_drop(*path_mail);
		return PAM_ABORT;
	    }
	    ctrl |= PAM_HOME_MAIL;
	    if (hashcount != 0) {
		_log_err(LOG_ALERT, "can't do hash= and home directory mail");
	    }
	}
    } else {
	path = DEFAULT_MAIL_DIRECTORY;
    }

    /* put folder together */

    if (ctrl & PAM_HOME_MAIL) {
	folder = malloc(sizeof(MAIL_FILE_FORMAT)
			+strlen(pwd->pw_dir)+strlen(path));
    } else {
	folder = malloc(sizeof(MAIL_FILE_FORMAT)+strlen(path)+strlen(user)
			+2*hashcount);
    }

    if (folder != NULL) {
	if (ctrl & PAM_HOME_MAIL) {
	    sprintf(folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path);
	} else {
	    int i;
	    char *hash = malloc(2*hashcount+1);

	    if (hash) {
		for (i = 0; i < hashcount; i++) {
		    hash[2*i] = '/';
		    hash[2*i+1] = user[i];
		}
		hash[2*i] = '\0';
		sprintf(folder, MAIL_FILE_FORMAT, path, hash, user);
		_pam_overwrite(hash);
		_pam_drop(hash);
	    } else {
		sprintf(folder, "error");
	    }
	}
	D(("folder =[%s]", folder));
    }

    /* tidy up */

    _pam_overwrite(*path_mail);
    _pam_drop(*path_mail);
    user = NULL;

    if (folder == NULL) {
	_log_err(LOG_CRIT, "out of memory for mail folder");
	return PAM_BUF_ERR;
    }

    *folder_p = folder;
    folder = NULL;

    return PAM_SUCCESS;
}
Exemplo n.º 24
0
static int
read_field(const pam_handle_t *pamh, int fd, char **buf, int *from, int *state)
{
    char *to;
    char *src;
    int i;
    char c;
    int onspace;

    /* is buf set ? */
    if (! *buf) {
	*buf = (char *) calloc(1, PAM_TIME_BUFLEN+1);
	if (! *buf) {
	    pam_syslog(pamh, LOG_ERR, "out of memory");
	    D(("no memory"));
	    *state = STATE_EOF;
	    return -1;
	}
	*from = 0;
        *state = STATE_NL;
	fd = open(PAM_TIME_CONF, O_RDONLY);
	if (fd < 0) {
	    pam_syslog(pamh, LOG_ERR, "error opening %s: %m", PAM_TIME_CONF);
	    _pam_drop(*buf);
	    *state = STATE_EOF;
	    return -1;
	}
    }


    if (*from > 0)
	to = shift_buf(*buf, *from);
    else
	to = *buf;

    while (fd != -1 && to - *buf < PAM_TIME_BUFLEN) {
	i = pam_modutil_read(fd, to, PAM_TIME_BUFLEN - (to - *buf));
	if (i < 0) {
	    pam_syslog(pamh, LOG_ERR, "error reading %s: %m", PAM_TIME_CONF);
	    close(fd);
	    memset(*buf, 0, PAM_TIME_BUFLEN);
	    _pam_drop(*buf);
	    *state = STATE_EOF;
	    return -1;
	} else if (!i) {
	    close(fd);
	    fd = -1;          /* end of file reached */
	}

	to += i;
    }

    if (to == *buf) {
	/* nothing previously in buf, nothing read */
	_pam_drop(*buf);
	*state = STATE_EOF;
	return -1;
    }

    memset(to, '\0', PAM_TIME_BUFLEN - (to - *buf));

    to = *buf;
    onspace = 1; /* delete any leading spaces */

    for (src = to; (c=*src) != '\0'; ++src) {
	if (*state == STATE_COMMENT && c != '\n') {
		continue;
	}

	switch (c) {
	    case '\n':
		*state = STATE_NL;
                *to = '\0';
		*from = (src - *buf) + 1;
		trim_spaces(*buf, to);
		return fd;

	    case '\t':
            case ' ':
		if (!onspace) {
		    onspace = 1;
		    *to++ = ' ';
		}
		break;

            case '!':
		onspace = 1; /* ignore following spaces */
		*to++ = '!';
		break;

	    case '#':
		*state = STATE_COMMENT;
		break;

	    case FIELD_SEPARATOR:
		*state = STATE_FIELD;
                *to = '\0';
		*from = (src - *buf) + 1;
		trim_spaces(*buf, to);
		return fd;

	    case '\\':
		if (src[1] == '\n') {
		    ++src; /* skip it */
		    break;
		}
	    default:
		*to++ = c;
		onspace = 0;
	}
	if (src > to)
	    *src = '\0'; /* clearing */
    }

    if (*state != STATE_COMMENT) {
	*state = STATE_COMMENT;
	pam_syslog(pamh, LOG_ERR, "field too long - ignored");
	**buf = '\0';
    } else {
	*to = '\0';
	trim_spaces(*buf, to);
    }

    *from = 0;
    return fd;
}
Exemplo n.º 25
0
Arquivo: pam_mail.c Projeto: aosm/pam
static int _do_mail(pam_handle_t *pamh, int flags, int argc,
    const char **argv, int est)
{
    int retval, ctrl, hashcount;
    char *path_mail=NULL, *folder;
    const char *type;

    /*
     * this module (un)sets the MAIL environment variable, and checks if
     * the user has any new mail.
     */

    ctrl = _pam_parse(flags, argc, argv, &path_mail, &hashcount);

    /* Do we have anything to do? */

    if (flags & PAM_SILENT)
	return PAM_SUCCESS;

    /* which folder? */

    retval = get_folder(pamh, ctrl, &path_mail, &folder, hashcount);
    if (retval != PAM_SUCCESS) {
	D(("failed to find folder"));
	return retval;
    }

    /* set the MAIL variable? */

    if (!(ctrl & PAM_NO_ENV) && est) {
	char *tmp;

	tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT));
	if (tmp != NULL) {
	    sprintf(tmp, MAIL_ENV_FORMAT, folder);
	    D(("setting env: %s", tmp));
	    retval = pam_putenv(pamh, tmp);
	    _pam_overwrite(tmp);
	    _pam_drop(tmp);
	    if (retval != PAM_SUCCESS) {
		_pam_overwrite(folder);
		_pam_drop(folder);
		_log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable");
		return retval;
	    }
	} else {
	    _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable");
	    _pam_overwrite(folder);
	    _pam_drop(folder);
	    return retval;
	}
    } else {
	D(("not setting " MAIL_ENV_NAME " variable"));
    }

    /*
     * OK. we've got the mail folder... what about its status?
     */

    if ((est && !(ctrl & PAM_NO_LOGIN))
	|| (!est && (ctrl & PAM_LOGOUT_TOO))) {
	type = get_mail_status(ctrl, folder);
	if (type != NULL) {
	    retval = report_mail(pamh, ctrl, type, folder);
	    type = NULL;
	}
    }
    
    /* Delete environment variable? */  
    if (!est)
	(void) pam_putenv(pamh, MAIL_ENV_NAME);

    _pam_overwrite(folder); /* clean up */
    _pam_drop(folder);

    /* indicate success or failure */

    return retval;
}
Exemplo n.º 26
0
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
			,const char **argv)
{
    int retval, anon=0, ctrl;
    const char *user;
    char *users=NULL;

    /*
     * this module checks if the user name is ftp or annonymous. If
     * this is the case, it can set the PAM_RUSER to the entered email
     * address and SUCCEEDS, otherwise it FAILS.
     */

    ctrl = _pam_parse(argc, argv, &users);

    retval = pam_get_user(pamh, &user, NULL);
    if (retval != PAM_SUCCESS || user == NULL) {
	_pam_log(LOG_ERR, "no user specified");
	return PAM_USER_UNKNOWN;
    }

    if (!(ctrl & PAM_NO_ANON)) {
	anon = lookup(user, users, &user);
    }

    if (anon) {
	retval = pam_set_item(pamh, PAM_USER, (const void *)user);
	if (retval != PAM_SUCCESS || user == NULL) {
	    _pam_log(LOG_ERR, "user resetting failed");
	    return PAM_USER_UNKNOWN;
	}
    }

    /*
     * OK. we require an email address for user or the user's password.
     * - build conversation and get their input.
     */

    {
	struct pam_message msg[1], *mesg[1];
	struct pam_response *resp=NULL;
	const char *token;
	char *prompt=NULL;
	int i=0;

	if (!anon) {
	    prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user));
	    if (prompt == NULL) {
		D(("out of memory!?"));
		return PAM_BUF_ERR;
	    } else {
		sprintf(prompt, PLEASE_ENTER_PASSWORD, user);
		msg[i].msg = prompt;
	    }
	} else {
	    msg[i].msg = GUEST_LOGIN_PROMPT;
	}

	msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
	mesg[i] = &msg[i];

	retval = converse(pamh, ++i, mesg, &resp);
	if (prompt) {
	    _pam_overwrite(prompt);
	    _pam_drop(prompt);
	}

	if (retval != PAM_SUCCESS) {
	    if (resp != NULL)
		_pam_drop_reply(resp,i);
	    return ((retval == PAM_CONV_AGAIN)
		    ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
	}

	if (anon) {
	    /* XXX: Some effort should be made to verify this email address! */

	    if (!(ctrl & PAM_IGNORE_EMAIL)) {
		token = strtok(resp->resp, "@");
		retval = pam_set_item(pamh, PAM_RUSER, token);

		if ((token) && (retval == PAM_SUCCESS)) {
		    token = strtok(NULL, "@");
		    retval = pam_set_item(pamh, PAM_RHOST, token);
		}
	    }

	    /* we are happy to grant annonymous access to the user */
	    retval = PAM_SUCCESS;

	} else {
	    /*
	     * we have a password so set AUTHTOK
	     */

	    (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp);

	    /*
	     * this module failed, but the next one might succeed with
	     * this password.
	     */

	    retval = PAM_AUTH_ERR;
	}

	if (resp) {                                      /* clean up */
	    _pam_drop_reply(resp, i);
	}

	/* success or failure */

	return retval;
    }
}
Exemplo n.º 27
0
/*
 * Change a user's password in NetInfo.
 */
PAM_EXTERN
int 
pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc, const char **argv)
{
	char           *oldHash, *newHash;
	char           *oldPassword = NULL, *newPassword = NULL;
	void           *d;
	int             status, isroot, tries, maxTries;
	int		options = 0;
	int		amChangingExpiredPassword;
	ni_id           dir;
	ni_proplist     pl;
	ni_property     p;
	ni_namelist     nl;
	int             ni_uid, uid, secure, minlen, lifetime;
	ni_index        where;
	struct pam_conv *appconv;
	struct pam_message msg, *pmsg;
	struct pam_response *resp;
	const char     *cmiscptr = NULL;
	char           *uname;
	char            salt[9];
	int i;

	amChangingExpiredPassword = flags & PAM_CHANGE_EXPIRED_AUTHTOK;

	status = pam_get_item(pamh, PAM_CONV, (void **) &appconv);
	if (status != PAM_SUCCESS)
		return status;

	status = pam_get_item(pamh, PAM_USER, (void **) &uname);
	if (status != PAM_SUCCESS)
		return status;

	if (uname == NULL)
		return PAM_USER_UNKNOWN;

	status = pam_get_item(pamh, PAM_OLDAUTHTOK, (void **) &oldPassword);
	if (status != PAM_SUCCESS) {
		return status;
	}

	if (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL) ||
	    pam_test_option(&options, PAM_OPT_TRY_FIRST_PASS, NULL))
	{
		if (pam_get_item(pamh, PAM_AUTHTOK, (void **) &newPassword) != PAM_SUCCESS)
			newPassword = NULL;

		if (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL) && newPassword == NULL)
			return PAM_AUTHTOK_RECOVER_ERR;
	}
	d = domain_for_user(uname, NULL, &dir);
	if (d == (void *) NULL)
	{
		syslog(LOG_ERR, "user %s not found in NetInfo", uname);
		return PAM_USER_UNKNOWN;
	}

	/*
	 * These should be configurable in NetInfo.
	 */
	secure = secure_passwords();
	maxTries = secure ? 3 : 5;
	minlen = secure ? 8 : 5;

	/*
         * Read the passwd and uid from NetInfo.
         */
	status = ni_lookupprop(d, &dir, "passwd", &nl);
	if (status == NI_NOPROP)
		nl.ni_namelist_len = 0;
	else if (status != NI_OK)
	{
		ni_free(d);
		syslog(LOG_ERR, "NetInfo read failed: %s", ni_error(status));
		return netinfo2PamStatus(status);
	}
	oldHash = NULL;
	if (nl.ni_namelist_len > 0)
		oldHash = nl.ni_namelist_val[0];

	status = ni_lookupprop(d, &dir, "uid", &nl);
	if (status != NI_OK)
	{
		ni_free(d);
		syslog(LOG_ERR, "NetInfo read failed: %s", ni_error(status));
		return netinfo2PamStatus(status);
	}
	ni_uid = -2;
	if (nl.ni_namelist_len > 0)
		ni_uid = atoi(nl.ni_namelist_val[0]);

	/*
         * See if I'm uid 0 on the master host for the user's NetInfo domain.
         */
	isroot = is_root_on_master(d);
	uid = getuid();
	if (isroot)
	{
		if (flags & PAM_PRELIM_CHECK)
		{
			/* Don't need old password. */
			return PAM_SUCCESS;
		}
	}
	else if (uid != ni_uid)
	{
		ni_free(d);
		return PAM_PERM_DENIED;
	}

	if (flags & PAM_PRELIM_CHECK)
	{
		/*
		 * If we are not root, we should verify the old
		 * password.
		 */
		char           *encrypted;

		if (oldPassword != NULL &&
		   (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL) ||
		    pam_test_option(&options, PAM_OPT_TRY_FIRST_PASS, NULL)))
		{
			encrypted = crypt(oldPassword, oldHash);

			if (oldPassword[0] == '\0' && oldHash != '\0')
				encrypted = ":";
			status = strcmp(encrypted, oldHash) == 0 ? PAM_SUCCESS : PAM_AUTH_ERR;
			if (status != PAM_SUCCESS)
			{
				if (pam_test_option(&options, PAM_OPT_USE_FIRST_PASS, NULL))
					sendConversationMessage(appconv, "NetInfo password incorrect", PAM_ERROR_MSG, &options);
				else
					sendConversationMessage(appconv, "NetInfo password incorrect: try again", PAM_ERROR_MSG, &options);
			}
			else
			{
				ni_free(d);
				return PAM_SUCCESS;
			}
		}
		tries = 0;

		while (oldPassword == NULL && tries++ < maxTries)
		{
			pmsg = &msg;
			msg.msg_style = PAM_PROMPT_ECHO_OFF;
			msg.msg = OLD_PASSWORD_PROMPT;
			resp = NULL;

			status = appconv->conv(1, (struct pam_message **) & pmsg, &resp, appconv->appdata_ptr);
			if (status != PAM_SUCCESS)
			{
				ni_free(d);
				return status;
			}
			oldPassword = resp->resp;
			free(resp);

			encrypted = crypt(oldPassword, oldHash);

			if (oldPassword[0] == '\0' && oldHash != '\0')
				encrypted = ":";

			status = strcmp(encrypted, oldHash) == 0 ? PAM_SUCCESS : PAM_AUTH_ERR;

			if (status != PAM_SUCCESS)
			{
				int             abortMe = 0;

				if (oldPassword != NULL && oldPassword[0] == '\0')
					abortMe = 1;

				_pam_overwrite(oldPassword);
				_pam_drop(oldPassword);

				if (!amChangingExpiredPassword & abortMe)
				{
					sendConversationMessage(appconv, "Password change aborted", PAM_ERROR_MSG, &options);
					ni_free(d);
					return PAM_AUTHTOK_RECOVER_ERR;
				}
				else
				{
					sendConversationMessage(appconv, "NetInfo password incorrect: try again", PAM_ERROR_MSG, &options);
				}
			}
		}

		if (oldPassword == NULL)
		{
			status = PAM_MAXTRIES;
		}
		(void) pam_set_item(pamh, PAM_OLDAUTHTOK, oldPassword);
		ni_free(d);

		return status;
	}			/* PAM_PRELIM_CHECK */

	status = PAM_ABORT;
	tries = 0;

	while (newPassword == NULL && tries++ < maxTries)
	{
		pmsg = &msg;
		msg.msg_style = PAM_PROMPT_ECHO_OFF;
		msg.msg = NEW_PASSWORD_PROMPT;
		resp = NULL;

		status = appconv->conv(1, &pmsg, &resp, appconv->appdata_ptr);
		if (status != PAM_SUCCESS)
		{
			ni_free(d);
			return status;
		}
		newPassword = resp->resp;
		free(resp);

		if (newPassword[0] == '\0')
		{
			free(newPassword);
			newPassword = NULL;
		}

		if (newPassword != NULL)
		{
			if (isroot == 0)
			{
				if (oldPassword != NULL && !strcmp(oldPassword, newPassword))
				{
					cmiscptr = "Passwords must differ";
					newPassword = NULL;
				}
				else if (strlen(newPassword) < minlen)
				{
					cmiscptr = "Password too short";
					newPassword = NULL;
				}
			}
		} else
		{
			ni_free(d);
			return PAM_AUTHTOK_RECOVER_ERR;
		}

		if (cmiscptr == NULL)
		{
			/* get password again */
			char           *miscptr;

			pmsg = &msg;
			msg.msg_style = PAM_PROMPT_ECHO_OFF;
			msg.msg = AGAIN_PASSWORD_PROMPT;
			resp = NULL;

			status = appconv->conv(1, &pmsg, &resp, appconv->appdata_ptr);

			if (status != PAM_SUCCESS)
			{
				ni_free(d);
				return status;
			}
			miscptr = resp->resp;
			free(resp);

			if (miscptr[0] == '\0')
			{
				free(miscptr);
				miscptr = NULL;
			}
			if (miscptr == NULL)
			{
				if (!amChangingExpiredPassword)
				{
					sendConversationMessage(appconv, "Password change aborted",
						    PAM_ERROR_MSG, &options);
					ni_free(d);
					return PAM_AUTHTOK_RECOVER_ERR;
				}
			}
			else if (!strcmp(newPassword, miscptr))
			{
				miscptr = NULL;
				break;
			}
			sendConversationMessage(appconv, "You must enter the same password",
						PAM_ERROR_MSG, &options);
			miscptr = NULL;
			newPassword = NULL;
		}
		else
		{
			sendConversationMessage(appconv, cmiscptr, PAM_ERROR_MSG, &options);
			cmiscptr = NULL;
			newPassword = NULL;
		}
	}

	if (cmiscptr != NULL || newPassword == NULL)
	{
		ni_free(d);
		return PAM_MAXTRIES;
	}
	/*
         * Lock onto the master server.
         */
	ni_needwrite(d, 1);

	/*
         * Authenticate if necessary
         */
	if (isroot == 0)
	{
		ni_setuser(d, uname);
		ni_setpassword(d, oldPassword);
	}
	/*
        * Create a random salt
        */
	srandom((int) time((time_t *) NULL));
	salt[0] = saltchars[random() % strlen(saltchars)];
	salt[1] = saltchars[random() % strlen(saltchars)];
	salt[2] = '\0';
	newHash = crypt(newPassword, salt);

	/*
         * Change the password in NetInfo.
         */
	status = ni_read(d, &dir, &pl);
	if (status != NI_OK)
	{
		ni_free(d);
		syslog(LOG_ERR, "NetInfo read failed: %s", ni_error(status));
		return netinfo2PamStatus(status);
	}
	p.nip_name = "passwd";
	p.nip_val.ni_namelist_len = 1;
	p.nip_val.ni_namelist_val = (ni_name *) malloc(sizeof(ni_name));
	p.nip_val.ni_namelist_val[0] = newHash;

	where = ni_proplist_match(pl, p.nip_name, NULL);
	if (where == NI_INDEX_NULL)
		status = ni_createprop(d, &dir, p, NI_INDEX_NULL);
	else
		status = ni_writeprop(d, &dir, where, p.nip_val);

	if (status != NI_OK)
	{
		ni_free(d);
		syslog(LOG_ERR, "NetInfo write property \"passwd\" failed: %s", ni_error(status));
		return netinfo2PamStatus(status);
	}

	/*
	 * Now, update "change" property. If this fails, we've still
	 * updated the password... perhaps the user should be alerted
	 * of this.
	 */
	lifetime = password_lifetime();
	if (lifetime > 0)
	{
		struct timeval tp;
		char change[64];

		where = ni_proplist_match(pl, "change", NULL);

		gettimeofday(&tp, NULL);
		tp.tv_sec += lifetime;

		snprintf(change, sizeof(change), "%ld", tp.tv_sec);

		p.nip_name = "change";
		p.nip_val.ni_namelist_len = 1;
		p.nip_val.ni_namelist_val[0] = change;

		if (where == NI_INDEX_NULL)
			status = ni_createprop(d, &dir, p, NI_INDEX_NULL);
		else
			status = ni_writeprop(d, &dir, where, p.nip_val);

		if (status != NI_OK)
		{
			ni_free(d);
			syslog(LOG_ERR, "NetInfo write property \"change\" failed: %s", ni_error(status));
			return netinfo2PamStatus(status);
		}
	}

	free(p.nip_val.ni_namelist_val);

	ni_free(d);

	/* tell lookupd to invalidate its cache */
	{
		int i, proc = -1;
		unit lookup_buf[MAX_INLINE_UNITS];
#ifdef __NeXT__
		port_t port;
#else
		mach_port_t port;
#endif

		port = _lookupd_port(0);
		(void) _lookup_link(port, "_invalidatecache", &proc);
		(void) _lookup_one(port, proc, NULL, 0, lookup_buf, &i);
	}

	return PAM_SUCCESS;
}
Exemplo n.º 28
0
static int
last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, time_t *lltime)
{
    struct flock last_lock;
    struct lastlog last_login;
    int retval = PAM_SUCCESS;
    char the_time[256];
    char *date = NULL;
    char *host = NULL;
    char *line = NULL;

    memset(&last_lock, 0, sizeof(last_lock));
    last_lock.l_type = F_RDLCK;
    last_lock.l_whence = SEEK_SET;
    last_lock.l_start = sizeof(last_login) * (off_t) uid;
    last_lock.l_len = sizeof(last_login);

    if (fcntl(last_fd, F_SETLK, &last_lock) < 0) {
        D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
	pam_syslog(pamh, LOG_WARNING,
		   "file %s is locked/read", _PATH_LASTLOG);
	sleep(LASTLOG_IGNORE_LOCK_TIME);
    }

    if (pam_modutil_read(last_fd, (char *) &last_login,
			 sizeof(last_login)) != sizeof(last_login)) {
        memset(&last_login, 0, sizeof(last_login));
    }

    last_lock.l_type = F_UNLCK;
    (void) fcntl(last_fd, F_SETLK, &last_lock);        /* unlock */

    *lltime = last_login.ll_time;
    if (!last_login.ll_time) {
        if (announce & LASTLOG_DEBUG) {
	    pam_syslog(pamh, LOG_DEBUG,
		       "first login for user with uid %lu",
		       (unsigned long int)uid);
	}
    }

    if (!(announce & LASTLOG_QUIET)) {

	if (last_login.ll_time) {

	    /* we want the date? */
	    if (announce & LASTLOG_DATE) {
	        struct tm *tm, tm_buf;
		time_t ll_time;

		ll_time = last_login.ll_time;
		tm = localtime_r (&ll_time, &tm_buf);
		strftime (the_time, sizeof (the_time),
	        /* TRANSLATORS: "strftime options for date of last login" */
			  _(" %a %b %e %H:%M:%S %Z %Y"), tm);

		date = the_time;
	    }

	    /* we want & have the host? */
	    if ((announce & LASTLOG_HOST)
		&& (last_login.ll_host[0] != '\0')) {
		/* TRANSLATORS: " from <host>" */
		if (asprintf(&host, _(" from %.*s"), UT_HOSTSIZE,
			     last_login.ll_host) < 0) {
		    pam_syslog(pamh, LOG_ERR, "out of memory");
		    retval = PAM_BUF_ERR;
		    goto cleanup;
		}
	    }

	    /* we want and have the terminal? */
	    if ((announce & LASTLOG_LINE)
		&& (last_login.ll_line[0] != '\0')) {
		/* TRANSLATORS: " on <terminal>" */
		if (asprintf(&line, _(" on %.*s"), UT_LINESIZE,
			     last_login.ll_line) < 0) {
		    pam_syslog(pamh, LOG_ERR, "out of memory");
		    retval = PAM_BUF_ERR;
		    goto cleanup;
		}
	    }

	    if (date != NULL || host != NULL || line != NULL)
		    /* TRANSLATORS: "Last login: <date> from <host> on <terminal>" */
		    retval = pam_info(pamh, _("Last login:%s%s%s"),
			      date ? date : "",
			      host ? host : "",
			      line ? line : "");
	} else if (announce & LASTLOG_NEVER) {
		D(("this is the first time this user has logged in"));
		retval = pam_info(pamh, "%s", _("Welcome to your new account!"));
	}
    }

    /* cleanup */
 cleanup:
    memset(&last_login, 0, sizeof(last_login));
    _pam_overwrite(date);
    _pam_overwrite(host);
    _pam_drop(host);
    _pam_overwrite(line);
    _pam_drop(line);

    return retval;
}
Exemplo n.º 29
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;
}
Exemplo n.º 30
0
static int
get_folder(pam_handle_t *pamh, int ctrl,
	   const char *path_mail, char **folder_p, size_t hashcount)
{
    int retval;
    const char *user, *path;
    char *folder = NULL;
    const struct passwd *pwd = NULL;

    retval = pam_get_user(pamh, &user, NULL);
    if (retval != PAM_SUCCESS || user == NULL) {
	pam_syslog(pamh, LOG_ERR, "cannot determine username");
	retval = PAM_USER_UNKNOWN;
	goto get_folder_cleanup;
    }

    if (ctrl & PAM_NEW_MAIL_DIR) {
	path = path_mail;
	if (*path == '~') {	/* support for $HOME delivery */
	    pwd = pam_modutil_getpwnam(pamh, user);
	    if (pwd == NULL) {
		pam_syslog(pamh, LOG_ERR, "user unknown");
		retval = PAM_USER_UNKNOWN;
		goto get_folder_cleanup;
	    }
	    /*
	     * "~/xxx" and "~xxx" are treated as same
	     */
	    if (!*++path || (*path == '/' && !*++path)) {
		pam_syslog(pamh, LOG_ERR,
			   "badly formed mail path [%s]", path_mail);
		retval = PAM_SERVICE_ERR;
		goto get_folder_cleanup;
	    }
	    ctrl |= PAM_HOME_MAIL;
	    if (hashcount != 0) {
		pam_syslog(pamh, LOG_ERR,
			   "cannot do hash= and home directory mail");
	    }
	}
    } else {
	path = DEFAULT_MAIL_DIRECTORY;
    }

    /* put folder together */

    hashcount = hashcount < strlen(user) ? hashcount : strlen(user);

    retval = PAM_BUF_ERR;
    if (ctrl & PAM_HOME_MAIL) {
	if (asprintf(&folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path) < 0)
	    goto get_folder_cleanup;
    } else {
	int rc;
	size_t i;
	char *hash;

	if ((hash = malloc(2 * hashcount + 1)) == NULL)
	    goto get_folder_cleanup;

	for (i = 0; i < hashcount; i++) {
	    hash[2 * i] = '/';
	    hash[2 * i + 1] = user[i];
	}
	hash[2 * i] = '\0';

	rc = asprintf(&folder, MAIL_FILE_FORMAT, path, hash, user);
	_pam_overwrite(hash);
	_pam_drop(hash);
	if (rc < 0)
	    goto get_folder_cleanup;
    }
    D(("folder=[%s]", folder));
    retval = PAM_SUCCESS;

    /* tidy up */

  get_folder_cleanup:
    user = NULL;
    path = NULL;

    *folder_p = folder;
    folder = NULL;

    if (retval == PAM_BUF_ERR)
	pam_syslog(pamh, LOG_CRIT, "out of memory for mail folder");

    return retval;
}