KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > knowgate > jcifs > http > NetworkExplorer


1 /* jcifs smb client library in Java
2  * Copyright (C) 2002 "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 com.knowgate.jcifs.http;
20
21 import java.util.Enumeration JavaDoc;
22 import java.util.LinkedList JavaDoc;
23 import java.util.ListIterator JavaDoc;
24 import java.util.Date JavaDoc;
25 import java.util.GregorianCalendar JavaDoc;
26
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.PrintWriter JavaDoc;
30
31 import javax.servlet.*;
32 import javax.servlet.http.*;
33
34 import java.text.SimpleDateFormat JavaDoc;
35 import java.net.UnknownHostException JavaDoc;
36
37 import com.knowgate.jcifs.Config;
38 import com.knowgate.jcifs.UniAddress;
39 import com.knowgate.jcifs.ntlmssp.*;
40 import com.knowgate.jcifs.smb.SmbFile;
41 import com.knowgate.jcifs.smb.SmbFileInputStream;
42 import com.knowgate.jcifs.smb.NtlmPasswordAuthentication;
43 import com.knowgate.jcifs.smb.SmbException;
44 import com.knowgate.jcifs.smb.SmbAuthException;
45 import com.knowgate.jcifs.smb.SmbSession;
46 import com.knowgate.jcifs.smb.DfsReferral;
47 import com.knowgate.jcifs.netbios.NbtAddress;
48 import com.knowgate.jcifs.util.MimeMap;
49
50 import com.knowgate.misc.Base64Decoder;
51
52 /**
53  * This servlet may be used to "browse" the entire hierarchy of resources
54  * on an SMB network like one might with Network Neighborhood or Windows
55  * Explorer. The users credentials with be negotiated using NTLM SSP if
56  * the client is Microsoft Internet Explorer.
57  *
58  * Please read <a HREF="../../../ntlmhttpauth.html">jCIFS NTLM HTTP Authentication and the Network Explorer Servlet</a>.
59  * @version 0.9.1
60  */

61
62 public class NetworkExplorer extends HttpServlet {
63
64     private MimeMap mimeMap;
65     private String JavaDoc style;
66     private NtlmSsp ntlmSsp;
67     private boolean credentialsSupplied;
68     private boolean enableBasic;
69     private boolean insecureBasic;
70     private String JavaDoc realm, defaultDomain;
71
72     public void init() throws ServletException {
73         InputStream JavaDoc is;
74         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
75         byte[] buf = new byte[1024];
76         int n;
77         String JavaDoc name;
78
79         Config.setProperty( "jcifs.smb.client.soTimeout", "600000" );
80         Config.setProperty( "jcifs.smb.client.attrExpirationPeriod", "300000" );
81
82         Enumeration JavaDoc e = getInitParameterNames();
83         while( e.hasMoreElements() ) {
84             name = (String JavaDoc)e.nextElement();
85             if( name.startsWith( "jcifs." )) {
86                 Config.setProperty( name, getInitParameter( name ));
87             }
88         }
89
90         if( Config.getProperty( "jcifs.smb.client.username" ) == null ) {
91             ntlmSsp = new NtlmSsp();
92         } else {
93             credentialsSupplied = true;
94         }
95
96         try {
97             mimeMap = new MimeMap();
98             is = getClass().getClassLoader().getResourceAsStream( "jcifs/http/ne.css" );
99             while(( n = is.read( buf )) != -1 ) {
100                 sb.append( new String JavaDoc( buf, 0, n, "ISO8859_1" ));
101             }
102             style = sb.toString();
103         } catch( IOException JavaDoc ioe ) {
104             throw new ServletException( ioe.getMessage() );
105         }
106
107         enableBasic = Config.getBoolean("jcifs.http.enableBasic", false );
108         insecureBasic = Config.getBoolean("jcifs.http.insecureBasic", false );
109         realm = Config.getProperty("jcifs.http.basicRealm");
110         if (realm == null) realm = "jCIFS";
111         defaultDomain = Config.getProperty("jcifs.smb.client.domain");
112     }
113
114     protected void doFile( HttpServletRequest req,
115                 HttpServletResponse resp, SmbFile file ) throws IOException JavaDoc {
116         byte[] buf = new byte[8192];
117         SmbFileInputStream in;
118         ServletOutputStream out;
119         String JavaDoc url, type;
120         int n;
121
122         in = new SmbFileInputStream( file );
123         out = resp.getOutputStream();
124         url = file.getPath();
125
126         resp.setContentType( "text/plain" );
127
128         if(( n = url.lastIndexOf( '.' )) > 0 &&
129                 ( type = url.substring( n + 1 )) != null &&
130                 type.length() > 1 && type.length() < 6 ) {
131             resp.setContentType( mimeMap.getMimeType( type ));
132         }
133         resp.setHeader( "Content-Length", file.length() + "" );
134         resp.setHeader( "Accept-Ranges", "Bytes" );
135
136         while(( n = in.read( buf )) != -1 ) {
137             out.write( buf, 0, n );
138         }
139     }
140     protected int compareNames( SmbFile f1, String JavaDoc f1name, SmbFile f2 ) throws IOException JavaDoc {
141         if( f1.isDirectory() != f2.isDirectory() ) {
142             return f1.isDirectory() ? -1 : 1;
143         }
144         return f1name.compareToIgnoreCase( f2.getName() );
145     }
146     protected int compareSizes( SmbFile f1, String JavaDoc f1name, SmbFile f2 ) throws IOException JavaDoc {
147         long diff;
148
149         if( f1.isDirectory() != f2.isDirectory() ) {
150             return f1.isDirectory() ? -1 : 1;
151         }
152         if( f1.isDirectory() ) {
153             return f1name.compareToIgnoreCase( f2.getName() );
154         }
155         diff = f1.length() - f2.length();
156         if( diff == 0 ) {
157             return f1name.compareToIgnoreCase( f2.getName() );
158         }
159         return diff > 0 ? -1 : 1;
160     }
161     protected int compareTypes( SmbFile f1, String JavaDoc f1name, SmbFile f2 ) throws IOException JavaDoc {
162         String JavaDoc f2name, t1, t2;
163         int i;
164
165         if( f1.isDirectory() != f2.isDirectory() ) {
166             return f1.isDirectory() ? -1 : 1;
167         }
168         f2name = f2.getName();
169         if( f1.isDirectory() ) {
170             return f1name.compareToIgnoreCase( f2name );
171         }
172         i = f1name.lastIndexOf( '.' );
173         t1 = i == -1 ? "" : f1name.substring( i + 1 );
174         i = f2name.lastIndexOf( '.' );
175         t2 = i == -1 ? "" : f2name.substring( i + 1 );
176
177         i = t1.compareToIgnoreCase( t2 );
178         if( i == 0 ) {
179             return f1name.compareToIgnoreCase( f2name );
180         }
181         return i;
182     }
183     protected int compareDates( SmbFile f1, String JavaDoc f1name, SmbFile f2 ) throws IOException JavaDoc {
184         if( f1.isDirectory() != f2.isDirectory() ) {
185             return f1.isDirectory() ? -1 : 1;
186         }
187         if( f1.isDirectory() ) {
188             return f1name.compareToIgnoreCase( f2.getName() );
189         }
190         return f1.lastModified() > f2.lastModified() ? -1 : 1;
191     }
192     protected void doDirectory( HttpServletRequest req, HttpServletResponse resp, SmbFile dir ) throws IOException JavaDoc {
193         PrintWriter JavaDoc out;
194         SmbFile[] dirents;
195         SmbFile f;
196         int i, j, len, maxLen, dirCount, fileCount, sort;
197         String JavaDoc str, name, path, fmt;
198         LinkedList JavaDoc sorted;
199         ListIterator JavaDoc iter;
200         SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc( "MM/d/yy h:mm a" );
201         GregorianCalendar JavaDoc cal = new GregorianCalendar JavaDoc();
202
203         sdf.setCalendar( cal );
204
205         dirents = dir.listFiles();
206         sorted = new LinkedList JavaDoc();
207         if(( fmt = req.getParameter( "fmt" )) == null ) {
208             fmt = "col";
209         }
210         sort = 0;
211         if(( str = req.getParameter( "sort" )) == null || str.equals( "name" )) {
212             sort = 0;
213         } else if( str.equals( "size" )) {
214             sort = 1;
215         } else if( str.equals( "type" )) {
216             sort = 2;
217         } else if( str.equals( "date" )) {
218             sort = 3;
219         }
220         dirCount = fileCount = 0;
221         maxLen = 28;
222         for( i = 0; i < dirents.length; i++ ) {
223             try {
224                 if( dirents[i].getType() == SmbFile.TYPE_NAMED_PIPE ) {
225                     continue;
226                 }
227             } catch( SmbAuthException sae ) {
228             } catch( SmbException se ) {
229                 if( se.getNtStatus() != se.NT_STATUS_UNSUCCESSFUL ) {
230                     throw se;
231                 }
232             }
233             if( dirents[i].isDirectory() ) {
234                 dirCount++;
235             } else {
236                 fileCount++;
237             }
238
239             name = dirents[i].getName();
240             len = name.length();
241             if( len > maxLen ) {
242                 maxLen = len;
243             }
244
245             iter = sorted.listIterator();
246             for( j = 0; iter.hasNext(); j++ ) {
247                 if( sort == 0 ) {
248                     if( compareNames( dirents[i], name, (SmbFile)iter.next() ) < 0 ) {
249                         break;
250                     }
251                 } else if( sort == 1 ) {
252                     if( compareSizes( dirents[i], name, (SmbFile)iter.next() ) < 0 ) {
253                         break;
254                     }
255                 } else if( sort == 2 ) {
256                     if( compareTypes( dirents[i], name, (SmbFile)iter.next() ) < 0 ) {
257                         break;
258                     }
259                 } else if( sort == 3 ) {
260                     if( compareDates( dirents[i], name, (SmbFile)iter.next() ) < 0 ) {
261                         break;
262                     }
263                 }
264             }
265             sorted.add( j, dirents[i] );
266         }
267         if( maxLen > 50 ) {
268             maxLen = 50;
269         }
270         maxLen *= 9; /* convert to px */
271
272         out = resp.getWriter();
273
274         resp.setContentType( "text/html" );
275
276         out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">" );
277         out.println( "<html><head><title>Network Explorer</title>" );
278         out.println( "<meta HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">" );
279         out.println( "<style TYPE=\"text/css\">" );
280
281         out.println( style );
282
283         if( dirents.length < 200 ) {
284             out.println( " a:hover {" );
285             out.println( " background: #a2ff01;" );
286             out.println( " }" );
287         }
288
289         out.println( "</STYLE>" );
290         out.println( "</head><body>" );
291
292         out.print( "<a class=\"sort\" style=\"width: " + maxLen + ";\" HREF=\"?fmt=detail&sort=name\">Name</a>" );
293         out.println( "<a class=\"sort\" HREF=\"?fmt=detail&sort=size\">Size</a>" );
294         out.println( "<a class=\"sort\" HREF=\"?fmt=detail&sort=type\">Type</a>" );
295         out.println( "<a class=\"sort\" style=\"width: 180\" HREF=\"?fmt=detail&sort=date\">Modified</a><br clear='all'><p>" );
296
297         path = dir.getCanonicalPath();
298
299         if( path.length() < 7 ) {
300             out.println( "<b><big>smb://</big></b><br>" );
301             path = ".";
302         } else {
303             out.println( "<b><big>" + path + "</big></b><br>" );
304             path = "../";
305         }
306         out.println( (dirCount + fileCount) + " objects (" + dirCount + " directories, " + fileCount + " files)<br>" );
307         out.println( "<b><a class=\"plain\" HREF=\".\">normal</a> | <a class=\"plain\" HREF=\"?fmt=detail\">detailed</a></b>" );
308         out.println( "<p><table border='0' cellspacing='0' cellpadding='0'><tr><td>" );
309
310         out.print( "<A style=\"width: " + maxLen );
311         out.print( "; height: 18;\" HREF=\"" );
312         out.print( path );
313         out.println( "\"><b>&uarr;</b></a>" );
314         if( fmt.equals( "detail" )) {
315             out.println( "<br clear='all'>" );
316         }
317
318         if( path.length() == 1 || dir.getType() != SmbFile.TYPE_WORKGROUP ) {
319             path = "";
320         }
321
322         iter = sorted.listIterator();
323         while( iter.hasNext() ) {
324             f = (SmbFile)iter.next();
325             name = f.getName();
326
327             if( fmt.equals( "detail" )) {
328                 out.print( "<A style=\"width: " + maxLen );
329                 out.print( "; height: 18;\" HREF=\"" );
330                 out.print( path );
331                 out.print( name );
332
333                 if( f.isDirectory() ) {
334                     out.print( "?fmt=detail\"><b>" );
335                     out.print( name );
336                     out.print( "</b></a>" );
337                 } else {
338                     out.print( "\"><b>" );
339                     out.print( name );
340                     out.print( "</b></a><div align='right'>" );
341                     out.print( (f.length() / 1024) + " KB </div><div>" );
342                     i = name.lastIndexOf( '.' ) + 1;
343                     if( i > 1 && (name.length() - i) < 6 ) {
344                         out.print( name.substring( i ).toUpperCase() + "</div class='ext'>" );
345                     } else {
346                         out.print( "&nbsp;</div>" );
347                     }
348                     out.print( "<div style='width: 180'>" );
349                     out.print( sdf.format( new Date JavaDoc( f.lastModified() )));
350                     out.print( "</div>" );
351                 }
352                 out.println( "<br clear='all'>" );
353             } else {
354                 out.print( "<A style=\"width: " + maxLen );
355                 if( f.isDirectory() ) {
356                     out.print( "; height: 18;\" HREF=\"" );
357                     out.print( path );
358                     out.print( name );
359                     out.print( "\"><b>" );
360                     out.print( name );
361                     out.print( "</b></a>" );
362                 } else {
363                     out.print( ";\" HREF=\"" );
364                     out.print( path );
365                     out.print( name );
366                     out.print( "\"><b>" );
367                     out.print( name );
368                     out.print( "</b><br><small>" );
369                     out.print( (f.length() / 1024) + "KB <br>" );
370                     out.print( sdf.format( new Date JavaDoc( f.lastModified() )));
371                     out.print( "</small>" );
372                     out.println( "</a>" );
373                 }
374             }
375         }
376
377         out.println( "</td></tr></table>" );
378         out.println( "</BODY></HTML>" );
379         out.close();
380     }
381     private String JavaDoc parseServerAndShare( String JavaDoc pathInfo ) {
382         char[] out = new char[256];
383         char ch;
384         int len, p, i;
385
386         if( pathInfo == null ) {
387             return null;
388         }
389         len = pathInfo.length();
390
391         p = i = 0;
392         while( p < len && pathInfo.charAt( p ) == '/' ) {
393             p++;
394         }
395         if( p == len ) {
396             return null;
397         }
398
399                                                /* collect server name */
400         while ( p < len && ( ch = pathInfo.charAt( p )) != '/' ) {
401             out[i++] = ch;
402             p++;
403         }
404         while( p < len && pathInfo.charAt( p ) == '/' ) {
405             p++;
406         }
407         if( p < len ) { /* then there must be a share */
408             out[i++] = '/';
409             do { /* collect the share name */
410                 out[i++] = (ch = pathInfo.charAt( p++ ));
411             } while( p < len && ch != '/' );
412         }
413         return new String JavaDoc( out, 0, i );
414     }
415     public void doGet( HttpServletRequest req,
416                 HttpServletResponse resp ) throws IOException JavaDoc, ServletException {
417         UniAddress dc;
418         String JavaDoc msg, pathInfo, server = null;
419         boolean offerBasic, possibleWorkgroup = true;
420         NtlmPasswordAuthentication ntlm = null;
421         HttpSession ssn = req.getSession( false );
422
423         if(( pathInfo = req.getPathInfo() ) != null ) {
424             int i;
425             server = parseServerAndShare( pathInfo );
426             if( server != null && ( i = server.indexOf( '/' )) > 0 ) {
427                 server = server.substring( 0, i ).toLowerCase();
428                 possibleWorkgroup = false;
429             }
430         }
431
432         msg = req.getHeader( "Authorization" );
433         offerBasic = enableBasic && (insecureBasic || req.isSecure());
434
435         if( msg != null && (msg.startsWith( "NTLM " ) ||
436                     (offerBasic && msg.startsWith("Basic ")))) {
437
438             if( msg.startsWith("NTLM ")) {
439                 byte[] challenge;
440
441                 if( pathInfo == null || server == null ) {
442                     String JavaDoc mb = NbtAddress.getByName( NbtAddress.MASTER_BROWSER_NAME, 0x01, null ).getHostAddress();
443                     dc = UniAddress.getByName( mb );
444                 } else {
445                     dc = UniAddress.getByName( server, possibleWorkgroup );
446                 }
447
448                 req.getSession(); /* ensure session id is set for cluster env. */
449                 challenge = SmbSession.getChallenge( dc );
450                 if(( ntlm = NtlmSsp.authenticate( req, resp, challenge )) == null ) {
451                     return;
452                 }
453             } else { /* Basic */
454                 String JavaDoc auth = new String JavaDoc( Base64Decoder.decodeToBytes(msg.substring(6)), "US-ASCII" );
455                 int index = auth.indexOf( ':' );
456                 String JavaDoc user = (index != -1) ? auth.substring(0, index) : auth;
457                 String JavaDoc password = (index != -1) ? auth.substring(index + 1) : "";
458                 index = user.indexOf('\\');
459                 if (index == -1) index = user.indexOf('/');
460                 String JavaDoc domain = (index != -1) ? user.substring(0, index) : defaultDomain;
461                 user = (index != -1) ? user.substring(index + 1) : user;
462                 ntlm = new NtlmPasswordAuthentication(domain, user, password);
463             }
464
465             req.getSession().setAttribute( "npa-" + server, ntlm );
466
467         } else if( !credentialsSupplied ) {
468             if( ssn != null ) {
469                 ntlm = (NtlmPasswordAuthentication)ssn.getAttribute( "npa-" + server );
470             }
471             if( ntlm == null ) {
472                 resp.setHeader( "WWW-Authenticate", "NTLM" );
473                 if (offerBasic) {
474                     resp.addHeader( "WWW-Authenticate", "Basic realm=\"" + realm + "\"");
475                 }
476                 resp.setHeader( "Connection", "close" );
477                 resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
478                 resp.flushBuffer();
479                 return;
480             }
481         }
482
483         try {
484             SmbFile file;
485
486             if( ntlm != null ) {
487                 file = new SmbFile( "smb:/" + pathInfo , ntlm );
488             } else if( server == null ) {
489                 file = new SmbFile( "smb://" );
490             } else {
491                 file = new SmbFile( "smb:/" + pathInfo );
492             }
493
494             if( file.isDirectory() ) {
495                 doDirectory( req, resp, file );
496             } else {
497                 doFile( req, resp, file );
498             }
499         } catch( SmbAuthException sae ) {
500             if( ssn != null ) {
501                 ssn.removeAttribute( "npa-" + server );
502             }
503             if( sae.getNtStatus() == sae.NT_STATUS_ACCESS_VIOLATION ) {
504                 /* Server challenge no longer valid for
505                  * externally supplied password hashes.
506                  */

507                 resp.sendRedirect( req.getRequestURL().toString() );
508                 return;
509             }
510             resp.setHeader( "WWW-Authenticate", "NTLM" );
511             if (offerBasic) {
512                 resp.addHeader( "WWW-Authenticate", "Basic realm=\"" + realm + "\"");
513             }
514             resp.setHeader( "Connection", "close" );
515             resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
516             resp.flushBuffer();
517             return;
518         } catch( DfsReferral dr ) {
519             StringBuffer JavaDoc redir = req.getRequestURL();
520             String JavaDoc qs = req.getQueryString();
521             redir = new StringBuffer JavaDoc( redir.substring( 0, redir.length() - req.getPathInfo().length() ));
522             redir.append( dr.node.replace( '\\', '/' ));
523             redir.append( '/' );
524             if( qs != null ) {
525                 redir.append( req.getQueryString() );
526             }
527             resp.sendRedirect( redir.toString() );
528             resp.flushBuffer();
529             return;
530         }
531     }
532 }
533
534
Popular Tags