1 /*
2 Copyright (C) 2002 Grid Systems, S.A.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2, as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17 package com.gridsystems.windowsutils;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.InputStream;
21 import java.util.StringTokenizer;
22
23 import com.gridsystems.utils.SystemUtils;
24
25 /**
26 * MS Windows service management.
27 *
28 * @author Xmas
29 * @version 1.0
30 */
31 public final class WindowsUtils {
32
33 /**
34 * Private constructor.
35 */
36 private WindowsUtils() {
37 }
38
39 static {
40 if (SystemUtils.isWindows()) {
41 try {
42 SystemUtils.extractDynamicLibrary("WindowsUtils", WindowsUtils.class);
43 } catch (Exception ex) {
44 System.err.println("Cannot load WindowsUtils dynamic library. Reason: \n");
45 ex.printStackTrace();
46 }
47 }
48 }
49
50
51 /**
52 * Installs a windows service allowing to set a specific user account.
53 *
54 * @param servicename a String with the name of the service.
55 * @param executable a String with the path to the executable file.
56 * @param user a String with the user account to run the service with. If
57 * null or empty, the service is set to run as a system service. If an user
58 * account is specified, it is checked that startst with ".\" and, if it does
59 * not, ".\" is added at the beginning of the user account.
60 * @param pass a String with the password of the account used to run the
61 * service, if it is an user account.
62 *
63 * @throws Exception with an human-readable message if any of the
64 * parameters was wrong or if the native process to install the service
65 * failed.
66 */
67 public static void createWindowsService(String servicename,
68 String executable, String user, String pass) throws Exception {
69 if (!SystemUtils.isWindows()) {
70 throw new Exception("SystemUtils.createWindowsService() -> "
71 + "This method is not supported in systems that are not Windows");
72 }
73
74 if ((servicename == null) || (servicename.equals(""))) {
75 throw new Exception(
76 "SystemUtils.createWindowsService() -> Service name is empty");
77 }
78
79 if ((executable == null) || (executable.equals(""))) {
80 throw new Exception(
81 "SystemUtils.createWindowsService() -> Executable name is empty");
82 }
83
84 java.io.File f = new java.io.File(executable);
85
86 if (!f.exists()) {
87 throw new Exception(
88 "SystemUtils.createWindowsService() -> Executable file not exists.("
89 + executable + ")");
90 }
91
92 if ((user != null) && (user.length() > 0)) {
93 if (!user.startsWith(".\\")) {
94 user = ".\\" + user;
95 }
96 } else {
97 // If the user is the empty one, we set it to NULL.
98 user = null;
99 pass = null;
100 }
101
102 String error =
103 nativeCreateWindowsService(servicename, executable, user, pass);
104
105 if (error != null) {
106 throw new Exception(
107 "RegistryKey.createWindowsService() -> Error:" + error);
108 }
109
110 // TODO Manage this in a more parametric way, to allow a different file to
111 // contain the messages.
112 executable = executable.replaceAll("/", "\\\\");
113 error = registerServiceMessages(servicename, executable);
114
115 if (error != null) {
116 throw new Exception(
117 "RegistryKey.registeringMessages() -> Error:" + error);
118 }
119 }
120
121 /**
122 * Elimina un Servicio Windows.
123 * @param servicename the service name
124 * @throws Exception if error
125 */
126 public static void removeWindowsService(String servicename) throws Exception {
127 if (!SystemUtils.isWindows()) {
128 throw new Exception("SystemUtils.removeWindowsService() -> "
129 + "This method is not supported in systems that are not Windows");
130 }
131
132 if ((servicename == null) || servicename.equals("")) {
133 throw new Exception(
134 "SystemUtils.createWindowsService() -> Service name is empty");
135 }
136
137 String error = nativeRemoveWindowsService(servicename);
138
139 if (error != null) {
140 throw new Exception(
141 "SystemUtils.removeWindowsService() -> Error:" + error);
142 }
143
144 // SJM: We do not check for errors yet; uninstalling a service that did not
145 // have the key set should not fail...
146 unregisterServiceMessages(servicename);
147 }
148
149 /**
150 * Adds a specific privilege to a user.
151 *
152 * @param hostName Host name
153 * @param user User name
154 * @param privilege Privilege name
155 *
156 * @throws Exception if error
157 */
158 public static void addUserPrivilege(String hostName, String user,
159 String privilege) throws Exception {
160
161 if (!SystemUtils.isWindows()) {
162 throw new Exception("SystemUtils.addUserPrivilege() -> "
163 + "This method is not supported in systems that are not Windows");
164 }
165
166 if ((user == null) || (user.equals(""))) {
167 throw new Exception("SystemUtils.addUserPrivilege() -> No user provided");
168 }
169
170 if ((privilege == null) || (privilege.equals(""))) {
171 throw new Exception(
172 "SystemUtils.addUserPrivilege() -> No privilege provided");
173 }
174
175 String error = nativeAddUserPrivilege(hostName, user, privilege);
176
177 if (error != null) {
178 throw new Exception("SystemUtils.addUserPrivilege() -> Error:" + error);
179 }
180 }
181
182 /**
183 * Checks if an user has a permission.
184 *
185 * @param user a String with the username that is checked.
186 * @param privilege a String with the permission being checked.
187 *
188 * @return a boolean that is true if and only if the user has granted the
189 * permission.
190 *
191 * @throws Exception if error
192 */
193 public static boolean userHasPrivilege(String user, String privilege)
194 throws Exception {
195
196 if (!SystemUtils.isWindows()) {
197 throw new Exception(
198 "SystemUtils.userHasPrivilege() -> This method is not supported"
199 + " in systems that are not Windows");
200 }
201
202 if (user == null || user.equals("")) {
203 throw new Exception("SystemUtils.userHasPrivilege() -> No user provided");
204 }
205
206 if (privilege == null || privilege.equals("")) {
207 throw new Exception(
208 "SystemUtils.userHasPrivilege() -> No privilege provided");
209 }
210
211 return nativeUserHasPrivilege(user, privilege);
212 }
213
214 /**
215 * Chequeo de usuarios en XP y NT.
216 * @param user el usuario.
217 * @return boolean Devuelve un boolean que indica si un usuario existe en XP
218 * y NT
219 * @throws Exception if error
220 */
221 public static boolean checkWindowsUser(String user) throws Exception {
222 boolean existUser = false;
223 /* Bloque de ejecucion y recogida de stream */
224 ByteArrayOutputStream baos = new ByteArrayOutputStream();
225 final String cmd = "net users";
226 Integer exitCode = SystemUtils.execAndSaveOutput(cmd, null, null, baos);
227 if (exitCode == null) {
228 throw new Exception("Unknown error executing " + cmd + ": " + baos.toString());
229 }
230
231 /* Fin bloque*/
232 /* Bloque de parseo */
233 String allUsers = baos.toString();
234 StringTokenizer st = new StringTokenizer(allUsers, "\n");
235 // Se salta las 3 primeras filas ya que no se corresponden a usuarios.
236 for (int i = 0; i <= 3; i++) {
237 st.nextToken();
238 }
239 int last = st.countTokens();
240 // Se salta las 2 ultimas filas que no corresponden a usuarios.
241 String lineOfNTUsers = null;
242 String currentNTUser = null;
243 int lon;
244 for (int i = 2; i < last; i++) {
245 /* Cada fila tiene 3 columnas, cada una de ellas corresponde a un
246 usuario.
247 Consideramos que cada usuario estara separado al menos 3 espacios
248 de esta manera evitamos problemas con usuarios del tipo :
249 "Asistente de ayuda"
250 */
251 lineOfNTUsers = st.nextToken();
252 lon = lineOfNTUsers.length();
253 for (int j = 25; j <= lon; j = j + 25) {
254 currentNTUser = lineOfNTUsers.substring(j - 25, j).trim();
255 if (user.equals(currentNTUser)) {
256 existUser = true;
257 }
258 }
259 }
260 return existUser;
261 }
262
263 // G R I D S Y S T E M S N A T I V E M E T H O D S
264 //
265
266 /**
267 * Creates a Windows Service.
268 *
269 * @param servicename the service name
270 * @param executable the executable
271 * @param usr the user name
272 * @param pass the password
273 * @return Si devuelve null es que todo ha concluido correctamente
274 * En caso contrario devuelve el error que se ha producido.
275 */
276 private static native String nativeCreateWindowsService(String servicename,
277 String executable, String usr, String pass);
278
279 /**
280 * Removes a Windows Service.
281 *
282 * @param servicename the service name
283 * @return Si devuelve null es que todo ha concluido correctamente
284 * En caso contrario devuelve el error que se ha producido.
285 */
286 private static native String nativeRemoveWindowsService(String servicename);
287
288 /**
289 * Adds a specific privilege to a user.
290 *
291 * @param hostName Host name
292 * @param user User name
293 * @param privilege Privilege name
294 *
295 * @return Si devuelve null es que todo ha concluido correctamente
296 * En caso contrario devuelve el error que se ha producido.
297 */
298 private static native String nativeAddUserPrivilege(String hostName,
299 String user, String privilege);
300
301 /**
302 * Asks if an user has a permission in the machine.
303 *
304 * @param userName a String with the name of the user.
305 * @param privilege a String with the permission that is being checked.
306 *
307 * @return a boolean that is true if and only if the user has the requested
308 * permission.
309 */
310 private static native boolean nativeUserHasPrivilege(String userName,
311 String privilege);
312
313 /**
314 * Register the sources for the log messages of a service.
315 *
316 * @param serviceName the name of the service.
317 * @param path the file (exe or dll) that contains the internationalized
318 * messages.
319 *
320 * @return null in case of success; an error message otherwise.
321 */
322 private static native String registerServiceMessages(
323 String serviceName, String path);
324
325 /**
326 * Unregister the sources for the log messages of a service.
327 *
328 * @param serviceName the name of the service.
329 *
330 * @return null in case of success; an error message otherwise.
331 */
332 private static native String unregisterServiceMessages(
333 String serviceName);
334
335 /**
336 * Starts a service.
337 *
338 * @param serviceName a String with the name of the service to start.
339 * @param arguments a String[] with the list of argument to pass to the
340 * service.
341 * @param errorIfRunning a boolean that is true if the method should consider
342 * that the service is already running as an error.
343 *
344 * @return a boolean that is true if and only if the service was correctly
345 * started or, if <code>errorIfRunning</code> is false, if the service was
346 * already running.
347 */
348 public static native boolean startService(String serviceName,
349 String[] arguments, boolean errorIfRunning);
350
351 /**
352 * Stops a service.
353 *
354 * @param serviceName a String with the name of the service to stop.
355 * @param errorIfStopped a boolean that is true if the method should consider
356 * that the service is already stopped or stopping as an error.
357 *
358 * @return a boolean that is true if and only if the service received
359 * correctly the signal to stop or, if <code>errorIfStopped</code> is false,
360 * if it was already stopped or stopping.
361 */
362 public static native boolean stopService(String serviceName,
363 boolean errorIfStopped);
364
365 /**
366 * Tells if a service with the specified name exists.
367 *
368 * @param serviceName a String with the name of the service.
369 *
370 * @return a boolean that is true if and only if a service with the specified
371 * name exists.
372 *
373 * @throws Exception if an error happened when getting the installed
374 * services.
375 */
376 public static native boolean serviceExists(String serviceName)
377 throws Exception;
378
379 /**
380 * Tells if the user executing the program has administrator rights.
381 *
382 * @return a boolean that is true if and only if the user running the program
383 * has administrator rights (belongs to the group of administrators).
384 *
385 * @throws Exception if an error happened when getting the information.
386 */
387 public static native boolean checkAdministrator() throws Exception;
388
389 /**
390 * Gets the name of the user on whose account the service starts.
391 *
392 * @param serviceName the name of the service being checked.
393 *
394 * @return a String with the name of the user as returned by the function
395 * QueryServiceConfig function. In case of error, it returns an empty String.
396 *
397 * @throws Exception in case of error.
398 */
399 public static native String getServiceStartUser(String serviceName)
400 throws Exception;
401 }