Mercurial > dropbear
comparison svr-authpam.c @ 391:00fcf5045160
propagate from branch 'au.asn.ucc.matt.ltc.dropbear' (head c1db4398d56c56c6d06ae1e20c1e0d04dbb598ed)
to branch 'au.asn.ucc.matt.dropbear' (head d26d5eb2837f46b56a33fb0e7573aa0201abd4d5)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 11 Jan 2007 04:29:08 +0000 |
parents | 306499676384 |
children | 517e76bdfb2d |
comparison
equal
deleted
inserted
replaced
390:d8e44bef7917 | 391:00fcf5045160 |
---|---|
1 /* | |
2 * Dropbear SSH | |
3 * | |
4 * Copyright (c) 2004 Martin Carlsson | |
5 * Portions (c) 2004 Matt Johnston | |
6 * All rights reserved. | |
7 * | |
8 * Permission is hereby granted, free of charge, to any person obtaining a copy | |
9 * of this software and associated documentation files (the "Software"), to deal | |
10 * in the Software without restriction, including without limitation the rights | |
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
12 * copies of the Software, and to permit persons to whom the Software is | |
13 * furnished to do so, subject to the following conditions: | |
14 * | |
15 * The above copyright notice and this permission notice shall be included in | |
16 * all copies or substantial portions of the Software. | |
17 * | |
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
24 * SOFTWARE. */ | |
25 | |
26 /* Validates a user password using PAM */ | |
27 | |
28 #include "includes.h" | |
29 #include "session.h" | |
30 #include "buffer.h" | |
31 #include "dbutil.h" | |
32 #include "auth.h" | |
33 | |
34 #if defined(HAVE_SECURITY_PAM_APPL_H) | |
35 #include <security/pam_appl.h> | |
36 #elif defined (HAVE_PAM_PAM_APPL_H) | |
37 #include <pam/pam_appl.h> | |
38 #endif | |
39 | |
40 #ifdef ENABLE_SVR_PAM_AUTH | |
41 | |
42 struct UserDataS { | |
43 char* user; | |
44 char* passwd; | |
45 }; | |
46 | |
47 /* PAM conversation function - for now we only handle one message */ | |
48 int | |
49 pamConvFunc(int num_msg, | |
50 const struct pam_message **msg, | |
51 struct pam_response **respp, | |
52 void *appdata_ptr) { | |
53 | |
54 int rc = PAM_SUCCESS; | |
55 struct pam_response* resp = NULL; | |
56 struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr; | |
57 unsigned int msg_len = 0; | |
58 unsigned int i = 0; | |
59 | |
60 const char* message = (*msg)->msg; | |
61 | |
62 /* make a copy we can strip */ | |
63 char * compare_message = m_strdup(message); | |
64 | |
65 TRACE(("enter pamConvFunc")) | |
66 | |
67 if (num_msg != 1) { | |
68 /* If you're getting here - Dropbear probably can't support your pam | |
69 * modules. This whole file is a bit of a hack around lack of | |
70 * asynchronocity in PAM anyway. */ | |
71 dropbear_log(LOG_INFO, "pamConvFunc() called with >1 messages: not supported."); | |
72 return PAM_CONV_ERR; | |
73 } | |
74 | |
75 TRACE(("msg_style is %d", (*msg)->msg_style)) | |
76 if (compare_message) { | |
77 TRACE(("message is '%s'", compare_message)) | |
78 } else { | |
79 TRACE(("null message")) | |
80 } | |
81 | |
82 | |
83 /* Make the string lowercase. */ | |
84 msg_len = strlen(compare_message); | |
85 for (i = 0; i < msg_len; i++) { | |
86 compare_message[i] = tolower(compare_message[i]); | |
87 } | |
88 | |
89 /* If the string ends with ": ", remove the space. | |
90 ie "login: " vs "login:" */ | |
91 if (msg_len > 2 | |
92 && compare_message[msg_len-2] == ':' | |
93 && compare_message[msg_len-1] == ' ') { | |
94 compare_message[msg_len-1] = '\0'; | |
95 } | |
96 | |
97 switch((*msg)->msg_style) { | |
98 | |
99 case PAM_PROMPT_ECHO_OFF: | |
100 | |
101 if (!(strcmp(compare_message, "password:") == 0)) { | |
102 /* We don't recognise the prompt as asking for a password, | |
103 so can't handle it. Add more above as required for | |
104 different pam modules/implementations */ | |
105 dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (no echo)", | |
106 compare_message); | |
107 rc = PAM_CONV_ERR; | |
108 break; | |
109 } | |
110 | |
111 /* You have to read the PAM module-writers' docs (do we look like | |
112 * module writers? no.) to find out that the module will | |
113 * free the pam_response and its resp element - ie we _must_ malloc | |
114 * it here */ | |
115 resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); | |
116 memset(resp, 0, sizeof(struct pam_response)); | |
117 | |
118 resp->resp = m_strdup(userDatap->passwd); | |
119 m_burn(userDatap->passwd, strlen(userDatap->passwd)); | |
120 (*respp) = resp; | |
121 break; | |
122 | |
123 | |
124 case PAM_PROMPT_ECHO_ON: | |
125 | |
126 if (!((strcmp(compare_message, "login:" ) == 0) | |
127 || (strcmp(compare_message, "please enter username:") == 0))) { | |
128 /* We don't recognise the prompt as asking for a username, | |
129 so can't handle it. Add more above as required for | |
130 different pam modules/implementations */ | |
131 dropbear_log(LOG_NOTICE, "PAM unknown prompt %s (with echo)", | |
132 compare_message); | |
133 rc = PAM_CONV_ERR; | |
134 break; | |
135 } | |
136 | |
137 /* You have to read the PAM module-writers' docs (do we look like | |
138 * module writers? no.) to find out that the module will | |
139 * free the pam_response and its resp element - ie we _must_ malloc | |
140 * it here */ | |
141 resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); | |
142 memset(resp, 0, sizeof(struct pam_response)); | |
143 | |
144 resp->resp = m_strdup(userDatap->user); | |
145 TRACE(("userDatap->user='%s'", userDatap->user)) | |
146 (*respp) = resp; | |
147 break; | |
148 | |
149 default: | |
150 TRACE(("Unknown message type")) | |
151 rc = PAM_CONV_ERR; | |
152 break; | |
153 } | |
154 | |
155 m_free(compare_message); | |
156 TRACE(("leave pamConvFunc, rc %d", rc)) | |
157 | |
158 return rc; | |
159 } | |
160 | |
161 /* Process a password auth request, sending success or failure messages as | |
162 * appropriate. To the client it looks like it's doing normal password auth (as | |
163 * opposed to keyboard-interactive or something), so the pam module has to be | |
164 * fairly standard (ie just "what's your username, what's your password, OK"). | |
165 * | |
166 * Keyboard interactive would be a lot nicer, but since PAM is synchronous, it | |
167 * gets very messy trying to send the interactive challenges, and read the | |
168 * interactive responses, over the network. */ | |
169 void svr_auth_pam() { | |
170 | |
171 struct UserDataS userData = {NULL, NULL}; | |
172 struct pam_conv pamConv = { | |
173 pamConvFunc, | |
174 &userData /* submitted to pamvConvFunc as appdata_ptr */ | |
175 }; | |
176 | |
177 pam_handle_t* pamHandlep = NULL; | |
178 | |
179 unsigned char * password = NULL; | |
180 unsigned int passwordlen; | |
181 | |
182 int rc = PAM_SUCCESS; | |
183 unsigned char changepw; | |
184 | |
185 /* check if client wants to change password */ | |
186 changepw = buf_getbool(ses.payload); | |
187 if (changepw) { | |
188 /* not implemented by this server */ | |
189 send_msg_userauth_failure(0, 1); | |
190 goto cleanup; | |
191 } | |
192 | |
193 password = buf_getstring(ses.payload, &passwordlen); | |
194 | |
195 /* used to pass data to the PAM conversation function - don't bother with | |
196 * strdup() etc since these are touched only by our own conversation | |
197 * function (above) which takes care of it */ | |
198 userData.user = ses.authstate.printableuser; | |
199 userData.passwd = password; | |
200 | |
201 /* Init pam */ | |
202 if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { | |
203 dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n", | |
204 rc, pam_strerror(pamHandlep, rc)); | |
205 goto cleanup; | |
206 } | |
207 | |
208 /* just to set it to something */ | |
209 if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) { | |
210 dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", | |
211 rc, pam_strerror(pamHandlep, rc)); | |
212 goto cleanup; | |
213 } | |
214 | |
215 (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); | |
216 | |
217 /* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */ | |
218 | |
219 if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) { | |
220 dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n", | |
221 rc, pam_strerror(pamHandlep, rc)); | |
222 dropbear_log(LOG_WARNING, | |
223 "bad PAM password attempt for '%s' from %s", | |
224 ses.authstate.printableuser, | |
225 svr_ses.addrstring); | |
226 send_msg_userauth_failure(0, 1); | |
227 goto cleanup; | |
228 } | |
229 | |
230 if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { | |
231 dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n", | |
232 rc, pam_strerror(pamHandlep, rc)); | |
233 dropbear_log(LOG_WARNING, | |
234 "bad PAM password attempt for '%s' from %s", | |
235 ses.authstate.printableuser, | |
236 svr_ses.addrstring); | |
237 send_msg_userauth_failure(0, 1); | |
238 goto cleanup; | |
239 } | |
240 | |
241 /* successful authentication */ | |
242 dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s", | |
243 ses.authstate.printableuser, | |
244 svr_ses.addrstring); | |
245 send_msg_userauth_success(); | |
246 | |
247 cleanup: | |
248 if (password != NULL) { | |
249 m_burn(password, passwordlen); | |
250 m_free(password); | |
251 } | |
252 if (pamHandlep != NULL) { | |
253 TRACE(("pam_end")) | |
254 (void) pam_end(pamHandlep, 0 /* pam_status */); | |
255 } | |
256 } | |
257 | |
258 #endif /* ENABLE_SVR_PAM_AUTH */ |