1 /* $OpenBSD: auth2.c,v 1.121 2009/06/22 05:39:28 dtucker Exp $ */
2 /*
3  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/uio.h>
30 
31 #include <fcntl.h>
32 #include <pwd.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include "atomicio.h"
38 #include "xmalloc.h"
39 #include "ssh2.h"
40 #include "packet.h"
41 #include "log.h"
42 #include "buffer.h"
43 #include "servconf.h"
44 #include "compat.h"
45 #include "key.h"
46 #include "hostfile.h"
47 #include "auth.h"
48 #include "dispatch.h"
49 #include "pathnames.h"
50 #include "monitor_wrap.h"
51 
52 __RCSID("$MirOS: src/usr.bin/ssh/auth2.c,v 1.11 2014/03/28 22:31:55 tg Exp $");
53 
54 /* import */
55 extern ServerOptions options;
56 extern u_char *session_id2;
57 extern u_int session_id2_len;
58 
59 /* methods */
60 
61 extern Authmethod method_none;
62 extern Authmethod method_pubkey;
63 extern Authmethod method_passwd;
64 extern Authmethod method_kbdint;
65 extern Authmethod method_hostbased;
66 
67 Authmethod *authmethods[] = {
68 	&method_none,
69 	&method_pubkey,
70 	&method_passwd,
71 	&method_kbdint,
72 	&method_hostbased,
73 	NULL
74 };
75 
76 /* protocol */
77 
78 static void input_service_request(int, u_int32_t, void *);
79 static void input_userauth_request(int, u_int32_t, void *);
80 
81 /* helper */
82 static Authmethod *authmethod_lookup(const char *);
83 static char *authmethods_get(void);
84 
85 char *
auth2_read_banner(void)86 auth2_read_banner(void)
87 {
88 	struct stat st;
89 	char *banner = NULL;
90 	size_t len, n;
91 	int fd;
92 
93 	if ((fd = open(options.banner, O_RDONLY)) == -1)
94 		return (NULL);
95 	if (fstat(fd, &st) == -1) {
96 		close(fd);
97 		return (NULL);
98 	}
99 	if (st.st_size > 1*1024*1024) {
100 		close(fd);
101 		return (NULL);
102 	}
103 
104 	len = (size_t)st.st_size;		/* truncate */
105 	banner = xmalloc(len + 1);
106 	n = atomicio(read, fd, banner, len);
107 	close(fd);
108 
109 	if (n != len) {
110 		xfree(banner);
111 		return (NULL);
112 	}
113 	banner[n] = '\0';
114 
115 	return (banner);
116 }
117 
118 static void
userauth_banner(void)119 userauth_banner(void)
120 {
121 	char *banner = NULL;
122 
123 	if (options.banner == NULL ||
124 	    strcasecmp(options.banner, "none") == 0 ||
125 	    (datafellows & SSH_BUG_BANNER) != 0)
126 		return;
127 
128 	if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
129 		goto done;
130 
131 	packet_start(SSH2_MSG_USERAUTH_BANNER);
132 	packet_put_cstring(banner);
133 	packet_put_cstring("");		/* language, unused */
134 	packet_send();
135 	debug("userauth_banner: sent");
136 done:
137 	if (banner)
138 		xfree(banner);
139 }
140 
141 /*
142  * loop until authctxt->success == TRUE
143  */
144 void
do_authentication2(Authctxt * authctxt)145 do_authentication2(Authctxt *authctxt)
146 {
147 	dispatch_init(&dispatch_protocol_error);
148 	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
149 	dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
150 }
151 
152 /*ARGSUSED*/
153 static void
input_service_request(int type,u_int32_t seq,void * ctxt)154 input_service_request(int type, u_int32_t seq, void *ctxt)
155 {
156 	Authctxt *authctxt = ctxt;
157 	u_int len;
158 	int acceptit = 0;
159 	char *service = packet_get_string(&len);
160 	packet_check_eom();
161 
162 	if (authctxt == NULL)
163 		fatal("input_service_request: no authctxt");
164 
165 	if (strcmp(service, "ssh-userauth") == 0) {
166 		if (!authctxt->success) {
167 			acceptit = 1;
168 			/* now we can handle user-auth requests */
169 			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
170 		}
171 	}
172 	/* XXX all other service requests are denied */
173 
174 	if (acceptit) {
175 		packet_start(SSH2_MSG_SERVICE_ACCEPT);
176 		packet_put_cstring(service);
177 		packet_send();
178 		packet_write_wait();
179 	} else {
180 		debug("bad service request %s", service);
181 		packet_disconnect("bad service request %s", service);
182 	}
183 	xfree(service);
184 }
185 
186 /*ARGSUSED*/
187 static void
input_userauth_request(int type,u_int32_t seq,void * ctxt)188 input_userauth_request(int type, u_int32_t seq, void *ctxt)
189 {
190 	Authctxt *authctxt = ctxt;
191 	Authmethod *m = NULL;
192 	char *user, *service, *method, *style = NULL;
193 	int authenticated = 0;
194 
195 	if (authctxt == NULL)
196 		fatal("input_userauth_request: no authctxt");
197 
198 	user = packet_get_string(NULL);
199 	service = packet_get_string(NULL);
200 	method = packet_get_string(NULL);
201 	debug("userauth-request for user %s service %s method %s", user, service, method);
202 	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
203 
204 	if ((style = strchr(user, ':')) != NULL)
205 		*style++ = 0;
206 
207 	if (authctxt->attempt++ == 0) {
208 		/* setup auth context */
209 		authctxt->pw = PRIVSEP(getpwnamallow(user));
210 		if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
211 			authctxt->valid = 1;
212 			debug2("input_userauth_request: setting up authctxt for %s", user);
213 		} else {
214 			logit("input_userauth_request: invalid user %s", user);
215 			authctxt->pw = fakepw();
216 		}
217 		setproctitle("%s%s", authctxt->valid ? user : "unknown",
218 		    use_privsep ? " [net]" : "");
219 		authctxt->user = xstrdup(user);
220 		authctxt->service = xstrdup(service);
221 		authctxt->style = style ? xstrdup(style) : NULL;
222 		if (use_privsep)
223 			mm_inform_authserv(service, style);
224 		userauth_banner();
225 	} else if (strcmp(user, authctxt->user) != 0 ||
226 	    strcmp(service, authctxt->service) != 0) {
227 		packet_disconnect("Change of username or service not allowed: "
228 		    "(%s,%s) -> (%s,%s)",
229 		    authctxt->user, authctxt->service, user, service);
230 	}
231 	/* reset state */
232 	auth2_challenge_stop(authctxt);
233 
234 	authctxt->postponed = 0;
235 
236 	/* try to authenticate user */
237 	m = authmethod_lookup(method);
238 	if (m != NULL && authctxt->failures < options.max_authtries) {
239 		debug2("input_userauth_request: try method %s", method);
240 		authenticated =	m->userauth(authctxt);
241 	}
242 	userauth_finish(authctxt, authenticated, method);
243 
244 	xfree(service);
245 	xfree(user);
246 	xfree(method);
247 }
248 
249 void
userauth_finish(Authctxt * authctxt,int authenticated,char * method)250 userauth_finish(Authctxt *authctxt, int authenticated, char *method)
251 {
252 	char *methods;
253 
254 	if (!authctxt->valid && authenticated)
255 		fatal("INTERNAL ERROR: authenticated invalid user %s",
256 		    authctxt->user);
257 
258 	/* Special handling for root */
259 	if (authenticated && authctxt->pw->pw_uid == 0 &&
260 	    !auth_root_allowed(method))
261 		authenticated = 0;
262 
263 	/* Log before sending the reply */
264 	auth_log(authctxt, authenticated, method, " ssh2");
265 
266 	if (authctxt->postponed)
267 		return;
268 
269 	/* XXX todo: check if multiple auth methods are needed */
270 	if (authenticated == 1) {
271 		/* turn off userauth */
272 		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
273 		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
274 		packet_send();
275 		packet_write_wait();
276 		/* now we can break out */
277 		authctxt->success = 1;
278 	} else {
279 		/* Allow initial try of "none" auth without failure penalty */
280 		if (authctxt->attempt > 1 || strcmp(method, "none") != 0)
281 			authctxt->failures++;
282 		if (authctxt->failures >= options.max_authtries)
283 			packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
284 		methods = authmethods_get();
285 		packet_start(SSH2_MSG_USERAUTH_FAILURE);
286 		packet_put_cstring(methods);
287 		packet_put_char(0);	/* XXX partial success, unused */
288 		packet_send();
289 		packet_write_wait();
290 		xfree(methods);
291 	}
292 }
293 
294 static char *
authmethods_get(void)295 authmethods_get(void)
296 {
297 	Buffer b;
298 	char *list;
299 	int i;
300 
301 	buffer_init(&b);
302 	for (i = 0; authmethods[i] != NULL; i++) {
303 		if (strcmp(authmethods[i]->name, "none") == 0)
304 			continue;
305 		if (authmethods[i]->enabled != NULL &&
306 		    *(authmethods[i]->enabled) != 0) {
307 			if (buffer_len(&b) > 0)
308 				buffer_append(&b, ",", 1);
309 			buffer_append(&b, authmethods[i]->name,
310 			    strlen(authmethods[i]->name));
311 		}
312 	}
313 	buffer_append(&b, "\0", 1);
314 	list = xstrdup(buffer_ptr(&b));
315 	buffer_free(&b);
316 	return list;
317 }
318 
319 static Authmethod *
authmethod_lookup(const char * name)320 authmethod_lookup(const char *name)
321 {
322 	int i;
323 
324 	if (name != NULL)
325 		for (i = 0; authmethods[i] != NULL; i++)
326 			if (authmethods[i]->enabled != NULL &&
327 			    *(authmethods[i]->enabled) != 0 &&
328 			    strcmp(name, authmethods[i]->name) == 0)
329 				return authmethods[i];
330 	debug2("Unrecognized authentication method name: %s",
331 	    name ? name : "NULL");
332 	return NULL;
333 }
334 
335