Xcode builds ("make xcode"): disable pam_fail_delay()
[ngircd-alex.git] / src / ngircd / pam.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2010 Alexander Barton (alex@barton.de).
4  *
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.
10  *
11  * PAM User Authentification
12  */
13
14 #include "portab.h"
15
16 #ifdef PAM
17
18 #include "imp.h"
19 #include <assert.h>
20
21 #include "defines.h"
22 #include "log.h"
23 #include "conn.h"
24 #include "client.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #ifdef HAVE_SECURITY_PAM_APPL_H
30 #include <security/pam_appl.h>
31 #endif
32
33 #ifdef HAVE_PAM_PAM_APPL_H
34 #include <pam/pam_appl.h>
35 #endif
36
37 #include "exp.h"
38 #include "pam.h"
39
40 static char *password;
41
42 /**
43  * PAM "conversation function".
44  * This is a callback function used by the PAM library to get the password.
45  * Please see the PAM documentation for details :-)
46  */
47 static int
48 password_conversation(int num_msg, const struct pam_message **msg,
49                       struct pam_response **resp, void *appdata_ptr) {
50         LogDebug("PAM: conv(%d, %d, '%s', '%s')",
51                  num_msg, msg[0]->msg_style, msg[0]->msg, appdata_ptr);
52
53         /* Can we deal with this request? */
54         if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
55                 Log(LOG_ERR, "PAM: Unexpected PAM conversation '%d:%s'!",
56                     msg[0]->msg_style, msg[0]->msg);
57                 return PAM_CONV_ERR;
58         }
59
60         if (!appdata_ptr) {
61                 /* Sometimes appdata_ptr gets lost!? */
62                 appdata_ptr = password;
63         }
64
65         /* Duplicate password ("application data") for the PAM library */
66         *resp = calloc(num_msg, sizeof(struct pam_response));
67         if (!*resp) {
68                 Log(LOG_ERR, "PAM: Out of memory!");
69                 return PAM_CONV_ERR;
70         }
71
72         (*resp)[0].resp = strdup((char *)appdata_ptr);
73         (*resp)[0].resp_retcode = 0;
74
75         return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
76 }
77
78 /**
79  * PAM "conversation" structure.
80  */
81 static struct pam_conv conv = {
82         &password_conversation,
83         NULL
84 };
85
86 /**
87  * Authenticate a connectiong client using PAM.
88  * @param Client The client to authenticate.
89  * @return true when authentication succeeded, false otherwise.
90  */
91 GLOBAL bool
92 PAM_Authenticate(CLIENT *Client) {
93         pam_handle_t *pam;
94         int retval = PAM_SUCCESS;
95
96         LogDebug("PAM: Authenticate \"%s\" (%s) ...",
97                  Client_OrigUser(Client), Client_Mask(Client));
98
99         /* Set supplied client password */
100         if (password)
101                 free(password);
102         password = strdup(Client_Password(Client));
103         conv.appdata_ptr = password;
104
105         /* Initialize PAM */
106         retval = pam_start("ngircd", Client_OrigUser(Client), &conv, &pam);
107         if (retval != PAM_SUCCESS) {
108                 Log(LOG_ERR, "PAM: Failed to create authenticator! (%d)", retval);
109                 return false;
110         }
111
112         pam_set_item(pam, PAM_RUSER, Client_User(Client));
113         pam_set_item(pam, PAM_RHOST, Client_Hostname(Client));
114 #if defined(HAVE_PAM_FAIL_DELAY) && !defined(NO_PAM_FAIL_DELAY)
115         pam_fail_delay(pam, 0);
116 #endif
117
118         /* PAM authentication ... */
119         retval = pam_authenticate(pam, 0);
120
121         /* Success? */
122         if (retval == PAM_SUCCESS)
123                 Log(LOG_INFO, "PAM: Authenticated \"%s\" (%s).",
124                     Client_OrigUser(Client), Client_Mask(Client));
125         else
126                 Log(LOG_ERR, "PAM: Error on \"%s\" (%s): %s",
127                     Client_OrigUser(Client), Client_Mask(Client),
128                     pam_strerror(pam, retval));
129
130         /* Free PAM structures */
131         if (pam_end(pam, retval) != PAM_SUCCESS)
132                 Log(LOG_ERR, "PAM: Failed to release authenticator!");
133
134         return (retval == PAM_SUCCESS);
135 }
136
137 #endif /* PAM */
138
139 /* -eof- */