001: /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
002: /*
003: Copyright (c) 2002-2008 ymnk, JCraft,Inc. All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without
006: modification, are permitted provided that the following conditions are met:
007:
008: 1. Redistributions of source code must retain the above copyright notice,
009: this list of conditions and the following disclaimer.
010:
011: 2. Redistributions in binary form must reproduce the above copyright
012: notice, this list of conditions and the following disclaimer in
013: the documentation and/or other materials provided with the distribution.
014:
015: 3. The names of the authors may not be used to endorse or promote products
016: derived from this software without specific prior written permission.
017:
018: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
019: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
020: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
021: INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
022: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
024: OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
027: EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jcraft.jsch;
031:
032: class UserAuthKeyboardInteractive extends UserAuth {
033: public boolean start(Session session) throws Exception {
034: super .start(session);
035:
036: if (userinfo != null
037: && !(userinfo instanceof UIKeyboardInteractive)) {
038: return false;
039: }
040:
041: String dest = username + "@" + session.host;
042: if (session.port != 22) {
043: dest += (":" + session.port);
044: }
045: byte[] password = session.password;
046:
047: boolean cancel = false;
048:
049: byte[] _username = null;
050: _username = Util.str2byte(username);
051:
052: while (true) {
053: // send
054: // byte SSH_MSG_USERAUTH_REQUEST(50)
055: // string user name (ISO-10646 UTF-8, as defined in [RFC-2279])
056: // string service name (US-ASCII) "ssh-userauth" ? "ssh-connection"
057: // string "keyboard-interactive" (US-ASCII)
058: // string language tag (as defined in [RFC-3066])
059: // string submethods (ISO-10646 UTF-8)
060: packet.reset();
061: buf.putByte((byte) SSH_MSG_USERAUTH_REQUEST);
062: buf.putString(_username);
063: buf.putString("ssh-connection".getBytes());
064: //buf.putString("ssh-userauth".getBytes());
065: buf.putString("keyboard-interactive".getBytes());
066: buf.putString("".getBytes());
067: buf.putString("".getBytes());
068: session.write(packet);
069:
070: boolean firsttime = true;
071: loop: while (true) {
072: buf = session.read(buf);
073: int command = buf.getCommand() & 0xff;
074:
075: if (command == SSH_MSG_USERAUTH_SUCCESS) {
076: return true;
077: }
078: if (command == SSH_MSG_USERAUTH_BANNER) {
079: buf.getInt();
080: buf.getByte();
081: buf.getByte();
082: byte[] _message = buf.getString();
083: byte[] lang = buf.getString();
084: String message = null;
085: try {
086: message = new String(_message, "UTF-8");
087: } catch (java.io.UnsupportedEncodingException e) {
088: message = new String(_message);
089: }
090: if (userinfo != null) {
091: userinfo.showMessage(message);
092: }
093: continue loop;
094: }
095: if (command == SSH_MSG_USERAUTH_FAILURE) {
096: buf.getInt();
097: buf.getByte();
098: buf.getByte();
099: byte[] foo = buf.getString();
100: int partial_success = buf.getByte();
101: // System.err.println(new String(foo)+
102: // " partial_success:"+(partial_success!=0));
103:
104: if (partial_success != 0) {
105: throw new JSchPartialAuthException(new String(
106: foo));
107: }
108:
109: if (firsttime) {
110: return false;
111: //throw new JSchException("USERAUTH KI is not supported");
112: //cancel=true; // ??
113: }
114: break;
115: }
116: if (command == SSH_MSG_USERAUTH_INFO_REQUEST) {
117: firsttime = false;
118: buf.getInt();
119: buf.getByte();
120: buf.getByte();
121: String name = new String(buf.getString());
122: String instruction = new String(buf.getString());
123: String languate_tag = new String(buf.getString());
124: int num = buf.getInt();
125: String[] prompt = new String[num];
126: boolean[] echo = new boolean[num];
127: for (int i = 0; i < num; i++) {
128: prompt[i] = new String(buf.getString());
129: echo[i] = (buf.getByte() != 0);
130: }
131:
132: byte[][] response = null;
133: if (num > 0
134: || (name.length() > 0 || instruction
135: .length() > 0)) {
136: if (userinfo != null) {
137: UIKeyboardInteractive kbi = (UIKeyboardInteractive) userinfo;
138: String[] _response = kbi
139: .promptKeyboardInteractive(dest,
140: name, instruction, prompt,
141: echo);
142: if (_response != null) {
143: response = new byte[_response.length][];
144: for (int i = 0; i < _response.length; i++) {
145: response[i] = Util
146: .str2byte(_response[i]);
147: }
148: }
149: } else if (password != null
150: && prompt.length == 1
151: && !echo[0]
152: && prompt[0].toLowerCase().startsWith(
153: "password:")) {
154: response = new byte[1][];
155: response[0] = password;
156: password = null;
157: }
158: }
159:
160: // byte SSH_MSG_USERAUTH_INFO_RESPONSE(61)
161: // int num-responses
162: // string response[1] (ISO-10646 UTF-8)
163: // ...
164: // string response[num-responses] (ISO-10646 UTF-8)
165: //if(response!=null)
166: //System.err.println("response.length="+response.length);
167: //else
168: //System.err.println("response is null");
169: packet.reset();
170: buf.putByte((byte) SSH_MSG_USERAUTH_INFO_RESPONSE);
171: if (num > 0 && (response == null || // cancel
172: num != response.length)) {
173:
174: if (response == null) {
175: // working around the bug in OpenSSH ;-<
176: buf.putInt(num);
177: for (int i = 0; i < num; i++) {
178: buf.putString("".getBytes());
179: }
180: } else {
181: buf.putInt(0);
182: }
183:
184: if (response == null)
185: cancel = true;
186: } else {
187: buf.putInt(num);
188: for (int i = 0; i < num; i++) {
189: //System.err.println("response: |"+new String(response[i])+"| <- replace here with **** if you need");
190: buf.putString(response[i]);
191: }
192: }
193: session.write(packet);
194: /*
195: if(cancel)
196: break;
197: */
198: continue loop;
199: }
200: //throw new JSchException("USERAUTH fail ("+command+")");
201: return false;
202: }
203: if (cancel) {
204: throw new JSchAuthCancelException(
205: "keyboard-interactive");
206: //break;
207: }
208: }
209: //return false;
210: }
211: }
|