annotate cli-auth.c @ 303:b27fcd28f9dc ucc-axis-hack

printf not fprintf for scp stuff
author Matt Johnston <matt@ucc.asn.au>
date Sat, 25 Mar 2006 13:35:44 +0000
parents baea1d43e7eb
children 8f3ec7c104d9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
74
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
1 /*
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
2 * Dropbear SSH
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
3 *
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
4 * Copyright (c) 2002,2003 Matt Johnston
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
5 * Copyright (c) 2004 by Mihnea Stoenescu
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
6 * All rights reserved.
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
7 *
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
9 * of this software and associated documentation files (the "Software"), to deal
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
10 * in the Software without restriction, including without limitation the rights
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
12 * copies of the Software, and to permit persons to whom the Software is
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
13 * furnished to do so, subject to the following conditions:
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
14 *
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
15 * The above copyright notice and this permission notice shall be included in
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
16 * all copies or substantial portions of the Software.
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
17 *
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
24 * SOFTWARE. */
e3adf4cf5465 License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents: 68
diff changeset
25
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
26 #include "includes.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
27 #include "session.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
28 #include "auth.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
29 #include "dbutil.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
30 #include "buffer.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
31 #include "ssh.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
32 #include "packet.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
33 #include "runopts.h"
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
34
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
35 void cli_authinitialise() {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
36
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
37 memset(&ses.authstate, 0, sizeof(ses.authstate));
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
38 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
39
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
40
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
41 /* Send a "none" auth request to get available methods */
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
42 void cli_auth_getmethods() {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
43
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
44 TRACE(("enter cli_auth_getmethods"))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
45
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
46 CHECKCLEARTOWRITE();
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
47
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
48 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
35
0ad5fb979f42 set the isserver flag (oops)
Matt Johnston <matt@ucc.asn.au>
parents: 34
diff changeset
49 buf_putstring(ses.writepayload, cli_opts.username,
0ad5fb979f42 set the isserver flag (oops)
Matt Johnston <matt@ucc.asn.au>
parents: 34
diff changeset
50 strlen(cli_opts.username));
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
51 buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION,
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
52 SSH_SERVICE_CONNECTION_LEN);
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
53 buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
54
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
55 encrypt_packet();
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
56 TRACE(("leave cli_auth_getmethods"))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
57
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
58 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
59
43
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
60 void recv_msg_userauth_banner() {
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
61
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
62 unsigned char* banner = NULL;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
63 unsigned int bannerlen;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
64 unsigned int i, linecount;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
65
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
66 TRACE(("enter recv_msg_userauth_banner"))
43
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
67 if (ses.authstate.authdone) {
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
68 TRACE(("leave recv_msg_userauth_banner: banner after auth done"))
43
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
69 return;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
70 }
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
71
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
72 banner = buf_getstring(ses.payload, &bannerlen);
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
73 buf_eatstring(ses.payload); /* The language string */
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
74
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
75 if (bannerlen > MAX_BANNER_SIZE) {
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
76 TRACE(("recv_msg_userauth_banner: bannerlen too long: %d", bannerlen))
43
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
77 goto out;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
78 }
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
79
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
80 cleantext(banner);
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
81
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
82 /* Limit to 25 lines */
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
83 linecount = 1;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
84 for (i = 0; i < bannerlen; i++) {
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
85 if (banner[i] == '\n') {
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
86 if (linecount >= MAX_BANNER_LINES) {
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
87 banner[i] = '\0';
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
88 break;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
89 }
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
90 linecount++;
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
91 }
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
92 }
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
93
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
94 printf("%s\n", banner);
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
95
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
96 out:
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
97 m_free(banner);
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
98 TRACE(("leave recv_msg_userauth_banner"))
43
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
99 }
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
100
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
101 /* This handles the message-specific types which
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
102 * all have a value of 60. These are
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
103 * SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
104 * SSH_MSG_USERAUTH_PK_OK, &
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
105 * SSH_MSG_USERAUTH_INFO_REQUEST. */
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
106 void recv_msg_userauth_specific_60() {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
107
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
108 #ifdef ENABLE_CLI_PUBKEY_AUTH
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
109 if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
110 recv_msg_userauth_pk_ok();
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
111 return;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
112 }
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
113 #endif
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
114
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
115 #ifdef ENABLE_CLI_INTERACT_AUTH
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
116 if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT) {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
117 recv_msg_userauth_info_request();
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
118 return;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
119 }
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
120 #endif
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
121
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
122 #ifdef ENABLE_CLI_PASSWORD_AUTH
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
123 if (cli_ses.lastauthtype == AUTH_TYPE_PASSWORD) {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
124 /* Eventually there could be proper password-changing
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
125 * support. However currently few servers seem to
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
126 * implement it, and password auth is last-resort
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
127 * regardless - keyboard-interactive is more likely
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
128 * to be used anyway. */
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
129 dropbear_close("Your password has expired.");
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
130 }
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
131 #endif
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
132
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
133 dropbear_exit("Unexpected userauth packet");
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
134 }
43
942b22d7dd1c Banner printing
Matt Johnston <matt@ucc.asn.au>
parents: 40
diff changeset
135
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
136 void recv_msg_userauth_failure() {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
137
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
138 unsigned char * methods = NULL;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
139 unsigned char * tok = NULL;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
140 unsigned int methlen = 0;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
141 unsigned int partial = 0;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
142 unsigned int i = 0;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
143
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
144 TRACE(("<- MSG_USERAUTH_FAILURE"))
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
145 TRACE(("enter recv_msg_userauth_failure"))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
146
45
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
147 if (cli_ses.state != USERAUTH_REQ_SENT) {
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
148 /* Perhaps we should be more fatal? */
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
149 dropbear_exit("Unexpected userauth failure");
45
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
150 }
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
151
68
eee77ac31ccc cleaning up the pubkey defines
Matt Johnston <matt@ucc.asn.au>
parents: 45
diff changeset
152 #ifdef ENABLE_CLI_PUBKEY_AUTH
45
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
153 /* If it was a pubkey auth request, we should cross that key
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
154 * off the list. */
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
155 if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
156 cli_pubkeyfail();
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
157 }
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
158 #endif
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
159
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
160 #ifdef ENABLE_CLI_INTERACT_AUTH
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
161 /* If we get a failure message for keyboard interactive without
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
162 * receiving any request info packet, then we don't bother trying
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
163 * keyboard interactive again */
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
164 if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
165 && !cli_ses.interact_request_received) {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
166 TRACE(("setting auth_interact_failed = 1"))
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
167 cli_ses.auth_interact_failed = 1;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
168 }
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
169 #endif
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
170
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
171 cli_ses.lastauthtype = AUTH_TYPE_NONE;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
172
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
173 methods = buf_getstring(ses.payload, &methlen);
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
174
179
161557a9dde8 * fix longstanding bug with connections being closed on failure to
Matt Johnston <matt@ucc.asn.au>
parents: 165
diff changeset
175 partial = buf_getbool(ses.payload);
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
176
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
177 if (partial) {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
178 dropbear_log(LOG_INFO, "Authentication partially succeeded, more attempts required");
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
179 } else {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
180 ses.authstate.failcount++;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
181 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
182
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
183 TRACE(("Methods (len %d): '%s'", methlen, methods))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
184
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
185 ses.authstate.authdone=0;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
186 ses.authstate.authtypes=0;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
187
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
188 /* Split with nulls rather than commas */
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
189 for (i = 0; i < methlen; i++) {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
190 if (methods[i] == ',') {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
191 methods[i] = '\0';
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
192 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
193 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
194
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
195 tok = methods; /* tok stores the next method we'll compare */
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
196 for (i = 0; i <= methlen; i++) {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
197 if (methods[i] == '\0') {
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
198 TRACE(("auth method '%s'", tok))
68
eee77ac31ccc cleaning up the pubkey defines
Matt Johnston <matt@ucc.asn.au>
parents: 45
diff changeset
199 #ifdef ENABLE_CLI_PUBKEY_AUTH
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
200 if (strncmp(AUTH_METHOD_PUBKEY, tok,
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
201 AUTH_METHOD_PUBKEY_LEN) == 0) {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
202 ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
203 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
204 #endif
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
205 #ifdef ENABLE_CLI_INTERACT_AUTH
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
206 if (strncmp(AUTH_METHOD_INTERACT, tok,
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
207 AUTH_METHOD_INTERACT_LEN) == 0) {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
208 ses.authstate.authtypes |= AUTH_TYPE_INTERACT;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
209 }
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
210 #endif
68
eee77ac31ccc cleaning up the pubkey defines
Matt Johnston <matt@ucc.asn.au>
parents: 45
diff changeset
211 #ifdef ENABLE_CLI_PASSWORD_AUTH
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
212 if (strncmp(AUTH_METHOD_PASSWORD, tok,
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
213 AUTH_METHOD_PASSWORD_LEN) == 0) {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
214 ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
215 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
216 #endif
34
e2a1eaa19f22 Client mostly works up to password auth
Matt Johnston <matt@ucc.asn.au>
parents: 33
diff changeset
217 tok = &methods[i+1]; /* Must make sure we don't use it after the
e2a1eaa19f22 Client mostly works up to password auth
Matt Johnston <matt@ucc.asn.au>
parents: 33
diff changeset
218 last loop, since it'll point to something
e2a1eaa19f22 Client mostly works up to password auth
Matt Johnston <matt@ucc.asn.au>
parents: 33
diff changeset
219 undefined */
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
220 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
221 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
222
114
2be6aa26a8c9 Leak found with MallocDebug - it's kinda useful
Matt Johnston <matt@ucc.asn.au>
parents: 74
diff changeset
223 m_free(methods);
2be6aa26a8c9 Leak found with MallocDebug - it's kinda useful
Matt Johnston <matt@ucc.asn.au>
parents: 74
diff changeset
224
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
225 cli_ses.state = USERAUTH_FAIL_RCVD;
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
226
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
227 TRACE(("leave recv_msg_userauth_failure"))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
228 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
229
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
230 void recv_msg_userauth_success() {
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
231 TRACE(("received msg_userauth_success"))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
232 ses.authstate.authdone = 1;
37
0913e2ee3545 we're nearly there yet
Matt Johnston <matt@ucc.asn.au>
parents: 35
diff changeset
233 cli_ses.state = USERAUTH_SUCCESS_RCVD;
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
234 cli_ses.lastauthtype = AUTH_TYPE_NONE;
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
235 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
236
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
237 void cli_auth_try() {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
238
300
baea1d43e7eb Some cleanups/fixes for various TRACE statements
Matt Johnston <matt@ucc.asn.au>
parents: 268
diff changeset
239 int finished = 0;
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
240 TRACE(("enter cli_auth_try"))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
241
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
242 CHECKCLEARTOWRITE();
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
243
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
244 /* Order to try is pubkey, interactive, password.
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
245 * As soon as "finished" is set for one, we don't do any more. */
68
eee77ac31ccc cleaning up the pubkey defines
Matt Johnston <matt@ucc.asn.au>
parents: 45
diff changeset
246 #ifdef ENABLE_CLI_PUBKEY_AUTH
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
247 if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
248 finished = cli_auth_pubkey();
45
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
249 cli_ses.lastauthtype = AUTH_TYPE_PUBKEY;
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
250 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
251 #endif
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
252
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
253 #ifdef ENABLE_CLI_INTERACT_AUTH
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
254 if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
255 if (cli_ses.auth_interact_failed) {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
256 finished = 0;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
257 } else {
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
258 cli_auth_interactive();
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
259 cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
260 finished = 1;
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
261 }
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
262 }
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
263 #endif
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
264
68
eee77ac31ccc cleaning up the pubkey defines
Matt Johnston <matt@ucc.asn.au>
parents: 45
diff changeset
265 #ifdef ENABLE_CLI_PASSWORD_AUTH
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
266 if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
267 cli_auth_password();
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
268 finished = 1;
45
9ee8996a375f Pubkey auth is mostly there for the client. Something strange with
Matt Johnston <matt@ucc.asn.au>
parents: 43
diff changeset
269 cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
270 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
271 #endif
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
272
249
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
273 TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
efbaf6b03837 added keyboard-interactive client support
Matt Johnston <matt@ucc.asn.au>
parents: 179
diff changeset
274
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
275 if (!finished) {
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
276 dropbear_exit("No auth methods could be used.");
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
277 }
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
278
165
0cfba3034be5 Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents: 114
diff changeset
279 TRACE(("leave cli_auth_try"))
33
f789045062e6 Progressing client support
Matt Johnston <matt@ucc.asn.au>
parents:
diff changeset
280 }
268
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
281
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
282 /* A helper for getpass() that exits if the user cancels. The returned
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
283 * password is statically allocated by getpass() */
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
284 char* getpass_or_cancel()
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
285 {
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
286 char* password = NULL;
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
287
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
288 password = getpass("Password: ");
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
289
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
290 /* 0x03 is a ctrl-c character in the buffer. */
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
291 if (password == NULL || strchr(password, '\3') != NULL) {
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
292 dropbear_close("Interrupted.");
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
293 }
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
294 return password;
475a818dd6e7 Cancel a dbclient password prompt if the user presses ctrl-c.
Matt Johnston <matt@ucc.asn.au>
parents: 249
diff changeset
295 }