/*************************************************************************** * Copyright (C) 2013 by Timothy Pearson * * kb9vqf@pearsoncomputing.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef KDE_CONFDIR #define KDE_CONFDIR "/etc/trinity" #endif static const char description[] = I18N_NOOP("TDE utility for managing a Kerberos realm"); static const char version[] = "v0.0.1"; static const TDECmdLineOptions options[] = { { "forcepwchangenextlogin", I18N_NOOP("Force the user to change password on next login"), 0 }, { "username ", I18N_NOOP("Specifies the user name in the Kerberos realm (mandatory)"), 0 }, { "uid ", I18N_NOOP("Specifies the POSIX user ID in the Kerberos realm"), 0 }, { "password ", I18N_NOOP("Sets the password for the specified account to the given value"), 0 }, { "displayname ", I18N_NOOP("Sets the display name (common name) of the specified account to the given value"), 0 }, { "homedirectory ", I18N_NOOP("Sets the home directory of the specified account to the given value"), 0 }, { "givenname ", I18N_NOOP("Sets the first name of the specified account to the given value"), 0 }, { "surname ", I18N_NOOP("Sets the last name of the specified account to the given value"), 0 }, { "telephone ", I18N_NOOP("Sets the telephone number of the specified account to the given value"), 0 }, { "website ", I18N_NOOP("Sets the website of the specified account to the given value"), 0 }, { "email ", I18N_NOOP("Sets the Email address of the specified account to the given value"), 0 }, { "group ", I18N_NOOP("Sets membership of the specified account in the groups listed on the command line, and revokes membership in any groups not listed. This option may be used multiple times."), 0 }, { "primarygroup ", I18N_NOOP("Sets membership of the specified account in the group listed on the command line, and sets that group as the user's primary group."), 0 }, { "revokeallgroups", I18N_NOOP("Revokes membership of the specified account for all groups"), 0 }, { "adminusername ", I18N_NOOP("Specifies the username of the administrative user with permissions to perform the requested task"), 0 }, { "adminpasswordfile ", I18N_NOOP("Specifies the location of a file which contains the password of the administrative user"), 0 }, { "anonymous", I18N_NOOP("Do not use authentication when contacting the realm controller"), 0 }, { "!+command", I18N_NOOP("The command to execute on the Kerberos realm. Valid commands are: adduser deluser listusers listgroups"), 0 }, { "!+realm", I18N_NOOP("The Kerberos realm on which to execute the specified command. Example: MY.REALM"), 0 }, { "", I18N_NOOP("This utility will use GSSAPI to connect to the realm controller. You must own an active, valid Kerberos ticket in order to use this utility!"), 0 }, TDECmdLineLastOption // End of options. }; int main(int argc, char *argv[]) { TDEAboutData aboutData( "tdeldapmanager", I18N_NOOP("Kerberos Realm Manager"), version, description, TDEAboutData::License_GPL, "(c) 2013, Timothy Pearson"); aboutData.addAuthor("Timothy Pearson",0, "kb9vqf@pearsoncomputing.net"); TDECmdLineArgs::init(argc, argv, &aboutData); TDECmdLineArgs::addCmdLineOptions(options); KUniqueApplication::addCmdLineOptions(); TDEApplication::disableAutoDcopRegistration(); TDEApplication app(false, false); TDEStartupInfo::appStarted(); KSimpleConfig systemconfig( TQString::fromLatin1( KDE_CONFDIR "/ldap/ldapconfigrc" )); //====================================================================================================================================================== // // Manager code follows // //====================================================================================================================================================== // FIXME // forcepwchangenextlogin not implemented! TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(); if (args->count() > 1) { int retcode; TQString command = TQString(args->arg(0)); TQString realm = TQString(args->arg(1)); systemconfig.setGroup("LDAPRealm-" + realm); TQString host = systemconfig.readEntry("admin_server"); LDAPCredentials credentials; if (!args->isSet("anonymous")) { if (args->isSet("adminusername") && args->isSet("adminpasswordfile")) { TQString passFileName = args->getOption("adminpasswordfile"); TQFile passFile(passFileName); if (!passFile.open(IO_ReadOnly)) { printf("[ERROR] Unable to open specified password file '%s'\n", passFileName.ascii()); fflush(stdout); return -1; } TQTextStream stream(&passFile); credentials.username = args->getOption("adminusername"); credentials.password = stream.readLine(); passFile.close(); } else { credentials.use_gssapi = true; } } credentials.realm = realm; LDAPManager ldapmanager(realm, host, &credentials); if (command == "adduser") { LDAPUserInfo user; TQString errorString; if (ldapmanager.bind(&errorString) != 0) { printf("[ERROR] Unable to bind to Kerberos realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } LDAPUserInfoList userInfoList = ldapmanager.users(&retcode, &errorString); if (retcode != 0) { printf("[ERROR] Unable to retrieve list of users from realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } LDAPGroupInfoList groupInfoList = ldapmanager.groups(&retcode, &errorString); if (retcode != 0) { printf("[ERROR] Unable to retrieve list of users from realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } // Find the next available, reasonable UID if (args->isSet("uid")) { uid_t uid = atoi(args->getOption("uid")); LDAPUserInfoList::Iterator it; for (it = userInfoList.begin(); it != userInfoList.end(); ++it) { LDAPUserInfo user = *it; if (user.uid == uid) { printf("[ERROR] The specified POSIX user ID is already in use\n"); return -1; } } user.uid = uid; } else { uid_t uid = 100; LDAPUserInfoList::Iterator it; for (it = userInfoList.begin(); it != userInfoList.end(); ++it) { LDAPUserInfo user = *it; if (user.uid >= uid) { uid = user.uid + 1; } } user.uid = uid; } if (!args->isSet("username")) { printf("[ERROR] You must specify a username when adding a user\n"); return -1; } if (!args->isSet("surname")) { printf("[ERROR] You must specify a surname when adding a user\n"); return -1; } if (!args->isSet("primarygroup")) { printf("[ERROR] You must specify a primary group when adding a user\n"); return -1; } // Get user data user.name = args->getOption("username"); user.new_password = args->getOption("password"); user.givenName = args->getOption("givenname"); user.surName = args->getOption("surname"); if (args->isSet("displayname")) { user.commonName = args->getOption("displayname"); } else { user.commonName = user.givenName + " " + user.surName; } if (args->isSet("homedirectory")) { user.homedir = args->getOption("homedirectory"); } else { user.homedir = "/home/" + user.name; } if (args->isSet("telephone")) { user.telephoneNumber = args->getOption("telephone"); } if (args->isSet("website")) { user.website = args->getOption("website"); } if (args->isSet("email")) { user.email = args->getOption("email"); } // Get list of groups QCStringList groupList = args->getOptionList("group"); // Try to find a reasonable place to stuff the new entry // Do any users exist right now? if (userInfoList.begin() != userInfoList.end()) { user.distinguishedName = (*userInfoList.begin()).distinguishedName; int eqpos = user.distinguishedName.find("=")+1; int cmpos = user.distinguishedName.find(",", eqpos); user.distinguishedName.remove(eqpos, cmpos-eqpos); user.distinguishedName.insert(eqpos, user.name); } else { user.distinguishedName = "uid=" + user.name + "," + ldapmanager.basedn(); } bool primary_gid_found = false; TQString primaryGroupName = args->getOption("primarygroup"); LDAPGroupInfoList::Iterator it; for (it = groupInfoList.begin(); it != groupInfoList.end(); ++it) { LDAPGroupInfo group = *it; if (primaryGroupName == group.name) { user.primary_gid = group.gid; primary_gid_found = true; break; } } if (!primary_gid_found) { printf("[ERROR] Invalid primary group specified\n"); return -1; } if (ldapmanager.addUserInfo(user, &errorString) == 0) { // Modify group(s) as needed bool revoke_all = args->isSet("revokeallgroups"); if ((groupList.count() > 0) || revoke_all) { LDAPGroupInfoList groupInfoList = ldapmanager.groups(&retcode, &errorString); if (retcode != 0) { printf("[ERROR] Unable to retrieve list of groups from realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } for (it = groupInfoList.begin(); it != groupInfoList.end(); ++it) { LDAPGroupInfo group = *it; if ((!revoke_all) && (groupList.contains(group.name.ascii()))) { // Make sure that we are in this group! if (!group.userlist.contains(user.distinguishedName)) { group.userlist.append(user.distinguishedName); ldapmanager.updateGroupInfo(group, &errorString); } } else { // Make sure that we are NOT in this group! if (group.userlist.contains(user.distinguishedName)) { group.userlist.remove(user.distinguishedName); ldapmanager.updateGroupInfo(group, &errorString); } } } } if (user.new_password != "") { // If a new password was set, use Kerberos to set it on the server if (ldapmanager.setPasswordForUser(user, &errorString) != 0) { printf("[ERROR] Unable to set password for user\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); } } } else { printf("[ERROR] Unable to add user with distingushed name '%s'\n[ERROR] Detailed debugging information: %s\n", user.distinguishedName.ascii(), errorString.ascii()); } } else if (command == "deluser") { LDAPUserInfo deluser; TQString errorString; if (ldapmanager.bind(&errorString) != 0) { printf("[ERROR] Unable to bind to Kerberos realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } LDAPUserInfoList userInfoList = ldapmanager.users(&retcode, &errorString); if (retcode != 0) { printf("[ERROR] Unable to retrieve list of users from realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } if (!args->isSet("username")) { printf("[ERROR] You must specify a username when deleting a user\n"); return -1; } TQString delUserName = args->getOption("username"); bool found = false; LDAPUserInfoList::Iterator it; for (it = userInfoList.begin(); it != userInfoList.end(); ++it) { LDAPUserInfo user = *it; if (user.name == delUserName) { found = true; deluser = user; break; } } if (found) { ldapmanager.deleteUserInfo(deluser); } else { printf("[ERROR] User not found\n"); return -1; } // FIXME } else if (command == "listusers") { TQString errorString; if (ldapmanager.bind(&errorString) != 0) { printf("[ERROR] Unable to bind to Kerberos realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } LDAPUserInfoList userInfoList = ldapmanager.users(&retcode, &errorString); if (retcode != 0) { printf("[ERROR] Unable to retrieve list of users from realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } printf("=======================================================================================================================================\n"); printf("UID\tdisplay name\tcommon name\tgiven name\tinitials\tsurname\tdefault shell\thome directory\ttelephone number\twebsite\temail address\n"); printf("=======================================================================================================================================\n"); LDAPUserInfoList::Iterator it; for (it = userInfoList.begin(); it != userInfoList.end(); ++it) { LDAPUserInfo user = *it; printf("%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", user.uid, user.name.ascii(), user.commonName.ascii(), user.givenName.ascii(), user.initials.ascii(), user.surName.ascii(), user.shell.ascii(), user.homedir.ascii(), user.telephoneNumber.ascii(), user.website.ascii(), user.email.ascii()); fflush(stdout); } printf("=======================================================================================================================================\n"); } else if (command == "listgroups") { TQString errorString; if (ldapmanager.bind(&errorString) != 0) { printf("[ERROR] Unable to bind to Kerberos realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } LDAPGroupInfoList groupInfoList = ldapmanager.groups(&retcode, &errorString); if (retcode != 0) { printf("[ERROR] Unable to retrieve list of groups from realm controller\n[ERROR] Detailed debugging information: %s\n", errorString.ascii()); return -1; } printf("=======================================================================================================================================\n"); printf("GID\tname\n"); printf("=======================================================================================================================================\n"); LDAPGroupInfoList::Iterator it; for (it = groupInfoList.begin(); it != groupInfoList.end(); ++it) { LDAPGroupInfo group = *it; printf("%d\t%s\n", group.gid, group.name.ascii()); fflush(stdout); } printf("=======================================================================================================================================\n"); } else { TDECmdLineArgs::usage(i18n("An invalid command was specified")); return -1; } } else { if (args->count() > 0) { TDECmdLineArgs::usage(i18n("No Kerberos realm was specified")); return -1; } else { TDECmdLineArgs::usage(i18n("No command was specified")); return -1; } } //====================================================================================================================================================== return 0; }