]> git.ipfire.org Git - thirdparty/sarg.git/blob - userinfo.c
Add support to decompress xz files
[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 extern struct ReadLogDataStruct ReadFilter;
69 extern char StripUserSuffix[MAX_USER_LEN];
70 extern int StripSuffixLen;
71 extern char *userfile;
72
73 struct userinfostruct *userinfo_create(const char *userid,const char *ip)
74 {
75 struct usergroupstruct *group, *last;
76 struct userinfostruct *user;
77 int i, j, lastuser;
78 int skip;
79 int flen;
80 int count, clen;
81 char cstr[9];
82 char filename[MAX_USER_FNAME_LEN];
83
84 if (!UserStrings) {
85 UserStrings=StringBuffer_Create();
86 if (!UserStrings) {
87 debuga(__FILE__,__LINE__,_("Not enough memory to store the user's strings\n"));
88 exit(EXIT_FAILURE);
89 }
90 }
91
92 last=NULL;
93 for (group=first_user_group ; group ; group=group->next) {
94 if (group->nusers<USERS_PER_GROUP) break;
95 last=group;
96 }
97
98 if (!group) {
99 group=malloc(sizeof(*group));
100 if (!group) {
101 debuga(__FILE__,__LINE__,_("Not enough memory to store user \"%s\"\n"),userid);
102 exit(EXIT_FAILURE);
103 }
104 memset(group,0,sizeof(*group));
105 if (last)
106 last->next=group;
107 else
108 first_user_group=group;
109 }
110 user=group->list+group->nusers++;
111
112 user->id=StringBuffer_Store(UserStrings,userid);
113 if (!user->id) {
114 debuga(__FILE__,__LINE__,_("Not enough memory to store user ID \"%s\"\n"),userid);
115 exit(EXIT_FAILURE);
116 }
117 user->label=user->id; //assign a label to avoid a NULL pointer in case none is provided
118 if (ip) {
119 /*
120 * IP address is not the same as the user's ID. A separate buffer
121 * must be allocated.
122 */
123 user->id_is_ip=false;
124 user->ip=StringBuffer_Store(UserStrings,ip);
125 } else {
126 /*
127 * User's IP address share the same buffer as the user's ID.
128 */
129 user->id_is_ip=true;
130 user->ip=user->id;
131 }
132
133 if (AnonymousOutputFiles) {
134 snprintf(filename,sizeof(filename),"%d",AnonymousCounter++);
135 } else {
136 skip=0;
137 j=0;
138 for (i=0 ; userid[i] && j<MAX_USER_FNAME_LEN-1 ; i++) {
139 if (isalnum(userid[i]) || userid[i]=='-' || userid[i]=='_') {
140 filename[j++]=userid[i];
141 skip=0;
142 } else {
143 if (!skip) {
144 filename[j++]='_';
145 skip=1;
146 }
147 }
148 }
149 if (j==0) filename[j++]='_'; //don't leave a file name empty
150 flen=j;
151 filename[j]='\0';
152
153 count=0;
154 for (group=first_user_group ; group ; group=group->next) {
155 lastuser=(group->next) ? group->nusers : group->nusers-1;
156 for (i=0 ; i<lastuser ; i++) {
157 if (strcasecmp(filename,group->list[i].filename)==0) {
158 clen=sprintf(cstr,"+%X",count++);
159 if (flen+clen<MAX_USER_FNAME_LEN)
160 strcpy(filename+flen,cstr);
161 else
162 strcpy(filename+MAX_USER_FNAME_LEN-clen,cstr);
163 }
164 }
165 }
166 }
167 user->filename=StringBuffer_Store(UserStrings,filename);
168 if (!user->filename)
169 {
170 debuga(__FILE__,__LINE__,_("Not enough memory to store the file name for user \"%s\"\n"),user->id);
171 exit(EXIT_FAILURE);
172 }
173
174 return(user);
175 }
176
177 void userinfo_free(void)
178 {
179 struct usergroupstruct *group, *next;
180
181 for (group=first_user_group ; group ; group=next) {
182 next=group->next;
183 free(group);
184 }
185 first_user_group=NULL;
186 StringBuffer_Destroy(&UserStrings);
187 }
188
189 /*!
190 * Store the user's label.
191 * \param uinfo The user info structure created by userinfo_create().
192 * \param label The string label to store.
193 */
194 void userinfo_label(struct userinfostruct *uinfo,const char *label)
195 {
196 if (!uinfo) return;
197 if (!UserStrings) return;
198 uinfo->label=StringBuffer_Store(UserStrings,label);
199 if (!uinfo->label) {
200 debuga(__FILE__,__LINE__,_("Not enough memory to store label \"%s\" of user \"%s\"\n"),label,uinfo->id);
201 exit(EXIT_FAILURE);
202 }
203 }
204
205 struct userinfostruct *userinfo_find_from_file(const char *filename)
206 {
207 struct usergroupstruct *group;
208 int i;
209
210 for (group=first_user_group ; group ; group=group->next) {
211 for (i=0 ; i<group->nusers ; i++)
212 if (strcmp(filename,group->list[i].filename)==0)
213 return(group->list+i);
214 }
215 return(NULL);
216 }
217
218 struct userinfostruct *userinfo_find_from_id(const char *id)
219 {
220 struct usergroupstruct *group;
221 int i;
222
223 for (group=first_user_group ; group ; group=group->next) {
224 for (i=0 ; i<group->nusers ; i++)
225 if (strcmp(id,group->list[i].id)==0)
226 return(group->list+i);
227 }
228 return(NULL);
229 }
230
231 struct userinfostruct *userinfo_find_from_ip(const char *ip)
232 {
233 struct usergroupstruct *group;
234 int i;
235
236 for (group=first_user_group ; group ; group=group->next) {
237 for (i=0 ; i<group->nusers ; i++)
238 if (strcmp(ip,group->list[i].ip)==0)
239 return(group->list+i);
240 }
241 return(NULL);
242 }
243
244 /*!
245 Start the scanning of the user list.
246
247 \return The object to pass to subsequent scanning functions or NULL
248 if it failed. The object must be freed with a call to userinfo_stop().
249 */
250 userscan userinfo_startscan(void)
251 {
252 userscan uscan;
253
254 uscan=malloc(sizeof(*uscan));
255 if (!uscan) return(NULL);
256 uscan->group=first_user_group;
257 uscan->index=0;
258 return(uscan);
259 }
260
261 /*!
262 Free the memory allocated by userinfo_start().
263
264 \param uscan The object created by userinfo_start().
265 */
266 void userinfo_stopscan(userscan uscan)
267 {
268 free(uscan);
269 }
270
271 /*!
272 Get the user pointed to by the object and advance the object
273 to the next user.
274
275 \param uscan The object created by userinfo_start().
276
277 \return The user in the list or NULL if the end of the list
278 is reached.
279 */
280 struct userinfostruct *userinfo_advancescan(userscan uscan)
281 {
282 struct userinfostruct *uinfo;
283
284 if (!uscan) return(NULL);
285 if (!uscan->group) return(NULL);
286 if (uscan->index<0 || uscan->index>=uscan->group->nusers) return(NULL);
287
288 uinfo=uscan->group->list+uscan->index;
289
290 ++uscan->index;
291 if (uscan->index>=uscan->group->nusers) {
292 uscan->group=uscan->group->next;
293 uscan->index=0;
294 }
295 return(uinfo);
296 }
297
298 /*!
299 Clear the general purpose flag from all the user's info.
300 */
301 void userinfo_clearflag(void)
302 {
303 struct usergroupstruct *group;
304 int i;
305
306 for (group=first_user_group ; group ; group=group->next) {
307 for (i=0 ; i<group->nusers ; i++)
308 group->list[i].flag=0;
309 }
310 }
311
312 /*!
313 Read the file containing the user names to alias in the report.
314
315 \param Filename The name of the file.
316 */
317 void read_useralias(const char *Filename)
318 {
319 FileObject *fi;
320 longline line;
321 char *buf;
322
323 if (debug) debuga(__FILE__,__LINE__,_("Reading user alias file \"%s\"\n"),Filename);
324
325 UserAliases=Alias_Create();
326 if (!UserAliases) {
327 debuga(__FILE__,__LINE__,_("Cannot store user's aliases\n"));
328 exit(EXIT_FAILURE);
329 }
330
331 fi=FileObject_Open(Filename);
332 if (!fi) {
333 debuga(__FILE__,__LINE__,_("Cannot read user name alias file \"%s\": %s\n"),Filename,FileObject_GetLastOpenError());
334 exit(EXIT_FAILURE);
335 }
336
337 if ((line=longline_create())==NULL) {
338 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),Filename);
339 exit(EXIT_FAILURE);
340 }
341
342 while ((buf=longline_read(fi,line)) != NULL) {
343 if (Alias_Store(UserAliases,buf)<0) {
344 debuga(__FILE__,__LINE__,_("While reading \"%s\"\n"),Filename);
345 exit(EXIT_FAILURE);
346 }
347 }
348
349 longline_destroy(&line);
350 if (FileObject_Close(fi)) {
351 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),Filename,FileObject_GetLastCloseError());
352 exit(EXIT_FAILURE);
353 }
354
355 if (debug) {
356 debuga(__FILE__,__LINE__,_("List of user names to alias:\n"));
357 Alias_PrintList(UserAliases);
358 }
359 }
360
361 /*!
362 Free the memory allocated by read_useralias().
363 */
364 void free_useralias(void)
365 {
366 Alias_Destroy(&UserAliases);
367 }
368
369 /*!
370 Replace the user's name or ID by an alias if one is defined.
371
372 \param user The user's name or ID as extracted from the report.
373
374 \retval USERERR_NoError No error.
375 \retval USERERR_NameTooLong User name too long.
376 */
377 enum UserProcessError process_user(const char **UserPtr,const char *IpAddress,bool *IsIp)
378 {
379 const char *user=*UserPtr;
380 static char UserBuffer[MAX_USER_LEN];
381 const char *auser;
382
383 if (UserIp) {
384 user=IpAddress;
385 *IsIp=true;
386 } else {
387 *IsIp=false;
388
389 if (StripSuffixLen>0)
390 {
391 int x=strlen(user);
392 if (x>StripSuffixLen && strcasecmp(user+(x-StripSuffixLen),StripUserSuffix)==0)
393 {
394 if (x-StripSuffixLen>=sizeof(UserBuffer))
395 return(USERERR_NameTooLong);
396 safe_strcpy(UserBuffer,user,x-StripSuffixLen+1);
397 user=UserBuffer;
398 }
399 }
400 if (strlen(user)>MAX_USER_LEN)
401 return(USERERR_NameTooLong);
402
403 if (testvaliduserchar(user))
404 return(USERERR_InvalidChar);
405
406 if ((user[0]=='\0') || (user[1]=='\0' && (user[0]=='-' || user[0]==' '))) {
407 if(RecordsWithoutUser == RECORDWITHOUTUSER_IP) {
408 user=IpAddress;
409 *IsIp=true;
410 }
411 if (RecordsWithoutUser == RECORDWITHOUTUSER_IGNORE)
412 return(USERERR_EmptyUser);
413 if (RecordsWithoutUser == RECORDWITHOUTUSER_EVERYBODY)
414 user="everybody";
415 } else {
416 if (NtlmUserFormat == NTLMUSERFORMAT_USER) {
417 const char *str;
418 if ((str=strchr(user,'+'))!=NULL || (str=strchr(user,'\\'))!=NULL || (str=strchr(user,'_'))!=NULL) {
419 user=str+1;
420 }
421 }
422 }
423 }
424
425 if (us[0]!='\0' && strcmp(user,us)!=0)
426 return(USERERR_Untracked);
427
428 if (ReadFilter.SysUsers) {
429 char wuser[MAX_USER_LEN+2]=":";
430
431 strcat(wuser,user);
432 strcat(wuser,":");
433 if (strstr(userfile, wuser) == 0)
434 return(USERERR_SysUser);
435 }
436
437 if (ReadFilter.UserFilter) {
438 if (!vuexclude(user)) {
439 if (debugz>=LogLevel_Process) debuga(__FILE__,__LINE__,_("Excluded user: %s\n"),user);
440 return(USERERR_Ignored);
441 }
442 }
443
444 auser=Alias_Replace(UserAliases,user);
445 if (auser!=user) {
446 if (*auser==ALIAS_PREFIX) auser++;//no need for that indicator for a user name
447 user=auser;
448 *IsIp=false;
449 }
450
451 // include_users
452 if (IncludeUsers[0] != '\0') {
453 char wuser[MAX_USER_LEN+2]=":";
454 char *str;
455
456 strcat(wuser,user);
457 strcat(wuser,":");
458 str=strstr(IncludeUsers,wuser);
459 if (!str)
460 return(USERERR_Excluded);
461 }
462
463 if (user[0]=='\0' || (user[1]=='\0' && (user[0]=='-' || user[0]==' ' || user[0]==':')))
464 return(USERERR_EmptyUser);
465
466 *UserPtr=user;
467 return(USERERR_NoError);
468 }