[go: up one dir, main page]

Menu

[533284]: / pam.c  Maximize  Restore  History

Download this file

180 lines (154 with data), 5.4 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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// 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 ISC license.
#include "defs.h"
#include <pam_appl.h>
#include <pam_ext.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 char _password [MAX_PW_LEN] = {};
//----------------------------------------------------------------------
static void PamSetEnvironment (void)
{
const char* tty = ttyname (STDIN_FILENO);
if (tty)
pam_set_item (_pamh, PAM_TTY, tty);
}
static bool PamLogError (const char* fn, int ec)
{
char errbuf [128];
snprintf (errbuf, sizeof(errbuf), "%s: %s", fn, pam_strerror(_pamh,ec));
pam_syslog (_pamh, LOG_ERR, "%s", errbuf);
AddMessage (errbuf, true);
return false;
}
void PamOpen (void)
{
static const struct pam_conv conv = { xconv, NULL };
int r = pam_start (LOGINX_NAME, NULL, &conv, &_pamh);
if (r != PAM_SUCCESS) {
pam_syslog (_pamh, LOG_ERR, "pam_start: %s", pam_strerror(_pamh,r));
exit (EXIT_FAILURE);
}
PamSetEnvironment();
atexit (PamClose);
}
void PamClose (void)
{
if (!_pamh)
return;
PamLogout();
pam_end (_pamh, PAM_SUCCESS);
_pamh = NULL;
}
bool PamLogin (void)
{
// Ensure PAM asks for the user, because that's the
// only time the conversation will ask for a password.
pam_set_item (_pamh, PAM_USER, NULL);
// Run authentication
int r;
do
r = pam_authenticate (_pamh, 0);
while (r == PAM_INCOMPLETE);
memset (_password, 0, sizeof(_password));
if (r != PAM_SUCCESS)
return PamLogError ("pam_authenticate", r);
r = pam_acct_mgmt (_pamh, 0);
// Requiring password change at login time is a very bad idea.
// The user can not be expected to come up with a good password
// on short notice. Also, the root filesystem could be mounted r/o.
if (r == PAM_NEW_AUTHTOK_REQD)
r = PAM_SUCCESS; // so, just ignore the demand
if (r != PAM_SUCCESS)
return PamLogError ("pam_acct_mgmt", r);
// Verify that a valid account was selected
const char* username = NULL;
r = pam_get_item (_pamh, PAM_USER, (const void**) &username);
if (r != PAM_SUCCESS || !username)
return PamLogError ("pam_get_item(PAM_USER)", r);
const struct account* acct = SetSelectedAccountByName (username);
if (!acct)
return PamLogError ("SetSelectedAccountByName", r);
// Initialize credentials
initgroups (acct->name, acct->gid);
r = pam_setcred(_pamh, PAM_ESTABLISH_CRED);
if (r != PAM_SUCCESS)
return PamLogError ("pam_setcred", r);
r = pam_open_session (_pamh, 0);
if (r != PAM_SUCCESS)
return PamLogError ("pam_open_session", r);
// Done with interactive login, remove the greeter
CursesCleanup();
// Give ownership of the tty
fchown (STDIN_FILENO, acct->uid, GetTTYGroup());
fchmod (STDIN_FILENO, 0620);
// Log the message
if (!acct->uid)
pam_syslog (_pamh, LOG_NOTICE, "ROOT LOGIN ON %s", _ttyname);
else
pam_syslog (_pamh, LOG_INFO, "LOGIN ON %s BY %s", _ttyname, acct->name);
return true;
}
void PamLogout (void)
{
memset (_password, 0, sizeof(_password));
// Retake ownership of the tty
fchown (STDIN_FILENO, getuid(), GetTTYGroup());
fchmod (STDIN_FILENO, 0620);
pam_close_session (_pamh, PAM_SILENT);
pam_setcred (_pamh, PAM_SILENT| PAM_DELETE_CRED);
}
const char* PamGetenv (const char* name)
{
return pam_getenv (_pamh, name);
}
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 = calloc (num_msg, sizeof(struct pam_response));
if (!reply)
return PAM_CONV_ERR;
int result = PAM_SUCCESS;
for (int i = 0; i < num_msg; ++i) {
const unsigned mss = msgm[i]->msg_style;
if (mss == PAM_PROMPT_ECHO_OFF) {
if (0 != strcmp (msgm[i]->msg, _(PAM_PASSWORD_PROMPT))) {
// If not the main password prompt, ask
reply[i].resp = calloc (MAX_PW_LEN, sizeof(char));
LoginBox (msgm[i]->msg, false, reply[i].resp, MAX_PW_LEN);
} else
reply[i].resp = strdup (_password);
} else if (mss == PAM_PROMPT_ECHO_ON) {
LoginBox (msgm[i]->msg, true, _password, sizeof(_password));
const struct account* acct = SelectedAccountInfo();
reply[i].resp = strdup (acct ? acct->name : "root");
} else if (mss == PAM_TEXT_INFO) {
AddMessage (msgm[i]->msg, false);
pam_syslog (_pamh, LOG_INFO, "%s", msgm[i]->msg);
} else if (mss == PAM_ERROR_MSG) {
AddMessage (msgm[i]->msg, true);
pam_syslog (_pamh, LOG_ERR, "%s", msgm[i]->msg);
} else { // Anything else fails login
// Delete any messages already processed
for (int j = 0; j < num_msg; ++j) {
if (reply[j].resp) {
memset (reply[j].resp, 0, strlen(reply[j].resp));
xfreenull (reply[j].resp);
}
}
xfreenull (reply);
pam_syslog (_pamh, LOG_ERR, _("erroneous conversation (%d)\n"), mss);
result = PAM_CONV_ERR;
break;
}
}
*response = reply;
return result;
}