2 * Author: Damien Miller
3 * Copyright (c) 1999 Damien Miller <djm@mindrot.org>
5 * Created: Thursday December 30 1999
6 * PAM authentication and session management code.
18 #define NEW_AUTHTOK_MSG \
19 "Warning: You password has expired, please change it now"
22 static int pamconv(int num_msg, const struct pam_message **msg,
23 struct pam_response **resp, void *appdata_ptr);
24 void pam_cleanup_proc(void *context);
25 void pam_msg_cat(const char *msg);
27 /* module-local variables */
28 static struct pam_conv conv = {
32 static struct pam_handle_t *pamh = NULL;
33 static const char *pampasswd = NULL;
34 static char *pam_msg = NULL;
36 /* PAM conversation function. This is really a kludge to get the password */
37 /* into PAM and to pick up any messages generated by PAM into pamconv_msg */
38 static int pamconv(int num_msg, const struct pam_message **msg,
39 struct pam_response **resp, void *appdata_ptr)
41 struct pam_response *reply;
44 /* PAM will free this later */
45 reply = malloc(num_msg * sizeof(*reply));
49 for(count = 0; count < num_msg; count++) {
50 switch (msg[count]->msg_style) {
51 case PAM_PROMPT_ECHO_OFF:
52 if (pampasswd == NULL) {
56 reply[count].resp_retcode = PAM_SUCCESS;
57 reply[count].resp = xstrdup(pampasswd);
60 reply[count].resp_retcode = PAM_SUCCESS;
61 reply[count].resp = xstrdup("");
63 if (msg[count]->msg != NULL)
64 pam_msg_cat(msg[count]->msg);
78 /* Called at exit to cleanly shutdown PAM */
79 void pam_cleanup_proc(void *context)
85 pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
86 if (pam_retval != PAM_SUCCESS) {
87 log("Cannot close PAM session: %.200s",
88 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
91 pam_retval = pam_setcred((pam_handle_t *)pamh, PAM_DELETE_CRED);
92 if (pam_retval != PAM_SUCCESS) {
93 log("Cannot delete credentials: %.200s",
94 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
97 pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
98 if (pam_retval != PAM_SUCCESS) {
99 log("Cannot release PAM authentication: %.200s",
100 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
105 /* Attempt password authentation using PAM */
106 int auth_pam_password(struct passwd *pw, const char *password)
108 extern ServerOptions options;
111 /* deny if no user. */
114 if (pw->pw_uid == 0 && options.permit_root_login == 2)
116 if (*password == '\0' && options.permit_empty_passwd == 0)
119 pampasswd = password;
121 pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
122 if (pam_retval == PAM_SUCCESS) {
123 debug("PAM Password authentication accepted for user \"%.100s\"",
127 debug("PAM Password authentication for \"%.100s\" failed: %s",
128 pw->pw_name, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
133 /* Do account management using PAM */
134 int do_pam_account(char *username, char *remote_user)
138 debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname());
139 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST,
140 get_canonical_hostname());
141 if (pam_retval != PAM_SUCCESS) {
142 fatal("PAM set rhost failed: %.200s",
143 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
146 if (remote_user != NULL) {
147 debug("PAM setting ruser to \"%.200s\"", remote_user);
148 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
149 if (pam_retval != PAM_SUCCESS) {
150 fatal("PAM set ruser failed: %.200s",
151 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
155 pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
156 switch (pam_retval) {
158 /* This is what we want */
160 case PAM_NEW_AUTHTOK_REQD:
161 pam_msg_cat(NEW_AUTHTOK_MSG);
164 log("PAM rejected by account configuration: %.200s",
165 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
172 /* Do PAM-specific session initialisation */
173 void do_pam_session(char *username, const char *ttyname)
177 if (ttyname != NULL) {
178 debug("PAM setting tty to \"%.200s\"", ttyname);
179 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_TTY, ttyname);
180 if (pam_retval != PAM_SUCCESS) {
181 fatal("PAM set tty failed: %.200s",
182 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
186 pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
187 if (pam_retval != PAM_SUCCESS) {
188 fatal("PAM session setup failed: %.200s",
189 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
193 /* Set PAM credentials */
194 void do_pam_setcred()
198 debug("PAM establishing creds");
199 pam_retval = pam_setcred((pam_handle_t *)pamh, PAM_ESTABLISH_CRED);
200 if (pam_retval != PAM_SUCCESS) {
201 fatal("PAM setcred failed: %.200s",
202 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
206 /* Cleanly shutdown PAM */
207 void finish_pam(void)
209 pam_cleanup_proc(NULL);
210 fatal_remove_cleanup(&pam_cleanup_proc, NULL);
213 /* Start PAM authentication for specified account */
214 void start_pam(struct passwd *pw)
218 debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
220 pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv,
221 (pam_handle_t**)&pamh);
223 if (pam_retval != PAM_SUCCESS) {
224 fatal("PAM initialisation failed: %.200s",
225 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
228 fatal_add_cleanup(&pam_cleanup_proc, NULL);
231 /* Return list of PAM enviornment strings */
232 char **fetch_pam_environment(void)
234 #ifdef HAVE_PAM_GETENVLIST
235 return(pam_getenvlist((pam_handle_t *)pamh));
236 #else /* HAVE_PAM_GETENVLIST */
238 #endif /* HAVE_PAM_GETENVLIST */
241 /* Print any messages that have been generated during authentication */
242 /* or account checking to stderr */
243 void print_pam_messages(void)
246 fprintf(stderr, pam_msg);
249 /* Append a message to the PAM message buffer */
250 void pam_msg_cat(const char *msg)
256 new_msg_len = strlen(msg);
259 pam_msg_len = strlen(pam_msg);
260 pam_msg = xrealloc(pam_msg, new_msg_len + pam_msg_len + 2);
261 p = pam_msg + pam_msg_len;
263 pam_msg = p = xmalloc(new_msg_len + 2);
266 memcpy(p, msg, new_msg_len);
267 p[new_msg_len] = '\n';
268 p[new_msg_len + 1] = '\0';