View Javadoc

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 }