[go: up one dir, main page]

Menu

[a2edf5]: / pam.c  Maximize  Restore  History

Download this file

140 lines (121 with data), 3.9 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// This file is part of the loginx project
//
// Copyright (c) 2013 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#include "defs.h"
#include <security/pam_appl.h>
#include <grp.h>
#include <pwd.h>
//----------------------------------------------------------------------
static int xconv (int num_msg, const struct pam_message** msgm, struct pam_response** response, void* appdata_ptr);
//----------------------------------------------------------------------
static pam_handle_t* _pamh = NULL;
static const char* _username = NULL;
static const char* _password = NULL; // Used only by xconv during PamLogin
//----------------------------------------------------------------------
static void verify (int r, const char* fn)
{
if (r == PAM_SUCCESS)
return;
syslog (LOG_ERR, "%s: %s", fn, pam_strerror(_pamh,r));
exit (EXIT_FAILURE);
}
static void PamSetEnvironment (void)
{
const char* user = getlogin();
if (user)
pam_set_item (_pamh, PAM_RUSER, user);
pam_set_item (_pamh, PAM_RHOST, "localhost");
const char* tty = ttyname (STDIN_FILENO);
if (tty)
pam_set_item (_pamh, PAM_TTY, tty);
}
void PamOpen (void)
{
static const struct pam_conv conv = { xconv, NULL };
int r = pam_start (LOGINX_NAME, NULL, &conv, &_pamh);
verify(r,"pam_start");
PamSetEnvironment();
atexit (PamClose);
}
void PamClose (void)
{
if (!_pamh)
return;
if (_username)
PamLogout();
pam_end (_pamh, PAM_SUCCESS);
_pamh = NULL;
}
bool PamLogin (const struct account* acct, const char* password)
{
pam_set_item (_pamh, PAM_USER, acct->name);
_password = password; // Used only by xconv
int r = pam_authenticate (_pamh, PAM_SILENT| PAM_DISALLOW_NULL_AUTHTOK);
verify(r,"pam_authenticate");
r = pam_acct_mgmt (_pamh, PAM_SILENT| PAM_DISALLOW_NULL_AUTHTOK);
if (r == PAM_NEW_AUTHTOK_REQD) {
r = pam_chauthtok(_pamh,PAM_CHANGE_EXPIRED_AUTHTOK);
verify(r,"pam_chauthtok");
}
initgroups (acct->name, acct->gid);
verify(r,"pam_acct_mgmt");
r = pam_setcred(_pamh, PAM_SILENT| PAM_ESTABLISH_CRED);
verify(r,"pam_setcred");
r = pam_open_session (_pamh, PAM_SILENT);
verify(r,"pam_open_session");
pam_get_item (_pamh, PAM_USER, (const void**) &_username);
_password = NULL;
if (!_username || 0 != strcmp (_username, acct->name))
return (false);
// Give ownership of the tty
fchown (STDIN_FILENO, acct->uid, _ttygroup ? _ttygroup : acct->gid);
fchmod (STDIN_FILENO, 0620);
return (true);
}
void PamLogout (void)
{
if (!_username)
return;
// Retake ownership of the tty
fchown (STDIN_FILENO, getuid(), _ttygroup ? _ttygroup : getgid());
fchmod (STDIN_FILENO, 0620);
pam_close_session (_pamh, PAM_SILENT);
pam_setcred (_pamh, PAM_SILENT| PAM_DELETE_CRED);
_username = NULL;
}
static int xconv (int num_msg, const struct pam_message** msgm, struct pam_response** response, void* appdata_ptr __attribute__((unused)))
{
if (num_msg <= 0)
return (PAM_CONV_ERR);
struct pam_response* reply = (struct pam_response*) calloc (num_msg, sizeof(struct pam_response));
if (!reply)
return (PAM_CONV_ERR);
for (int i = 0; i < num_msg; ++i) {
switch (msgm[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
case PAM_PROMPT_ECHO_ON:
reply[i].resp = strdup(_password ? _password : "");
reply[i].resp_retcode = 0;
break;
case PAM_ERROR_MSG:
syslog (LOG_ERR, "%s", msgm[i]->msg);
break;
case PAM_TEXT_INFO:
syslog (LOG_INFO, "%s", msgm[i]->msg);
break;
default: // Anything else fails login
for (int j = 0; j < num_msg; ++j) {
if (reply[j].resp) {
memset (reply[j].resp, 0, strlen(reply[j].resp));
free (reply[j].resp);
reply[j].resp = NULL;
}
}
free(reply);
return (PAM_CONV_ERR);
}
}
*response = reply;
return (PAM_SUCCESS);
}