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