KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jcifs > smb > SmbSession


1 /* jcifs smb client library in Java
2  * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18
19 package jcifs.smb;
20
21 import java.util.Vector JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.net.InetAddress JavaDoc;
24 import java.net.UnknownHostException JavaDoc;
25 import jcifs.Config;
26 import jcifs.UniAddress;
27 import jcifs.netbios.NbtAddress;
28
29 /**
30  * The class represents a user's session established with an SMB/CIFS
31  * server. This class is used internally to the jCIFS library however
32  * applications may wish to authenticate aribrary user credentials
33  * with the <tt>logon</tt> method. It is noteworthy that jCIFS does not
34  * support DCE/RPC at this time and therefore does not use the NETLOGON
35  * procedure. Instead, it simply performs a "tree connect" to IPC$ using
36  * the supplied credentials. This is only a subset of the NETLOGON procedure
37  * but is achives the same effect.
38
39 Note that it is possible to change the resource against which clients
40 are authenticated to be something other than <tt>IPC$</tt> using the
41 <tt>jcifs.smb.client.logonShare</tt> property. This can be used to
42 provide simple group based access control. For example, one could setup
43 the NTLM HTTP Filter with the <tt>jcifs.smb.client.domainController</tt>
44 init parameter set to the name of the server used for authentication. On
45 that host, create a share called JCIFSAUTH and adjust the access control
46 list for that share to permit only the clients that should have access to
47 the target website. Finally, set the <tt>jcifs.smb.client.logonShare</tt>
48 to JCIFSAUTH. This should restrict access to only those clients that have
49 access to the JCIFSAUTH share. The access control on that share can be
50 changed without changing init parameters or reinitializing the webapp.
51  */

52
53 public final class SmbSession {
54
55     private static final String JavaDoc LOGON_SHARE =
56                 Config.getProperty( "jcifs.smb.client.logonShare", null );
57     private static final int LOOKUP_RESP_LIMIT =
58                 Config.getInt( "jcifs.netbios.lookupRespLimit", 3 );
59     private static final String JavaDoc DOMAIN =
60                 Config.getProperty("jcifs.smb.client.domain", null);
61     private static final String JavaDoc USERNAME =
62                 Config.getProperty("jcifs.smb.client.username", null);
63     private static final int CACHE_POLICY =
64                 Config.getInt( "jcifs.netbios.cachePolicy", 60 * 10 ) * 60; /* 10 hours */
65
66     static NbtAddress[] dc_list = null;
67     static long dc_list_expiration;
68     static int dc_list_counter;
69
70     private static NtlmChallenge interrogate( NbtAddress addr ) throws SmbException {
71         UniAddress dc = new UniAddress( addr );
72         SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 );
73         if (USERNAME == null) {
74             trans.connect();
75             if (SmbTransport.log.level > 2)
76                 SmbTransport.log.println(
77                     "Default credentials (jcifs.smb.client.username/password)" +
78                     " not specified. SMB signing may not work propertly." +
79                     " Skipping DC interrogation." );
80         } else {
81             SmbSession ssn = trans.getSmbSession( NtlmPasswordAuthentication.DEFAULT );
82             ssn.getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
83         }
84         return new NtlmChallenge( trans.server.encryptionKey, dc );
85     }
86     public static NtlmChallenge getChallengeForDomain()
87                 throws SmbException, UnknownHostException JavaDoc {
88         if( DOMAIN == null ) {
89             throw new SmbException( "A domain was not specified" );
90         }
91         synchronized (DOMAIN) {
92             long now = System.currentTimeMillis();
93             if (dc_list_expiration < now) {
94                 dc_list_expiration = now + CACHE_POLICY * 1000L;
95                 NbtAddress[] list = NbtAddress.getAllByName( DOMAIN, 0x1C, null, null );
96                 if (list != null && list.length > 0) {
97                     dc_list = list;
98                 } else { /* keep using the old list */
99                     dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */
100                     if (SmbTransport.log.level > 1) {
101                         SmbTransport.log.println( "Failed to retrieve DC list from WINS" );
102                     }
103                 }
104             }
105
106             int max = Math.min( dc_list.length, LOOKUP_RESP_LIMIT );
107             for (int j = 0; j < max; j++) {
108                 int i = dc_list_counter++ % max;
109                 if (dc_list[i] != null) {
110                     try {
111                         return interrogate( dc_list[i] );
112                     } catch (SmbException se) {
113                         if (SmbTransport.log.level > 1) {
114                             SmbTransport.log.println( "Failed validate DC: " + dc_list[i] );
115                             if (SmbTransport.log.level > 2)
116                                 se.printStackTrace( SmbTransport.log );
117                         }
118                     }
119                     dc_list[i] = null;
120                 }
121             }
122
123             dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */
124         }
125
126         throw new UnknownHostException JavaDoc(
127                 "Failed to negotiate with a suitable domain controller for " + DOMAIN );
128     }
129
130     public static byte[] getChallenge( UniAddress dc )
131                 throws SmbException, UnknownHostException JavaDoc {
132         return getChallenge(dc, 0);
133     }
134
135     public static byte[] getChallenge( UniAddress dc, int port )
136                 throws SmbException, UnknownHostException JavaDoc {
137         SmbTransport trans = SmbTransport.getSmbTransport( dc, port );
138         trans.connect();
139         return trans.server.encryptionKey;
140     }
141 /**
142  * Authenticate arbitrary credentials represented by the
143  * <tt>NtlmPasswordAuthentication</tt> object against the domain controller
144  * specified by the <tt>UniAddress</tt> parameter. If the credentials are
145  * not accepted, an <tt>SmbAuthException</tt> will be thrown. If an error
146  * occurs an <tt>SmbException</tt> will be thrown. If the credentials are
147  * valid, the method will return without throwing an exception. See the
148  * last <a HREF="../../../faq.html">FAQ</a> question.
149  *
150  * See also the <tt>jcifs.smb.client.logonShare</tt> property.
151  */

152     public static void logon( UniAddress dc,
153                         NtlmPasswordAuthentication auth ) throws SmbException {
154         logon(dc, 0, auth);
155     }
156
157     public static void logon( UniAddress dc, int port,
158                         NtlmPasswordAuthentication auth ) throws SmbException {
159         SmbTree tree = SmbTransport.getSmbTransport( dc, port ).getSmbSession( auth ).getSmbTree( LOGON_SHARE, null );
160         if( LOGON_SHARE == null ) {
161             tree.treeConnect( null, null );
162         } else {
163             Trans2FindFirst2 req = new Trans2FindFirst2( "\\", "*", SmbFile.ATTR_DIRECTORY );
164             Trans2FindFirst2Response resp = new Trans2FindFirst2Response();
165             tree.send( req, resp );
166         }
167     }
168
169     private int uid;
170     private Vector JavaDoc trees;
171     private boolean sessionSetup;
172     // Transport parameters allows trans to be removed from CONNECTIONS
173
private UniAddress address;
174     private int port, localPort;
175     private InetAddress JavaDoc localAddr;
176
177     SmbTransport transport = null;
178     NtlmPasswordAuthentication auth;
179     long expiration;
180
181     SmbSession( UniAddress address, int port,
182                 InetAddress JavaDoc localAddr, int localPort,
183                 NtlmPasswordAuthentication auth ) {
184         this.address = address;
185         this.port = port;
186         this.localAddr = localAddr;
187         this.localPort = localPort;
188         this.auth = auth;
189         trees = new Vector JavaDoc();
190     }
191
192     synchronized SmbTree getSmbTree( String JavaDoc share, String JavaDoc service ) {
193         SmbTree t;
194
195         if( share == null ) {
196             share = "IPC$";
197         }
198         for( Enumeration JavaDoc e = trees.elements(); e.hasMoreElements(); ) {
199             t = (SmbTree)e.nextElement();
200             if( t.matches( share, service )) {
201                 return t;
202             }
203         }
204         t = new SmbTree( this, share, service );
205         trees.addElement( t );
206         return t;
207     }
208     boolean matches( NtlmPasswordAuthentication auth ) {
209         return this.auth == auth || this.auth.equals( auth );
210     }
211     synchronized SmbTransport transport() {
212         if( transport == null ) {
213             transport = SmbTransport.getSmbTransport( address, port, localAddr, localPort );
214         }
215         return transport;
216     }
217     void send( ServerMessageBlock request,
218                             ServerMessageBlock response ) throws SmbException {
219         if( response != null ) {
220             response.received = false;
221         }
222         expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT;
223         sessionSetup( request, response );
224         if( response != null && response.received ) {
225             return;
226         }
227         request.uid = uid;
228         request.auth = auth;
229         transport.send( request, response );
230     }
231     void sessionSetup( ServerMessageBlock andx,
232                             ServerMessageBlock andxResponse ) throws SmbException {
233 synchronized( transport() ) {
234         if( sessionSetup ) {
235             return;
236         }
237
238         transport.connect();
239
240         /*
241          * Session Setup And X Request / Response
242          */

243
244         if( transport.log.level > 3 )
245             transport.log.println( "sessionSetup: accountName=" + auth.username + ",primaryDomain=" + auth.domain );
246
247         SmbComSessionSetupAndX request = new SmbComSessionSetupAndX( this, andx );
248         SmbComSessionSetupAndXResponse response = new SmbComSessionSetupAndXResponse( andxResponse );
249
250         /* Create SMB signature digest if necessary
251          * Only the first SMB_COM_SESSION_SETUP_ANX with non-null or
252          * blank password initializes signing.
253          */

254         if (transport.isSignatureSetupRequired( auth )) {
255             if( auth.hashesExternal && NtlmPasswordAuthentication.DEFAULT_PASSWORD != NtlmPasswordAuthentication.BLANK ) {
256                 /* preauthentication
257                  */

258                 transport.getSmbSession( NtlmPasswordAuthentication.DEFAULT ).getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
259             }
260             request.digest = new SigningDigest( transport, auth );
261         }
262
263         request.auth = auth;
264         transport.send( request, response );
265
266         if( response.isLoggedInAsGuest &&
267                     "GUEST".equalsIgnoreCase( auth.username ) == false) {
268             throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE );
269         }
270
271         uid = response.uid;
272         sessionSetup = true;
273
274         if( request.digest != null ) {
275             /* success - install the signing digest */
276             transport.digest = request.digest;
277         }
278 }
279     }
280     void logoff( boolean inError ) {
281 synchronized( transport() ) {
282         if( sessionSetup == false ) {
283             return;
284         }
285
286         for( Enumeration JavaDoc e = trees.elements(); e.hasMoreElements(); ) {
287             SmbTree t = (SmbTree)e.nextElement();
288             t.treeDisconnect( inError );
289         }
290
291         if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) {
292
293             /*
294              * Logoff And X Request / Response
295              */

296
297             SmbComLogoffAndX request = new SmbComLogoffAndX( null );
298             request.uid = uid;
299             try {
300                 transport.send( request, null );
301             } catch( SmbException se ) {
302             }
303         }
304
305         sessionSetup = false;
306 }
307     }
308     public String JavaDoc toString() {
309         return "SmbSession[accountName=" + auth.username +
310                 ",primaryDomain=" + auth.domain +
311                 ",uid=" + uid +
312                 ",sessionSetup=" + sessionSetup + "]";
313     }
314 }
315
Popular Tags