]> git.ipfire.org Git - thirdparty/sarg.git/blame - userinfo.c
Update the man page
[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
074a6d8f
FM
68extern struct ReadLogDataStruct ReadFilter;
69extern char StripUserSuffix[MAX_USER_LEN];
70extern int StripSuffixLen;
71extern char *userfile;
72
aa6ac9f2 73struct userinfostruct *userinfo_create(const char *userid,const char *ip)
f2ec8c75 74{
9bd92830
FM
75 struct usergroupstruct *group, *last;
76 struct userinfostruct *user;
d09d93c6 77 int i, j, lastuser;
9bd92830
FM
78 int skip;
79 int flen;
80 int count, clen;
81 char cstr[9];
b6b6cb8c
FM
82 char filename[MAX_USER_FNAME_LEN];
83
84 if (!UserStrings) {
85 UserStrings=StringBuffer_Create();
86 if (!UserStrings) {
af961877 87 debuga(__FILE__,__LINE__,_("Not enough memory to store the user's strings\n"));
b6b6cb8c
FM
88 exit(EXIT_FAILURE);
89 }
90 }
9bd92830
FM
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) {
af961877 101 debuga(__FILE__,__LINE__,_("Not enough memory to store user \"%s\"\n"),userid);
9bd92830
FM
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
b6b6cb8c
FM
112 user->id=StringBuffer_Store(UserStrings,userid);
113 if (!user->id) {
af961877 114 debuga(__FILE__,__LINE__,_("Not enough memory to store user ID \"%s\"\n"),userid);
b6b6cb8c
FM
115 exit(EXIT_FAILURE);
116 }
117 user->label=user->id; //assign a label to avoid a NULL pointer in case none is provided
aa6ac9f2 118 if (ip) {
acf0b78c
FM
119 /*
120 * IP address is not the same as the user's ID. A separate buffer
121 * must be allocated.
122 */
dc34d345 123 user->id_is_ip=false;
aa6ac9f2
FM
124 user->ip=StringBuffer_Store(UserStrings,ip);
125 } else {
acf0b78c
FM
126 /*
127 * User's IP address share the same buffer as the user's ID.
128 */
dc34d345 129 user->id_is_ip=true;
aa6ac9f2
FM
130 user->ip=user->id;
131 }
9bd92830 132
829a53c2 133 if (AnonymousOutputFiles) {
b6b6cb8c 134 snprintf(filename,sizeof(filename),"%d",AnonymousCounter++);
829a53c2
FM
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]=='_') {
b6b6cb8c 140 filename[j++]=userid[i];
829a53c2
FM
141 skip=0;
142 } else {
143 if (!skip) {
b6b6cb8c 144 filename[j++]='_';
829a53c2
FM
145 skip=1;
146 }
9bd92830
FM
147 }
148 }
b6b6cb8c 149 if (j==0) filename[j++]='_'; //don't leave a file name empty
4754959e 150 flen=j;
b6b6cb8c 151 filename[j]='\0';
829a53c2
FM
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++) {
b6b6cb8c 157 if (strcasecmp(filename,group->list[i].filename)==0) {
4754959e 158 clen=sprintf(cstr,"+%X",count++);
829a53c2 159 if (flen+clen<MAX_USER_FNAME_LEN)
b6b6cb8c 160 strcpy(filename+flen,cstr);
829a53c2 161 else
b6b6cb8c 162 strcpy(filename+MAX_USER_FNAME_LEN-clen,cstr);
829a53c2 163 }
9bd92830
FM
164 }
165 }
166 }
b6b6cb8c
FM
167 user->filename=StringBuffer_Store(UserStrings,filename);
168 if (!user->filename)
169 {
af961877 170 debuga(__FILE__,__LINE__,_("Not enough memory to store the file name for user \"%s\"\n"),user->id);
b6b6cb8c
FM
171 exit(EXIT_FAILURE);
172 }
9bd92830
FM
173
174 return(user);
f2ec8c75
FM
175}
176
177void userinfo_free(void)
178{
9bd92830 179 struct usergroupstruct *group, *next;
f2ec8c75 180
9bd92830
FM
181 for (group=first_user_group ; group ; group=next) {
182 next=group->next;
183 free(group);
184 }
185 first_user_group=NULL;
b6b6cb8c
FM
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 */
194void 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) {
af961877 200 debuga(__FILE__,__LINE__,_("Not enough memory to store label \"%s\" of user \"%s\"\n"),label,uinfo->id);
b6b6cb8c
FM
201 exit(EXIT_FAILURE);
202 }
f2ec8c75
FM
203}
204
205struct userinfostruct *userinfo_find_from_file(const char *filename)
206{
9bd92830
FM
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);
f2ec8c75
FM
216}
217
218struct userinfostruct *userinfo_find_from_id(const char *id)
219{
9bd92830
FM
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);
f2ec8c75 229}
93551487 230
05fea6e7
FM
231struct 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
93551487
FM
244/*!
245Start the scanning of the user list.
246
247\return The object to pass to subsequent scanning functions or NULL
248if it failed. The object must be freed with a call to userinfo_stop().
249*/
250userscan 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/*!
262Free the memory allocated by userinfo_start().
263
264\param uscan The object created by userinfo_start().
265*/
266void userinfo_stopscan(userscan uscan)
267{
268 free(uscan);
269}
270
271/*!
272Get the user pointed to by the object and advance the object
273to 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
278is reached.
279*/
280struct 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}
a58e6d54
FM
297
298/*!
299Clear the general purpose flag from all the user's info.
300*/
301void 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
c4f0ea8f
FM
312/*!
313Read the file containing the user names to alias in the report.
314
315\param Filename The name of the file.
316*/
317void read_useralias(const char *Filename)
318{
800eafb8 319 FileObject *fi;
c4f0ea8f
FM
320 longline line;
321 char *buf;
322
af961877 323 if (debug) debuga(__FILE__,__LINE__,_("Reading user alias file \"%s\"\n"),Filename);
c4f0ea8f
FM
324
325 UserAliases=Alias_Create();
326 if (!UserAliases) {
af961877 327 debuga(__FILE__,__LINE__,_("Cannot store user's aliases\n"));
c4f0ea8f
FM
328 exit(EXIT_FAILURE);
329 }
330
800eafb8 331 fi=FileObject_Open(Filename);
c4f0ea8f 332 if (!fi) {
800eafb8 333 debuga(__FILE__,__LINE__,_("Cannot read user name alias file \"%s\": %s\n"),Filename,FileObject_GetLastOpenError());
c4f0ea8f
FM
334 exit(EXIT_FAILURE);
335 }
336
337 if ((line=longline_create())==NULL) {
af961877 338 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),Filename);
c4f0ea8f
FM
339 exit(EXIT_FAILURE);
340 }
341
342 while ((buf=longline_read(fi,line)) != NULL) {
343 if (Alias_Store(UserAliases,buf)<0) {
af961877 344 debuga(__FILE__,__LINE__,_("While reading \"%s\"\n"),Filename);
c4f0ea8f
FM
345 exit(EXIT_FAILURE);
346 }
347 }
348
349 longline_destroy(&line);
800eafb8
FM
350 if (FileObject_Close(fi)) {
351 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),Filename,FileObject_GetLastCloseError());
204781f4
FM
352 exit(EXIT_FAILURE);
353 }
c4f0ea8f
FM
354
355 if (debug) {
af961877 356 debuga(__FILE__,__LINE__,_("List of user names to alias:\n"));
c4f0ea8f
FM
357 Alias_PrintList(UserAliases);
358 }
359}
360
361/*!
362Free the memory allocated by read_useralias().
363*/
364void free_useralias(void)
365{
366 Alias_Destroy(&UserAliases);
367}
368
369/*!
370Replace 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.
074a6d8f
FM
373
374\retval USERERR_NoError No error.
375\retval USERERR_NameTooLong User name too long.
c4f0ea8f 376*/
074a6d8f 377enum UserProcessError process_user(const char **UserPtr,const char *IpAddress,bool *IsIp)
c4f0ea8f 378{
074a6d8f
FM
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
074a6d8f
FM
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) {
284dab99 446 if (*auser==ALIAS_PREFIX) auser++;//no need for that indicator for a user name
074a6d8f
FM
447 user=auser;
448 *IsIp=false;
449 }
450
b58ca721
FM
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
074a6d8f
FM
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);
c4f0ea8f 468}