Annotation of src/usr.bin/ssh/auth2-pubkey.c, Revision 1.8
1.1 markus 1: /*
2: * Copyright (c) 2000 Markus Friedl. All rights reserved.
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following conditions
6: * are met:
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: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23: */
24:
25: #include "includes.h"
1.8 ! dtucker 26: RCSID("$OpenBSD: auth2-pubkey.c,v 1.7 2004/06/21 17:36:31 avsm Exp $");
1.1 markus 27:
1.8 ! dtucker 28: #include "ssh.h"
1.1 markus 29: #include "ssh2.h"
30: #include "xmalloc.h"
31: #include "packet.h"
32: #include "buffer.h"
33: #include "log.h"
34: #include "servconf.h"
35: #include "compat.h"
36: #include "bufaux.h"
37: #include "auth.h"
38: #include "key.h"
39: #include "pathnames.h"
40: #include "uidswap.h"
41: #include "auth-options.h"
42: #include "canohost.h"
43: #include "monitor_wrap.h"
44:
45: /* import */
46: extern ServerOptions options;
47: extern u_char *session_id2;
1.4 markus 48: extern u_int session_id2_len;
1.1 markus 49:
1.2 markus 50: static int
1.1 markus 51: userauth_pubkey(Authctxt *authctxt)
52: {
53: Buffer b;
54: Key *key = NULL;
55: char *pkalg;
56: u_char *pkblob, *sig;
57: u_int alen, blen, slen;
58: int have_sig, pktype;
59: int authenticated = 0;
60:
61: if (!authctxt->valid) {
62: debug2("userauth_pubkey: disabled because of invalid user");
63: return 0;
64: }
65: have_sig = packet_get_char();
66: if (datafellows & SSH_BUG_PKAUTH) {
67: debug2("userauth_pubkey: SSH_BUG_PKAUTH");
68: /* no explicit pkalg given */
69: pkblob = packet_get_string(&blen);
70: buffer_init(&b);
71: buffer_append(&b, pkblob, blen);
72: /* so we have to extract the pkalg from the pkblob */
73: pkalg = buffer_get_string(&b, &alen);
74: buffer_free(&b);
75: } else {
76: pkalg = packet_get_string(&alen);
77: pkblob = packet_get_string(&blen);
78: }
79: pktype = key_type_from_name(pkalg);
80: if (pktype == KEY_UNSPEC) {
81: /* this is perfectly legal */
1.3 itojun 82: logit("userauth_pubkey: unsupported public key algorithm: %s",
1.1 markus 83: pkalg);
84: goto done;
85: }
86: key = key_from_blob(pkblob, blen);
87: if (key == NULL) {
88: error("userauth_pubkey: cannot decode key: %s", pkalg);
89: goto done;
90: }
91: if (key->type != pktype) {
92: error("userauth_pubkey: type mismatch for decoded key "
93: "(received %d, expected %d)", key->type, pktype);
94: goto done;
95: }
96: if (have_sig) {
97: sig = packet_get_string(&slen);
98: packet_check_eom();
99: buffer_init(&b);
100: if (datafellows & SSH_OLD_SESSIONID) {
101: buffer_append(&b, session_id2, session_id2_len);
102: } else {
103: buffer_put_string(&b, session_id2, session_id2_len);
104: }
105: /* reconstruct packet */
106: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
107: buffer_put_cstring(&b, authctxt->user);
108: buffer_put_cstring(&b,
109: datafellows & SSH_BUG_PKSERVICE ?
110: "ssh-userauth" :
111: authctxt->service);
112: if (datafellows & SSH_BUG_PKAUTH) {
113: buffer_put_char(&b, have_sig);
114: } else {
115: buffer_put_cstring(&b, "publickey");
116: buffer_put_char(&b, have_sig);
117: buffer_put_cstring(&b, pkalg);
118: }
119: buffer_put_string(&b, pkblob, blen);
120: #ifdef DEBUG_PK
121: buffer_dump(&b);
122: #endif
123: /* test for correct signature */
124: authenticated = 0;
125: if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
126: PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
1.6 markus 127: buffer_len(&b))) == 1)
1.1 markus 128: authenticated = 1;
1.6 markus 129: buffer_free(&b);
1.1 markus 130: xfree(sig);
131: } else {
132: debug("test whether pkalg/pkblob are acceptable");
133: packet_check_eom();
134:
135: /* XXX fake reply and always send PK_OK ? */
136: /*
137: * XXX this allows testing whether a user is allowed
138: * to login: if you happen to have a valid pubkey this
139: * message is sent. the message is NEVER sent at all
140: * if a user is not allowed to login. is this an
141: * issue? -markus
142: */
143: if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
144: packet_start(SSH2_MSG_USERAUTH_PK_OK);
145: packet_put_string(pkalg, alen);
146: packet_put_string(pkblob, blen);
147: packet_send();
148: packet_write_wait();
149: authctxt->postponed = 1;
150: }
151: }
152: if (authenticated != 1)
153: auth_clear_options();
154: done:
155: debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
156: if (key != NULL)
157: key_free(key);
158: xfree(pkalg);
159: xfree(pkblob);
160: return authenticated;
161: }
162:
163: /* return 1 if user allows given key */
164: static int
165: user_key_allowed2(struct passwd *pw, Key *key, char *file)
166: {
1.8 ! dtucker 167: char line[SSH_MAX_PUBKEY_BYTES];
1.1 markus 168: int found_key = 0;
169: FILE *f;
170: u_long linenum = 0;
171: struct stat st;
172: Key *found;
173: char *fp;
174:
175: /* Temporarily use the user's uid. */
176: temporarily_use_uid(pw);
177:
178: debug("trying public key file %s", file);
179:
180: /* Fail quietly if file does not exist */
181: if (stat(file, &st) < 0) {
182: /* Restore the privileged uid. */
183: restore_uid();
184: return 0;
185: }
186: /* Open the file containing the authorized keys. */
187: f = fopen(file, "r");
188: if (!f) {
189: /* Restore the privileged uid. */
190: restore_uid();
191: return 0;
192: }
193: if (options.strict_modes &&
194: secure_filename(f, file, pw, line, sizeof(line)) != 0) {
195: fclose(f);
1.3 itojun 196: logit("Authentication refused: %s", line);
1.1 markus 197: restore_uid();
198: return 0;
199: }
200:
201: found_key = 0;
202: found = key_new(key->type);
203:
1.8 ! dtucker 204: while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
1.7 avsm 205: char *cp, *key_options = NULL;
1.8 ! dtucker 206:
1.1 markus 207: /* Skip leading whitespace, empty and comment lines. */
208: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
209: ;
210: if (!*cp || *cp == '\n' || *cp == '#')
211: continue;
212:
213: if (key_read(found, &cp) != 1) {
214: /* no key? check if there are options for this key */
215: int quoted = 0;
216: debug2("user_key_allowed: check options: '%s'", cp);
1.7 avsm 217: key_options = cp;
1.1 markus 218: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
219: if (*cp == '\\' && cp[1] == '"')
220: cp++; /* Skip both */
221: else if (*cp == '"')
222: quoted = !quoted;
223: }
224: /* Skip remaining whitespace. */
225: for (; *cp == ' ' || *cp == '\t'; cp++)
226: ;
227: if (key_read(found, &cp) != 1) {
228: debug2("user_key_allowed: advance: '%s'", cp);
229: /* still no key? advance to next line*/
230: continue;
231: }
232: }
233: if (key_equal(found, key) &&
1.7 avsm 234: auth_parse_options(pw, key_options, file, linenum) == 1) {
1.1 markus 235: found_key = 1;
236: debug("matching key found: file %s, line %lu",
237: file, linenum);
238: fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
239: verbose("Found matching %s key: %s",
240: key_type(found), fp);
241: xfree(fp);
242: break;
243: }
244: }
245: restore_uid();
246: fclose(f);
247: key_free(found);
248: if (!found_key)
249: debug2("key not found");
250: return found_key;
251: }
252:
253: /* check whether given key is in .ssh/authorized_keys* */
254: int
255: user_key_allowed(struct passwd *pw, Key *key)
256: {
257: int success;
258: char *file;
259:
260: file = authorized_keys_file(pw);
261: success = user_key_allowed2(pw, key, file);
262: xfree(file);
263: if (success)
264: return success;
265:
266: /* try suffix "2" for backward compat, too */
267: file = authorized_keys_file2(pw);
268: success = user_key_allowed2(pw, key, file);
269: xfree(file);
270: return success;
271: }
1.2 markus 272:
273: Authmethod method_pubkey = {
274: "publickey",
275: userauth_pubkey,
276: &options.pubkey_authentication
277: };