diff options
Diffstat (limited to 'ldap/admin/src/cfg_sspt.c')
| -rw-r--r-- | ldap/admin/src/cfg_sspt.c | 1621 |
1 files changed, 1621 insertions, 0 deletions
diff --git a/ldap/admin/src/cfg_sspt.c b/ldap/admin/src/cfg_sspt.c new file mode 100644 index 00000000..2ff883d3 --- /dev/null +++ b/ldap/admin/src/cfg_sspt.c @@ -0,0 +1,1621 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <assert.h> +#include "ldap.h" +#include "dsalib.h" +#include "nspr.h" +#include "plstr.h" +#include <string.h> + +#define __CFG_SSPT_C + +#include "cfg_sspt.h" + +/*#define CGI_DEBUG 1*/ + +#define TEST_CONFIG /* for testing cn=config40 dummy entry instead of real one */ + +char* const class_top = "top"; +char* const class_organization = "organization"; +char* const class_organizationalUnit = "organizationalunit"; +char* const class_person = "person"; +char* const class_organizationalPerson = "organizationalperson"; +char* const class_inetOrgPerson = "inetorgperson"; +char* const class_groupOfUniqueNames = "groupofuniquenames"; +char* const class_domain = "domain"; +char* const class_extensibleObject = "extensibleObject"; +char* const class_adminDomain = "nsadmindomain"; +char* const class_country = "country"; +char* const class_locality = "locality"; + +char* const name_objectClass = "objectclass"; +char* const name_cn = "cn"; +char* const name_sn = "sn"; +char* const name_givenname = "givenname"; +char* const name_uid = "uid"; +char* const name_userPassword = "userpassword"; +char* const name_passwordExpirationTime = "passwordExpirationTime"; +char* const name_o = "o"; +char* const name_ou = "ou"; +char* const name_dc = "dc"; +char* const name_member = "member"; +char* const name_uniqueMember = "uniquemember"; +char* const name_aci = "aci"; +char* const name_description = "description"; +char* const name_adminDomain = "nsadmindomainname"; +char* const name_c = "c"; +char* const name_st = "st"; +char* const name_l = "l"; + +char* const value_configAdminGroupCN = "Configuration Administrators"; +char* const value_configAdminGroupRDN = "cn=Configuration Administrators"; +char* const value_configAdminCN = "Configuration Administrator"; +char* const value_configAdminSN = "Administrator"; +char* const value_configAdminGN = "Configuration"; +char* const value_globalPreferencesOU = "Global Preferences"; +char* const value_hostPreferencesOU = "Host Preferences"; +char* const value_netscapeConfigDesc = "Standard branch for configuration information"; +char* const value_peopleOU = "People"; +char* const value_peopleDesc = "Standard branch for people (uid) entries"; +char* const value_groupsOU = "Groups"; +char* const value_groupsDesc = "Standard Branch for group entries"; +#ifdef TEST_CONFIG +char* const value_config40 = "config40"; +char* const value_config40DN = "cn=config40"; +#endif /* TEST_CONFIG */ + +char* dbg_log_file = "ds_sscfg.log"; + +char* const name_netscaperoot = "NetscapeRoot"; +char* const name_netscaperootDN = "o=NetscapeRoot"; +char* const name_topology = "TopologyManagement"; +char* const name_topologyRDN = "ou=TopologyManagement"; +char* const value_topologyDESC = "Branch for Configuration Administration users and groups"; +char* const name_administratorsOU = "Administrators"; +char* const name_administratorsRDN = "ou=Administrators"; +char* const value_administratorsDESC = "Standard branch for Configuration Administrator (uid) entries"; +char* const name_localDAGroup = "Directory Administrators"; +char* const value_localDAGroupDesc = "Entities with administrative access to this directory server"; + +static char* const ACI_self_allow = "(targetattr=\"" + "carLicense ||" + "description ||" + "displayName ||" + "facsimileTelephoneNumber ||" + "homePhone ||" + "homePostalAddress ||" + "initials ||" + "jpegPhoto ||" + "labeledURL ||" + "mail ||" + "mobile ||" + "pager ||" + "photo ||" + "postOfficeBox ||" + "postalAddress ||" + "postalCode ||" + "preferredDeliveryMethod ||" + "preferredLanguage ||" + "registeredAddress ||" + "roomNumber ||" + "secretary ||" + "seeAlso ||" + "st ||" + "street ||" + "telephoneNumber ||" + "telexNumber ||" + "title ||" + "userCertificate ||" + "userPassword ||" + "userSMIMECertificate ||" + "x500UniqueIdentifier\")" + "(version 3.0; acl \"Enable self write for common attributes\"; allow (write) " + "userdn=\"ldap:///self\";)"; + +static char* const ACI_anonymous_allow = "(targetattr!=\"userPassword\")" + "(version 3.0; " + "acl \"Enable anonymous access\"; allow (read, search, compare)" + "userdn=\"ldap:///anyone\";)"; + +static char* const ACI_anonymous_allow_with_filter = + "(targetattr=\"*\")(targetfilter=(%s))" + "(version 3.0; acl \"Default anonymous access\"; " + "allow (read, search) userdn=\"ldap:///anyone\";)"; + +static char* const ACI_config_admin_group_allow_all = "(targetattr=\"*\")" + "(version 3.0; " + "acl \"Enable Configuration Administrator Group modification\"; " + "allow (all) groupdn=\"ldap:///%s, %s=%s, %s, %s\";)"; + +static char* const ACI_config_admin_group_allow = "(targetattr=\"*\")" + "(version 3.0; " + "acl \"Configuration Administrators Group\"; allow (%s) " + "groupdn=\"ldap:///%s\";)"; + +static char* const ACI_local_DA_allow = "(targetattr = \"*\")(version 3.0; " + "acl \"Local Directory Administrators Group\"; allow (%s) " + "groupdn=\"ldap:///%s\";)"; + +static char* const ACI_group_expansion = "(targetattr=\"*\")" + "(version 3.0; acl \"Enable Group Expansion\"; " + "allow (read, search, compare) groupdnattr=\"uniquemember\";)"; + +static char* const ACI_user_allow_1 = "(targetattr=\"*\")(version 3.0; " + "acl \"Configuration Administrator\"; allow (%s) " + "userdn=\"ldap:///uid=%s, %s\";)"; + +static char* const ACI_user_allow_2 = "(targetattr=\"*\")(version 3.0; " + "acl \"Configuration Administrator\"; allow (%s) " + "userdn=\"ldap:///%s\";)"; +/* + This is a list of DSE entries that the Configuration Admin Group has + access to and the access rights for that entry +*/ +static struct _DSEEntriesAndAccess { + char *entryDN; + char *access; +} entryAndAccessList[] = { + {"cn=config", "all"}, + {"cn=schema", "all"} +}; + +static int entryAndAccessListSize = + sizeof(entryAndAccessList)/sizeof(entryAndAccessList[0]); + +int +getEntryAndAccess(int index, const char **entry, const char **access) +{ + if (!entry || !access) + return 0; + + *entry = 0; + *access = 0; + + if (index < 0 || index >= entryAndAccessListSize) + return 0; + + *entry = entryAndAccessList[index].entryDN; + *access = entryAndAccessList[index].access; + + return 1; +} + +/* +** --------------------------------------------------------------------------- +** +** Utility Routines - Functions for performing string and file operations. +** +*/ + +#ifdef CGI_DEBUG +#include <stdarg.h> + +static void +debug_log (const char* file, const char* format, ...) +{ + va_list args; + FILE* fp = fopen(file, "a+"); + if (fp) { + va_start(args, format); + vfprintf(fp, format, args); + va_end(args); + fflush(fp); + fclose(fp); + } +} + +static void +debug_log_array (const char* file, char* name, char** vals) +{ + FILE* fp = fopen(file, "a+"); + + if (fp) { + if (vals != NULL) { + for (; *vals != NULL; LDAP_UTF8INC(vals)) { + fprintf (fp, "%s: %s\n", name, *vals); + } + fflush(fp); + } + fclose(fp); + } +} + +#endif /* CGI_DEBUG */ + +static char * +extract_name_from_dn(const char *dn) +{ + char **rdnList = 0; + char *ret = 0; + if (!dn) + return ret; + + rdnList = ldap_explode_dn(dn, 1); /* leave out types */ + if (!rdnList || !rdnList[0]) + ret = strdup(dn); /* the given dn is not really a dn */ + else + ret = strdup(rdnList[0]); + + if (rdnList) + ldap_value_free(rdnList); + + return ret; +} + +int +entry_exists(LDAP* ld, const char* entrydn) +{ + int exists = 0; + int err; + + struct timeval sto = { 10L, 0L }; + LDAPMessage* pLdapResult; + + err = ldap_search_st(ld, entrydn, LDAP_SCOPE_BASE, + "objectClass=*", NULL, 0, &sto, &pLdapResult); + + if (err == LDAP_SUCCESS) + { + LDAPMessage* pLdapEntry; + char* dn; + + for (pLdapEntry = ldap_first_entry(ld, pLdapResult); + pLdapEntry != NULL; + pLdapEntry = ldap_next_entry(ld, pLdapEntry)) + { + if ((dn = ldap_get_dn(ld, pLdapEntry)) != NULL) + { + exists = 1; + free(dn); + /*ldap_memfree(dn);*/ + break; + } + } + + ldap_msgfree(pLdapResult); + } + + return exists; +} + +int +add_aci(LDAP* ld, char* DN, char* privilege) +{ + int err; + int ret = 0; + LDAPMod mod; + LDAPMod* mods[2]; + char* aci[2]; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "add_aci('%s', '%s')\n", + DN ? DN : "NULL", + privilege ? privilege : "NULL"); +#endif + + if (ld == NULL || DN == NULL || privilege == NULL) + { + return -1; + } + + mods[0] = &mod; + mods[1] = NULL; + mod.mod_op = LDAP_MOD_ADD; + mod.mod_type = name_aci; + mod.mod_values = aci; + aci[0] = privilege; + aci[1] = NULL; + /* fprintf (stdout, "ldap_modify_s('%s')<br>\n",DN); fflush (stdout); */ + err = ldap_modify_s (ld, DN, mods); + if (err != LDAP_SUCCESS && err != LDAP_TYPE_OR_VALUE_EXISTS) { + char* exp = "can't add privilege. "; + char* format; + char* errmsg; + char* explanation; + format = "%s (%i) returned from ldap_modify_s(%s, %i). Privilege: %s"; + errmsg = ldap_err2string (err); + explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (DN) + 10 + strlen(aci[0])); + sprintf (explanation, format, errmsg, err, DN, LDAP_MOD_ADD, aci[0]); + ds_report_warning (DS_INCORRECT_USAGE, exp, explanation); + free (explanation); + ret = 1; + } + + return ret; +} + +/* + Same as add_aci, except that the 3rd parameter is a format string + in printf style format, and the 4th - Nth parameters are a NULL terminated + list of strings to substitute in the format; basically just constructs + the correct aci string and passes it to add_aci +*/ +int +add_aci_v(LDAP* ld, char* DN, char* format, ...) +{ + char* acistring = NULL; + int ii = 0; + int len = 0; + int status = 0; + int fudge = 10; /* a little extra just to make sure */ + char *s = 0; + va_list ap; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "add_aci_v('%s', '%s')\n", + DN ? DN : "NULL", + format ? format : "NULL"); +#endif + + if (ld == NULL || DN == NULL || format == NULL) + { + return -1; + } + + /* determine the length of the string to allocate to hold + the aci string + */ + len += strlen(format) + fudge; + va_start(ap, format); + s = va_arg(ap, char*); + while (s) + { + len += strlen(s) + 1; + s = va_arg(ap, char*); + } + va_end(ap); + + va_start(ap, format); + acistring = (char *)malloc(len); + vsprintf(acistring, format, ap); + va_end(ap); + status = add_aci(ld, DN, acistring); + + free(acistring); + + return status; +} + +/* + Make a dn from lists of dn components. The format argument is in the + standard printf format. The varargs list contains the various dn + components. The string returned is malloc()'d and must be free()'d by + the caller after use. example: + make_dn("cn=%s, ou=%s, %s", "Admins", "TopologyManagement", "o=NetscapeRoot", NULL) + returns + "cn=Admins, ou=TopologyManagement, o=NetscapeRoot" +*/ +char * +make_dn(const char* format, ...) +{ + char *s; + int len = 0; + int fudge = 3; + va_list ap; + char *dnstring; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "make_dn('%s', ...)\n", + format ? format : "NULL"); +#endif + + if (format == NULL) + { + return NULL; + } + + /* determine the length of the string to allocate to hold + the dn string + */ + len += strlen(format) + fudge; + va_start(ap, format); + s = va_arg(ap, char*); + while (s) + { + len += strlen(s) + 3; + s = va_arg(ap, char*); + } + va_end(ap); + + va_start(ap, format); + dnstring = (char *)malloc(len); + vsprintf(dnstring, format, ap); + va_end(ap); + + return dnstring; +} + +char * +admin_user_exists(LDAP* ld, char* base, char *userID) +{ + int exists = 0; + int err; + char search_str[MAX_STRING_LEN]; + + struct timeval sto = { 10L, 0L }; + LDAPMessage* pLdapResult; + sprintf (search_str, "uid=%s*", userID ? userID : "admin"); + + err = ldap_search_st(ld, base, LDAP_SCOPE_SUBTREE, + search_str, NULL, 0, &sto, &pLdapResult); + + if (err == LDAP_SUCCESS) + { + LDAPMessage* pLdapEntry; + char* dn = NULL; + + for (pLdapEntry = ldap_first_entry(ld, pLdapResult); + pLdapEntry != NULL; + pLdapEntry = ldap_next_entry(ld, pLdapEntry)) + { + if ((dn = ldap_get_dn(ld, pLdapEntry)) != NULL) + { + exists = 1; + /*ldap_memfree(dn);*/ + break; + } + } + + ldap_msgfree(pLdapResult); + return dn; + } + + return NULL; +} + +static void +getUIDFromDN(const char *userID, char *uid) +{ + char **rdnListTypes = 0; + char **rdnListNoTypes = 0; + int ii = 0; + int uidindex = -1; + uid[0] = 0; + + rdnListTypes = ldap_explode_dn(userID, 0); + if (!rdnListTypes) + return; /* userID is not a DN */ + + /* find the first rdn in the given userID DN which begins with + "uid=" */ + for (ii = 0; uidindex < 0 && rdnListTypes[ii]; ++ii) + { + if (!PL_strncasecmp(rdnListTypes[ii], "uid=", 4)) + uidindex = ii; + } + ldap_value_free(rdnListTypes); + + if (uidindex < 0) /* did not find an rdn beginning with "uid=" */ + return; + + rdnListNoTypes = ldap_explode_dn(userID, 1); + strcpy(uid, rdnListNoTypes[uidindex]); + ldap_value_free(rdnListNoTypes); + + return; +} + +static char * +create_ssadmin_user(LDAP* ld, char *base, char* userID, char* password) +{ + int err; + char *ret = 0; + char entrydn[1024] = {0}; + char realuid[1024] = {0}; + char *admin_dn = NULL; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_ssadmin_user('%s','%s','%s')\n", + base ? base : "NULL", userID ? userID : "NULL", + password ? password : "NULL"); +#endif + + if (ld == NULL || base == NULL || userID == NULL || *userID == '\0' || + password == NULL || *password == '\0') + { + return NULL; + } + + getUIDFromDN(userID, realuid); + if (realuid[0]) + { + sprintf(entrydn, userID); + if (entry_exists(ld, entrydn)) + admin_dn = entrydn; + } + else + { + sprintf(entrydn, "%s=%s, %s", name_uid, userID, base); + admin_dn = admin_user_exists(ld, base, userID); + strcpy(realuid, userID); + } + + if (admin_dn) + { + char error[BIG_LINE]; + sprintf(error, "A user with uid=%s \"%s\" already exists in the directory" + " and will not be overwritten.", realuid[0] ? realuid : "admin", admin_dn); + ds_send_error(error, 0); + return admin_dn; + } + else + { + LDAPMod* attrs[8]; + LDAPMod attr[7]; + char* objectClasses[5]; + char* cn[2]; + char* sn[2]; + char* givenname[2]; + char* uid[2]; + char* userPassword[2]; + char* passwordExpirationTime[2]; + + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = &attr[2]; + attrs[3] = &attr[3]; + attrs[4] = &attr[4]; + attrs[5] = &attr[5]; + attrs[6] = &attr[6]; + attrs[7] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_person; + objectClasses[2] = class_organizationalPerson; + objectClasses[3] = class_inetOrgPerson; + objectClasses[4] = NULL; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = cn; + cn[0] = value_configAdminCN; + cn[1] = NULL; + attr[2].mod_op = LDAP_MOD_ADD; + attr[2].mod_type = name_sn; + attr[2].mod_values = sn; + sn[0] = value_configAdminSN; + sn[1] = NULL; + attr[3].mod_op = LDAP_MOD_ADD; + attr[3].mod_type = name_givenname; + attr[3].mod_values = givenname; + givenname[0] = value_configAdminGN; + givenname[1] = NULL; + attr[4].mod_op = LDAP_MOD_ADD; + attr[4].mod_type = name_uid; + attr[4].mod_values = uid; + uid[0] = realuid; + uid[1] = NULL; + attr[5].mod_op = LDAP_MOD_ADD; + attr[5].mod_type = name_userPassword; + attr[5].mod_values = userPassword; + userPassword[0] = password; + userPassword[1] = NULL; + attr[6].mod_op = LDAP_MOD_ADD; + attr[6].mod_type = name_passwordExpirationTime; + attr[6].mod_values = passwordExpirationTime; + passwordExpirationTime[0] = "20380119031407Z"; + passwordExpirationTime[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", entrydn); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create administrative user." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (entrydn)); + sprintf (explanation, format, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create user", explanation); + free (explanation); + ret = NULL; + } + } + + return NULL; +} + +static int +create_base_entry( + LDAP* ld, + char* basedn, + char *naming_attr_type, + char *naming_attr_value, + char *objectclassname +) +{ + int err; + int ret = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_base_entry('%s','%s')\n", + basedn ? basedn : "NULL", naming_attr_value: "NULL"); +#endif + + if (ld == NULL || basedn == NULL || *basedn == '\0') + { + return -1; + } + + if (!entry_exists(ld, basedn)) + { + LDAPMod* attrs[3]; + LDAPMod attr[2]; + char* objectClasses[3]; + char* names[2]; + + attrs[0] = &attr[0]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = objectclassname; + objectClasses[2] = NULL; + attrs[1] = &attr[1]; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = naming_attr_type; + attr[1].mod_values = names; + names[0] = naming_attr_value; + names[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", basedn); fflush (stdout); */ + + err = ldap_add_s (ld, basedn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create base entry." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (basedn)); + sprintf (explanation, format, errmsg, err, basedn); + ds_report_warning (DS_NETWORK_ERROR, " can't create base entry", + explanation); + free (explanation); + ret = 1; + } + } + + return ret; +} + +static int +create_organization(LDAP* ld, char* base, char* org) +{ + return create_base_entry(ld, base, name_o, org, class_organization); +} + +static int +create_organizational_unit(LDAP* ld, char* base, char* unit, char *description, + char *extra_objectclassName, + char *extra_attrName, + char *extra_attrValue) +{ + int err; + int ret = 0; + char *entrydn = NULL; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_organizational_unit('%s','%s')\n", + base ? base : "NULL", unit ? unit : "NULL"); +#endif + + if (ld == NULL || unit == NULL || *unit == '\0') + { + return -1; + } + + /* + if base is null, assume the unit is the full DN of the entry + to create; this assumes the caller knows what he/she is doing + and has already created the parent entry(ies) + */ + if (!base) + entrydn = strdup(unit); + else + entrydn = make_dn("%s=%s, %s", name_ou, unit, base, 0); + + if (!entry_exists(ld, entrydn)) + { + LDAPMod* attrs[5]; + LDAPMod attr[4]; + char* objectClasses[4]; + char* names[2]; + char* desc[2]; + char* extra[2]; + char *baseName = unit; + int attrnum = 0; + if (base) + { + baseName = strdup(unit); + } + else + { + /* since the unit is in DN form, we need to extract something to + use for the ou: attribute */ + baseName = extract_name_from_dn(unit); + } + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_organizationalUnit; + objectClasses[2] = extra_objectclassName; /* may be null */ + objectClasses[3] = NULL; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_ou; + attr[1].mod_values = names; + names[0] = baseName; + names[1] = NULL; + attrnum = 2; + if (description && *description) + { + attr[attrnum].mod_op = LDAP_MOD_ADD; + attr[attrnum].mod_type = name_description; + attr[attrnum].mod_values = desc; + desc[0] = description; + desc[1] = NULL; + attrs[attrnum] = &attr[attrnum]; + attrs[++attrnum] = NULL; + } + if (extra_attrName && extra_attrValue && + *extra_attrName && *extra_attrValue) + { + attr[attrnum].mod_op = LDAP_MOD_ADD; + attr[attrnum].mod_type = extra_attrName; + attr[attrnum].mod_values = extra; + extra[0] = extra_attrValue; + extra[1] = NULL; + attrs[attrnum] = &attr[attrnum]; + attrs[++attrnum] = NULL; + } + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + if (baseName) + free(baseName); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create organizational unit." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (entrydn)); + sprintf (explanation, format, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create organizational unit", + explanation); + free (explanation); + ret = 1; + } + } + + if (entrydn) + free(entrydn); + + return ret; +} + +static int +create_domain_component(LDAP* ld, char* base, char* domcomp) +{ + return create_base_entry(ld, base, name_dc, domcomp, class_domain); +} + +static int +create_country(LDAP* ld, char* base, char* country) +{ + return create_base_entry(ld, base, name_c, country, class_country); +} + +static int +create_state(LDAP* ld, char* base, char* state) +{ + return create_base_entry(ld, base, name_st, state, class_locality); +} + +static int +create_locality(LDAP* ld, char* base, char* locality) +{ + return create_base_entry(ld, base, name_l, locality, class_locality); +} + +static int +create_base(LDAP* ld, char* base) +{ + int ret = 0; + char* attr; + char **rdnList = 0; + char **rdnListNoTypes = 0; + enum BASETYPE { unknown, org, orgunit, domcomp, country, state, locality } base_type = unknown; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_base('%s')\n", base ? base : "NULL"); +#endif + + if (ld == NULL || base == NULL || *base == '\0') + { + return -1; + } + + rdnList = ldap_explode_dn(base, 0); + if (!rdnList) + { + char error[BIG_LINE]; + sprintf(error, "The given base suffix [%s] is not a valid DN", base); + ds_send_error(error, 0); + return -1; + } + + if (PL_strncasecmp(rdnList[0], "o=", 2) == 0) + { + base_type = org; + } + else if (PL_strncasecmp(rdnList[0], "ou=", 3) == 0) + { + base_type = orgunit; + } + else if (PL_strncasecmp(rdnList[0], "dc=", 3) == 0) + { + base_type = domcomp; + } + else if (PL_strncasecmp(rdnList[0], "c=", 2) == 0) + { + base_type = country; + } + else if (PL_strncasecmp(rdnList[0], "st=", 3) == 0) + { + base_type = state; + } + else if (PL_strncasecmp(rdnList[0], "l=", 2) == 0) + { + base_type = locality; + } + else + { + ds_report_warning (DS_INCORRECT_USAGE, " Unable to create the root suffix.", + "In order to create the root suffix in the directory, you must " + "specify a distinguished name beginning with o=, ou=, dc=, c=, st=, or l=. " + "If you wish to use something else for your root suffix, you " + "should first create the directory with one of these suffixes, then you can " + "create additional suffixes in any form you choose." + ); + return -1; + } + + ldap_value_free(rdnList); + /* + We need to extract from the base the value to use for the attribute + name_attr e.g. ou: foo or o: org. + */ + rdnListNoTypes = ldap_explode_dn(base, 1); + attr = rdnListNoTypes[0]; + + if (!entry_exists(ld, base)) + { + if (base_type == org) + { + ret = create_organization(ld, base, attr); + } + else if (base_type == orgunit) + { + /* this function is smart enough to extract the name from the DN */ + ret = create_organizational_unit(ld, 0, base, 0, 0, 0, 0); + } + else if (base_type == domcomp) + { + ret = create_domain_component(ld, base, attr); + } + else if (base_type == country) + { + ret = create_country(ld, base, attr); + } + else if (base_type == state) + { + ret = create_state(ld, base, attr); + } + else if (base_type == locality) + { + ret = create_locality(ld, base, attr); + } + } + + ldap_value_free(rdnListNoTypes); + + /* now add the anon search and self mod acis */ + if (!ret) + { + ret = add_aci(ld, base, ACI_anonymous_allow); + if (!ret) + ret = add_aci(ld, base, ACI_self_allow); + } + + return ret; +} + +static int +create_NetscapeRoot(LDAP* ld, const char *DN) +{ +/* + dn: o=NetscapeRoot + o: NetscapeRoot + objectclass: top + objectclass: organization + */ + int err; + int ret = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_NetscapeRoot()\n"); +#endif + + if (ld == NULL) + { + return -1; + } + + if (!entry_exists(ld, DN)) + { + LDAPMod* attrs[4]; + LDAPMod attr[3]; + char* objectClasses[4]; + char* names[2]; + + attrs[0] = &attr[0]; + attrs[3] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_organization; + objectClasses[2] = NULL; + attrs[1] = &attr[1]; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_o; + attr[1].mod_values = names; + names[0] = name_netscaperoot; + names[1] = NULL; + attrs[2] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, DN, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create %s." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (name_netscaperoot)); + sprintf (explanation, format, name_netscaperoot, errmsg, err, + DN); + ds_report_warning (DS_NETWORK_ERROR, " can't create NetscapeRoot", + explanation); + free (explanation); + ret = 1; + } + + } + + return ret; +} + +static int +create_configEntry(LDAP* ld) +{ +/* + dn: cn=config40 + objectclass: top + objectclass: extensibleObject + cn: config40 + */ + char *entrydn = NULL; + int err; + int ret = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_configEntry()\n"); +#endif + + if (ld == NULL) + { + return -1; + } + + entrydn = make_dn("%s=%s", name_cn, value_config40, 0); + if (!entry_exists(ld, entrydn)) + { + LDAPMod* attrs[3]; + LDAPMod attr[2]; + char* objectClasses[3]; + char* names[2]; + + attrs[0] = &attr[0]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_extensibleObject; + objectClasses[2] = NULL; + attrs[1] = &attr[1]; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = names; + names[0] = value_config40; + names[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create %s." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (name_netscaperoot)); + sprintf (explanation, format, value_config40, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create config40", + explanation); + free (explanation); + ret = 1; + } + + } + + if (entrydn) + free(entrydn); + + return ret; +} + +int +create_group(LDAP* ld, char* base, char* group) +{ + int err; + int ret = 0; + LDAPMod* attrs[3]; + LDAPMod attr[2]; + char* objectClasses[3]; + char* names[2]; + char *entrydn = 0; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_group('%s','%s')\n", + base ? base : "NULL", group ? group : "NULL"); +#endif + + if (ld == NULL || base == NULL || *base == '\0' || + group == NULL || *group == '\0') + { + return -1; + } + + entrydn = make_dn("%s=%s, %s", name_cn, group, base, 0); + + if (!entry_exists(ld, entrydn)) + { + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = NULL; + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_groupOfUniqueNames; + objectClasses[2] = NULL; + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = names; + names[0] = group; + names[1] = NULL; + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", entrydn); fflush (stdout); */ + + err = ldap_add_s (ld, entrydn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create group." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (entrydn)); + sprintf (explanation, format, errmsg, err, entrydn); + ds_report_warning (DS_NETWORK_ERROR, " can't create group", explanation); + free (explanation); + ret = 1; + } + } + + if (entrydn) + free(entrydn); + + return ret; +} + +int +create_consumer_dn(LDAP* ld, char* dn, char* hashedpw) +{ + int err; + int ret = 0; + LDAPMod* attrs[7]; + LDAPMod attr[6]; + char* objectClasses[3]; + char* names[2]; + char* snames[2]; + char* desc[2]; + char* pwd[2]; + char* passwordExpirationTime[2]; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "create_consumer_dn('%s','%s')\n", + dn ? dn : "NULL", hashedpw ? hashedpw : "NULL"); +#endif + + if (ld == NULL || dn == NULL || hashedpw == NULL) + { + return -1; + } + + if (!entry_exists(ld, dn)) + { + attrs[0] = &attr[0]; + attrs[1] = &attr[1]; + attrs[2] = &attr[2]; + attrs[3] = &attr[3]; + attrs[4] = &attr[4]; + attrs[5] = &attr[5]; + attrs[6] = NULL; + + attr[0].mod_op = LDAP_MOD_ADD; + attr[0].mod_type = name_objectClass; + attr[0].mod_values = objectClasses; + objectClasses[0] = class_top; + objectClasses[1] = class_person; + objectClasses[2] = NULL; + + attr[1].mod_op = LDAP_MOD_ADD; + attr[1].mod_type = name_cn; + attr[1].mod_values = names; + names[0] = "Replication Consumer"; + names[1] = NULL; + + attr[2].mod_op = LDAP_MOD_ADD; + attr[2].mod_type = name_sn; + attr[2].mod_values = snames; + snames[0] = "Consumer"; + snames[1] = NULL; + + attr[3].mod_op = LDAP_MOD_ADD; + attr[3].mod_type = name_description; + attr[3].mod_values = desc; + desc[0] = "Replication Consumer bind entity"; + desc[1] = NULL; + + attr[4].mod_op = LDAP_MOD_ADD; + attr[4].mod_type = name_userPassword; + attr[4].mod_values = pwd; + pwd[0] = hashedpw; + pwd[1] = NULL; + + attr[5].mod_op = LDAP_MOD_ADD; + attr[5].mod_type = name_passwordExpirationTime; + attr[5].mod_values = passwordExpirationTime; + passwordExpirationTime[0] = "20380119031407Z"; + passwordExpirationTime[1] = NULL; + + /* fprintf (stdout, "ldap_add_s(%s)<br>\n", DN); fflush (stdout); */ + + err = ldap_add_s (ld, dn, attrs); + + if (err != LDAP_SUCCESS) + { + char* format = "Unable to create consumer dn." + " (%s (%i) returned from ldap_add_s(%s))"; + char* errmsg = ldap_err2string (err); + char* explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (dn)); + sprintf (explanation, format, errmsg, err, dn); + ds_report_warning (DS_NETWORK_ERROR, " can't create consumer dn", explanation); + free (explanation); + ret = 1; + } + } + + return ret; +} + +static int +add_group_member(LDAP* ld, char* DN, char* attr, char* member) +{ + int err; + int ret = 0; + LDAPMod mod; + LDAPMod* mods[2]; + char* members[2]; + +#ifdef CGI_DEBUG + debug_log (dbg_log_file, "add_group_member('%s', '%s', '%s')\n", + DN ? DN : "NULL", + attr ? attr : "NULL", + member ? member : "NULL"); +#endif + + if (ld == NULL || DN == NULL || attr == NULL || member == NULL) + { + return -1; + } + + mods[0] = &mod; + mods[1] = NULL; + mod.mod_op = LDAP_MOD_ADD; + mod.mod_type = attr; + mod.mod_values = members; + members[0] = member; + members[1] = NULL; + /* fprintf (stdout, "ldap_modify_s('%s')<br>\n",DN); fflush (stdout); */ + err = ldap_modify_s (ld, DN, mods); + if (err != LDAP_SUCCESS && err != LDAP_TYPE_OR_VALUE_EXISTS) { + char* exp = "can't add member. "; + char* format; + char* errmsg; + char* explanation; + format = "%s (%i) returned from ldap_modify_s(%s, %i)."; + errmsg = ldap_err2string (err); + explanation = (char*)malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (DN) + 10); + sprintf (explanation, format, errmsg, err, DN, LDAP_MOD_ADD); + ds_report_warning (DS_INCORRECT_USAGE, exp, explanation); + free (explanation); + ret = 1; + } + + return ret; +} + +static LDAP* +do_bind(SLAPD_CONFIG* slapd, char* rootdn, char* rootpw) +{ + LDAP* connection = NULL; + int retrymax = 1800; /* wait up to 30 min; init dbcache could be slow. */ + int err = LDAP_SUCCESS; + + /* added error retry to work around the slow start introduced + by blackflag 624053 */ + while ( retrymax-- ) + { + if (connection == NULL) { + connection = ldap_open ("127.0.0.1", slapd->port); + } + + if (connection) { + err = ldap_simple_bind_s (connection, rootdn, rootpw ? rootpw : ""); + if (LDAP_SUCCESS == err) + break; + } + + PR_Sleep(PR_SecondsToInterval(1)); + } + + if (connection == NULL) { + char* format = " Cannot connect to server."; + ds_report_warning (DS_NETWORK_ERROR, format, ""); + } else if (err != LDAP_SUCCESS) { + char* errmsg = ldap_err2string (err); + char* format = "Unable to bind to server." + " (%s (%i) returned from ldap_simple_bind_s(%s))"; + char* explanation = malloc (strlen (format) + strlen (errmsg) + + 9 + strlen (rootdn) + 1); + sprintf (explanation, format, errmsg, err, rootdn); + ds_report_warning (DS_NETWORK_ERROR, " can't bind to server", + explanation); + free (explanation); + ldap_unbind (connection); + connection = NULL; + } + fflush (stdout); + return connection; +} + +static int +write_ldap_info(SLAPD_CONFIG* slapd, char* base, char* admnm) +{ + FILE* fp; + int ret = 0; + + char* fmt = "%s/shared/config/ldap.conf"; + char* infoFileName; + + infoFileName = (char*)malloc(strlen(fmt) + strlen(slapd->slapd_server_root) + 1); + sprintf(infoFileName, fmt, slapd->slapd_server_root); + + if ((fp = fopen(infoFileName, "w")) == NULL) + { + ret = -1; + } + else + { + fprintf(fp, "url\tldap://%s:%d/", + slapd->host, slapd->port); + + if (base) + fprintf(fp, "%s", base); + + fprintf(fp, "\n"); + + fprintf(fp, "admnm\t%s\n", admnm); + + fclose(fp); + } + + free(infoFileName); + + return ret; +} + +int +config_configEntry(LDAP* connection, QUERY_VARS* query) +{ + /* initial ACIs for o=NetscapeRoot */ + + int ret = add_aci_v (connection, value_config40DN, ACI_self_allow, 0); + return ret; +} + +int +config_suitespot(SLAPD_CONFIG* slapd, QUERY_VARS* query) +{ + LDAP* connection; + const char* DN_formatUID = "uid=%s,%s"; + char* usageShortMsg = " Required field missing."; + char* usageErrorMsg = NULL; + int status = 0; + char *admin_domainDN = 0; + int ii = 0; + char *configAdminDN = 0; + char *adminGroupDN = 0; + char *parentDN = 0; + char *localDAGroupDN = 0; + + if (!query->rootDN || *query->rootDN == '\0') { + usageErrorMsg = "You must enter the distinguished name of a user with " + "unrestricted access to the directory."; + } else if (!query->rootPW || *query->rootPW == '\0') { + usageErrorMsg = "You must enter the password of the user with " + "unrestricted access to the directory."; + } + + if (usageErrorMsg) { + ds_report_warning (DS_INCORRECT_USAGE, usageShortMsg, usageErrorMsg); + return -1; + } + + if (!(connection = do_bind (slapd, query->rootDN, query->rootPW))) + return 1; + + /* parent dn of admin uid entry */ + parentDN = make_dn("%s, %s, %s", name_administratorsRDN, + name_topologyRDN, query->netscaperoot, 0); + if (query->suffix) + { + status = create_base(connection, query->suffix); + if (!status) + { + add_aci_v(connection, query->suffix, ACI_user_allow_1, + "all", query->config_admin_uid, parentDN, 0); + + status = create_group(connection, query->suffix, name_localDAGroup); + } + } + + if (!status && query->consumerDN && query->consumerPW && + PL_strcasecmp(query->consumerDN, query->rootDN)) + status = create_consumer_dn(connection, + query->consumerDN, query->consumerPW); + + if (!status) + { + char realuid[1024] = {0}; + getUIDFromDN(query->config_admin_uid, realuid); + if (realuid[0]) + { + /* admid is already a DN */ + configAdminDN = strdup(query->config_admin_uid); + } + else + { + /* create a DN for admid */ + configAdminDN = make_dn(DN_formatUID, query->config_admin_uid, parentDN, 0); + } + + /* + Give the Configuration Admin group access to the root DSE entries + */ + adminGroupDN = make_dn("%s, %s=%s, %s, %s", value_configAdminGroupRDN, + name_ou, value_groupsOU, + name_topologyRDN, + query->netscaperoot, 0); + if (query->suffix) + { + localDAGroupDN = make_dn("cn=%s, %s", name_localDAGroup, + query->suffix, 0); + } + else + { + localDAGroupDN = NULL; + } + for (ii = 0; ii < entryAndAccessListSize; ++ii) + { + if (query->cfg_sspt) { + add_aci_v(connection, entryAndAccessList[ii].entryDN, + ACI_config_admin_group_allow, + entryAndAccessList[ii].access, + adminGroupDN, 0); + } + add_aci_v(connection, entryAndAccessList[ii].entryDN, + ACI_user_allow_2, + entryAndAccessList[ii].access, + configAdminDN, 0); + if (localDAGroupDN) + { + add_aci_v(connection, entryAndAccessList[ii].entryDN, + ACI_local_DA_allow, + entryAndAccessList[ii].access, + localDAGroupDN, 0); + } + } + } + + if (query->cfg_sspt) + { + /* create and set ACIs for o=netscaperoot entry */ + if (!status) + status = create_NetscapeRoot(connection, query->netscaperoot); + + if (!status) + status = add_aci_v(connection, query->netscaperoot, + ACI_config_admin_group_allow_all, + value_configAdminGroupRDN, + name_ou, value_groupsOU, name_topologyRDN, + query->netscaperoot, 0); + + if (!status) + status = add_aci_v(connection, query->netscaperoot, + ACI_anonymous_allow_with_filter, + query->netscaperoot, 0); + + if (!status) + status = add_aci_v(connection, query->netscaperoot, ACI_group_expansion, + query->netscaperoot, 0); + + /* create "topologyOU, netscaperoot" entry and set ACIs */ + if (!status) + { + char *dn = make_dn("%s, %s", name_topologyRDN, + query->netscaperoot, 0); + status = create_organizational_unit(connection, NULL, dn, + value_topologyDESC, + 0, 0, 0); + + if (!status) + add_aci(connection, dn, ACI_anonymous_allow); + + free(dn); + } + + /* create "ou=Groups, ..." */ + if (!status) + { + char *dn = make_dn("%s=%s, %s, %s", name_ou, value_groupsOU, + name_topologyRDN, query->netscaperoot, 0); + status = create_organizational_unit (connection, NULL, dn, + value_groupsDesc, 0, 0, 0); + free(dn); + } + + /* create "ou=Administrators, ..." */ + if (!status) + { + char *dn = make_dn("%s, %s, %s", name_administratorsRDN, + name_topologyRDN, query->netscaperoot, 0); + status = create_organizational_unit (connection, NULL, dn, + value_administratorsDESC, + 0, 0, 0); + free(dn); + } + + /* create "cn=Configuration Administrators, ou=Groups, ..." */ + if (!status) + { + char *dn = make_dn("%s=%s, %s, %s", name_ou, value_groupsOU, + name_topologyRDN, + query->netscaperoot, 0); + status = create_group (connection, dn, value_configAdminGroupCN); + free(dn); + } + + /* create the ss admin user */ + if (!status) + { + /* group to add the uid to */ + char *groupdn = make_dn("%s, %s=%s, %s, %s", value_configAdminGroupRDN, + name_ou, value_groupsOU, name_topologyRDN, + query->netscaperoot, 0); + create_ssadmin_user(connection, parentDN, + query->ssAdmID, query->ssAdmPW1); + + status = add_group_member (connection, groupdn, + name_uniqueMember, configAdminDN); + free (groupdn); + } + + admin_domainDN = make_dn("%s=%s, %s", name_ou, query->admin_domain, + query->netscaperoot, 0); + + if (!status) + status = create_organizational_unit (connection, 0, + admin_domainDN, + value_netscapeConfigDesc, + class_adminDomain, + name_adminDomain, + query->admin_domain); + + if (!status) { + status = create_organizational_unit(connection, + admin_domainDN, + value_globalPreferencesOU, 0, + 0, 0, 0); + } + if (!status) { + status = create_organizational_unit(connection, + admin_domainDN, + value_hostPreferencesOU, 0, + 0, 0, 0); + } + + /* + ** Write the ldap.info file and the SuiteSpot.ldif file + */ + + write_ldap_info(slapd, query->suffix, query->ssAdmID); + } + + if (!status && query->testconfig) + status = create_configEntry(connection); + + if (!status && query->testconfig) + status = config_configEntry(connection, query); + + if (connection) + ldap_unbind (connection); + if (adminGroupDN) + free(adminGroupDN); + if (configAdminDN) + free(configAdminDN); + if (parentDN) + free(parentDN); + if (localDAGroupDN) + free(localDAGroupDN); + + return status; +} |
