1 /* ========================================================================
2  * Copyright 1988-2006 University of Washington
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *
11  * ========================================================================
12  */
13 
14 /*
15  * Program:	Pluggable Authentication Modules login services
16  *
17  * Author:	Mark Crispin
18  *		Networks and Distributed Computing
19  *		Computing & Communications
20  *		University of Washington
21  *		Administration Building, AG-44
22  *		Seattle, WA  98195
23  *		Internet: MRC@CAC.Washington.EDU
24  *
25  * Date:	1 August 1988
26  * Last Edited:	31 August 2006
27  */
28 
29 
30 #ifdef MAC_OSX_KLUDGE		/* why can't Apple be compatible? */
31 #include <pam/pam_appl.h>
32 #else
33 #include <security/pam_appl.h>
34 #endif
35 
36 struct checkpw_cred {
37   char *uname;			/* user name */
38   char *pass;			/* password */
39 };
40 
41 /* PAM conversation function
42  * Accepts: number of messages
43  *	    vector of messages
44  *	    pointer to response return
45  *	    application data
46  * Returns: PAM_SUCCESS if OK, response vector filled in, else PAM_CONV_ERR
47  */
48 
checkpw_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)49 static int checkpw_conv (int num_msg,const struct pam_message **msg,
50 			 struct pam_response **resp,void *appdata_ptr)
51 {
52   int i;
53   struct checkpw_cred *cred = (struct checkpw_cred *) appdata_ptr;
54   struct pam_response *reply = fs_get (sizeof (struct pam_response) * num_msg);
55   for (i = 0; i < num_msg; i++) switch (msg[i]->msg_style) {
56   case PAM_PROMPT_ECHO_ON:	/* assume want user name */
57     reply[i].resp_retcode = PAM_SUCCESS;
58     reply[i].resp = cpystr (cred->uname);
59     break;
60   case PAM_PROMPT_ECHO_OFF:	/* assume want password */
61     reply[i].resp_retcode = PAM_SUCCESS;
62     reply[i].resp = cpystr (cred->pass);
63     break;
64   case PAM_TEXT_INFO:
65   case PAM_ERROR_MSG:
66     reply[i].resp_retcode = PAM_SUCCESS;
67     reply[i].resp = NULL;
68     break;
69   default:			/* unknown message style */
70     fs_give ((void **) &reply);
71     return PAM_CONV_ERR;
72   }
73   *resp = reply;
74   return PAM_SUCCESS;
75 }
76 
77 
78 /* PAM cleanup
79  * Accepts: handle
80  */
81 
checkpw_cleanup(pam_handle_t * hdl)82 static void checkpw_cleanup (pam_handle_t *hdl)
83 {
84 #if 0	/* see checkpw() for why this is #if 0 */
85   pam_close_session (hdl,NIL);	/* close session [uw]tmp */
86 #endif
87   pam_setcred (hdl,PAM_DELETE_CRED);
88   pam_end (hdl,PAM_SUCCESS);
89 }
90 
91 /* Server log in
92  * Accepts: user name string
93  *	    password string
94  * Returns: T if password validated, NIL otherwise
95  */
96 
checkpw(struct passwd * pw,char * pass,int argc,char * argv[])97 struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
98 {
99   pam_handle_t *hdl;
100   struct pam_conv conv;
101   struct checkpw_cred cred;
102   char *name = cpystr (pw->pw_name);
103   conv.conv = &checkpw_conv;
104   conv.appdata_ptr = &cred;
105   cred.uname = name;
106   cred.pass = pass;
107   if (pw = ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
108 			pw->pw_name,&conv,&hdl) == PAM_SUCCESS) &&
109 	    (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) == PAM_SUCCESS) &&
110 	    (pam_authenticate (hdl,NIL) == PAM_SUCCESS) &&
111 	    (pam_acct_mgmt (hdl,NIL) == PAM_SUCCESS) &&
112 	    (pam_setcred (hdl,PAM_ESTABLISH_CRED) == PAM_SUCCESS)) ?
113       getpwnam (name) : NIL) {
114 #if 0
115     /*
116      * Some people have reported that this causes a SEGV in strncpy() from
117      * pam_unix.so.1
118      */
119     /*
120      * This pam_open_session() call is inconsistant with how we handle other
121      * platforms, where we don't write [uw]tmp records.  However, unlike our
122      * code on other platforms, pam_acct_mgmt() will check those records for
123      * inactivity and deny the authentication.
124      */
125     pam_open_session (hdl,NIL);	/* make sure account doesn't go inactive */
126 #endif
127 				/* arm hook to delete credentials */
128     mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup);
129     mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl);
130   }
131   else checkpw_cleanup (hdl);	/* clean up */
132   fs_give ((void **) &name);
133 				/* reset log facility in case PAM broke it */
134   if (myServerName) openlog (myServerName,LOG_PID,syslog_facility);
135   return pw;
136 }
137