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

« back to all changes in this revision

Viewing changes to auth2.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.c,v 1.104 2003/11/04 08:54:09 djm Exp $");
 
27
 
 
28
#include "ssh2.h"
 
29
#include "xmalloc.h"
 
30
#include "packet.h"
 
31
#include "log.h"
 
32
#include "servconf.h"
 
33
#include "compat.h"
 
34
#include "auth.h"
 
35
#include "dispatch.h"
 
36
#include "pathnames.h"
 
37
#include "monitor_wrap.h"
 
38
 
 
39
#ifdef GSSAPI
 
40
#include "ssh-gss.h"
 
41
#endif
 
42
 
 
43
/* import */
 
44
extern ServerOptions options;
 
45
extern u_char *session_id2;
 
46
extern u_int session_id2_len;
 
47
 
 
48
/* methods */
 
49
 
 
50
extern Authmethod method_none;
 
51
extern Authmethod method_pubkey;
 
52
extern Authmethod method_passwd;
 
53
extern Authmethod method_kbdint;
 
54
extern Authmethod method_hostbased;
 
55
#ifdef GSSAPI
 
56
extern Authmethod method_gssapi;
 
57
#endif
 
58
 
 
59
Authmethod *authmethods[] = {
 
60
        &method_none,
 
61
        &method_pubkey,
 
62
#ifdef GSSAPI
 
63
        &method_gssapi,
 
64
#endif
 
65
        &method_passwd,
 
66
        &method_kbdint,
 
67
        &method_hostbased,
 
68
        NULL
 
69
};
 
70
 
 
71
/* protocol */
 
72
 
 
73
static void input_service_request(int, u_int32_t, void *);
 
74
static void input_userauth_request(int, u_int32_t, void *);
 
75
 
 
76
/* helper */
 
77
static Authmethod *authmethod_lookup(const char *);
 
78
static char *authmethods_get(void);
 
79
int user_key_allowed(struct passwd *, Key *);
 
80
 
 
81
/*
 
82
 * loop until authctxt->success == TRUE
 
83
 */
 
84
 
 
85
void
 
86
do_authentication2(Authctxt *authctxt)
 
87
{
 
88
        /* challenge-response is implemented via keyboard interactive */
 
89
        if (options.challenge_response_authentication)
 
90
                options.kbd_interactive_authentication = 1;
 
91
 
 
92
        dispatch_init(&dispatch_protocol_error);
 
93
        dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
 
94
        dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
 
95
}
 
96
 
 
97
static void
 
98
input_service_request(int type, u_int32_t seq, void *ctxt)
 
99
{
 
100
        Authctxt *authctxt = ctxt;
 
101
        u_int len;
 
102
        int acceptit = 0;
 
103
        char *service = packet_get_string(&len);
 
104
        packet_check_eom();
 
105
 
 
106
        if (authctxt == NULL)
 
107
                fatal("input_service_request: no authctxt");
 
108
 
 
109
        if (strcmp(service, "ssh-userauth") == 0) {
 
110
                if (!authctxt->success) {
 
111
                        acceptit = 1;
 
112
                        /* now we can handle user-auth requests */
 
113
                        dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
 
114
                }
 
115
        }
 
116
        /* XXX all other service requests are denied */
 
117
 
 
118
        if (acceptit) {
 
119
                packet_start(SSH2_MSG_SERVICE_ACCEPT);
 
120
                packet_put_cstring(service);
 
121
                packet_send();
 
122
                packet_write_wait();
 
123
        } else {
 
124
                debug("bad service request %s", service);
 
125
                packet_disconnect("bad service request %s", service);
 
126
        }
 
127
        xfree(service);
 
128
}
 
129
 
 
130
static void
 
131
input_userauth_request(int type, u_int32_t seq, void *ctxt)
 
132
{
 
133
        Authctxt *authctxt = ctxt;
 
134
        Authmethod *m = NULL;
 
135
        char *user, *service, *method, *style = NULL;
 
136
        int authenticated = 0;
 
137
 
 
138
        if (authctxt == NULL)
 
139
                fatal("input_userauth_request: no authctxt");
 
140
 
 
141
        user = packet_get_string(NULL);
 
142
        service = packet_get_string(NULL);
 
143
        method = packet_get_string(NULL);
 
144
        debug("userauth-request for user %s service %s method %s", user, service, method);
 
145
        debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
 
146
 
 
147
        if ((style = strchr(user, ':')) != NULL)
 
148
                *style++ = 0;
 
149
 
 
150
        if (authctxt->attempt++ == 0) {
 
151
                /* setup auth context */
 
152
                authctxt->pw = PRIVSEP(getpwnamallow(user));
 
153
                authctxt->user = xstrdup(user);
 
154
                if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
 
155
                        authctxt->valid = 1;
 
156
                        debug2("input_userauth_request: setting up authctxt for %s", user);
 
157
#ifdef USE_PAM
 
158
                        if (options.use_pam)
 
159
                                PRIVSEP(start_pam(authctxt));
 
160
#endif
 
161
                } else {
 
162
                        logit("input_userauth_request: illegal user %s", user);
 
163
                        authctxt->pw = fakepw();
 
164
#ifdef USE_PAM
 
165
                        if (options.use_pam)
 
166
                                PRIVSEP(start_pam(authctxt));
 
167
#endif
 
168
                }
 
169
                setproctitle("%s%s", authctxt->pw ? user : "unknown",
 
170
                    use_privsep ? " [net]" : "");
 
171
                authctxt->service = xstrdup(service);
 
172
                authctxt->style = style ? xstrdup(style) : NULL;
 
173
                if (use_privsep)
 
174
                        mm_inform_authserv(service, style);
 
175
        } else if (strcmp(user, authctxt->user) != 0 ||
 
176
            strcmp(service, authctxt->service) != 0) {
 
177
                packet_disconnect("Change of username or service not allowed: "
 
178
                    "(%s,%s) -> (%s,%s)",
 
179
                    authctxt->user, authctxt->service, user, service);
 
180
        }
 
181
        /* reset state */
 
182
        auth2_challenge_stop(authctxt);
 
183
 
 
184
#ifdef GSSAPI
 
185
        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
 
186
        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
 
187
#endif
 
188
 
 
189
        authctxt->postponed = 0;
 
190
 
 
191
        /* try to authenticate user */
 
192
        m = authmethod_lookup(method);
 
193
        if (m != NULL) {
 
194
                debug2("input_userauth_request: try method %s", method);
 
195
                authenticated = m->userauth(authctxt);
 
196
        }
 
197
        userauth_finish(authctxt, authenticated, method);
 
198
 
 
199
        xfree(service);
 
200
        xfree(user);
 
201
        xfree(method);
 
202
}
 
203
 
 
204
void
 
205
userauth_finish(Authctxt *authctxt, int authenticated, char *method)
 
206
{
 
207
        char *methods;
 
208
 
 
209
        if (!authctxt->valid && authenticated)
 
210
                fatal("INTERNAL ERROR: authenticated invalid user %s",
 
211
                    authctxt->user);
 
212
 
 
213
        /* Special handling for root */
 
214
        if (authenticated && authctxt->pw->pw_uid == 0 &&
 
215
            !auth_root_allowed(method))
 
216
                authenticated = 0;
 
217
 
 
218
#ifdef USE_PAM
 
219
        if (options.use_pam && authenticated && !PRIVSEP(do_pam_account()))
 
220
                authenticated = 0;
 
221
#endif
 
222
 
 
223
#ifdef _UNICOS
 
224
        if (authenticated && cray_access_denied(authctxt->user)) {
 
225
                authenticated = 0;
 
226
                fatal("Access denied for user %s.",authctxt->user);
 
227
        }
 
228
#endif /* _UNICOS */
 
229
 
 
230
        /* Log before sending the reply */
 
231
        auth_log(authctxt, authenticated, method, " ssh2");
 
232
 
 
233
        if (authctxt->postponed)
 
234
                return;
 
235
 
 
236
        /* XXX todo: check if multiple auth methods are needed */
 
237
        if (authenticated == 1) {
 
238
                /* turn off userauth */
 
239
                dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
 
240
                packet_start(SSH2_MSG_USERAUTH_SUCCESS);
 
241
                packet_send();
 
242
                packet_write_wait();
 
243
                /* now we can break out */
 
244
                authctxt->success = 1;
 
245
        } else {
 
246
                if (authctxt->failures++ > AUTH_FAIL_MAX)
 
247
                        packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
 
248
                methods = authmethods_get();
 
249
                packet_start(SSH2_MSG_USERAUTH_FAILURE);
 
250
                packet_put_cstring(methods);
 
251
                packet_put_char(0);     /* XXX partial success, unused */
 
252
                packet_send();
 
253
                packet_write_wait();
 
254
                xfree(methods);
 
255
        }
 
256
}
 
257
 
 
258
#define DELIM   ","
 
259
 
 
260
static char *
 
261
authmethods_get(void)
 
262
{
 
263
        Buffer b;
 
264
        char *list;
 
265
        int i;
 
266
 
 
267
        buffer_init(&b);
 
268
        for (i = 0; authmethods[i] != NULL; i++) {
 
269
                if (strcmp(authmethods[i]->name, "none") == 0)
 
270
                        continue;
 
271
                if (authmethods[i]->enabled != NULL &&
 
272
                    *(authmethods[i]->enabled) != 0) {
 
273
                        if (buffer_len(&b) > 0)
 
274
                                buffer_append(&b, ",", 1);
 
275
                        buffer_append(&b, authmethods[i]->name,
 
276
                            strlen(authmethods[i]->name));
 
277
                }
 
278
        }
 
279
        buffer_append(&b, "\0", 1);
 
280
        list = xstrdup(buffer_ptr(&b));
 
281
        buffer_free(&b);
 
282
        return list;
 
283
}
 
284
 
 
285
static Authmethod *
 
286
authmethod_lookup(const char *name)
 
287
{
 
288
        int i;
 
289
 
 
290
        if (name != NULL)
 
291
                for (i = 0; authmethods[i] != NULL; i++)
 
292
                        if (authmethods[i]->enabled != NULL &&
 
293
                            *(authmethods[i]->enabled) != 0 &&
 
294
                            strcmp(name, authmethods[i]->name) == 0)
 
295
                                return authmethods[i];
 
296
        debug2("Unrecognized authentication method name: %s",
 
297
            name ? name : "NULL");
 
298
        return NULL;
 
299
}