"Fossies" - the Fresh Open Source Software Archive

Member "sarg-2.4.0/usertab.c" (22 Dec 2019, 14691 Bytes) of package /linux/privat/sarg-2.4.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "usertab.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.11_vs_2.4.0.

    1 /*
    2  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
    3  *                                                            1998, 2015
    4  *
    5  * SARG donations:
    6  *      please look at http://sarg.sourceforge.net/donations.php
    7  * Support:
    8  *     http://sourceforge.net/projects/sarg/forums/forum/363374
    9  * ---------------------------------------------------------------------
   10  *
   11  *  This program is free software; you can redistribute it and/or modify
   12  *  it under the terms of the GNU General Public License as published by
   13  *  the Free Software Foundation; either version 2 of the License, or
   14  *  (at your option) any later version.
   15  *
   16  *  This program is distributed in the hope that it will be useful,
   17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19  *  GNU General Public License for more details.
   20  *
   21  *  You should have received a copy of the GNU General Public License
   22  *  along with this program; if not, write to the Free Software
   23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   24  *
   25  */
   26 /*!\file
   27 \brief Provide a meanigfull name instead of the user ID or IP address shown in the
   28 reports.
   29 */
   30 
   31 #include "include/conf.h"
   32 #include "include/defs.h"
   33 
   34 #ifdef HAVE_LDAP_H
   35 #define LDAP_DEPRECATED 1
   36 
   37 #include <ldap.h>
   38 #include <ldap_cdefs.h>
   39 #include <ldap_features.h>
   40 
   41 #if defined(HAVE_ICONV_H)
   42 #include <iconv.h>
   43 #define USE_ICONV 1
   44 #endif //HAVE_ICONV_H
   45 
   46 #endif //HAVE_LDAP_H
   47 
   48 /*!
   49 The possible sources to map the user ID or IP address to the name to display
   50 in the reports.
   51 */
   52 enum UserTabEnum
   53 {
   54     //! Users matched against the ::UserTabFile file.
   55     UTT_File,
   56     //! Users matched agains a LDAP.
   57     UTT_Ldap,
   58     //! No user matching performed.
   59     UTT_None
   60 };
   61 
   62 /*!
   63 Tell the database source to use to map the user ID or IP address to a meaningfull
   64 name.
   65 */
   66 enum UserTabEnum which_usertab=UTT_None;
   67 
   68 static char *userfile=NULL;
   69 
   70 #ifdef HAVE_LDAP_H
   71 static LDAP *ldap_handle=NULL;
   72 #endif //HAVE_LDAP_H
   73 
   74 #ifdef USE_ICONV
   75 //! iconv conversion descriptor to convert the string returned by LDAP.
   76 static iconv_t ldapiconv=(iconv_t)-1;
   77 //! Buffer to store the converted string.
   78 static char *ldapconvbuffer=NULL;
   79 //! Size of the converted string buffer.
   80 static int ldapconvbuffersize=0;
   81 #endif
   82 
   83 /*!
   84 Read the \a UserTabFile database.
   85 
   86 The file contains the IP address or ID of the user then some spaces and
   87 the real name of the user to show in the report.
   88 
   89 Any trailing space or tabulation is removed from the real name. The user ID or IP cannot contain
   90 a space or a tabulation but it may contain any other character, including the colon that was
   91 forbidden in the past. That change was made to allow IPv6 addresses.
   92 
   93 The file may contain comments if the line starts with a #.
   94 
   95 \param UserTabFile The name of the file to read.
   96 */
   97 static void init_file_usertab(const char *UserTabFile)
   98 {
   99     FILE *fp_usr;
  100     long int nreg;
  101     char buf[MAXLEN];
  102     int z1, z2;
  103 
  104     if ((fp_usr=fopen(UserTabFile,"r"))==NULL) {
  105         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),UserTabFile,strerror(errno));
  106         exit(EXIT_FAILURE);
  107     }
  108     if (fseek(fp_usr, 0, SEEK_END)==-1) {
  109         debuga(__FILE__,__LINE__,_("Failed to move till the end of file \"%s\": %s\n"),UserTabFile,strerror(errno));
  110         exit(EXIT_FAILURE);
  111     }
  112     nreg = ftell(fp_usr);
  113     if (nreg<0) {
  114         debuga(__FILE__,__LINE__,_("Cannot get the size of file \"%s\"\n"),UserTabFile);
  115         exit(EXIT_FAILURE);
  116     }
  117     nreg += 100;
  118     if (fseek(fp_usr, 0, SEEK_SET)==-1) {
  119         debuga(__FILE__,__LINE__,_("Failed to rewind file \"%s\": %s\n"),UserTabFile,strerror(errno));
  120         exit(EXIT_FAILURE);
  121     }
  122     if ((userfile=(char *) malloc(nreg))==NULL){
  123         debuga(__FILE__,__LINE__,_("ERROR: Cannot load. Memory fault\n"));
  124         exit(EXIT_FAILURE);
  125     }
  126     userfile[0]='\t';
  127     z2=1;
  128     while(fgets(buf,sizeof(buf),fp_usr)!=NULL) {
  129         if (buf[0]=='#') continue;
  130         fixendofline(buf);
  131         z1=0;
  132         while(buf[z1] && (unsigned char)buf[z1]>' ') {
  133             if (z2+3>=nreg) { //need at least 3 additional bytes for the minimum string "\n\t\0"
  134                 debuga(__FILE__,__LINE__,_("The list of users is too long in file \"%s\"\n"),UserTabFile);
  135                 exit(EXIT_FAILURE);
  136             }
  137             userfile[z2++]=buf[z1++];
  138         }
  139         while(buf[z1] && (unsigned char)buf[z1]<=' ') z1++;
  140         userfile[z2++]='\n';
  141         while(buf[z1] && (unsigned char)buf[z1]>=' ') {
  142             if (z2+2>=nreg) { //need at least 2 additional bytes for "\t\0"
  143                 debuga(__FILE__,__LINE__,_("The list of users is too long in file \"%s\"\n"),UserTabFile);
  144                 exit(EXIT_FAILURE);
  145             }
  146             userfile[z2++]=buf[z1++];
  147         }
  148         while(userfile[z2-1]==' ') z2--;
  149         userfile[z2++]='\t';
  150     }
  151     userfile[z2]='\0';
  152     if (fclose(fp_usr)==EOF) {
  153         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),UserTabFile,strerror(errno));
  154         exit(EXIT_FAILURE);
  155     }
  156 }
  157 
  158 /*!
  159 Get the real name of the user from the usertab file read by init_file_usertab().
  160 
  161 \param user The user ID or IP address to search.
  162 \param name The buffer to store the real name of the user.
  163 \param namelen The size of the \a name buffer.
  164 
  165 If the user ID or IP address isn't found, the output buffer \a name contains
  166 the unmatched input string.
  167 */
  168 static void get_usertab_name(const char *user,char *name,int namelen)
  169 {
  170     char warea[MAXLEN];
  171     char *str;
  172 
  173     sprintf(warea,"\t%s\n",user);
  174     if ((str=(char *) strstr(userfile,warea)) == (char *) NULL ) {
  175         safe_strcpy(name,user,namelen);
  176     } else {
  177         str=strchr(str+1,'\n');
  178         str++;
  179         namelen--;
  180         for (z1=0; *str != '\t' && z1<namelen ; z1++) {
  181             name[z1]=*str++;
  182         }
  183         name[z1]='\0';
  184     }
  185 }
  186 
  187 #ifdef HAVE_LDAP_H
  188 /*!
  189  * \brief Connect to the LDAP server
  190  */
  191 static void connect_ldap(void)
  192 {
  193     char *ldapuri;
  194     LDAPURLDesc url;
  195     int rc;
  196 
  197     if (ldap_handle)
  198         ldap_unbind(ldap_handle);
  199 
  200     /* Setting LDAP connection and initializing cache */
  201     memset(&url,0,sizeof(url));
  202     url.lud_scheme = "ldap";
  203     url.lud_host = LDAPHost;
  204     url.lud_port = LDAPPort;
  205     url.lud_scope = LDAP_SCOPE_DEFAULT;
  206     ldapuri = ldap_url_desc2str(&url);
  207     if (ldapuri==NULL) {
  208         debuga(__FILE__,__LINE__,_("Cannot prepare ldap URI for server %s on port %d\n"),LDAPHost,LDAPPort);
  209         exit(EXIT_FAILURE);
  210     }
  211 
  212     rc = ldap_initialize(&ldap_handle, ldapuri);
  213     if (rc != LDAP_SUCCESS) {
  214         debuga(__FILE__,__LINE__,_("Unable to connect to LDAP server %s on port %d: %d (%s)\n"), LDAPHost, LDAPPort, rc, ldap_err2string(rc));
  215         exit(EXIT_FAILURE);
  216     }
  217     ldap_memfree(ldapuri);
  218 
  219     if (ldap_set_option(ldap_handle, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) != LDAP_OPT_SUCCESS) {
  220         debuga(__FILE__,__LINE__,_("Could not disable LDAP_OPT_REFERRALS\n"));
  221         exit(EXIT_FAILURE);
  222     }
  223     int ldap_protocol_version = LDAPProtocolVersion;
  224     if (ldap_set_option(ldap_handle, LDAP_OPT_PROTOCOL_VERSION, &ldap_protocol_version) != LDAP_SUCCESS) {
  225         debuga(__FILE__,__LINE__,_("Could not set LDAP protocol version %d\n"), ldap_protocol_version);
  226         exit(EXIT_FAILURE);
  227     }
  228 
  229     /* Bind to the LDAP server. */
  230     rc = ldap_simple_bind_s( ldap_handle, LDAPBindDN, LDAPBindPW );
  231     if ( rc != LDAP_SUCCESS ) {
  232         debuga(__FILE__,__LINE__,_("Cannot bind to LDAP server: %s\n"), ldap_err2string(rc));
  233         exit(EXIT_FAILURE);
  234     }
  235 }
  236 
  237 /*!
  238 Initialize the communication with the LDAP server whose name is in
  239 ::LDAPHost and connect to port ::LDAPPort.
  240 */
  241 static void init_ldap_usertab(void)
  242 {
  243     ldap_handle = NULL;
  244     connect_ldap();
  245 
  246 #ifdef USE_ICONV
  247     // prepare for the string conversion
  248     if (LDAPNativeCharset[0]!='\0') {
  249         ldapiconv = iconv_open( LDAPNativeCharset, "UTF-8" );
  250         if (ldapiconv==(iconv_t)-1) {
  251             debuga(__FILE__,__LINE__,_("iconv cannot convert from UTF-8 to %s: %s\n"),LDAPNativeCharset,strerror(errno));
  252             exit(EXIT_FAILURE);
  253         }
  254     }
  255     ldapconvbuffer=NULL;
  256     ldapconvbuffersize=0;
  257 #endif
  258 
  259     /* Initializing cache */
  260     init_cache();
  261 }
  262 
  263 const char * charset_convert( const char * str_in, const char * charset_to )
  264 {
  265 #ifdef USE_ICONV
  266     size_t return_value;
  267     const char * str_in_orig;
  268     char * str_out;
  269     size_t str_in_len;
  270     size_t str_out_len;
  271 
  272     str_in_len = strlen( str_in ) + 1;//process the terminating NUL too
  273     str_out_len = ( 2 * str_in_len );
  274     if (ldapconvbuffer==NULL || ldapconvbuffersize<str_out_len) {
  275         ldapconvbuffersize=str_out_len;
  276         str_out = realloc(ldapconvbuffer,ldapconvbuffersize);
  277         if (!str_out) {
  278             debuga(__FILE__,__LINE__,_("Not enough memory to convert a LDAP returned string: %lu bytes required\n"),(unsigned long int)str_out_len);
  279             exit(EXIT_FAILURE);
  280         }
  281         ldapconvbuffer = str_out;
  282     } else {
  283         str_out = ldapconvbuffer;
  284         str_out_len = ldapconvbuffersize;
  285     }
  286     str_in_orig = str_in;
  287     return_value = iconv(ldapiconv, (ICONV_CONST char **)&str_in, &str_in_len, &str_out, &str_out_len );
  288     if ( return_value == ( size_t ) -1 ) {
  289         /* TRANSLATORS: The message is followed by the reason for the failure. */
  290         debuga(__FILE__,__LINE__,_("iconv failed on string \"%s\":\n"),str_in_orig);
  291         switch ( errno ) {
  292             /* See "man 3 iconv" for an explanation. */
  293             case EILSEQ:
  294                 debuga(__FILE__,__LINE__,_("Invalid multibyte sequence.\n"));
  295                 break;
  296             case EINVAL:
  297                 debuga(__FILE__,__LINE__,_("Incomplete multibyte sequence.\n"));
  298                 break;
  299             case E2BIG:
  300                 debuga(__FILE__,__LINE__,_("No more room.\n"));
  301                 break;
  302             default:
  303                 debuga(__FILE__,__LINE__,_("Error: %s.\n"),strerror( errno ));
  304         }
  305         exit(EXIT_FAILURE);
  306     }
  307     return(ldapconvbuffer);
  308 #else //USE_ICONV
  309     return(str_in);
  310 #endif //USE_ICONV
  311 }
  312 
  313 /*!
  314 Get the real name of a user by searching the userlogin (user ID) in a LDAP.
  315 
  316 \param userlogin The user ID to search.
  317 \param name The buffer to store the real name of the user.
  318 \param namelen The size of the \a name buffer.
  319 
  320 If the user ID isn't found in the LDAP, the output buffer \a name contains
  321 the unmatched input string.
  322 */
  323 static void get_ldap_name(const char *userlogin,char *mappedname,int namelen)
  324 {
  325     /* Start searching username in cache */
  326     // According to rfc2254 section 4, only *()\ and NUL must be escaped. This list is rather conservative !
  327     const char strictchars[] = " ~!@^&(){}|<>?:;\"\'\\[]`,\r\n\0";
  328     char filtersearch[256], *searched_in_cache;
  329     char searchloginname[3*MAX_USER_LEN];
  330     char *attr, **vals;
  331     const char *attr_out;
  332     const char *ptr;
  333     LDAPMessage *result, *e;
  334     BerElement *ber;
  335     int i;
  336     int slen;
  337     int rc;
  338     char *attrs[2];
  339 
  340     searched_in_cache = search_in_cache(userlogin);
  341     if (searched_in_cache!=NULL) {
  342         safe_strcpy(mappedname, searched_in_cache,namelen);
  343         return;
  344     }
  345 
  346     // escape characters according to rfc2254 section 4
  347     for (slen=0 , ptr=userlogin ; slen<sizeof(searchloginname)-1 && *ptr ; ptr++) {
  348         if (strchr(strictchars,*ptr)) {
  349             if (slen+3>=sizeof(searchloginname)-1) break;
  350             slen+=sprintf(searchloginname+slen,"\\%02X",*ptr);
  351         } else {
  352             searchloginname[slen++]=*ptr;
  353         }
  354     }
  355     searchloginname[slen]='\0';
  356 
  357     i=0;
  358     ptr=LDAPFilterSearch;
  359     while (i<sizeof(filtersearch)-1 && *ptr) {
  360         if (ptr[0]=='%' && ptr[1]=='s') {
  361             if (i+slen>=sizeof(filtersearch)) break;
  362             memcpy(filtersearch+i,searchloginname,slen);
  363             i+=slen;
  364             ptr+=2;
  365         } else {
  366             filtersearch[i++]=*ptr++;
  367         }
  368     }
  369     filtersearch[i]='\0';
  370 
  371     /* Search record(s) in LDAP base */
  372     attrs[0]=LDAPTargetAttr;
  373     attrs[1]=NULL;
  374     rc=ldap_search_ext_s(ldap_handle, LDAPBaseSearch, LDAP_SCOPE_SUBTREE, filtersearch, attrs, 0, NULL, NULL, NULL, -1, &result);
  375     if (rc != LDAP_SUCCESS) {
  376         /*
  377          * We know the connection was successfully established once. If it fails now,
  378          * it may be because the server timed out between two requests or because
  379          * there is an error in the request.
  380          *
  381          * Just in case the failure is due to a timeout, we try to connect and send
  382          * the query again.
  383          */
  384         connect_ldap();
  385         rc=ldap_search_ext_s(ldap_handle, LDAPBaseSearch, LDAP_SCOPE_SUBTREE, filtersearch, attrs, 0, NULL, NULL, NULL, -1, &result);
  386         if (rc != LDAP_SUCCESS) {
  387             debuga(__FILE__,__LINE__,_("LDAP search failed: %s\nlooking for \"%s\" at or below \"%s\"\n"), ldap_err2string(rc),filtersearch,LDAPBaseSearch);
  388             safe_strcpy(mappedname,userlogin,namelen);
  389             return;
  390         }
  391     }
  392 
  393     if (!(e = ldap_first_entry(ldap_handle, result))) {
  394         insert_to_cache(userlogin, userlogin);
  395         safe_strcpy(mappedname, userlogin,namelen);
  396         return;
  397     }
  398 
  399     for (attr = ldap_first_attribute(ldap_handle, e, &ber); attr != NULL; attr = ldap_next_attribute(ldap_handle, e, ber)) {
  400         if (!strcasecmp(attr, LDAPTargetAttr)) {
  401             if ((vals = (char **)ldap_get_values(ldap_handle, e, attr))!=NULL) {
  402                 attr_out = charset_convert( vals[0], LDAPNativeCharset );
  403                 insert_to_cache(userlogin, attr_out);
  404                 safe_strcpy(mappedname, attr_out, namelen);
  405                 ldap_memfree(vals);
  406             }
  407             ldap_memfree(attr);
  408             break;
  409         }
  410         ldap_memfree(attr);
  411     }
  412     ldap_msgfree(result);
  413 }
  414 #endif //HAVE_LDAP_H
  415 
  416 /*!
  417 Initialize the data used by user_find().
  418 
  419 If \a UserTabFile is ldap, the user ID is fetched from a LDAP server.
  420 
  421 \param UserTabFile The name of the file to read or ldap. If it is empty, the function does nothing.
  422 
  423 \note The memory and resources allocated by this function must be released by
  424 a call to close_usertab().
  425 */
  426 void init_usertab(const char *UserTabFile)
  427 {
  428     if (strcmp(UserTabFile, "ldap") == 0) {
  429         if (debug) {
  430             /* TRANSLATORS: The %s may be the string "ldap" or a file name.*/
  431             debuga(__FILE__,__LINE__,_("Loading User table from \"%s\"\n"),UserTabFile);
  432         }
  433 #ifdef HAVE_LDAP_H
  434         which_usertab=UTT_Ldap;
  435         init_ldap_usertab();
  436 #else
  437         debuga(__FILE__,__LINE__,_("LDAP module not compiled in sarg\n"));
  438         exit(EXIT_FAILURE);
  439 #endif //HAVE_LDAP_H
  440     } else if (UserTabFile[0] != '\0') {
  441         if (debug)
  442             debuga(__FILE__,__LINE__,_("Loading User table from \"%s\"\n"),UserTabFile);
  443         which_usertab=UTT_File;
  444         init_file_usertab(UserTabFile);
  445     } else {
  446         which_usertab=UTT_None;
  447     }
  448 }
  449 
  450 /*!
  451 Find the real name of the user with the ID or IP address in \a userlogin. The name is fetched
  452 from the source initialized by init_usertab().
  453 
  454 The usertab data must have been initialized by init_usertab().
  455 
  456 \param mappedname A buffer to write the real name of the user.
  457 \param namelen The size of the buffer.
  458 \param userlogin The ID or IP address of the user.
  459 */
  460 void user_find(char *mappedname, int namelen, const char *userlogin)
  461 {
  462     if (which_usertab==UTT_File) {
  463         get_usertab_name(userlogin,mappedname,namelen);
  464     }
  465 #ifdef HAVE_LDAP_H
  466     else if (which_usertab==UTT_Ldap) {
  467         get_ldap_name(userlogin,mappedname,namelen);
  468     }
  469 #endif //HAVE_LDAP_H
  470     else {
  471         safe_strcpy(mappedname,userlogin,namelen);
  472     }
  473 }
  474 
  475 /*!
  476 Free the memory and resources allocated by init_usertab().
  477 */
  478 void close_usertab(void)
  479 {
  480 #ifdef HAVE_LDAP_H
  481     if (ldap_handle) {
  482         destroy_cache();
  483         ldap_unbind(ldap_handle);
  484         ldap_handle=NULL;
  485     }
  486 #endif //HAVE_LDAP_H
  487 #ifdef USE_ICONV
  488     if (ldapiconv!=(iconv_t)-1) {
  489         iconv_close (ldapiconv);
  490         ldapiconv=(iconv_t)-1;
  491     }
  492     if (ldapconvbuffer) {
  493         free(ldapconvbuffer);
  494         ldapconvbuffer=NULL;
  495     }
  496 #endif // USE_ICONV
  497     if (userfile) {
  498         free(userfile);
  499         userfile=NULL;
  500     }
  501 }
  502