]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/pam.c
Add PAMServiceName setting to specify the used PAM configuration
[ngircd-alex.git] / src / ngircd / pam.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
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
12 #include "portab.h"
13
14 #ifdef PAM
15
16 /**
17  * @file
18  * PAM User Authentication
19  */
20
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #ifdef HAVE_SECURITY_PAM_APPL_H
25 # include <security/pam_appl.h>
26 #endif
27 #ifdef HAVE_PAM_PAM_APPL_H
28 # include <pam/pam_appl.h>
29 #endif
30
31 #include "defines.h"
32 #include "log.h"
33 #include "conn.h"
34 #include "client.h"
35 #include "conf.h"
36
37 #include "pam.h"
38
39 static char *password;
40
41 /**
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 :-)
45  */
46 static int
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);
51
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);
56                 return PAM_CONV_ERR;
57         }
58
59         if (!appdata_ptr) {
60                 /* Sometimes appdata_ptr gets lost!? */
61                 appdata_ptr = password;
62         }
63
64         /* Duplicate password ("application data") for the PAM library */
65         *resp = calloc(num_msg, sizeof(struct pam_response));
66         if (!*resp) {
67                 Log(LOG_ERR, "PAM: Out of memory!");
68                 return PAM_CONV_ERR;
69         }
70
71         (*resp)[0].resp = strdup((char *)appdata_ptr);
72         (*resp)[0].resp_retcode = 0;
73
74         return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
75 }
76
77 /**
78  * PAM "conversation" structure.
79  */
80 static struct pam_conv conv = {
81         &password_conversation,
82         NULL
83 };
84
85 /**
86  * Authenticate a connecting client using PAM.
87  * @param Client The client to authenticate.
88  * @return true when authentication succeeded, false otherwise.
89  */
90 GLOBAL bool
91 PAM_Authenticate(CLIENT *Client) {
92         pam_handle_t *pam;
93         int retval = PAM_SUCCESS;
94
95         LogDebug("PAM: Authenticate \"%s\" (%s) ...",
96                  Client_OrigUser(Client), Client_Mask(Client));
97
98         /* Set supplied client password */
99         if (password)
100                 free(password);
101         password = strdup(Conn_Password(Client_Conn(Client)));
102         conv.appdata_ptr = Conn_Password(Client_Conn(Client));
103
104         /* Initialize PAM */
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);
108                 return false;
109         }
110
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);
115 #endif
116
117         /* PAM authentication ... */
118         retval = pam_authenticate(pam, 0);
119
120         /* Success? */
121         if (retval == PAM_SUCCESS)
122                 Log(LOG_INFO, "PAM: Authenticated \"%s\" (%s).",
123                     Client_OrigUser(Client), Client_Mask(Client));
124         else
125                 Log(LOG_ERR, "PAM: Error on \"%s\" (%s): %s",
126                     Client_OrigUser(Client), Client_Mask(Client),
127                     pam_strerror(pam, retval));
128
129         /* Free PAM structures */
130         if (pam_end(pam, retval) != PAM_SUCCESS)
131                 Log(LOG_ERR, "PAM: Failed to release authenticator!");
132
133         return (retval == PAM_SUCCESS);
134 }
135
136 #endif /* PAM */
137
138 /* -eof- */