2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * Please read the file COPYING, README and AUTHORS for more information.
18 * PAM User Authentication
24 #ifdef HAVE_SECURITY_PAM_APPL_H
25 # include <security/pam_appl.h>
27 #ifdef HAVE_PAM_PAM_APPL_H
28 # include <pam/pam_appl.h>
39 static char *password;
42 * PAM "conversation function".
43 * This is a callback function used by the PAM library to get the password.
44 * Please see the PAM documentation for details :-)
47 password_conversation(int num_msg, const struct pam_message **msg,
48 struct pam_response **resp, void *appdata_ptr) {
49 LogDebug("PAM: conv(%d, %d, '%s', '%s')",
50 num_msg, msg[0]->msg_style, msg[0]->msg, appdata_ptr);
52 /* Can we deal with this request? */
53 if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
54 Log(LOG_ERR, "PAM: Unexpected PAM conversation '%d:%s'!",
55 msg[0]->msg_style, msg[0]->msg);
60 /* Sometimes appdata_ptr gets lost!? */
61 appdata_ptr = password;
64 /* Duplicate password ("application data") for the PAM library */
65 *resp = calloc(num_msg, sizeof(struct pam_response));
67 Log(LOG_ERR, "PAM: Out of memory!");
71 (*resp)[0].resp = strdup((char *)appdata_ptr);
72 (*resp)[0].resp_retcode = 0;
74 return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
78 * PAM "conversation" structure.
80 static struct pam_conv conv = {
81 &password_conversation,
86 * Authenticate a connecting client using PAM.
87 * @param Client The client to authenticate.
88 * @return true when authentication succeeded, false otherwise.
91 PAM_Authenticate(CLIENT *Client) {
93 int retval = PAM_SUCCESS;
95 LogDebug("PAM: Authenticate \"%s\" (%s) ...",
96 Client_OrigUser(Client), Client_Mask(Client));
98 /* Set supplied client password */
101 password = strdup(Conn_Password(Client_Conn(Client)));
102 conv.appdata_ptr = Conn_Password(Client_Conn(Client));
105 retval = pam_start(Conf_PAMServiceName, Client_OrigUser(Client), &conv, &pam);
106 if (retval != PAM_SUCCESS) {
107 Log(LOG_ERR, "PAM: Failed to create authenticator! (%d)", retval);
111 pam_set_item(pam, PAM_RUSER, Client_User(Client));
112 pam_set_item(pam, PAM_RHOST, Client_Hostname(Client));
113 #if defined(HAVE_PAM_FAIL_DELAY) && !defined(NO_PAM_FAIL_DELAY)
114 pam_fail_delay(pam, 0);
117 /* PAM authentication ... */
118 retval = pam_authenticate(pam, 0);
121 if (retval == PAM_SUCCESS)
122 Log(LOG_INFO, "PAM: Authenticated \"%s\" (%s).",
123 Client_OrigUser(Client), Client_Mask(Client));
125 Log(LOG_ERR, "PAM: Error on \"%s\" (%s): %s",
126 Client_OrigUser(Client), Client_Mask(Client),
127 pam_strerror(pam, retval));
129 /* Free PAM structures */
130 if (pam_end(pam, retval) != PAM_SUCCESS)
131 Log(LOG_ERR, "PAM: Failed to release authenticator!");
133 return (retval == PAM_SUCCESS);