~ubuntu-branches/ubuntu/edgy/openssh/edgy

« back to all changes in this revision

Viewing changes to auth2-pubkey.c

  • Committer: Bazaar Package Importer
  • Author(s): Noah Meyerhans
  • Date: 2006-10-31 17:53:38 UTC
  • Revision ID: james.westby@ubuntu.com-20061031175338-kh299ada2qc2kzlb
Tags: upstream-3.8.1p1
ImportĀ upstreamĀ versionĀ 3.8.1p1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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"
 
26
RCSID("$OpenBSD: auth2-pubkey.c,v 1.6 2004/01/19 21:25: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 */
 
45
extern ServerOptions options;
 
46
extern u_char *session_id2;
 
47
extern u_int session_id2_len;
 
48
 
 
49
static int
 
50
userauth_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
                logit("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_free(&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();
 
153
done:
 
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 */
 
167
static int
 
168
user_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
        /* Temporarily use the user's uid. */
 
179
        temporarily_use_uid(pw);
 
180
 
 
181
        debug("trying public key file %s", file);
 
182
 
 
183
        /* Fail quietly if file does not exist */
 
184
        if (stat(file, &st) < 0) {
 
185
                /* Restore the privileged uid. */
 
186
                restore_uid();
 
187
                return 0;
 
188
        }
 
189
        /* Open the file containing the authorized keys. */
 
190
        f = fopen(file, "r");
 
191
        if (!f) {
 
192
                /* Restore the privileged uid. */
 
193
                restore_uid();
 
194
                return 0;
 
195
        }
 
196
        if (options.strict_modes &&
 
197
            secure_filename(f, file, pw, line, sizeof(line)) != 0) {
 
198
                fclose(f);
 
199
                logit("Authentication refused: %s", line);
 
200
                restore_uid();
 
201
                return 0;
 
202
        }
 
203
 
 
204
        found_key = 0;
 
205
        found = key_new(key->type);
 
206
 
 
207
        while (fgets(line, sizeof(line), f)) {
 
208
                char *cp, *options = NULL;
 
209
                linenum++;
 
210
                /* Skip leading whitespace, empty and comment lines. */
 
211
                for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
 
212
                        ;
 
213
                if (!*cp || *cp == '\n' || *cp == '#')
 
214
                        continue;
 
215
 
 
216
                if (key_read(found, &cp) != 1) {
 
217
                        /* no key?  check if there are options for this key */
 
218
                        int quoted = 0;
 
219
                        debug2("user_key_allowed: check options: '%s'", cp);
 
220
                        options = cp;
 
221
                        for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
 
222
                                if (*cp == '\\' && cp[1] == '"')
 
223
                                        cp++;   /* Skip both */
 
224
                                else if (*cp == '"')
 
225
                                        quoted = !quoted;
 
226
                        }
 
227
                        /* Skip remaining whitespace. */
 
228
                        for (; *cp == ' ' || *cp == '\t'; cp++)
 
229
                                ;
 
230
                        if (key_read(found, &cp) != 1) {
 
231
                                debug2("user_key_allowed: advance: '%s'", cp);
 
232
                                /* still no key?  advance to next line*/
 
233
                                continue;
 
234
                        }
 
235
                }
 
236
                if (key_equal(found, key) &&
 
237
                    auth_parse_options(pw, options, file, linenum) == 1) {
 
238
                        found_key = 1;
 
239
                        debug("matching key found: file %s, line %lu",
 
240
                            file, linenum);
 
241
                        fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
 
242
                        verbose("Found matching %s key: %s",
 
243
                            key_type(found), fp);
 
244
                        xfree(fp);
 
245
                        break;
 
246
                }
 
247
        }
 
248
        restore_uid();
 
249
        fclose(f);
 
250
        key_free(found);
 
251
        if (!found_key)
 
252
                debug2("key not found");
 
253
        return found_key;
 
254
}
 
255
 
 
256
/* check whether given key is in .ssh/authorized_keys* */
 
257
int
 
258
user_key_allowed(struct passwd *pw, Key *key)
 
259
{
 
260
        int success;
 
261
        char *file;
 
262
 
 
263
        file = authorized_keys_file(pw);
 
264
        success = user_key_allowed2(pw, key, file);
 
265
        xfree(file);
 
266
        if (success)
 
267
                return success;
 
268
 
 
269
        /* try suffix "2" for backward compat, too */
 
270
        file = authorized_keys_file2(pw);
 
271
        success = user_key_allowed2(pw, key, file);
 
272
        xfree(file);
 
273
        return success;
 
274
}
 
275
 
 
276
Authmethod method_pubkey = {
 
277
        "publickey",
 
278
        userauth_pubkey,
 
279
        &options.pubkey_authentication
 
280
};