]> git.ipfire.org Git - thirdparty/sarg.git/blob - userinfo.c
Avoid rereading the user_limit file each time a user is added
[thirdparty/sarg.git] / userinfo.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2013
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(_("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(_("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(_("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 user->id_is_ip=0;
115 user->ip=StringBuffer_Store(UserStrings,ip);
116 } else {
117 user->id_is_ip=1;
118 user->ip=user->id;
119 }
120 user->user_limit=0;
121
122 if (AnonymousOutputFiles) {
123 snprintf(filename,sizeof(filename),"%d",AnonymousCounter++);
124 } else {
125 skip=0;
126 j=0;
127 for (i=0 ; userid[i] && j<MAX_USER_FNAME_LEN-1 ; i++) {
128 if (isalnum(userid[i]) || userid[i]=='-' || userid[i]=='_') {
129 filename[j++]=userid[i];
130 skip=0;
131 } else {
132 if (!skip) {
133 filename[j++]='_';
134 skip=1;
135 }
136 }
137 }
138 if (j==0) filename[j++]='_'; //don't leave a file name empty
139 flen=j;
140 filename[j]='\0';
141
142 count=0;
143 for (group=first_user_group ; group ; group=group->next) {
144 lastuser=(group->next) ? group->nusers : group->nusers-1;
145 for (i=0 ; i<lastuser ; i++) {
146 if (strcasecmp(filename,group->list[i].filename)==0) {
147 clen=sprintf(cstr,"+%X",count++);
148 if (flen+clen<MAX_USER_FNAME_LEN)
149 strcpy(filename+flen,cstr);
150 else
151 strcpy(filename+MAX_USER_FNAME_LEN-clen,cstr);
152 }
153 }
154 }
155 }
156 user->filename=StringBuffer_Store(UserStrings,filename);
157 if (!user->filename)
158 {
159 debuga(_("Not enough memory to store the file name for user \"%s\"\n"),user->id);
160 exit(EXIT_FAILURE);
161 }
162
163 return(user);
164 }
165
166 void userinfo_free(void)
167 {
168 struct usergroupstruct *group, *next;
169
170 for (group=first_user_group ; group ; group=next) {
171 next=group->next;
172 free(group);
173 }
174 first_user_group=NULL;
175 StringBuffer_Destroy(&UserStrings);
176 }
177
178 /*!
179 * Store the user's label.
180 * \param uinfo The user info structure created by userinfo_create().
181 * \param label The string label to store.
182 */
183 void userinfo_label(struct userinfostruct *uinfo,const char *label)
184 {
185 if (!uinfo) return;
186 if (!UserStrings) return;
187 uinfo->label=StringBuffer_Store(UserStrings,label);
188 if (!uinfo->label) {
189 debuga(_("Not enough memory to store label \"%s\" of user \"%s\"\n"),label,uinfo->id);
190 exit(EXIT_FAILURE);
191 }
192 }
193
194 struct userinfostruct *userinfo_find_from_file(const char *filename)
195 {
196 struct usergroupstruct *group;
197 int i;
198
199 for (group=first_user_group ; group ; group=group->next) {
200 for (i=0 ; i<group->nusers ; i++)
201 if (strcmp(filename,group->list[i].filename)==0)
202 return(group->list+i);
203 }
204 return(NULL);
205 }
206
207 struct userinfostruct *userinfo_find_from_id(const char *id)
208 {
209 struct usergroupstruct *group;
210 int i;
211
212 for (group=first_user_group ; group ; group=group->next) {
213 for (i=0 ; i<group->nusers ; i++)
214 if (strcmp(id,group->list[i].id)==0)
215 return(group->list+i);
216 }
217 return(NULL);
218 }
219
220 /*!
221 Start the scanning of the user list.
222
223 \return The object to pass to subsequent scanning functions or NULL
224 if it failed. The object must be freed with a call to userinfo_stop().
225 */
226 userscan userinfo_startscan(void)
227 {
228 userscan uscan;
229
230 uscan=malloc(sizeof(*uscan));
231 if (!uscan) return(NULL);
232 uscan->group=first_user_group;
233 uscan->index=0;
234 return(uscan);
235 }
236
237 /*!
238 Free the memory allocated by userinfo_start().
239
240 \param uscan The object created by userinfo_start().
241 */
242 void userinfo_stopscan(userscan uscan)
243 {
244 free(uscan);
245 }
246
247 /*!
248 Get the user pointed to by the object and advance the object
249 to the next user.
250
251 \param uscan The object created by userinfo_start().
252
253 \return The user in the list or NULL if the end of the list
254 is reached.
255 */
256 struct userinfostruct *userinfo_advancescan(userscan uscan)
257 {
258 struct userinfostruct *uinfo;
259
260 if (!uscan) return(NULL);
261 if (!uscan->group) return(NULL);
262 if (uscan->index<0 || uscan->index>=uscan->group->nusers) return(NULL);
263
264 uinfo=uscan->group->list+uscan->index;
265
266 ++uscan->index;
267 if (uscan->index>=uscan->group->nusers) {
268 uscan->group=uscan->group->next;
269 uscan->index=0;
270 }
271 return(uinfo);
272 }
273
274 /*!
275 Clear the general purpose flag from all the user's info.
276 */
277 void userinfo_clearflag(void)
278 {
279 struct usergroupstruct *group;
280 int i;
281
282 for (group=first_user_group ; group ; group=group->next) {
283 for (i=0 ; i<group->nusers ; i++)
284 group->list[i].flag=0;
285 }
286 }
287
288 /*!
289 Read the file containing the user names to alias in the report.
290
291 \param Filename The name of the file.
292 */
293 void read_useralias(const char *Filename)
294 {
295 FILE *fi;
296 longline line;
297 char *buf;
298
299 if (debug) debuga(_("Reading user alias file \"%s\"\n"),Filename);
300
301 UserAliases=Alias_Create();
302 if (!UserAliases) {
303 debuga(_("Cannot store user's aliases\n"));
304 exit(EXIT_FAILURE);
305 }
306
307 fi=fopen(Filename,"rt");
308 if (!fi) {
309 debuga(_("Cannot read user name alias file \"%s\" - %s\n"),Filename,strerror(errno));
310 exit(EXIT_FAILURE);
311 }
312
313 if ((line=longline_create())==NULL) {
314 debuga(_("Not enough memory to read the user name aliases\n"));
315 exit(EXIT_FAILURE);
316 }
317
318 while ((buf=longline_read(fi,line)) != NULL) {
319 if (Alias_Store(UserAliases,buf)<0) {
320 debuga(_("While reading \"%s\"\n"),Filename);
321 exit(EXIT_FAILURE);
322 }
323 }
324
325 longline_destroy(&line);
326 fclose(fi);
327
328 if (debug) {
329 debuga(_("List of user names to alias:\n"));
330 Alias_PrintList(UserAliases);
331 }
332 }
333
334 /*!
335 Free the memory allocated by read_useralias().
336 */
337 void free_useralias(void)
338 {
339 Alias_Destroy(&UserAliases);
340 }
341
342 /*!
343 Replace the user's name or ID by an alias if one is defined.
344
345 \param user The user's name or ID as extracted from the report.
346 */
347 const char *process_user(const char *user)
348 {
349 user=Alias_Replace(UserAliases,user);
350 return(user);
351 }