package arlut.csd.ganymede.userKit; import arlut.csd.ganymede.server.*; import arlut.csd.ganymede.common.*; import arlut.csd.Util.FileOps; import java.util.*; import java.text.*; import java.io.*; /** * This class is intended to dump the Ganymede datastore to the * UNIX passwd and group files. */ public class UNIXBuilderTask extends GanymedeBuilderTask { private String buildScript = null; private String md5passwdFile = null; private String passwdFile = null; private String groupFile = null; // --- private Date now = null; private boolean backedup = false; /* -- */ /** * <p>The constructor for GanymedeBuilderTask subclasses takes an * Invid for the DBObject in the Ganymede data store that defines * the task. The taskDefObjInvid member variable is comes from the * GanymedeBuilderTask that we are inheriting from. Setting it * in this constructor allows us to use the getOptionValue() method to read * our configuration strings for this task.</p> */ public UNIXBuilderTask(Invid _taskObjInvid) { // set the taskDefObjInvid in GanymedeBuilderTask so // we can look up option strings taskDefObjInvid = _taskObjInvid; } /** * This method runs with a dumpLock obtained for the builder task. * * Code run in builderPhase1() can call enumerateObjects() and * baseChanged(). * * @return true if builderPhase1 made changes necessitating the * execution of builderPhase2. */ public boolean builderPhase1() { PrintWriter out; boolean result = false; /* -- */ // initialize operational variables for the new run backedup = false; now = null; // now see what our current option values are passwdFile = getOptionValue("passwdFile"); md5passwdFile = getOptionValue("md5passwdFile"); if (passwdFile == null && md5passwdFile == null) { Ganymede.debug("UNIXBuilderTask: error, no passwdFile specified"); } if (passwdFile != null && passwdFile.equals(md5passwdFile)) { Ganymede.debug("UNIXBuilderTask: error, md5passwdFile and passwdFile are the same, skipping md5passwdFile"); md5passwdFile = null; } groupFile = getOptionValue("groupFile"); if (groupFile == null) { Ganymede.debug("UNIXBuilderTask: error, no groupFile specified"); } // passwd if (baseChanged(SchemaConstants.UserBase)) { Ganymede.debug("UNIXBuilderTask: Need to build user map"); if (passwdFile != null) { out = null; try { out = openOutFile(passwdFile, "unix"); } catch (IOException ex) { ex.printStackTrace(); Ganymede.debug("UNIXBuilderTask.builderPhase1(): couldn't open " + passwdFile + ": " + ex); } if (out != null) { Enumeration users = enumerateObjects(SchemaConstants.UserBase); while (users.hasMoreElements()) { DBObject user = (DBObject) users.nextElement(); writeUserLine(user, out, false); } out.close(); } result = true; } if (md5passwdFile != null) { out = null; try { out = openOutFile(md5passwdFile, "unix"); } catch (IOException ex) { ex.printStackTrace(); Ganymede.debug("UNIXBuilderTask.builderPhase1(): couldn't open " + md5passwdFile + ": " + ex); } if (out != null) { Enumeration users = enumerateObjects(SchemaConstants.UserBase); while (users.hasMoreElements()) { DBObject user = (DBObject) users.nextElement(); writeUserLine(user, out, true); } out.close(); } result = true; } } // group if (baseChanged((short) 257)) { Ganymede.debug("UNIXBuilderTask: Need to build group map"); if (groupFile != null) { out = null; try { out = openOutFile(groupFile, "unix"); } catch (IOException ex) { ex.printStackTrace(); Ganymede.debug("UNIXBuilderTask.builderPhase1(): couldn't open " + groupFile + ": " + ex); } if (out != null) { Enumeration groups = enumerateObjects((short) 257); while (groups.hasMoreElements()) { DBObject group = (DBObject) groups.nextElement(); writeGroupLine(group, out); } out.close(); } result = true; } } return result; } /** * * This method runs after this task's dumpLock has been * relinquished. This method is intended to be used to finish off a * build process by running (probably external) code that does not * require direct access to the database. * * builderPhase2 is only run if builderPhase1 returns true. * */ public boolean builderPhase2() { File file; /* -- */ buildScript = getOptionValue("buildScript"); if (buildScript == null || buildScript.equals("")) { Ganymede.debug("UNIXBuilderTask: no buildScript defined in task object's option string vector"); Ganymede.debug(" not running any external update script."); return false; } file = new File(buildScript); if (file.exists()) { Ganymede.debug("UNIXBuilderTask builderPhase2 running"); try { FileOps.runProcess(buildScript); } catch (IOException ex) { Ganymede.debug("Couldn't exec buildScript (" + buildScript + ") due to IOException: " + ex); } catch (InterruptedException ex) { Ganymede.debug("Failure during exec of buildScript (" + buildScript + "): " + ex); } } else { Ganymede.debug(buildScript + " doesn't exist, not running external UNIX build script"); } Ganymede.debug("UNIXBuilderTask builderPhase2 completed"); return true; } // *** // // The following private methods are used to support the UNIX builder logic. // // *** /** * * This method writes out a line to the passwd UNIX source file. * * The lines in this file look like the following. * * broccol:393T6k3e/9/w2:12003:12010:Jonathan Abbey,S321 CSD,3199,8343915:/home/broccol:/bin/tcsh * * @param object An object from the Ganymede user object base * @param writer The destination for this user line * @param useMD5 If true, passwords will be written out in md5 format if possible * */ private void writeUserLine(DBObject object, PrintWriter writer, boolean useMD5) { String username; String cryptedPass = null; int uid; int gid; String name; String room; String officePhone; String homePhone; String directory; String shell; PasswordDBField passField; Vector invids; Invid groupInvid; DBObject group; StringBuffer result = new StringBuffer(); /* -- */ username = (String) object.getFieldValueLocal(SchemaConstants.UserUserName); passField = (PasswordDBField) object.getField(SchemaConstants.UserPassword); if (passField != null) { if (useMD5) { cryptedPass = passField.getMD5CryptText(); } // if the Ganymede server doesn't have an MD5 password for // this user, go ahead and devolve to the crypt() password if // available. This might have been set by rpcpass and the NIS // passwd daemon. if (cryptedPass == null) { cryptedPass = passField.getUNIXCryptText(); } } else { Ganymede.debug("UNIXBuilderTask.writeUserLine(): null password for user " + username); cryptedPass = "**Nopass**"; } uid = ((Integer) object.getFieldValueLocal(userSchema.UID)).intValue(); // get the gid groupInvid = (Invid) object.getFieldValueLocal(userSchema.HOMEGROUP); // home group if (groupInvid == null) { Ganymede.debug("UNIXBuilderTask.writeUserLine(): null gid for user " + username); gid = -1; } else { group = getObject(groupInvid); if (group == null) { Ganymede.debug("UNIXBuilderTask.writeUserLine(): couldn't get reference to home group"); gid = -1; } else { Integer gidInt = (Integer) group.getFieldValueLocal(groupSchema.GID); if (gidInt == null) { Ganymede.debug("UNIXBuilderTask.writeUserLine(): couldn't get gid value"); gid = -1; } else { gid = gidInt.intValue(); } } } name = (String) object.getFieldValueLocal(userSchema.FULLNAME); room = (String) object.getFieldValueLocal(userSchema.ROOM); officePhone = (String) object.getFieldValueLocal(userSchema.OFFICEPHONE); homePhone = (String) object.getFieldValueLocal(userSchema.HOMEPHONE); directory = (String) object.getFieldValueLocal(userSchema.HOMEDIR); shell = (String) object.getFieldValueLocal(userSchema.LOGINSHELL); // now build our output line result.append(username); result.append(":"); result.append(cryptedPass); result.append(":"); result.append(Integer.toString(uid)); result.append(":"); result.append(Integer.toString(gid)); result.append(":"); result.append(name); if (room != null && !room.equals("")) { result.append(","); result.append(room); } if (officePhone != null && !officePhone.equals("")) { result.append(","); result.append(officePhone); } if (homePhone != null && !homePhone.equals("")) { result.append(","); result.append(homePhone); } result.append(":"); result.append(directory); result.append(":"); result.append(shell); if (result.length() > 1024) { Ganymede.debug("UNIXBuilderTask.writeUserLine(): Warning! user " + username + " overflows the UNIX line length!"); } writer.println(result.toString()); } /** * * This method writes out a line to the group UNIX source file. * * The lines in this file look like the following. * * adgacc:ZzZz:4015:hammp,jgeorge,dd,doodle,dhoss,corbett,monk * * @param object An object from the Ganymede user object base * @param writer The destination for this user line * */ private void writeGroupLine(DBObject object, PrintWriter writer) { String groupname; String pass; int gid; Vector users = new Vector(); PasswordDBField passField; Vector invids; Invid userInvid; String userName; StringBuffer result = new StringBuffer(); /* -- */ groupname = (String) object.getFieldValueLocal(groupSchema.GROUPNAME); // currently in the Ganymede schema, group passwords aren't in passfields. pass = (String) object.getFieldValueLocal(groupSchema.PASSWORD); Integer gidInt = (Integer) object.getFieldValueLocal(groupSchema.GID); if (gidInt == null) { Ganymede.debug("Error, couldn't find gid for group " + groupname); return; } gid = gidInt.intValue(); // we currently don't explicitly record the home group.. just take the first group // that the user is in. invids = object.getFieldValuesLocal(groupSchema.USERS); if (invids == null) { // Ganymede.debug("UNIXBuilder.writeUserLine(): null user list for group " + groupname); } else { for (int i = 0; i < invids.size(); i++) { userInvid = (Invid) invids.elementAt(i); userName = getLabel(userInvid); if (userName != null) { users.addElement(userName); } } } // now build our output line result.append(groupname); result.append(":"); result.append(pass); result.append(":"); result.append(Integer.toString(gid)); result.append(":"); for (int i = 0; i < users.size(); i++) { if (i > 0) { result.append(","); } result.append((String) users.elementAt(i)); } if (result.length() > 1024) { Ganymede.debug("UNIXBuilderTask.writeGroupLine(): Warning! group " + groupname + " overflows the UNIX line length!"); } writer.println(result.toString()); } }