/*************************************************************************/ /* LDAPCONF - Linuxconf module for LDAP operation. Copyright (C) 1999,2000,2001 Stein Vråle 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. **************************************************************************/ /*! LDAP_OBJECT.cc #Specification: Manage ldap data entries and directory access. This class will store all information for one LDAP object, when it is retrieved from the directory. The class provides methods to retrieve data from directory, manipulate it, export and import to other formats, and write it back to the directory again. TODO: The class should probably be split into two or maybe three classes, as the current object has grown so big, and contain methods which are totally unrelated to each other. Should not be to hard to split it, but we need a good design for a new class structure first. Note: This is still using LDIF internally to store information. It is also using the user tools (ldapsearch, ldapmodify) to communicate with LDAP. This should be change to using the C API, much faster and also more informative (errors ...) **************************************************************************/ #pragma implementation #include #include #include #include #include #include #include #include "ldapconf_defs.h" #include #include PUBLIC SSTRINGS *TB_SSTRINGS::getitem(int no) const { return (SSTRINGS*)ARRAY::getitem(no); } /*! Create and initialize a new object. */ PUBLIC LDAPOBJECT::LDAPOBJECT () { D(debugf(4,">>>LDAPOBJECT::CREATE:")); init(); } /*! Create and initialize a new object. Load named directory profile. */ PUBLIC LDAPOBJECT::LDAPOBJECT (const char *profile_name) { D(debugf(4,">>>LDAPOBJECT::CREATE(%s)",profile_name)); init(); load_profile(profile_name); } /*! Init new object. */ PUBLIC void LDAPOBJECT::init () { D(debugf(4,"---LDAPOBJECT::init")); // We assemble a unique name for the temporary ldif file static int instance=0; ldapconf_entry.setfromf ("/var/run/ldapconf.entry.%d.%d",getpid(),instance++); form = NULL; reset(); } PUBLIC const char *LDAPOBJECT::gettmpfile() const { return ldapconf_entry.get(); } /*! Destroy object and free allocations. */ PUBLIC LDAPOBJECT::~LDAPOBJECT () { delete form; D(debugf(4,"<<LDAPOBJECT::ldap_command: %s",command)); SSTRING parameters; if (!bind.usesasl) parameters.append (" -x"); /* Directory config */ if (bind.dn.is_filled()) parameters.appendf(" -D %s",bind.dn.get()); if (bind.pw.is_filled()) parameters.appendf(" -w %s",bind.pw.get()); if (bind.host.is_filled()) parameters.appendf(" -h %s",bind.host.get()); if (bind.port.is_filled()) parameters.appendf(" -p %s",bind.port.get()); /* Standard args */ parameters.appendf(" %s",mode_openldap_params.get()); if (strcmp(command,"ldapsearch")==0){ parameters.append(" -LLL"); // Removes comment and version indication (OpenLdap 2.x) if (search_base.is_filled()) parameters.appendf(" -b %s",search_base.get()); } /* OpenLDAP version depended parameters */ if (!mode_openldap_version.cmp("2")) { // This is for 2.x if (strcmp(command,"ldappasswd")!=0){ // Add LDAP protocol version for this directory if (this->c_profile->getval("profile","protocol")){ // User defined parameters.appendf(" -P %s",this->c_profile->getval("profile","protocol",mode_ldap_protocol.get())); } else{ // Use default parameters.appendf(" -P %s",mode_ldap_protocol.get()); } } // Add option to disable SASL with OL-2.x parameters.append(" -x"); } /* Custom args */ if (command_line.is_filled()) parameters.appendf(" %s",command_line.get()); /* Filter */ if (filter.is_filled() && strcmp(command,"ldapsearch")==0) parameters.appendf(" \"%s\"",filter.get()); /* Attr */ if (attr.is_filled() && strcmp(command,"ldapsearch")==0) parameters.appendf(" %s",attr.get()); /* Run command*/ int ret = sys_command (command,parameters.get(),resmsg); D(debugf(4,"<--LDAPOBJECT::ldap_command:")); return ret; } /*! LDAPOBJECT.add Add object to directory. */ PUBLIC int LDAPOBJECT::add () { D(debugf(4,"-->LDAPOBJECT::ADD")); int ret=0; SSTRINGS resmsg; export_ldif(gettmpfile()); command_line.setfromf(" -a -f %s",gettmpfile()); // Entry /* Run command*/ ret = command ("ldapmodify",resmsg); /* Remove tmp entry file */ unlink(gettmpfile()); D(debugf(4,"<--LDAPOBJECT::ADD")); return ret; } /*! LDAPOBJECT.modify Update object to database */ PUBLIC int LDAPOBJECT::modify () { D(debugf(4,"-->LDAPOBJECT::MODIFY")); int ret=0; SSTRINGS resmsg; export_ldif(gettmpfile()); command_line.setfromf(" -r -f %s",gettmpfile()); /* Run command*/ ret = command ("ldapmodify",resmsg); /* Remove tmp entry file */ unlink(gettmpfile()); D(debugf(4,"<--LDAPOBJECT::MODIFY")); return ret; } /*! LDAPOBJECT.export_ldif Write object data to file in ldif format */ PUBLIC int LDAPOBJECT::export_ldif(const char *path, bool append) { int ret=0; /* Remove creator/modifier stamps */ at_del("modifytimestamp"); at_del("modifiersname"); at_del("createtimestamp"); at_del("creatorsname"); // Remove duplicates // \bug : Doing this will bypass the problem with duplicates of some entries (eg mail2), // but it will also hide the cause of the real problem - why/where do the duplicates come from? // it does not work , I think the problem is the file modify just add things but never tell openldap to remove attributes so they become duplicates ! atlist.remove_dups(); oclist.remove_dups(); /* Build dataentry */ FILE *fout = fopen (path,append ? "a" : "w"); if (fout != NULL){ fprintf (fout,"%s\n",dn.get()); D(debugf(4,"LDIF: %s",dn.get())); //write objectclass before attributes for (int i=0; iget()); D(debugf(4,"LDIF: %s",oclist.getitem(i)->get())); } for (int i=0; iget()); D(debugf(4,"LDIF: %s",atlist.getitem(i)->get())); } fputs ("\n",fout); fclose (fout); } return ret; } PUBLIC int LDAPOBJECT::export_ldif(const char *path) { return export_ldif (path,false); } /*! LDAPOBJECT.del Delete object from database */ PUBLIC int LDAPOBJECT::del () { D(debugf(4,"---LDAPOBJECT::DEL")); int ret=0; SSTRINGS resmsg; command_line.setfrom(dn.get()); /* Run command*/ ret = command ("ldapdelete",resmsg); return ret; } /*! LDAPOBJECT.exist Return true if entry exists in directory. */ PUBLIC char LDAPOBJECT::exist (const char *dn) { D(debugf(4,"-->LDAPOBJECT::exist (%s)",dn)); char ret = false; filter.setfrom(dn); if (search() > 0 ) ret = true; D(debugf(4,"<--LDAPOBJECT::exist = %c",ret)); return ret; } /*! LDAPOBJECT.search Search uniq object */ PUBLIC int LDAPOBJECT::search () { D(debugf(4,"-->LDAPOBJECT::search (%s)",filter.get())); SSTRINGS data; reset_data(); /* Run ldapsearch command*/ command("ldapsearch",data); /* Split the objects */ int c = 1; /* Line counter */ int d; /* Number of lines */ int idx = 0; /* Object index number */ int i = 1; /* Object internal count */ d = data.getnb(); c = 0; c++; /* Skip command message */ while (c < d ) { SSTRING *s = data.getitem(c); s->strip_end(); const char *a = str_skip(s->get()); SSTRING name,val; if (s->is_empty()) { // Empty line is object seperator i=0; } else if (s->strstr("dn:") != 0) { // DN line found dn.setfrom(s->get()); idx++; i=1; D(debugf(6,"search: found dn=%s",dn.get())); } else if (ldif_splitline(a,name,val)==0) { if (name.nicmp("objectClass",11) == 0) { oc_add(val.get()); } else{ //fprintf (stderr,"a :%s: name=:%s: val=:%s:\n",a,name.get(),val.get()); at_add(name.get(),val.get()); } } else { // Should not happen D(debugf(4,"search Warning - undecoded ldif line %s\n",s->get())); } c++; } return idx; } /*! LDAPOBJECT.search_list Search and return resultlist */ PUBLIC int LDAPOBJECT::search_list (SSTRINGS &lst) { D(debugf(4,"-->LDAPOBJECT::SEARCH_LIST")); int ret=0; SSTRINGS data; reset_data(); attr.setfrom("dn"); ret = command ("ldapsearch",data); int c = 0; /* Line counter */ int d = 0; /* Number of lines */ int idx = 0; /* Object index number */ int i = 0; /* Object internal count */ d = data.getnb(); c++; // Skip the first line, its the ldapsearch commandline while (c < d ) { SSTRING *s = data.getitem(c); s->strip_end(); const char *a = str_skip(s->get()); if (s->is_empty()) { // Empty line is object seperator i=0; } else if (s->strstr("dn:") != NULL) { // DN line found lst.add(new SSTRING(a)); idx++; i=1; } // Skip the rest of this object c++; } return idx; } /*! LDAPOBJECT.search_list_val Search and return resultlist, where entries are the values of the key attribute only. */ PUBLIC int LDAPOBJECT::search_list_val (SSTRINGS &lst,const char *key) { D(debugf(4,"-->LDAPOBJECT::SEARCH_LIST_VAL (%s)",key)); int ret=0; SSTRINGS data; reset_data(); attr.setfrom(key); ret = command ("ldapsearch",data); int c = 0; /* Line counter */ int d = 0; /* Number of lines */ int idx = 0; /* Object index number */ int i = 0; /* Object internal count */ d = data.getnb(); c++; // Skip the first line, its the ldapsearch commandline while (c < d ) { SSTRING *s = data.getitem(c); s->strip_end(); const char *a = str_skip(s->get()); SSTRING name,val; if (s->is_empty()) { // Empty line is object seperator i=0; } else if (s->strstr("dn:") != NULL) { // DN line found idx++; if (strcmp(key,"dn")==0) { // the result we're looking at is the dn , we must catch this case here ! if (ldif_splitline(a,name,val)==0) { lst.add(new SSTRING(val)); i++; } } i=1; } else if (i==1 && ldif_splitline(a,name,val)==0) { lst.add(new SSTRING(val)); i++; } c++; } return idx; } /*! LDAPOBJECT.search_list_vals Search and return resultlist, where entries are the values of the specified attributes. The key attribute must always be specified. */ PUBLIC int LDAPOBJECT::search_list_vals ( SSTRINGS &lst, const char *key, const char *at_name[]) { D(debugf(4,"-->LDAPOBJECT::SEARCH_LIST_VALS (%s)(%s)",key,at_name)); int ret=0; SSTRINGS data; reset_data(); attr.setfrom(key); int atc = 0; while (at_name[atc] != NULL){ attr.appendf(" %s",at_name[atc]); atc++; } ret = command ("ldapsearch",data); int c = 0; /* Line counter */ int d = 0; /* Number of lines */ int idx = 0; /* Object index number */ int i = 0; /* Object internal count */ d = data.getnb(); c++; // Skip the first line, its the ldapsearch commandline while (c < d ) { SSTRING *s = data.getitem(c); s->strip_end(); const char *a = str_skip(s->get()); SSTRING name,val; if (s->is_empty()) { // Empty line is object seperator i=0; } else if (s->strstr("dn:") != NULL) { // DN line found idx++; i=1; } else if (i==1 && ldif_splitline(a,name,val)==0) { lst.add(new SSTRING(a)); i++; } else if (ldif_splitline(a,name,val)==0) { lst.getitem(idx-1)->appendf("\t%s",a); i++; } c++; } return idx; } PUBLIC int LDAPOBJECT::search_list_vals ( TB_SSTRINGS &lst, // Each record will be stored in an SSTRINGS const char *key, const char *at_name[]) { D(debugf(4,"-->LDAPOBJECT::SEARCH_LIST_VALS (%s)(%s)",key,at_name)); SSTRINGS data; reset_data(); attr.setfrom(key); int atc = 0; while (at_name[atc] != NULL){ attr.appendf(" %s",at_name[atc]); atc++; } command ("ldapsearch",data); int d = data.getnb(); SSTRINGS *cur = NULL; // c=1: Skip the first line, its the ldapsearch commandline for (int c=1; cstrip_end(); if (s->is_filled()) { // Empty line is object seperator const char *a = str_skip(s->get()); SSTRING name,val; if (s->strstr("dn:") != NULL) { // DN line found cur = new SSTRINGS; lst.add (cur); } else if (cur != NULL && ldif_splitline(a,name,val)==0) { cur->add(new SSTRING(a)); } } } return lst.getnb(); } /********************************************************************** LDAPOBJECT datamanipulation The object data will be stored internally using SSTRING objects. Each SSTRING object will hold one attribute name and value, using the same format as the one used in LDIF data: attrname: attrvalue The SSTRINGS object will be used to hold lists of related LDAP data. Following is a set of small methods to handle the internal datastorage. External functions should if possible try to use these methods when dealing with the data, so it will be easy to change the internal data storage system later. This interface is not yet completed, but most of the current functions in ldapconf make use of it already. ***********************************************************************/ /*! LDAPOBJECT.dn_set Set dn. */ PUBLIC int LDAPOBJECT::dn_set (const char *val) { int ret=0; dn.setfromf("dn: %s",val); D(debugf(4,"---LDAPOBJECT::dn_set (%s)",val)); return ret; } /************** Attributes **************/ /*! LDAPOBJECT.at_list Copy all attribute names to the list. Return number of attributes. */ PUBLIC int LDAPOBJECT::at_list (SSTRINGS &lst) { int n = atlist.getnb(); D(debugf(4,"---LDAPOBJECT::at_list number of attr=%d\n",n)); for (int i=0; iget(),':',tb); if (tb.getitem(0)) { lst.add (new SSTRING( tb.getitem(0)->get()) ); D(debugf(6,"---LDAPOBJECT::at_list found attr %s\n",tb.getitem(0)->get())); } } } return n; } /*! LDAPOBJECT.at_get Locate the value of the named attribute. Return NULL if the name is not defined. Eventual quote surrounding the value are removed. */ PUBLIC const char* LDAPOBJECT::at_get (const char *name) { return LDAPOBJECT::at_get(name,1); } /*! LDAPOBJECT.at_get Locate the value of the k named attribute. Return NULL if the name is not defined. Eventual quote surrounding the value are removed. */ PUBLIC const char* LDAPOBJECT::at_get (const char *name, int k) { char tmp[2000]; const char *ret = NULL; SSTRING *it = locateassign(name,k); if (it != NULL){ const char *pt = it->strchr(':'); if (pt != NULL){ ret = pt+2; if (ret[0] == '"'){ ret++; strncpy (tmp,ret,sizeof(tmp)); strip_end (tmp); int len = strlen(tmp)-1; if (len >= 0 && tmp[len] == '"') tmp[len] = '\0'; ret = tmp; } } } D(debugf(4,"---LDAPOBJECT::at_get %s: %s\n",name,ret)); return ret; } /*! LDAPOBJECT.at_getall Copy multiple attribute values from the named attribute to the list. Return number of values found. */ PUBLIC int LDAPOBJECT::at_getall (const char *name,SSTRINGS &lst) { int num = 0; num = locate(name,lst); D(debugf(4,"---LDAPOBJECT::at_getall name=%s num=%d \n",name,num)); return num; } /*! LDAPOBJECT.at_getname Return the name of attribute n. Return NULL if not found. */ PUBLIC const char* LDAPOBJECT::at_getname (int num) { char name[ATTR_NAME_MAX]; const char *ret = NULL; SSTRING *it = atlist.getitem(num); if (it != NULL){ SSTRINGS tb; str_splitline(it->get(),':',tb); // 2.0 strncpy(name,tb.getitem(0)->get(),ATTR_NAME_MAX); strip_end(name); ret = name; } D(debugf(4,"---LDAPOBJECT::at_getname %d=%s\n",num,name)); return ret; } /*! LDAPOBJECT.at_getval Return the value of attribute n. Return NULL if not found. */ PUBLIC const char* LDAPOBJECT::at_getval (int num) { char val[ATTR_VAL_MAX]; const char *ret = NULL; SSTRING *it = atlist.getitem(num); if (it != NULL){ SSTRINGS tb; str_splitline(it->get(),':',tb); // 2.0 strncpy(val,tb.getitem(1)->get(),ATTR_VAL_MAX); strip_end(val); ret = val; } D(debugf(4,"---LDAPOBJECT::at_getval %d=%s\n",num,val)); return ret; } static const char *utf_do ( const char *val, const char *enc_from, const char *enc_to, iconv_t &cd, SSTRING &buf) { if (strcasecmp(enc_from,enc_to)!=0){ if (cd == (iconv_t)-1){ cd = iconv_open (enc_to,enc_from); // fprintf (stderr,"cd = %p\n",cd); } if (cd != (iconv_t)-1){ size_t inbytes = strlen(val); size_t outbytes = 6*inbytes; char out[outbytes+1]; char *ptin = (char*)val; char *ptout = out; size_t len = iconv (cd,&ptin,&inbytes,&ptout,&outbytes); if (len >= 0){ *ptout = '\0'; buf = out; // fprintf (stderr,"utf len=%d :%s: -> :%s:\n",len,val,bufutf.get()); val = buf.get(); }else{ buf = val; } } }else{ buf = val; } return val; } /* Convert an UTF-8 string to the local character set */ const char *utf_convfromutf(const char *val, SSTRING &dst) { static iconv_t cd = (iconv_t)-1; return utf_do (val,"utf-8","iso-8859-1",cd,dst); } /* Encode to UTF-8 and/or base64 as needed */ static const char *utf_conv ( const char *val, SSTRING &bufutf, SSTRING &bufb64) { bool utf_needed = false; bool b64_needed = false; const char *ptv = val; while (*ptv != '\0'){ if (*ptv < ' '){ b64_needed = true; }else if (*ptv > 127){ utf_needed = true; } ptv++; } // fprintf (stderr,"val :%s: %d %d\n",val,utf_needed,b64_needed); if (utf_needed){ static iconv_t cd = (iconv_t)-1; val = utf_do (val,"iso-8859-1","utf-8",cd,bufutf); } if (b64_needed){ char *base64 = base64_encode (val,strlen(val)); bufb64 = base64; free (base64); val = bufb64.get(); } return val; } /*! LDAPOBJECT.at_set Update or add an attribute STR value. It will replace any existing value. */ PUBLIC int LDAPOBJECT::at_set (const char *name ,const char *val) { D(debugf(4,"-->LDAPOBJECT::at_set:str (%s,%s)",name,val)); int ret=0; // Don't save empty attributes. // \bug - sometimes it should be saved as empty in directroy, sometimes not - // we need something to handle both situations if (strlen(val) == 0) { D(debugf(4,"<--LDAPOBJECT::at_set:str NULL value - not saved")); return 0; } // we must remove extra numbers at the end // to manage multi attribute values // ie we want to add mail not mail3 or mail5 // The number must be removed before we can search // for other dublicates int lenname = strlen(name); char basename[lenname+1]; strcpy (basename,name); char * p=basename+strlen(basename)-1; bool multivalue = false; D(debugf(4,"p=(%c)",*p)); while (isdigit(*p)) { D(debugf(4,"at_set multiattribute value %c",*p)); *p = '\0'; p--; multivalue=true; } // Use at_add instead of at_set if this is multivalue and current index >= 2 if (multivalue) { at_add(basename,val); return ret; } D(debugf(4,"str=(%s) p=(%c)",basename,*p)); // Check for non-ascii char, if attr is not a password field. // \bug : total rewrite when we find out how to handle this problem SSTRING bufb64,bufutf; val = utf_conv (val,bufutf,bufb64); // Got our real name, now search for duplicates SSTRING *it = locateassign(basename); if (it == NULL){ it = new SSTRING(""); atlist.add (it); } it->setfrom (basename); // lowering attribute name only, not the value // we have to lower because comparing the values with strncasecmp // is not enough as the attribute will be indexed by using its name // so we would miss it sometimes it->to_lower(); // if (it->cmp("userpassword")==0) it->append(":"); it->appendf(bufb64.is_filled() ? ":: %s" : ": %s",val); it->strip_end(); // Make sure it is clean D(debugf(4,"<--LDAPOBJECT::at_set:str (%s)",it->get())); return ret; } /*! LDAPOBJECT.at_set Update or add an attribute NUM value. Will replace existing value. */ PUBLIC int LDAPOBJECT::at_set (const char *name ,int val) { D(debugf(4,"-->LDAPOBJECT::at_set:num (%s,%i)",name,val)); int ret=0; SSTRING *it = locateassign(name); if (it == NULL){ it = new SSTRING(""); atlist.add (it); } it->setfrom (name); // lowering attribute name only, not the value it->to_lower(); it->appendf(": %d",val); D(debugf(4,"<--LDAPOBJECT::at_set:num (%s)",it->get())); return ret; } /*! LDAPOBJECT.at_add Add attribute STR value. Should always add a new attr value, even if an attr with same name already exist, to support multivalue fields. (Use at_set to replace attributes.) */ PUBLIC int LDAPOBJECT::at_add (const char *name ,const char *val) { D(debugf(4,"-->LDAPOBJECT::at_add:str (%s,%s)",name,val)); int ret=0; if (strlen(val) == 0) { D(debugf(4,"<--LDAPOBJECT::at_add:str NULL value - not saved")); return ret; } SSTRING bufb64,bufutf; val = utf_conv (val,bufutf,bufb64); SSTRING *it = new SSTRING(name); atlist.add (it); // lowering attribute name only, not the value it->to_lower(); it->appendf(bufb64.is_filled() ? ":: %s" : ": %s",val); it->strip_end(); D(debugf(4,"<--LDAPOBJECT::at_add:str (%s)",it->get())); return ret; } /*! LDAPOBJECT.at_add Add attribute NUM value. Will not replace existing values. */ PUBLIC int LDAPOBJECT::at_add (const char *name ,int val) { D(debugf(4,"-->LDAPOBJECT::at_add:num (%s,%i)",name,val)); int ret=0; SSTRING *it = new SSTRING(name); atlist.add (it); // lowering attribute name only, not the value it->to_lower(); it->appendf(": %d",val); D(debugf(4,"<--LDAPOBJECT::at_set:num (%s)",it->get())); return ret; } /*! LDAPOBJECT.at_del Delete all instances of the named attribute. */ PUBLIC int LDAPOBJECT::at_del (const char *name) { D(debugf(4,"-->LDAPOBJECT::at_del (%s)",name)); int ret=0; while (1){ SSTRING *it = locateassign (name); if (it == NULL) break; ret = atlist.remove_del(it); D(debugf(3,":at_del: Deleting (%s)",name)); } D(debugf(4,"<--LDAPOBJECT::at_del (%s)",name)); return ret; } /**************** Objectclasses ****************/ /*! LDAPOBJECT.oc_list Copy objectclass names to the list. Return number of items found. */ PUBLIC int LDAPOBJECT::oc_list (SSTRINGS&lst) { int n =oclist.getnb(); for (int i=0; iget(),':',tb); name = tb.getitem(1)->get(); lst.add ( new SSTRING(name) ); D(debugf(7,"---LDAPOBJECT::oc_list += (%s)",name)); } D(debugf(4,"---LDAPOBJECT::oc_list = (%i)",n)); return n; } /*! LDAPOBJECT.oc_add Add named objectclass. */ PUBLIC int LDAPOBJECT::oc_add (const char *val) { if (val != NULL && val[0] != '\0'){ SSTRING *buf = new SSTRING; buf->setfromf ("objectClass: %s",val); // Make sure it is not already there if (oclist.lookup(buf->get())==-1){ oclist.add(buf); }else{ delete buf; } } return 0; } PUBLIC int LDAPOBJECT::oc_add (const SSTRING &val) { return oc_add (val.get()); } /* Add the objectclass definition associated with this profile */ PUBLIC void LDAPOBJECT::addclasses () { SSTRINGS tb; str_splitline (classes.get(),' ',tb); for (int i=0; iget()); } } /*! LDAPOBJECT.oc_del Delete named objectclass. */ PUBLIC int LDAPOBJECT::oc_del (const char *name) { int ret=0; // Locate named class and remove it if found int n = oclist.lookup(name); if (n >= 0) ret = oclist.remove_del(oclist.getitem(n)); else ret = -1; D(debugf(4,"---LDAPOBJECT::oc_del (%s) = (%i)", name, ret)); return ret; } /*! LDAPOBJECT.oc_getval Return the name of objectclass n Return NULL if not found. */ PUBLIC const char* LDAPOBJECT::oc_getval (int num) { SSTRINGS tb; const char *val = NULL; SSTRING *it = oclist.getitem(num); if (it){ str_splitline(it->get(),':',tb); val = tb.getitem(1)->get(); } // Remove frontspace str_skip(val); D(debugf(6,"---LDAPOBJECT::oc_getval (%i) = (%s)\n",num,val)); return val; } /*! LDAPOBJECT.oc_exist Return !=0 if specified objectclass exist in current object */ PUBLIC int LDAPOBJECT::oc_exist (const char *name) { int ret; SSTRING s; s.setfromf("objectClass: %s",name); // Lookup objectclass int n = oclist.lookup(&s); if (n >= 0) ret = 1; else ret = 0; D(debugf(4,"---LDAPOBJECT::oc_exist (%s) = (%i)", name,ret)); return ret; } /******************** Utility functions ********************/ /*! LDAPOBJECT.locateassign Lookup attribute and return in "raw" SSTRING format (name: value) Return NULL if not found. */ PUBLIC SSTRING* LDAPOBJECT::locateassign (const char *key) { return LDAPOBJECT::locateassign (key,1); }; /*! LDAPOBJECT.locateassign Lookup attribute number k and return in "raw" SSTRING format (name: value) Return NULL if not found. k is >=1 and is the number of the attribute we are looking for 1 means the first 3 means the third.... usefull for example if many mail attributes for the same person */ PUBLIC SSTRING* LDAPOBJECT::locateassign (const char *key, int k) { int lenkey = strlen(key); int k2=0; SSTRING *ret = NULL; int n = atlist.getnb(); for (int i=0; iget(); pt = str_skip(pt); if (strncasecmp(pt,key,lenkey)==0 && pt[lenkey] == ':'){ // 2.0 k2++; if (k==k2) { // k th attribute of value key, this is the good one ret = it; break; } } } return ret; } /*! LDAPOBJECT.locate Locate all attributes with the given name. Return number found. */ PUBLIC int LDAPOBJECT::locate (const char *key, SSTRINGS &lst) { int lenkey = strlen(key); int ret = 0; int n = atlist.getnb(); for (int i=0; iget(); pt = str_skip(pt); if (strncasecmp(pt,key,lenkey)==0 && pt[lenkey] == ':'){ // Strip the key pt += strlen(key)+1; pt = str_skip (pt); lst.add(new SSTRING (pt)); ret++; } } return ret; } /*! LDAPOBJECT.ldif_splitline Split ldif formatted stringline into attribute and value components. */ PUBLIC int LDAPOBJECT::ldif_splitline ( const char *ldif, SSTRING &name, SSTRING &val) { int ret = -1; const char *pt = strchr(ldif,':'); if (pt != NULL) { // Extract name name.setfrom (ldif,(pt-ldif)); name.strip_end(); // Extract value pt++; if (*pt == ':'){ // base64 and potentially utf-8 char tmp[strlen(pt)]; pt += 2; if (base64_decode (tmp,sizeof(tmp),pt)==-1){ val = pt; val.strip_end(); }else{ utf_convfromutf (tmp,val); // fprintf (stderr,"convfrom :%s: :%s:\n",tmp,val.get()); } }else{ val = pt+1; val.strip_end(); } ret = 0; } return ret; } /*************** Utilities ****************/ /*! Load LDAP configuration from CONFDB profile object */ PUBLIC int LDAPOBJECT::load_profile(const char *profile_name) { D(debugf(4,"LDAPOBJECT::load_profile(%s)",profile_name)); int ret = -1; CONFDB c_ldapconf(f_ldapconf); char fpath[PATH_MAX]; /* Load profile */ sprintf(fpath,"%s/%s",PROFILE_DIR,profile_name); CONFIG_FILE f_profile (fpath,help_ldap ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","root",0600 ,subsys_ldap); c_profile = new CONFDB (f_profile); bindname = c_profile->getval ("profile","bind","formclient"); formname = c_profile->getval ("profile","form","formclient"); dn_prefix = c_profile->getval ("profile","prefix","ou=People"); group_prefix = c_profile->getval ("profile","groupprefix","ou=Group"); primary_key = c_profile->getval ("profile","primarykey","uid"); crypt_hash = c_profile->getval ("profile","crypt_hash",""); classes = c_profile->getval ("profile","classes",""); bind.protocol = c_profile->getvalnum ("profile","protocol",2); /* Load binding */ sprintf (fpath,"%s/%s",DBBIND_DIR,this->bindname.get()); CONFIG_FILE f_bind (fpath,help_ldap ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","root",0600 ,subsys_ldap); CONFDB c_bind (f_bind); /* Set default binding */ bind.host = c_bind.getval("ldap","host"); bind.port = c_bind.getval("ldap","port"); bind.base = c_bind.getval("ldap","base"); bind.dn = c_bind.getval("ldap","binddn"); bind.pw = c_bind.getval("ldap","bindpw"); bind.usesasl = c_bind.getvalnum("ldap","usesasl",0) != 0; /* Load form */ sprintf (fpath,"%s/%s",DBFORM_DIR,formname.get()); CONFIG_FILE f_form (fpath,help_ldap ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","root",0600 ,subsys_ldap); delete form; form = new CONFDB(f_form); ret = 0; return ret; } /*! Set new password for the named user. Return error message if update failed. (normally caused by denied access) */ PUBLIC int LDAPOBJECT::set_password (const char *username,const char *password) { int ret=0; SSTRINGS resmsg; command_line.setfrom(""); if (!mode_openldap_version.cmp("2")) { // OpenLDAP 2.x command_line.appendf(" -s %s",password); //2.0 1.0= -e command_line.appendf(" uid=%s,%s,%s",username,dn_prefix.get(),bind.base.get()); } else { // OpenLDAP 1.x if (!crypt_hash.is_empty()) command_line.appendf(" -H %s",crypt_hash.get()); command_line.appendf(" -e %s",password); command_line.appendf(" -t uid=%s,%s,%s",username,dn_prefix.get(),bind.base.get()); } ret = command ("ldappasswd",resmsg); return ret; } /*! LDAPOBJECT.export_confdb Export data to CONFDB object. */ PUBLIC int LDAPOBJECT::export_confdb(CONFDB &c_data) { int ret = 0; SSTRINGS at_names; const char *prefix = at_get(primary_key.get()); int n = at_list(at_names); // Get all attribute names D(debugf(4,"LDAPOBJECT::export_confdb prefix=%s attrcount=%d\n",prefix,n)); for (int i=0; iget(); // Get attribute key // const char *save_attr=attr; int k=0; c_data.removeall(prefix,attr); // Reset item while (k++<1000) { // avoid infinite loop (should not happen !) const char *val = at_get(attr,k); // Get k attribute value if (!val) break ; //exit the loop if no more value for this attribute SSTRING tmp; val = utf_convfromutf (val,tmp); #if 0 attr=save_attr; SSTRING attrk; if (k>1) { // multivalue attribute // trick : // we will use mail2 mail3 instead of mail attrk.setfrom(attr); attrk.appendf("%d",k); attr=attrk.get(); // will be restored with save_attr } #endif c_data.add(prefix,attr,val); // Add item D(debugf(6,"LDAPOBJECT::export k=%d %s.%s=%s\n",k,prefix,attr,val)); } } return ret; } /*! LDAPOBJECT.import_confdb Import data from CONFDB object. */ PUBLIC int LDAPOBJECT::import_confdb(const CONFDB &c_data, bool reset) { D(debugf(4,"-->LDAPOBJECT::import_confdb")); int ret = 0; const char *bkey; const char *key; const char *val; int n = c_data.getnb(); // Reset/replace all existing attributes before import. if (reset); atlist.remove_all(); // Get all keys from confdb and register their data inside ldapobject for (int i=0; ikey.get(); // Get full key // Split key in minor and major str_splitline(fullkey,'.',tb); bkey = tb.getitem(0)->get(); key = tb.getitem(1)->get(); if (key == NULL) key = bkey; // Get the value val = c_data.getitem(i)->val.get(); // Add attribute at_set(key,val); D(debugf(4,":import_confdb: %s.%s=%s",bkey,key,val)); } D(debugf(4,"<--LDAPOBJECT::import_confdb:")); return ret; } /*! LDAPOBJECT.import_keys Import data from SSTRING_KEYS object. */ PUBLIC int LDAPOBJECT::import_keys(const SSTRING_KEYS &c_data, bool reset) { D(debugf(4,"-->LDAPOBJECT::import_keys")); int ret = 0; int n = c_data.getnb(); // Reset/replace all existing attributes before import. if (reset); atlist.remove_all(); for (int i=0; iget(),k->getobjval()); } D(debugf(4,"<--LDAPOBJECT::import_keys:")); return ret; } /*! Return free uid to available for used by new object */ PUBLIC int LDAPOBJECT::get_free_uid() { int uid = 999; return uid; } /*! Return next free gid to be used by a new object */ PUBLIC int LDAPOBJECT::get_free_gid() { int gid = 999; return gid; }