View Javadoc

1   /*******************************************************************************
2    * Copyright (c) 2007, 2014 Massimiliano Ziccardi
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *******************************************************************************/
16  package it.jnrpe.server;
17  
18  import it.jnrpe.JNRPE;
19  import it.jnrpe.JNRPEBuilder;
20  import it.jnrpe.commands.CommandRepository;
21  import it.jnrpe.plugins.IPluginRepository;
22  import it.jnrpe.plugins.PluginConfigurationException;
23  import it.jnrpe.plugins.PluginDefinition;
24  import it.jnrpe.plugins.PluginProxy;
25  import it.jnrpe.server.console.JNRPEConsole;
26  import it.jnrpe.server.plugins.DynaPluginRepository;
27  
28  import java.io.File;
29  import java.net.UnknownHostException;
30  
31  import org.apache.commons.cli2.CommandLine;
32  import org.apache.commons.cli2.DisplaySetting;
33  import org.apache.commons.cli2.Group;
34  import org.apache.commons.cli2.OptionException;
35  import org.apache.commons.cli2.builder.ArgumentBuilder;
36  import org.apache.commons.cli2.builder.DefaultOptionBuilder;
37  import org.apache.commons.cli2.builder.GroupBuilder;
38  import org.apache.commons.cli2.commandline.Parser;
39  import org.apache.commons.cli2.option.DefaultOption;
40  import org.apache.commons.cli2.util.HelpFormatter;
41  
42  /**
43   * The JNRPE Server entry point.
44   * 
45   * @author Massimiliano Ziccardi
46   */
47  public final class JNRPEServer {
48  
49  	/**
50  	 * The default JNRPE server listening port.
51  	 */
52  	private static final int DEFAULT_PORT = 5666;
53  
54  	/**
55  	 * The JNRPE Server version.
56  	 */
57  	private static final String VERSION = JNRPEServer.class.getPackage()
58  			.getImplementationVersion();
59  
60  	/**
61  	 * Default constructor.
62  	 */
63  	private JNRPEServer() {
64  	}
65  
66  	/**
67  	 * Configure the command line parser.
68  	 * 
69  	 * @return The configuration
70  	 */
71  	private static Group configureCommandLine() {
72  		DefaultOptionBuilder oBuilder = new DefaultOptionBuilder();
73  		ArgumentBuilder aBuilder = new ArgumentBuilder();
74  		GroupBuilder gBuilder = new GroupBuilder();
75  
76  		DefaultOption listOption = oBuilder.withLongName("list")
77  				.withShortName("l")
78  				.withDescription("Lists all the installed plugins").create();
79  
80  		DefaultOption versionOption = oBuilder.withLongName("version")
81  				.withShortName("v")
82  				.withDescription("Print the server version number").create();
83  
84  		DefaultOption helpOption = oBuilder.withLongName("help")
85  				.withShortName("h").withDescription("Show this help").create();
86  
87  		// DefaultOption pluginNameOption = oBuilder.withLongName("plugin")
88  		// .withShortName("p").withDescription("The plugin name")
89  		// .withArgument(
90  		// aBuilder.withName("name").withMinimum(1).withMaximum(1)
91  		// .create()).create();
92  
93  		DefaultOption pluginHelpOption = oBuilder
94  				.withLongName("help")
95  				.withShortName("h")
96  				.withDescription("Shows help about a plugin")
97  				.withArgument(
98  						aBuilder.withName("name").withMinimum(1).withMaximum(1)
99  								.create()).create();
100 
101 		Group alternativeOptions = gBuilder.withOption(listOption)
102 				.withOption(pluginHelpOption).create();
103 
104 		DefaultOption confOption = oBuilder
105 				.withLongName("conf")
106 				.withShortName("c")
107 				.withDescription("Specifies the JNRPE configuration file")
108 				.withArgument(
109 						aBuilder.withName("path").withMinimum(1).withMaximum(1)
110 								.create()).withChildren(alternativeOptions)
111 				.withRequired(true).create();
112 
113 		DefaultOption interactiveOption = oBuilder.withLongName("interactive")
114 				.withShortName("i")
115 				.withDescription("Starts JNRPE in command line mode").create();
116 
117 		Group jnrpeOptions = gBuilder.withOption(confOption)
118 				.withOption(interactiveOption).withMinimum(1).create();
119 
120 		Group mainGroup = gBuilder.withOption(versionOption)
121 				.withOption(helpOption).withOption(jnrpeOptions).create();
122 
123 		return mainGroup;
124 	}
125 
126 	/**
127 	 * Parses the command line.
128 	 * 
129 	 * @param vsArgs
130 	 *            The command line
131 	 * @return The parsed command line
132 	 */
133 	private static CommandLine parseCommandLine(final String[] vsArgs) {
134 		try {
135 			Group opts = configureCommandLine();
136 			// configure a HelpFormatter
137 			HelpFormatter hf = new HelpFormatter();
138 
139 			// configure a parser
140 			Parser p = new Parser();
141 			p.setGroup(opts);
142 			p.setHelpFormatter(hf);
143 			// p.setHelpTrigger("--help");
144 			CommandLine cl = p.parse(vsArgs);
145 
146 			return cl;
147 		} catch (OptionException oe) {
148 			printUsage(oe);
149 		} catch (Exception e) {
150 			e.printStackTrace();
151 			// Should never happen...
152 		}
153 		return null;
154 	}
155 
156 	/**
157 	 * Prints the help about a plugin.
158 	 * 
159 	 * @param pr
160 	 *            The plugin repository
161 	 * @param pluginName
162 	 *            The plugin name
163 	 */
164 	private static void printHelp(final IPluginRepository pr,
165 			final String pluginName) {
166 		try {
167 			PluginProxy pp = (PluginProxy) pr.getPlugin(pluginName);
168 
169 			// CPluginProxy pp =
170 			// CPluginFactory.getInstance().getPlugin(sPluginName);
171 			if (pp == null) {
172 				System.out
173 						.println("Plugin " + pluginName + " does not exists.");
174 			} else {
175 				pp.printHelp();
176 			}
177 		} catch (Exception e) {
178 			// TODO Auto-generated catch block
179 			e.printStackTrace();
180 		}
181 		System.exit(0);
182 	}
183 
184 	/**
185 	 * Prints the JNRPE Server version.
186 	 */
187 	private static void printVersion() {
188 		System.out.println("JNRPE version " + VERSION);
189 		System.out.println("Copyright (c) 2011 Massimiliano Ziccardi");
190 		System.out.println("Licensed under the Apache License, Version 2.0");
191 		System.out.println();
192 	}
193 
194 	/**
195 	 * Prints the JNRPE Server usage and, eventually, the error about the last
196 	 * invocation.
197 	 * 
198 	 * @param e
199 	 *            The last error. Can be null.
200 	 */
201 	private static void printUsage(final Exception e) {
202 		printVersion();
203 		if (e != null) {
204 			System.out.println(e.getMessage() + "\n");
205 		}
206 
207 		HelpFormatter hf = new HelpFormatter();
208 
209 		StringBuffer sbDivider = new StringBuffer("=");
210 		while (sbDivider.length() < hf.getPageWidth()) {
211 			sbDivider.append("=");
212 		}
213 
214 		// DISPLAY SETTING
215 		hf.getDisplaySettings().clear();
216 		hf.getDisplaySettings().add(DisplaySetting.DISPLAY_GROUP_EXPANDED);
217 		hf.getDisplaySettings().add(DisplaySetting.DISPLAY_PARENT_CHILDREN);
218 
219 		// USAGE SETTING
220 
221 		hf.getFullUsageSettings().clear();
222 		hf.getFullUsageSettings().add(DisplaySetting.DISPLAY_PARENT_ARGUMENT);
223 		hf.getFullUsageSettings()
224 				.add(DisplaySetting.DISPLAY_ARGUMENT_BRACKETED);
225 		hf.getFullUsageSettings().add(DisplaySetting.DISPLAY_PARENT_CHILDREN);
226 		hf.getFullUsageSettings().add(DisplaySetting.DISPLAY_GROUP_EXPANDED);
227 
228 		hf.setDivider(sbDivider.toString());
229 
230 		hf.setGroup(configureCommandLine());
231 		hf.print();
232 		System.exit(0);
233 	}
234 
235 	/**
236 	 * Loads the JNRPE configuration from the INI or the XML file.
237 	 * 
238 	 * @param configurationFilePath
239 	 *            The path to the configuration file
240 	 * @return The parsed configuration.
241 	 * @throws ConfigurationException
242 	 *             -
243 	 */
244 	private static JNRPEConfiguration loadConfiguration(
245 			final String configurationFilePath) throws ConfigurationException {
246 		File confFile = new File(configurationFilePath);
247 
248 		if (!confFile.exists() || !confFile.canRead()) {
249 			throw new ConfigurationException("Cannot access config file : "
250 					+ configurationFilePath);
251 		}
252 
253 		return JNRPEConfigurationFactory
254 				.createConfiguration(configurationFilePath);
255 
256 	}
257 
258 	/**
259 	 * Loads a plugin repository from a directory.
260 	 * 
261 	 * @param sPluginDirPath
262 	 *            The path to the directory
263 	 * @return The plugin repository
264 	 * @throws PluginConfigurationException
265 	 *             -
266 	 */
267 	private static IPluginRepository loadPluginDefinitions(
268 			final String sPluginDirPath) throws PluginConfigurationException {
269 		File fDir = new File(sPluginDirPath);
270 		DynaPluginRepository repo = new DynaPluginRepository();
271 		repo.load(fDir);
272 
273 		return repo;
274 	}
275 
276 	/**
277 	 * Prints the list of installed plugins.
278 	 * 
279 	 * @param pr
280 	 *            The plugin repository
281 	 */
282 	private static void printPluginList(final IPluginRepository pr) {
283 		System.out.println("List of installed plugins : ");
284 
285 		for (PluginDefinition pd : pr.getAllPlugins()) {
286 			System.out.println("  * " + pd.getName());
287 		}
288 
289 		System.exit(0);
290 	}
291 
292 	/**
293 	 * The main method.
294 	 * 
295 	 * @param args
296 	 *            The command line
297 	 */
298 	public static void main(final String[] args) {
299 		CommandLine cl = parseCommandLine(args);
300 		if (cl.hasOption("--help")) {
301 			if (!cl.hasOption("--conf")) {
302 				printUsage(null);
303 			}
304 		}
305 
306 		if (cl.hasOption("--version")) {
307 			printVersion();
308 			System.exit(0);
309 		}
310 
311 		JNRPEConfiguration conf = null;
312 		try {
313 			conf = loadConfiguration((String) cl.getValue("--conf"));
314 		} catch (Exception e) {
315 			System.out.println("Unable to parse the configuration at "
316 					+ cl.getValue("--conf") + ". The error is : "
317 					+ e.getMessage());
318 			e.printStackTrace();
319 			System.exit(-1);
320 		}
321 
322 		String sPluginPath = conf.getServerSection().getPluginPath();
323 		if (sPluginPath == null) {
324 			System.out.println("Plugin path has not been specified");
325 			System.exit(-1);
326 		}
327 		File fPluginPath = new File(sPluginPath);
328 
329 		if (fPluginPath.exists()) {
330 			if (!fPluginPath.isDirectory()) {
331 				System.out.println("Specified plugin path ('" + sPluginPath
332 						+ "') must be a directory");
333 				System.exit(-1);
334 			}
335 		} else {
336 			System.out.println("Specified plugin path ('" + sPluginPath
337 					+ "') do not exist");
338 			System.exit(-1);
339 		}
340 
341 		IPluginRepository pr = null;
342 		try {
343 			pr = loadPluginDefinitions(conf.getServerSection().getPluginPath());
344 		} catch (PluginConfigurationException e) {
345 			System.out.println("An error has occurred while parsing "
346 					+ "the plugin packages : " + e.getMessage());
347 			System.exit(-1);
348 		}
349 
350 		if (cl.hasOption("--help") && cl.getValue("--help") != null) {
351 			printHelp(pr, (String) cl.getValue("--help"));
352 		}
353 
354 		if (cl.hasOption("--list")) {
355 			printPluginList(pr);
356 		}
357 
358 		CommandRepository cr = conf.createCommandRepository();
359 
360 		JNRPEBuilder builder = JNRPEBuilder
361 				.forRepositories(pr, cr)
362 				.acceptParams(conf.getServerSection().acceptParams())
363 				.withMaxAcceptedConnections(
364 						conf.getServerSection().getBacklogSize())
365 				.withReadTimeout(conf.getServerSection().getReadTimeout())
366 				.withWriteTimeout(conf.getServerSection().getWriteTimeout())
367 				.withListener(new EventLoggerListener());
368 
369 		for (String sAcceptedAddress : conf.getServerSection()
370 				.getAllowedAddresses()) {
371 			builder.acceptHost(sAcceptedAddress);
372 		}
373 
374 		JNRPE jnrpe = builder.build();
375 
376 		for (BindAddress bindAddress : conf.getServerSection()
377 				.getBindAddresses()) {
378 			int iPort = DEFAULT_PORT;
379 			String[] vsParts = bindAddress.getBindingAddress().split(":");
380 			String sIp = vsParts[0];
381 			if (vsParts.length > 1) {
382 				iPort = Integer.parseInt(vsParts[1]);
383 			}
384 
385 			try {
386 				jnrpe.listen(sIp, iPort, bindAddress.isSSL());
387 			} catch (UnknownHostException e) {
388 				System.out.println(String.format(
389 						"Error binding the server to %s:%d : %s", sIp, iPort,
390 						e.getMessage()));
391 			}
392 		}
393 
394 		if (cl.hasOption("--interactive")) {
395 			new JNRPEConsole(jnrpe, pr, cr).start();
396 			System.exit(0);
397 		}
398 	}
399 }