]> git.ipfire.org Git - thirdparty/sarg.git/blame - userinfo.c
Rename configure.in as configure.ac
[thirdparty/sarg.git] / userinfo.c
CommitLineData
f2ec8c75
FM
1/*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
110ce984 3 * 1998, 2015
f2ec8c75
FM
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
27#include "include/conf.h"
28#include "include/defs.h"
b6b6cb8c 29#include "include/stringbuffer.h"
c4f0ea8f 30#include "include/alias.h"
f2ec8c75
FM
31
32//! The number of users to group in one unit.
33#define USERS_PER_GROUP 50
34
35/*! \brief Group the users in one allocation unit.
36Structure to store a group of users and reduce the number of memory
37allocations.
38*/
39struct usergroupstruct
40{
9bd92830
FM
41 //! The next group of users.
42 struct usergroupstruct *next;
43 //! A group of users.
44 struct userinfostruct list[USERS_PER_GROUP];
45 //! The number of users stored in the list.
46 int nusers;
f2ec8c75
FM
47};
48
93551487
FM
49/*! \brief Hold pointer to scan through the user list.
50*/
51struct userscanstruct
52{
53 //! The group containing the user.
54 struct usergroupstruct *group;
55 //! The index of the user in the group.
56 int index;
57};
58
f2ec8c75
FM
59//! The first group of users.
60static struct usergroupstruct *first_user_group=NULL;
829a53c2
FM
61//! The counter to generate unique user number when ::AnonymousOutputFiles is set.
62static int AnonymousCounter=0;
b6b6cb8c
FM
63//! String buffer to store the user's related constants.
64static StringBufferObject UserStrings=NULL;
c4f0ea8f
FM
65//! User aliases.
66static AliasObject UserAliases=NULL;
f2ec8c75 67
aa6ac9f2 68struct userinfostruct *userinfo_create(const char *userid,const char *ip)
f2ec8c75 69{
9bd92830
FM
70 struct usergroupstruct *group, *last;
71 struct userinfostruct *user;
d09d93c6 72 int i, j, lastuser;
9bd92830
FM
73 int skip;
74 int flen;
75 int count, clen;
76 char cstr[9];
b6b6cb8c
FM
77 char filename[MAX_USER_FNAME_LEN];
78
79 if (!UserStrings) {
80 UserStrings=StringBuffer_Create();
81 if (!UserStrings) {
af961877 82 debuga(__FILE__,__LINE__,_("Not enough memory to store the user's strings\n"));
b6b6cb8c
FM
83 exit(EXIT_FAILURE);
84 }
85 }
9bd92830
FM
86
87 last=NULL;
88 for (group=first_user_group ; group ; group=group->next) {
89 if (group->nusers<USERS_PER_GROUP) break;
90 last=group;
91 }
92
93 if (!group) {
94 group=malloc(sizeof(*group));
95 if (!group) {
af961877 96 debuga(__FILE__,__LINE__,_("Not enough memory to store user \"%s\"\n"),userid);
9bd92830
FM
97 exit(EXIT_FAILURE);
98 }
99 memset(group,0,sizeof(*group));
100 if (last)
101 last->next=group;
102 else
103 first_user_group=group;
104 }
105 user=group->list+group->nusers++;
106
b6b6cb8c
FM
107 user->id=StringBuffer_Store(UserStrings,userid);
108 if (!user->id) {
af961877 109 debuga(__FILE__,__LINE__,_("Not enough memory to store user ID \"%s\"\n"),userid);
b6b6cb8c
FM
110 exit(EXIT_FAILURE);
111 }
112 user->label=user->id; //assign a label to avoid a NULL pointer in case none is provided
aa6ac9f2 113 if (ip) {
acf0b78c
FM
114 /*
115 * IP address is not the same as the user's ID. A separate buffer
116 * must be allocated.
117 */
dc34d345 118 user->id_is_ip=false;
aa6ac9f2
FM
119 user->ip=StringBuffer_Store(UserStrings,ip);
120 } else {
acf0b78c
FM
121 /*
122 * User's IP address share the same buffer as the user's ID.
123 */
dc34d345 124 user->id_is_ip=true;
aa6ac9f2
FM
125 user->ip=user->id;
126 }
9bd92830 127
829a53c2 128 if (AnonymousOutputFiles) {
b6b6cb8c 129 snprintf(filename,sizeof(filename),"%d",AnonymousCounter++);
829a53c2
FM
130 } else {
131 skip=0;
132 j=0;
133 for (i=0 ; userid[i] && j<MAX_USER_FNAME_LEN-1 ; i++) {
134 if (isalnum(userid[i]) || userid[i]=='-' || userid[i]=='_') {
b6b6cb8c 135 filename[j++]=userid[i];
829a53c2
FM
136 skip=0;
137 } else {
138 if (!skip) {
b6b6cb8c 139 filename[j++]='_';
829a53c2
FM
140 skip=1;
141 }
9bd92830
FM
142 }
143 }
b6b6cb8c 144 if (j==0) filename[j++]='_'; //don't leave a file name empty
4754959e 145 flen=j;
b6b6cb8c 146 filename[j]='\0';
829a53c2
FM
147
148 count=0;
149 for (group=first_user_group ; group ; group=group->next) {
150 lastuser=(group->next) ? group->nusers : group->nusers-1;
151 for (i=0 ; i<lastuser ; i++) {
b6b6cb8c 152 if (strcasecmp(filename,group->list[i].filename)==0) {
4754959e 153 clen=sprintf(cstr,"+%X",count++);
829a53c2 154 if (flen+clen<MAX_USER_FNAME_LEN)
b6b6cb8c 155 strcpy(filename+flen,cstr);
829a53c2 156 else
b6b6cb8c 157 strcpy(filename+MAX_USER_FNAME_LEN-clen,cstr);
829a53c2 158 }
9bd92830
FM
159 }
160 }
161 }
b6b6cb8c
FM
162 user->filename=StringBuffer_Store(UserStrings,filename);
163 if (!user->filename)
164 {
af961877 165 debuga(__FILE__,__LINE__,_("Not enough memory to store the file name for user \"%s\"\n"),user->id);
b6b6cb8c
FM
166 exit(EXIT_FAILURE);
167 }
9bd92830
FM
168
169 return(user);
f2ec8c75
FM
170}
171
172void userinfo_free(void)
173{
9bd92830 174 struct usergroupstruct *group, *next;
f2ec8c75 175
9bd92830
FM
176 for (group=first_user_group ; group ; group=next) {
177 next=group->next;
178 free(group);
179 }
180 first_user_group=NULL;
b6b6cb8c
FM
181 StringBuffer_Destroy(&UserStrings);
182}
183
184/*!
185 * Store the user's label.
186 * \param uinfo The user info structure created by userinfo_create().
187 * \param label The string label to store.
188 */
189void userinfo_label(struct userinfostruct *uinfo,const char *label)
190{
191 if (!uinfo) return;
192 if (!UserStrings) return;
193 uinfo->label=StringBuffer_Store(UserStrings,label);
194 if (!uinfo->label) {
af961877 195 debuga(__FILE__,__LINE__,_("Not enough memory to store label \"%s\" of user \"%s\"\n"),label,uinfo->id);
b6b6cb8c
FM
196 exit(EXIT_FAILURE);
197 }
f2ec8c75
FM
198}
199
200struct userinfostruct *userinfo_find_from_file(const char *filename)
201{
9bd92830
FM
202 struct usergroupstruct *group;
203 int i;
204
205 for (group=first_user_group ; group ; group=group->next) {
206 for (i=0 ; i<group->nusers ; i++)
207 if (strcmp(filename,group->list[i].filename)==0)
208 return(group->list+i);
209 }
210 return(NULL);
f2ec8c75
FM
211}
212
213struct userinfostruct *userinfo_find_from_id(const char *id)
214{
9bd92830
FM
215 struct usergroupstruct *group;
216 int i;
217
218 for (group=first_user_group ; group ; group=group->next) {
219 for (i=0 ; i<group->nusers ; i++)
220 if (strcmp(id,group->list[i].id)==0)
221 return(group->list+i);
222 }
223 return(NULL);
f2ec8c75 224}
93551487 225
05fea6e7
FM
226struct userinfostruct *userinfo_find_from_ip(const char *ip)
227{
228 struct usergroupstruct *group;
229 int i;
230
231 for (group=first_user_group ; group ; group=group->next) {
232 for (i=0 ; i<group->nusers ; i++)
233 if (strcmp(ip,group->list[i].ip)==0)
234 return(group->list+i);
235 }
236 return(NULL);
237}
238
93551487
FM
239/*!
240Start the scanning of the user list.
241
242\return The object to pass to subsequent scanning functions or NULL
243if it failed. The object must be freed with a call to userinfo_stop().
244*/
245userscan userinfo_startscan(void)
246{
247 userscan uscan;
248
249 uscan=malloc(sizeof(*uscan));
250 if (!uscan) return(NULL);
251 uscan->group=first_user_group;
252 uscan->index=0;
253 return(uscan);
254}
255
256/*!
257Free the memory allocated by userinfo_start().
258
259\param uscan The object created by userinfo_start().
260*/
261void userinfo_stopscan(userscan uscan)
262{
263 free(uscan);
264}
265
266/*!
267Get the user pointed to by the object and advance the object
268to the next user.
269
270\param uscan The object created by userinfo_start().
271
272\return The user in the list or NULL if the end of the list
273is reached.
274*/
275struct userinfostruct *userinfo_advancescan(userscan uscan)
276{
277 struct userinfostruct *uinfo;
278
279 if (!uscan) return(NULL);
280 if (!uscan->group) return(NULL);
281 if (uscan->index<0 || uscan->index>=uscan->group->nusers) return(NULL);
282
283 uinfo=uscan->group->list+uscan->index;
284
285 ++uscan->index;
286 if (uscan->index>=uscan->group->nusers) {
287 uscan->group=uscan->group->next;
288 uscan->index=0;
289 }
290 return(uinfo);
291}
a58e6d54
FM
292
293/*!
294Clear the general purpose flag from all the user's info.
295*/
296void userinfo_clearflag(void)
297{
298 struct usergroupstruct *group;
299 int i;
300
301 for (group=first_user_group ; group ; group=group->next) {
302 for (i=0 ; i<group->nusers ; i++)
303 group->list[i].flag=0;
304 }
305}
306
c4f0ea8f
FM
307/*!
308Read the file containing the user names to alias in the report.
309
310\param Filename The name of the file.
311*/
312void read_useralias(const char *Filename)
313{
314 FILE *fi;
315 longline line;
316 char *buf;
317
af961877 318 if (debug) debuga(__FILE__,__LINE__,_("Reading user alias file \"%s\"\n"),Filename);
c4f0ea8f
FM
319
320 UserAliases=Alias_Create();
321 if (!UserAliases) {
af961877 322 debuga(__FILE__,__LINE__,_("Cannot store user's aliases\n"));
c4f0ea8f
FM
323 exit(EXIT_FAILURE);
324 }
325
326 fi=fopen(Filename,"rt");
327 if (!fi) {
af961877 328 debuga(__FILE__,__LINE__,_("Cannot read user name alias file \"%s\": %s\n"),Filename,strerror(errno));
c4f0ea8f
FM
329 exit(EXIT_FAILURE);
330 }
331
332 if ((line=longline_create())==NULL) {
af961877 333 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),Filename);
c4f0ea8f
FM
334 exit(EXIT_FAILURE);
335 }
336
337 while ((buf=longline_read(fi,line)) != NULL) {
338 if (Alias_Store(UserAliases,buf)<0) {
af961877 339 debuga(__FILE__,__LINE__,_("While reading \"%s\"\n"),Filename);
c4f0ea8f
FM
340 exit(EXIT_FAILURE);
341 }
342 }
343
344 longline_destroy(&line);
204781f4 345 if (fclose(fi)==EOF) {
af961877 346 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),Filename,strerror(errno));
204781f4
FM
347 exit(EXIT_FAILURE);
348 }
c4f0ea8f
FM
349
350 if (debug) {
af961877 351 debuga(__FILE__,__LINE__,_("List of user names to alias:\n"));
c4f0ea8f
FM
352 Alias_PrintList(UserAliases);
353 }
354}
355
356/*!
357Free the memory allocated by read_useralias().
358*/
359void free_useralias(void)
360{
361 Alias_Destroy(&UserAliases);
362}
363
364/*!
365Replace the user's name or ID by an alias if one is defined.
366
367\param user The user's name or ID as extracted from the report.
368*/
369const char *process_user(const char *user)
370{
371 user=Alias_Replace(UserAliases,user);
372 return(user);
373}