1 /* $Id$ */
2 /*
3 * Copyright (c) 2006 Aidan Van Dyk
4 * Copyright (c) 2006 iFAX Solutions, Inc.
5 * HylaFAX is a trademark of Silicon Graphics
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
14 *
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 */
26
27 #include "HylaFAXServer.h"
28
29 #include <unistd.h>
30
31 #ifdef HAVE_PAM
32 extern "C" {
33 #include <security/pam_appl.h>
34 }
35
36
37
38 extern int
39 pamconv(int num_msg, STRUCT_PAM_MESSAGE **msg, struct pam_response **resp, void *appdata);
40
41
42 int
pamconv(int num_msg,STRUCT_PAM_MESSAGE ** msg,struct pam_response ** resp,void * appdata)43 pamconv(int num_msg, STRUCT_PAM_MESSAGE **msg, struct pam_response **resp, void *appdata)
44 {
45 char *password =(char*) appdata;
46 struct pam_response* replies;
47
48 if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
49 return PAM_CONV_ERR;
50
51 //logWarning("pamconv: %d [%x] with \"%s\"", num_msg, msg[0]->msg_style, password);
52
53 if (password == NULL)
54 return PAM_CONV_ERR;
55 #if 0
56 /*
57 * Solaris doesn't have PAM_CONV_AGAIN defined.
58 */
59 #ifdef PAM_CONV_AGAIN
60 return PAM_CONV_AGAIN;
61 #else
62 return PAM_CONV_ERR;
63 #endif
64 #endif
65
66 replies=(struct pam_response*)calloc(num_msg, sizeof(struct pam_response));
67
68 replies[0].resp = strdup(password);
69 replies[0].resp_retcode = 0;
70 *resp = replies;
71
72 return PAM_SUCCESS;
73 }
74
do_pamauth(pam_handle_t * pamh)75 int do_pamauth(pam_handle_t * pamh)
76 {
77 int pamret;
78
79 for (int i = 0; i < 10; i++)
80 {
81 /*
82 * PAM supports event-driven applications by returning PAM_INCOMPLETE
83 * and requiring the application to recall pam_authenticate after the
84 * underlying PAM module is ready. The application is supposed to
85 * utilize the pam_conv structure to determine when the authentication
86 * module is ready. However, in our case we're not event-driven, and
87 * so we can wait, and a call to sleep saves us the headache.
88 */
89 pamret = pam_authenticate(pamh, 0);
90 #ifdef PAM_INCOMPLETE
91 if (pamret != PAM_INCOMPLETE)
92 #endif
93 break;
94 sleep(1);
95 };
96
97 if (pamret == PAM_SUCCESS)
98 {
99 pamret = pam_acct_mgmt(pamh, 0);
100 if (pamret != PAM_SUCCESS)
101 logNotice("pam_acct_mgmt failed in pamCheck with 0x%X: %s", pamret, pam_strerror(pamh, pamret));
102 }
103 return pamret;
104 }
105
do_pamcheck(const char * user,const char * passwd,const char * remoteaddr)106 bool do_pamcheck(const char* user, const char* passwd, const char* remoteaddr)
107 {
108 /*
109 * The effective uid must be privileged enough to
110 * handle whatever the PAM module may require.
111 */
112 bool retval = false;
113 uid_t ouid = geteuid();
114 (void) seteuid(0);
115
116 int pamret = PAM_SUCCESS;;
117 pam_handle_t *pamh;
118 struct pam_conv conv = {pamconv, (void*)passwd};
119
120 pamret = pam_start(FAX_SERVICE, user, &conv, &pamh);
121 if (pamret != PAM_SUCCESS)
122 {
123 logNotice("pam_start failed in pamCheck with 0x%X: %s", pamret, pam_strerror(pamh, pamret));
124 return false;
125 }
126 pamret = pam_set_item(pamh, PAM_RHOST, remoteaddr);
127 if (pamret == PAM_SUCCESS)
128 {
129 pamret = do_pamauth(pamh);
130 if (pamret == PAM_SUCCESS)
131 retval = true;
132 else
133 logNotice("pam_authenticate failed in pamCheck with 0x%X: %s", pamret, pam_strerror(pamh, pamret));
134 } else
135 logNotice("pam_set_item (PAM_RHOST) failed in pamCheck with 0x%X: %s", pamret, pam_strerror(pamh, pamret));
136
137
138 pamret = pam_end(pamh, pamret);
139
140 if (pamret != PAM_SUCCESS)
141 logNotice("pam_end failed with 0x%X: %s", pamret, pam_strerror(pamh, pamret));
142
143 (void) seteuid(ouid);
144
145 /*
146 * And we need to reset our logging because pam clobbers us
147 */
148 HylaFAXServer::setupLogging();
149
150 return retval;
151 }
152
153 #endif // HAVE_PAM
154
155 bool
checkuserPAM(const char * name)156 HylaFAXServer::checkuserPAM(const char* name)
157 {
158 #ifdef HAVE_PAM
159 if (IS(LOGGEDIN)) {
160 logNotice("PAM authentication for %s can't be used for a re-issuance of USER command because of chroot jail\n", name);
161 return false;
162 }
163
164
165 /*
166 * Here should go code to se if the user is valid for PAM
167 */
168 return do_pamcheck(name, NULL, remoteaddr);
169 #endif
170
171 return(false);
172 }
173
checkpasswdPAM(const char * pass)174 bool HylaFAXServer::checkpasswdPAM (const char* pass)
175 {
176 #ifdef HAVE_PAM
177 /*
178 * Here should go code to see if the password is ok for the PAM user
179 */
180 return do_pamcheck(the_user, pass, remoteaddr);
181 #endif
182
183 return false;
184 }
185
186
187