source: trunk/third/openssh/auth2-pubkey.c @ 18759

Revision 18759, 7.5 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
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"
26RCSID("$OpenBSD: auth2-pubkey.c,v 1.2 2002/05/31 11:35:15 markus Exp $");
27
28#include "ssh2.h"
29#include "xmalloc.h"
30#include "packet.h"
31#include "buffer.h"
32#include "log.h"
33#include "servconf.h"
34#include "compat.h"
35#include "bufaux.h"
36#include "auth.h"
37#include "key.h"
38#include "pathnames.h"
39#include "uidswap.h"
40#include "auth-options.h"
41#include "canohost.h"
42#include "monitor_wrap.h"
43
44/* import */
45extern ServerOptions options;
46extern u_char *session_id2;
47extern int session_id2_len;
48
49static int
50userauth_pubkey(Authctxt *authctxt)
51{
52        Buffer b;
53        Key *key = NULL;
54        char *pkalg;
55        u_char *pkblob, *sig;
56        u_int alen, blen, slen;
57        int have_sig, pktype;
58        int authenticated = 0;
59
60        if (!authctxt->valid) {
61                debug2("userauth_pubkey: disabled because of invalid user");
62                return 0;
63        }
64        have_sig = packet_get_char();
65        if (datafellows & SSH_BUG_PKAUTH) {
66                debug2("userauth_pubkey: SSH_BUG_PKAUTH");
67                /* no explicit pkalg given */
68                pkblob = packet_get_string(&blen);
69                buffer_init(&b);
70                buffer_append(&b, pkblob, blen);
71                /* so we have to extract the pkalg from the pkblob */
72                pkalg = buffer_get_string(&b, &alen);
73                buffer_free(&b);
74        } else {
75                pkalg = packet_get_string(&alen);
76                pkblob = packet_get_string(&blen);
77        }
78        pktype = key_type_from_name(pkalg);
79        if (pktype == KEY_UNSPEC) {
80                /* this is perfectly legal */
81                log("userauth_pubkey: unsupported public key algorithm: %s",
82                    pkalg);
83                goto done;
84        }
85        key = key_from_blob(pkblob, blen);
86        if (key == NULL) {
87                error("userauth_pubkey: cannot decode key: %s", pkalg);
88                goto done;
89        }
90        if (key->type != pktype) {
91                error("userauth_pubkey: type mismatch for decoded key "
92                    "(received %d, expected %d)", key->type, pktype);
93                goto done;
94        }
95        if (have_sig) {
96                sig = packet_get_string(&slen);
97                packet_check_eom();
98                buffer_init(&b);
99                if (datafellows & SSH_OLD_SESSIONID) {
100                        buffer_append(&b, session_id2, session_id2_len);
101                } else {
102                        buffer_put_string(&b, session_id2, session_id2_len);
103                }
104                /* reconstruct packet */
105                buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
106                buffer_put_cstring(&b, authctxt->user);
107                buffer_put_cstring(&b,
108                    datafellows & SSH_BUG_PKSERVICE ?
109                    "ssh-userauth" :
110                    authctxt->service);
111                if (datafellows & SSH_BUG_PKAUTH) {
112                        buffer_put_char(&b, have_sig);
113                } else {
114                        buffer_put_cstring(&b, "publickey");
115                        buffer_put_char(&b, have_sig);
116                        buffer_put_cstring(&b, pkalg);
117                }
118                buffer_put_string(&b, pkblob, blen);
119#ifdef DEBUG_PK
120                buffer_dump(&b);
121#endif
122                /* test for correct signature */
123                authenticated = 0;
124                if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
125                    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
126                                buffer_len(&b))) == 1)
127                        authenticated = 1;
128                buffer_clear(&b);
129                xfree(sig);
130        } else {
131                debug("test whether pkalg/pkblob are acceptable");
132                packet_check_eom();
133
134                /* XXX fake reply and always send PK_OK ? */
135                /*
136                 * XXX this allows testing whether a user is allowed
137                 * to login: if you happen to have a valid pubkey this
138                 * message is sent. the message is NEVER sent at all
139                 * if a user is not allowed to login. is this an
140                 * issue? -markus
141                 */
142                if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
143                        packet_start(SSH2_MSG_USERAUTH_PK_OK);
144                        packet_put_string(pkalg, alen);
145                        packet_put_string(pkblob, blen);
146                        packet_send();
147                        packet_write_wait();
148                        authctxt->postponed = 1;
149                }
150        }
151        if (authenticated != 1)
152                auth_clear_options();
153done:
154        debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
155        if (key != NULL)
156                key_free(key);
157        xfree(pkalg);
158        xfree(pkblob);
159#ifdef HAVE_CYGWIN
160        if (check_nt_auth(0, authctxt->pw) == 0)
161                return(0);
162#endif
163        return authenticated;
164}
165
166/* return 1 if user allows given key */
167static int
168user_key_allowed2(struct passwd *pw, Key *key, char *file)
169{
170        char line[8192];
171        int found_key = 0;
172        FILE *f;
173        u_long linenum = 0;
174        struct stat st;
175        Key *found;
176        char *fp;
177
178        if (pw == NULL)
179                return 0;
180
181        /* Temporarily use the user's uid. */
182        temporarily_use_uid(pw);
183
184        debug("trying public key file %s", file);
185
186        /* Fail quietly if file does not exist */
187        if (stat(file, &st) < 0) {
188                /* Restore the privileged uid. */
189                restore_uid();
190                return 0;
191        }
192        /* Open the file containing the authorized keys. */
193        f = fopen(file, "r");
194        if (!f) {
195                /* Restore the privileged uid. */
196                restore_uid();
197                return 0;
198        }
199        if (options.strict_modes &&
200            secure_filename(f, file, pw, line, sizeof(line)) != 0) {
201                fclose(f);
202                log("Authentication refused: %s", line);
203                restore_uid();
204                return 0;
205        }
206
207        found_key = 0;
208        found = key_new(key->type);
209
210        while (fgets(line, sizeof(line), f)) {
211                char *cp, *options = NULL;
212                linenum++;
213                /* Skip leading whitespace, empty and comment lines. */
214                for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
215                        ;
216                if (!*cp || *cp == '\n' || *cp == '#')
217                        continue;
218
219                if (key_read(found, &cp) != 1) {
220                        /* no key?  check if there are options for this key */
221                        int quoted = 0;
222                        debug2("user_key_allowed: check options: '%s'", cp);
223                        options = cp;
224                        for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
225                                if (*cp == '\\' && cp[1] == '"')
226                                        cp++;   /* Skip both */
227                                else if (*cp == '"')
228                                        quoted = !quoted;
229                        }
230                        /* Skip remaining whitespace. */
231                        for (; *cp == ' ' || *cp == '\t'; cp++)
232                                ;
233                        if (key_read(found, &cp) != 1) {
234                                debug2("user_key_allowed: advance: '%s'", cp);
235                                /* still no key?  advance to next line*/
236                                continue;
237                        }
238                }
239                if (key_equal(found, key) &&
240                    auth_parse_options(pw, options, file, linenum) == 1) {
241                        found_key = 1;
242                        debug("matching key found: file %s, line %lu",
243                            file, linenum);
244                        fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
245                        verbose("Found matching %s key: %s",
246                            key_type(found), fp);
247                        xfree(fp);
248                        break;
249                }
250        }
251        restore_uid();
252        fclose(f);
253        key_free(found);
254        if (!found_key)
255                debug2("key not found");
256        return found_key;
257}
258
259/* check whether given key is in .ssh/authorized_keys* */
260int
261user_key_allowed(struct passwd *pw, Key *key)
262{
263        int success;
264        char *file;
265
266        file = authorized_keys_file(pw);
267        success = user_key_allowed2(pw, key, file);
268        xfree(file);
269        if (success)
270                return success;
271
272        /* try suffix "2" for backward compat, too */
273        file = authorized_keys_file2(pw);
274        success = user_key_allowed2(pw, key, file);
275        xfree(file);
276        return success;
277}
278
279Authmethod method_pubkey = {
280        "publickey",
281        userauth_pubkey,
282        &options.pubkey_authentication
283};
Note: See TracBrowser for help on using the repository browser.