const char *GetNameOfHostsByDns(const NsswitchConf *conf, const DistroInfo *distro) { int line = FindEntry(conf, 0, "hosts"); if (FindModuleOnLine(conf, line, "dns") != -1) return "dns"; if (FindModuleOnLine(conf, line, "bind") != -1) return "bind"; if(distro->os == OS_AIX) return "bind"; else return "dns"; }
const char *GetNameOfHostsByFile(const NsswitchConf *conf, const DistroInfo *distro) { int line = FindEntry(conf, 0, "hosts"); if (FindModuleOnLine(conf, line, "local") != -1) return "local"; if (FindModuleOnLine(conf, line, "files") != -1) return "files"; if(distro->os == OS_AIX) return "local"; else return "files"; }
//Does the platform-specific equivalent of this in nsswitch.conf: // hosts: files dns DWORD DJConfigureHostsEntry(const char *testPrefix) { DWORD ceError = ERROR_SUCCESS; NsswitchConf conf; DistroInfo distro; int line; const char *hostsByFile; const char *hostsByDns; int moduleIndex; if(testPrefix == NULL) testPrefix = ""; memset(&distro, 0, sizeof(distro)); memset(&conf, 0, sizeof(conf)); GCE(ceError = DJGetDistroInfo(testPrefix, &distro)); ceError = ReadNsswitchConf(&conf, testPrefix, TRUE); GCE(ceError); hostsByFile = GetNameOfHostsByFile(&conf, &distro); hostsByDns = GetNameOfHostsByDns(&conf, &distro); line = FindEntry(&conf, 0, "hosts"); if(line == -1) { DJ_LOG_INFO("Adding hosts line"); GCE(ceError = AddEntry(&conf, &distro, &line, "hosts")); GCE(ceError = InsertModule(&conf, &distro, line, 0, hostsByDns)); GCE(ceError = InsertModule(&conf, &distro, line, 0, hostsByFile)); } moduleIndex = FindModuleOnLine(&conf, line, hostsByFile); if(moduleIndex > 0) { /* The local module exists on the line, but it is not the first * entry. */ GCE(ceError = RemoveModule(&conf, line, moduleIndex)); } if(moduleIndex != 0) { GCE(ceError = InsertModule(&conf, &distro, line, 0, hostsByFile)); } if(conf.modified) WriteNsswitchConfiguration(testPrefix, &conf); else DJ_LOG_INFO("nsswitch not modified"); cleanup: FreeNsswitchConfContents(&conf); DJFreeDistroInfo(&distro); return ceError; }
DWORD UpdateNsswitchConf(NsswitchConf *conf, BOOLEAN enable) { DWORD ceError = ERROR_SUCCESS; DistroInfo distro; int line; int lwiIndex; static const char* moduleName = "lsass"; static const char* oldModule = "lwidentity"; GCE(ceError = DJGetDistroInfo(NULL, &distro)); line = FindEntry(conf, 0, "passwd"); if(enable && line == -1) { DJ_LOG_INFO("Adding passwd line"); GCE(ceError = AddEntry(conf, &distro, &line, "passwd")); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } line = FindEntry(conf, 0, "group"); if(line == -1) { line = FindEntry(conf, 0, "groups"); } if(enable && line == -1) { /* The nsswitch file doesn't have an existing groups line. We have to * guess based on platform whether it uses 'group' or 'groups'. */ const char *groupName = "group"; if(distro.os == OS_AIX || distro.os == OS_DARWIN) { groupName = "groups"; } DJ_LOG_INFO("Adding %s line", groupName); GCE(ceError = AddEntry(conf, &distro, &line, groupName)); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } cleanup: DJFreeDistroInfo(&distro); return ceError; }
static QueryResult RemoveCompat(NsswitchConf *conf, PSTR *description, LWException **exc) { DistroInfo distro; int compatLine; int noncompatLine; int compatModIndex; BOOLEAN passwdNeedUpdate = FALSE; BOOLEAN groupNeedUpdate = FALSE; QueryResult result = FullyConfigured; memset(&distro, 0, sizeof(distro)); /* The default configuration on FreeBSD is: * passwd: compat * passwd_compat: nis * group: compat * group_compat: nis * * The nsswitch man page says that compat must be the only module on the * line if it is used. Unfortunately, if a module is listed on the compat * line, it goes through a different interface which LSASS does not * understand. So this configuration must first be transformed into: * * passwd: files nis * group: files nis * * If the user is using compat mode with a non-default configuration, show * an error message instead. */ LW_CLEANUP_CTERR(exc, DJGetDistroInfo(NULL, &distro)); compatLine = FindEntry(conf, 0, "passwd_compat"); if(compatLine != -1) { const NsswitchEntry *lineEntry = GetEntry(conf, compatLine); passwdNeedUpdate = TRUE; if(lineEntry->modules.size != 1) { result = CannotConfigure; goto done_configuring; } if(FindModuleOnLine(conf, compatLine, "nis") == -1) { result = CannotConfigure; goto done_configuring; } noncompatLine = FindEntry(conf, 0, "passwd"); if(noncompatLine == -1) { result = CannotConfigure; goto done_configuring; } lineEntry = GetEntry(conf, noncompatLine); if(lineEntry->modules.size != 1) { result = CannotConfigure; goto done_configuring; } compatModIndex = FindModuleOnLine(conf, noncompatLine, "compat"); if(compatModIndex == -1) { result = CannotConfigure; goto done_configuring; } result = NotConfigured; LW_CLEANUP_CTERR(exc, InsertModule(conf, &distro, noncompatLine, -1, "files")); LW_CLEANUP_CTERR(exc, InsertModule(conf, &distro, noncompatLine, -1, "nis")); LW_CLEANUP_CTERR(exc, RemoveModule(conf, noncompatLine, compatModIndex)); LW_CLEANUP_CTERR(exc, RemoveLine(conf, compatLine)); } compatLine = FindEntry(conf, 0, "group_compat"); if(compatLine != -1) { const NsswitchEntry *lineEntry = GetEntry(conf, compatLine); groupNeedUpdate = TRUE; if(lineEntry->modules.size != 1) { result = CannotConfigure; goto done_configuring; } if(FindModuleOnLine(conf, compatLine, "nis") == -1) { result = CannotConfigure; goto done_configuring; } noncompatLine = FindEntry(conf, 0, "group"); if(noncompatLine == -1) { result = CannotConfigure; goto done_configuring; } lineEntry = GetEntry(conf, noncompatLine); if(lineEntry->modules.size != 1) { result = CannotConfigure; goto done_configuring; } compatModIndex = FindModuleOnLine(conf, noncompatLine, "compat"); if(compatModIndex == -1) { result = CannotConfigure; goto done_configuring; } result = NotConfigured; LW_CLEANUP_CTERR(exc, InsertModule(conf, &distro, noncompatLine, -1, "files")); LW_CLEANUP_CTERR(exc, InsertModule(conf, &distro, noncompatLine, -1, "nis")); LW_CLEANUP_CTERR(exc, RemoveModule(conf, noncompatLine, compatModIndex)); LW_CLEANUP_CTERR(exc, RemoveLine(conf, compatLine)); } done_configuring: if(result == CannotConfigure && description != NULL) { LW_CLEANUP_CTERR(exc, CTStrdup("Remove the passwd_compat and/or group_compat lines and use passwd and group instead. This cannot be done automatically because your system has a non-default nsswitch configuration.\n", description)); } else if((passwdNeedUpdate || groupNeedUpdate) && description != NULL) { LW_CLEANUP_CTERR(exc, CTStrdup("Remove the passwd_compat and/or group_compat lines and use passwd and group instead.\n", description)); result = NotConfigured; } else if(description != NULL) { LW_CLEANUP_CTERR(exc, CTStrdup("Fully Configured.", description)); } cleanup: DJFreeDistroInfo(&distro); return result; }
DWORD UpdateNsswitchConf(NsswitchConf *conf, BOOLEAN enable) { DWORD ceError = ERROR_SUCCESS; LwDistroInfo distro; int line; int lwiIndex; static const char* moduleName = "lsass"; static const char* oldModule = "lwidentity"; const char* pszModule = NULL; CHAR szCommand[2 * PATH_MAX + 1] = {}; GCE(ceError = DJGetDistroInfo(NULL, &distro)); line = FindEntry(conf, 0, "passwd"); if(enable && line == -1) { DJ_LOG_INFO("Adding passwd line"); GCE(ceError = AddEntry(conf, &distro, &line, "passwd")); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } line = FindEntry(conf, 0, "group"); if(line == -1) { line = FindEntry(conf, 0, "groups"); } if(enable && line == -1) { /* The nsswitch file doesn't have an existing groups line. We have to * guess based on platform whether it uses 'group' or 'groups'. */ const char *groupName = "group"; if(distro.os == OS_AIX || distro.os == OS_DARWIN) { groupName = "groups"; } DJ_LOG_INFO("Adding %s line", groupName); GCE(ceError = AddEntry(conf, &distro, &line, groupName)); GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); } if(!enable && lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } lwiIndex = FindModuleOnLine(conf, line, oldModule); if(lwiIndex != -1) { GCE(ceError = RemoveModule(conf, line, lwiIndex)); } // If lwidentity was the only entry // and we removed that now, don't write // an empty entry into the file if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } // If initgroups is present, it overrides the groups line // and has different semantics. // As soon as a module reports success, processing stops. We don't want // that so we need to add '[SUCCESS=continue]' // We are not adding initgroups if it is not present. line = FindEntry(conf, 0, "initgroups"); lwiIndex = FindModuleOnLine(conf, line, moduleName); if(enable && line != -1 && lwiIndex == -1) { GCE(ceError = InsertModule(conf, &distro, line, -1, moduleName)); lwiIndex = FindModuleOnLine(conf, line, moduleName); if (lwiIndex > 0) { ceError = InsertModule(conf, &distro, line, lwiIndex, "[SUCCESS=continue]"); if (ceError) { RemoveModule(conf, line, lwiIndex - 1); GCE(ceError); } } } if (!enable && line != -1 && lwiIndex != -1) { if (lwiIndex > 0) { pszModule = GetModule(conf, line, lwiIndex - 1); if (pszModule && *pszModule == '[') { GCE(ceError = RemoveModule(conf, line, lwiIndex - 1)); lwiIndex = lwiIndex - 1; } } GCE(ceError = RemoveModule(conf, line, lwiIndex)); } if(!enable && line != -1 && GetEntry(conf, line)->modules.size == 0) { GCE(ceError = InsertModule(conf, &distro, line, -1, "files")); } if(distro.os == OS_SUNOS) { if(strcmp("5.11", distro.version) == 0) { if(enable) { sprintf(szCommand, "svccfg -s name-service/switch setprop config/password=\\\"files %s\\\"", moduleName); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svccfg -s name-service/switch setprop config/group=\\\"files %s\\\"", moduleName); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svcadm refresh name-service/switch"); if(system(szCommand) < 0) { goto cleanup; } } else { memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svccfg -s name-service/switch setprop config/password=files"); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svccfg -s name-service/switch setprop config/group=files"); if(system(szCommand) < 0) { goto cleanup; } memset(szCommand, 0, sizeof(szCommand)); sprintf(szCommand, "svcadm refresh name-service/switch"); if(system(szCommand) < 0) { goto cleanup; } } } else { goto cleanup; } } cleanup: DJFreeDistroInfo(&distro); return ceError; }