]> git.ipfire.org Git - thirdparty/sarg.git/blob - userinfo.c
Generate redirector log even if -d is not given
[thirdparty/sarg.git] / userinfo.c
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
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/stringbuffer.h"
30 #include "include/alias.h"
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.
36 Structure to store a group of users and reduce the number of memory
37 allocations.
38 */
39 struct usergroupstruct
40 {
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;
47 };
48
49 /*! \brief Hold pointer to scan through the user list.
50 */
51 struct 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
59 //! The first group of users.
60 static struct usergroupstruct *first_user_group=NULL;
61 //! The counter to generate unique user number when ::AnonymousOutputFiles is set.
62 static int AnonymousCounter=0;
63 //! String buffer to store the user's related constants.
64 static StringBufferObject UserStrings=NULL;
65 //! User aliases.
66 static AliasObject UserAliases=NULL;
67
68 struct userinfostruct *userinfo_create(const char *userid,const char *ip)
69 {
70 struct usergroupstruct *group, *last;
71 struct userinfostruct *user;
72 int i, j, lastuser;
73 int skip;
74 int flen;
75 int count, clen;
76 char cstr[9];
77 char filename[MAX_USER_FNAME_LEN];
78
79 if (!UserStrings) {
80 UserStrings=StringBuffer_Create();
81 if (!UserStrings) {
82 debuga(__FILE__,__LINE__,_("Not enough memory to store the user's strings\n"));
83 exit(EXIT_FAILURE);
84 }
85 }
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) {
96 debuga(__FILE__,__LINE__,_("Not enough memory to store user \"%s\"\n"),userid);
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
107 user->id=StringBuffer_Store(UserStrings,userid);
108 if (!user->id) {
109 debuga(__FILE__,__LINE__,_("Not enough memory to store user ID \"%s\"\n"),userid);
110 exit(EXIT_FAILURE);
111 }
112 user->label=user->id; //assign a label to avoid a NULL pointer in case none is provided
113 if (ip) {
114 /*
115 * IP address is not the same as the user's ID. A separate buffer
116 * must be allocated.
117 */
118 user->id_is_ip=false;
119 user->ip=StringBuffer_Store(UserStrings,ip);
120 } else {
121 /*
122 * User's IP address share the same buffer as the user's ID.
123 */
124 user->id_is_ip=true;
125 user->ip=user->id;
126 }
127
128 if (AnonymousOutputFiles) {
129 snprintf(filename,sizeof(filename),"%d",AnonymousCounter++);
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]=='_') {
135 filename[j++]=userid[i];
136 skip=0;
137 } else {
138 if (!skip) {
139 filename[j++]='_';
140 skip=1;
141 }
142 }
143 }
144 if (j==0) filename[j++]='_'; //don't leave a file name empty
145 flen=j;
146 filename[j]='\0';
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++) {
152 if (strcasecmp(filename,group->list[i].filename)==0) {
153 clen=sprintf(cstr,"+%X",count++);
154 if (flen+clen<MAX_USER_FNAME_LEN)
155 strcpy(filename+flen,cstr);
156 else
157 strcpy(filename+MAX_USER_FNAME_LEN-clen,cstr);
158 }
159 }
160 }
161 }
162 user->filename=StringBuffer_Store(UserStrings,filename);
163 if (!user->filename)
164 {
165 debuga(__FILE__,__LINE__,_("Not enough memory to store the file name for user \"%s\"\n"),user->id);
166 exit(EXIT_FAILURE);
167 }
168
169 return(user);
170 }
171
172 void userinfo_free(void)
173 {
174 struct usergroupstruct *group, *next;
175
176 for (group=first_user_group ; group ; group=next) {
177 next=group->next;
178 free(group);
179 }
180 first_user_group=NULL;
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 */
189 void 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) {
195 debuga(__FILE__,__LINE__,_("Not enough memory to store label \"%s\" of user \"%s\"\n"),label,uinfo->id);
196 exit(EXIT_FAILURE);
197 }
198 }
199
200 struct userinfostruct *userinfo_find_from_file(const char *filename)
201 {
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);
211 }
212
213 struct userinfostruct *userinfo_find_from_id(const char *id)
214 {
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);
224 }
225
226 struct 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
239 /*!
240 Start the scanning of the user list.
241
242 \return The object to pass to subsequent scanning functions or NULL
243 if it failed. The object must be freed with a call to userinfo_stop().
244 */
245 userscan 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 /*!
257 Free the memory allocated by userinfo_start().
258
259 \param uscan The object created by userinfo_start().
260 */
261 void userinfo_stopscan(userscan uscan)
262 {
263 free(uscan);
264 }
265
266 /*!
267 Get the user pointed to by the object and advance the object
268 to 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
273 is reached.
274 */
275 struct 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 }
292
293 /*!
294 Clear the general purpose flag from all the user's info.
295 */
296 void 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
307 /*!
308 Read the file containing the user names to alias in the report.
309
310 \param Filename The name of the file.
311 */
312 void read_useralias(const char *Filename)
313 {
314 FileObject *fi;
315 longline line;
316 char *buf;
317
318 if (debug) debuga(__FILE__,__LINE__,_("Reading user alias file \"%s\"\n"),Filename);
319
320 UserAliases=Alias_Create();
321 if (!UserAliases) {
322 debuga(__FILE__,__LINE__,_("Cannot store user's aliases\n"));
323 exit(EXIT_FAILURE);
324 }
325
326 fi=FileObject_Open(Filename);
327 if (!fi) {
328 debuga(__FILE__,__LINE__,_("Cannot read user name alias file \"%s\": %s\n"),Filename,FileObject_GetLastOpenError());
329 exit(EXIT_FAILURE);
330 }
331
332 if ((line=longline_create())==NULL) {
333 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),Filename);
334 exit(EXIT_FAILURE);
335 }
336
337 while ((buf=longline_read(fi,line)) != NULL) {
338 if (Alias_Store(UserAliases,buf)<0) {
339 debuga(__FILE__,__LINE__,_("While reading \"%s\"\n"),Filename);
340 exit(EXIT_FAILURE);
341 }
342 }
343
344 longline_destroy(&line);
345 if (FileObject_Close(fi)) {
346 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),Filename,FileObject_GetLastCloseError());
347 exit(EXIT_FAILURE);
348 }
349
350 if (debug) {
351 debuga(__FILE__,__LINE__,_("List of user names to alias:\n"));
352 Alias_PrintList(UserAliases);
353 }
354 }
355
356 /*!
357 Free the memory allocated by read_useralias().
358 */
359 void free_useralias(void)
360 {
361 Alias_Destroy(&UserAliases);
362 }
363
364 /*!
365 Replace 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 */
369 const char *process_user(const char *user)
370 {
371 user=Alias_Replace(UserAliases,user);
372 return(user);
373 }