Initial revision
[freeradius.git] / src / modules / rlm_pam / rlm_pam.c
1 /*
2  * pam.c        Functions to access the PAM library. This was taken
3  *              from the hacks that miguel a.l. paraz <map@iphil.net>
4  *              did on radiusd-cistron-1.5.3 and migrated to a
5  *              separate file.
6  *
7  *              That, in fact, was again based on the original stuff
8  *              from Jeph Blaize <jab@kiva.net> done in May 1997.
9  *
10  * Version:     @(#)pam.c  1.10  14-Jul-1998  cdent@kiva.net
11  *
12  */
13
14 #include        "autoconf.h"
15
16 #include        <sys/types.h>
17 #include        <sys/socket.h>
18 #include        <sys/time.h>
19 #include        <netinet/in.h>
20
21 #include        <stdio.h>
22 #include        <string.h>
23 #include        <pwd.h>
24 #include        <time.h>
25 #include        <ctype.h>
26
27 #ifdef WITH_PAM
28 #  include      <security/pam_appl.h>
29 #endif
30
31 #if HAVE_MALLOC_H
32 #  include      <malloc.h>
33 #endif
34
35 #include        "radiusd.h"
36 #include        "modules.h"
37
38 #ifdef WITH_PAM
39 /*************************************************************************
40  *
41  *      Function: PAM_conv
42  *
43  *      Purpose: Dialogue between RADIUS and PAM modules.
44  *
45  * jab - stolen from pop3d
46  *************************************************************************/
47
48 static char *PAM_username;
49 static char *PAM_password;
50 static int PAM_error =0;
51
52 static int PAM_conv (int num_msg,
53                      const struct pam_message **msg,
54                      struct pam_response **resp,
55                      void *appdata_ptr) {
56   int count = 0, replies = 0;
57   struct pam_response *reply = NULL;
58   int size = sizeof(struct pam_response);
59   
60 #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
61   if (!reply) return PAM_CONV_ERR; \
62   size += sizeof(struct pam_response)
63 #define COPY_STRING(s) (s) ? strdup(s) : NULL
64                                      
65   for (count = 0; count < num_msg; count++) {
66     switch (msg[count]->msg_style) {
67     case PAM_PROMPT_ECHO_ON:
68       GET_MEM;
69       reply[replies].resp_retcode = PAM_SUCCESS;
70       reply[replies++].resp = COPY_STRING(PAM_username);
71       /* PAM frees resp */
72       break;
73     case PAM_PROMPT_ECHO_OFF:
74       GET_MEM;
75       reply[replies].resp_retcode = PAM_SUCCESS;
76       reply[replies++].resp = COPY_STRING(PAM_password);
77       /* PAM frees resp */
78       break;
79     case PAM_TEXT_INFO:
80       /* ignore it... */
81       break;
82     case PAM_ERROR_MSG:
83     default:
84       /* Must be an error of some sort... */
85       free (reply);
86       PAM_error = 1;
87       return PAM_CONV_ERR;
88     }
89   }
90   if (reply) *resp = reply;
91
92   return PAM_SUCCESS;
93 }
94
95 struct pam_conv conv = {
96   PAM_conv,
97   NULL
98 };
99
100 /*************************************************************************
101  *
102  *      Function: pam_pass
103  *
104  *      Purpose: Check the users password against the standard UNIX
105  *               password table + PAM.
106  *
107  * jab start 19970529
108  *************************************************************************/
109
110 /* cjd 19980706
111  * 
112  * for most flexibility, passing a pamauth type to this function
113  * allows you to have multiple authentication types (i.e. multiple
114  * files associated with radius in /etc/pam.d)
115  */
116 static int pam_pass(char *name, char *passwd, const char *pamauth)
117 {
118     pam_handle_t *pamh=NULL;
119     int retval;
120
121     PAM_username = name;
122     PAM_password = passwd;
123
124     DEBUG("pam_pass: using pamauth string <%s> for pam.conf lookup", pamauth);
125     retval = pam_start(pamauth, name, &conv, &pamh);
126     if (retval != PAM_SUCCESS) {
127       DEBUG("pam_pass: function pam_start FAILED for <%s>. Reason: %s",
128             name, pam_strerror(pamh, retval));
129       return -1;
130     }
131
132     retval = pam_authenticate(pamh, 0);
133     if (retval != PAM_SUCCESS) {
134       DEBUG("pam_pass: function pam_authenticate FAILED for <%s>. Reason: %s",
135             name, pam_strerror(pamh, retval));
136       pam_end(pamh, 0);
137       return -1;
138     }
139
140     retval = pam_acct_mgmt(pamh, 0);
141     if (retval != PAM_SUCCESS) {
142       DEBUG("pam_pass: function pam_acct_mgmt FAILED for <%s>. Reason: %s",
143             name, pam_strerror(pamh, retval));
144       pam_end(pamh, 0);
145       return -1;
146     }
147
148     DEBUG("pam_pass: authentication succeeded for <%s>", name);
149     pam_end(pamh, 0);
150     return 0;
151 }
152
153 /* translate between function declarations */
154 static int pam_auth(REQUEST *request, char *username, char *password)
155 {
156         int     r;
157
158         r = pam_pass(username, password, "radiusd");
159         return (r == 0) ? RLM_AUTH_OK : RLM_AUTH_REJECT;
160 }
161
162 #else /* WITH_PAM */
163
164 static int pam_auth(REQUEST *request, char *username, char *password)
165 {
166         return RLM_AUTH_REJECT;
167 }
168
169 #endif
170
171 module_t rlm_pam = {
172   "PAM",
173   0,                            /* type: reserved */
174   NULL,                         /* initialize */
175   NULL,                         /* authorize */
176   pam_auth,                     /* authenticate */
177   NULL,                         /* accounting */
178   NULL,                         /* detach */
179 };
180