2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 RCSID("$OpenBSD: auth2.c,v 1.3 2000/04/27 15:23:02 markus Exp $");
32 #include <openssl/dsa.h>
33 #include <openssl/rsa.h>
34 #include <openssl/evp.h>
59 extern ServerOptions options;
60 extern unsigned char *session_id2;
61 extern int session_id2_len;
65 void input_service_request(int type, int plen);
66 void input_userauth_request(int type, int plen);
67 void protocol_error(int type, int plen);
70 int ssh2_auth_none(struct passwd *pw);
71 int ssh2_auth_password(struct passwd *pw);
72 int ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
75 struct passwd* auth_set_user(char *u, char *s);
76 int user_dsa_key_allowed(struct passwd *pw, Key *key);
78 typedef struct Authctxt Authctxt;
85 static Authctxt *authctxt = NULL;
86 static int userauth_success = 0;
89 * loop until userauth_success == TRUE
95 dispatch_init(&protocol_error);
96 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
97 dispatch_run(DISPATCH_BLOCK, &userauth_success);
102 protocol_error(int type, int plen)
104 log("auth: protocol error: type %d plen %d", type, plen);
105 packet_start(SSH2_MSG_UNIMPLEMENTED);
112 input_service_request(int type, int plen)
116 char *service = packet_get_string(&len);
119 if (strcmp(service, "ssh-userauth") == 0) {
120 if (!userauth_success) {
122 /* now we can handle user-auth requests */
123 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
126 /* XXX all other service requests are denied */
129 packet_start(SSH2_MSG_SERVICE_ACCEPT);
130 packet_put_cstring(service);
134 debug("bad service request %s", service);
135 packet_disconnect("bad service request %s", service);
141 input_userauth_request(int type, int plen)
143 static void (*authlog) (const char *fmt,...) = verbose;
144 static int attempt = 0;
145 unsigned int len, rlen;
146 int authenticated = 0;
147 char *raw, *user, *service, *method, *authmsg = NULL;
150 if (++attempt == AUTH_FAIL_MAX)
151 packet_disconnect("too many failed userauth_requests");
153 raw = packet_get_raw(&rlen);
155 fatal("plen != rlen");
156 user = packet_get_string(&len);
157 service = packet_get_string(&len);
158 method = packet_get_string(&len);
159 debug("userauth-request for user %s service %s method %s", user, service, method);
161 /* XXX we only allow the ssh-connection service */
162 pw = auth_set_user(user, service);
163 if (pw && strcmp(service, "ssh-connection")==0) {
164 if (strcmp(method, "none") == 0) {
165 authenticated = ssh2_auth_none(pw);
166 } else if (strcmp(method, "password") == 0) {
167 authenticated = ssh2_auth_password(pw);
168 } else if (strcmp(method, "publickey") == 0) {
169 authenticated = ssh2_auth_pubkey(pw, raw, rlen);
172 if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
174 log("ROOT LOGIN REFUSED FROM %.200s",
175 get_canonical_hostname());
179 if (authenticated && !do_pam_account(pw->pw_name, NULL))
183 /* XXX todo: check if multiple auth methods are needed */
184 if (authenticated == 1) {
185 authmsg = "Accepted";
186 /* turn off userauth */
187 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
188 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
191 /* now we can break out */
192 userauth_success = 1;
193 } else if (authenticated == 0) {
195 packet_start(SSH2_MSG_USERAUTH_FAILURE);
196 packet_put_cstring("publickey,password"); /* XXX dynamic */
197 packet_put_char(0); /* XXX partial success, unused */
201 authmsg = "Postponed";
203 /* Raise logging level */
204 if (authenticated == 1||
205 attempt == AUTH_FAIL_LOG ||
206 strcmp(method, "password") == 0)
209 authlog("%s %s for %.200s from %.200s port %d ssh2",
212 pw && pw->pw_uid == 0 ? "ROOT" : user,
222 ssh2_auth_none(struct passwd *pw)
226 return auth_pam_password(pw, "");
228 return auth_password(pw, "");
232 ssh2_auth_password(struct passwd *pw)
235 int authenticated = 0;
238 change = packet_get_char();
240 log("password change not supported");
241 password = packet_get_string(&len);
243 if (options.password_authentication &&
245 auth_pam_password(pw, password) == 1)
247 auth_password(pw, password) == 1)
250 memset(password, 0, len);
252 return authenticated;
255 ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
259 char *pkalg, *pkblob, *sig;
260 unsigned int alen, blen, slen;
262 int authenticated = 0;
264 if (options.rsa_authentication == 0) {
265 debug("pubkey auth disabled");
268 have_sig = packet_get_char();
269 pkalg = packet_get_string(&alen);
270 if (strcmp(pkalg, KEX_DSS) != 0) {
272 log("bad pkalg %s", pkalg); /*XXX*/
275 pkblob = packet_get_string(&blen);
276 key = dsa_key_from_blob(pkblob, blen);
279 sig = packet_get_string(&slen);
282 buffer_append(&b, session_id2, session_id2_len);
283 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
285 fatal("bad rlen/slen");
286 buffer_append(&b, raw, rlen - slen - 4);
290 /* test for correct signature */
291 if (user_dsa_key_allowed(pw, key) &&
292 dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
298 debug("test key...");
299 /* test whether pkalg/pkblob are acceptable */
300 /* XXX fake reply and always send PK_OK ? */
301 if (user_dsa_key_allowed(pw, key)) {
302 packet_start(SSH2_MSG_USERAUTH_PK_OK);
303 packet_put_string(pkalg, alen);
304 packet_put_string(pkblob, blen);
314 return authenticated;
317 /* set and get current user */
322 return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
326 auth_set_user(char *u, char *s)
328 struct passwd *pw, *copy;
330 if (authctxt == NULL) {
331 authctxt = xmalloc(sizeof(*authctxt));
333 authctxt->user = xstrdup(u);
334 authctxt->service = xstrdup(s);
335 setproctitle("%s", u);
337 if (!pw || !allowed_user(pw)) {
338 log("auth_set_user: illegal user %s", u);
344 copy = &authctxt->pw;
345 memset(copy, 0, sizeof(*copy));
346 copy->pw_name = xstrdup(pw->pw_name);
347 copy->pw_passwd = xstrdup(pw->pw_passwd);
348 copy->pw_uid = pw->pw_uid;
349 copy->pw_gid = pw->pw_gid;
350 copy->pw_dir = xstrdup(pw->pw_dir);
351 copy->pw_shell = xstrdup(pw->pw_shell);
354 if (strcmp(u, authctxt->user) != 0 ||
355 strcmp(s, authctxt->service) != 0) {
356 log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
357 u, s, authctxt->user, authctxt->service);
361 return auth_get_user();
364 /* return 1 if user allows given key */
366 user_dsa_key_allowed(struct passwd *pw, Key *key)
368 char line[8192], file[1024];
370 unsigned int bits = -1;
372 unsigned long linenum = 0;
376 /* Temporarily use the user's uid. */
377 temporarily_use_uid(pw->pw_uid);
379 /* The authorized keys. */
380 snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
381 SSH_USER_PERMITTED_KEYS2);
383 /* Fail quietly if file does not exist */
384 if (stat(file, &st) < 0) {
385 /* Restore the privileged uid. */
389 /* Open the file containing the authorized keys. */
390 f = fopen(file, "r");
392 /* Restore the privileged uid. */
396 if (options.strict_modes) {
399 /* Check open file in order to avoid open/stat races */
400 if (fstat(fileno(f), &st) < 0 ||
401 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
402 (st.st_mode & 022) != 0) {
403 snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
404 "bad ownership or modes for '%s'.", pw->pw_name, file);
407 /* Check path to SSH_USER_PERMITTED_KEYS */
409 static const char *check[] = {
410 "", SSH_USER_DIR, NULL
412 for (i = 0; check[i]; i++) {
413 snprintf(line, sizeof line, "%.500s/%.100s",
414 pw->pw_dir, check[i]);
415 if (stat(line, &st) < 0 ||
416 (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
417 (st.st_mode & 022) != 0) {
418 snprintf(buf, sizeof buf,
419 "DSA authentication refused for %.100s: "
420 "bad ownership or modes for '%s'.",
435 found = key_new(KEY_DSA);
437 while (fgets(line, sizeof(line), f)) {
440 /* Skip leading whitespace, empty and comment lines. */
441 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
443 if (!*cp || *cp == '\n' || *cp == '#')
445 bits = key_read(found, &cp);
448 if (key_equal(found, key)) {
450 debug("matching key found: file %s, line %ld",