001: /* jcifs smb client library in Java
002: * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package com.knowgate.jcifs.smb;
020:
021: import java.util.Vector;
022: import java.util.Enumeration;
023: import java.net.InetAddress;
024: import java.net.UnknownHostException;
025:
026: import com.knowgate.jcifs.Config;
027: import com.knowgate.jcifs.UniAddress;
028: import com.knowgate.debug.*;
029:
030: /**
031: * The class represents a user's session established with an SMB/CIFS
032: * server. This class is used internally to the jCIFS library however
033: * applications may wish to authenticate aribrary user credentials
034: * with the <tt>logon</tt> method. It is noteworthy that jCIFS does not
035: * support DCE/RPC at this time and therefore does not use the NETLOGON
036: * procedure. Instead, it simply performs a "tree connect" to IPC$ using
037: * the supplied credentials. This is only a subset of the NETLOGON procedure
038: * but is achives the same effect.
039:
040: Note that it is possible to change the resource against which clients
041: are authenticated to be something other than <tt>IPC$</tt> using the
042: <tt>jcifs.smb.client.logonShare</tt> property. This can be used to
043: provide simple group based access control. For example, one could setup
044: the NTLM HTTP Filter with the <tt>jcifs.smb.client.domainController</tt>
045: init parameter set to the name of the server used for authentication. On
046: that host, create a share called JCIFSAUTH and adjust the access control
047: list for that share to permit only the clients that should have access to
048: the target website. Finally, set the <tt>jcifs.smb.client.logonShare</tt>
049: to JCIFSAUTH. This should restrict access to only those clients that have
050: access to the JCIFSAUTH share. The access control on that share can be
051: changed without changing init parameters or reinitializing the webapp.
052: */
053:
054: public final class SmbSession {
055:
056: private static final String LOGON_SHARE = Config.getProperty(
057: "jcifs.smb.client.logonShare", "IPC$");
058:
059: public static byte[] getChallenge(UniAddress dc)
060: throws SmbException, UnknownHostException {
061: SmbTransport trans = SmbTransport.getSmbTransport(dc, 0);
062: trans.negotiate();
063: return trans.server.encryptionKey;
064: }
065:
066: /**
067: * Authenticate arbitrary credentials represented by the
068: * <tt>NtlmPasswordAuthentication</tt> object against the domain controller
069: * specified by the <tt>UniAddress</tt> parameter. If the credentials are
070: * not accepted, an <tt>SmbAuthException</tt> will be thrown. If an error
071: * occurs an <tt>SmbException</tt> will be thrown. If the credentials are
072: * valid, the method will return without throwing an exception. See the
073: * last <a href="../../../../FAQ.html">FAQ</a> question.
074: *
075: * See also the <tt>jcifs.smb.client.logonShare</tt> property.
076: */
077: public static void logon(UniAddress dc,
078: NtlmPasswordAuthentication auth) throws SmbException {
079: SmbTransport.getSmbTransport(dc, 0).getSmbSession(auth)
080: .getSmbTree(LOGON_SHARE, null).treeConnect(null, null);
081: }
082:
083: private int uid;
084: private Vector trees;
085: private boolean sessionSetup;
086: // Transport parameters allows trans to be removed from CONNECTIONS
087: private UniAddress address;
088: private int port, localPort;
089: private InetAddress localAddr;
090:
091: SmbTransport transport = SmbTransport.NULL_TRANSPORT;
092: NtlmPasswordAuthentication auth;
093:
094: SmbSession(UniAddress address, int port, InetAddress localAddr,
095: int localPort, NtlmPasswordAuthentication auth) {
096: this .address = address;
097: this .port = port;
098: this .localAddr = localAddr;
099: this .localPort = localPort;
100: this .auth = auth;
101: trees = new Vector();
102: }
103:
104: synchronized SmbTree getSmbTree(String share, String service) {
105: SmbTree t;
106:
107: if (share == null) {
108: share = "IPC$";
109: }
110: for (Enumeration e = trees.elements(); e.hasMoreElements();) {
111: t = (SmbTree) e.nextElement();
112: if (t.matches(share, service)) {
113: return t;
114: }
115: }
116: t = new SmbTree(this , share, service);
117: trees.addElement(t);
118: return t;
119: }
120:
121: boolean matches(NtlmPasswordAuthentication auth) {
122: return this .auth == auth || this .auth.equals(auth);
123: }
124:
125: synchronized SmbTransport transport() throws SmbException {
126: if (transport == SmbTransport.NULL_TRANSPORT) {
127: transport = SmbTransport.getSmbTransport(address, port,
128: localAddr, localPort);
129: }
130: return transport;
131: }
132:
133: void sendTransaction(SmbComTransaction request,
134: SmbComTransactionResponse response) throws SmbException {
135: // transactions are not batchable
136: sessionSetup(null, null);
137: request.uid = uid;
138: request.auth = auth;
139: transport().sendTransaction(request, response);
140: }
141:
142: void send(ServerMessageBlock request, ServerMessageBlock response)
143: throws SmbException {
144: if (response != null) {
145: response.received = false;
146: }
147: sessionSetup(request, response);
148: if (response != null && response.received) {
149: return;
150: }
151: request.uid = uid;
152: request.auth = auth;
153: transport().send(request, response);
154: }
155:
156: void sessionSetup(ServerMessageBlock andx,
157: ServerMessageBlock andxResponse) throws SmbException {
158:
159: synchronized (transport()) {
160: if (sessionSetup) {
161: return;
162: }
163:
164: transport.negotiate();
165:
166: /*
167: * Session Setup And X Request / Response
168: */
169:
170: if (DebugFile.trace)
171: DebugFile.writeln("sessionSetup: accountName="
172: + auth.username + ",primaryDomain="
173: + auth.domain);
174:
175: SmbComSessionSetupAndX request = new SmbComSessionSetupAndX(
176: this , andx);
177: SmbComSessionSetupAndXResponse response = new SmbComSessionSetupAndXResponse(
178: andxResponse);
179:
180: /* Create SMB signature digest if necessary
181: * Only the first SMB_COM_SESSION_SETUP_ANX with creds other than NULL initializes signing.
182: */
183: if (transport.isSignatureSetupRequired(auth)) {
184: if (auth.hashesExternal
185: && NtlmPasswordAuthentication.DEFAULT_PASSWORD != null) {
186: /* preauthentication
187: */
188: transport.getSmbSession(
189: NtlmPasswordAuthentication.DEFAULT)
190: .getSmbTree(LOGON_SHARE, null).treeConnect(
191: null, null);
192: }
193: request.digest = new SigningDigest(transport, auth);
194: }
195:
196: request.auth = auth;
197: transport.send(request, response);
198:
199: if (response.isLoggedInAsGuest
200: && "GUEST".equals(auth.username)) {
201: throw new SmbAuthException(
202: NtStatus.NT_STATUS_LOGON_FAILURE);
203: }
204:
205: uid = response.uid;
206: sessionSetup = true;
207:
208: if (request.digest != null) {
209: /* success - install the signing digest */
210: transport.digest = request.digest;
211: }
212: }
213: }
214:
215: void logoff(boolean inError) {
216: synchronized (transport) {
217: try {
218: if (sessionSetup == false) {
219: return;
220: }
221:
222: for (Enumeration e = trees.elements(); e
223: .hasMoreElements();) {
224: SmbTree t = (SmbTree) e.nextElement();
225: t.treeDisconnect(inError);
226: }
227:
228: if (transport.server.security == ServerMessageBlock.SECURITY_SHARE) {
229: return;
230: }
231:
232: if (!inError) {
233:
234: /*
235: * Logoff And X Request / Response
236: */
237:
238: SmbComLogoffAndX request = new SmbComLogoffAndX(
239: null);
240: request.uid = uid;
241: try {
242: transport.send(request, null);
243: } catch (SmbException se) {
244: }
245: }
246: sessionSetup = false;
247: } finally {
248: transport = SmbTransport.NULL_TRANSPORT;
249: }
250: }
251: }
252:
253: public String toString() {
254: return "SmbSession[accountName=" + auth.username
255: + ",primaryDomain=" + auth.domain + ",uid=" + uid
256: + ",sessionSetup=" + sessionSetup + "]";
257: }
258: }
|