1 /* This file is part of GNU Radius.
2    Copyright (C) 2000,2001,2002,2003,2004,2005,
3    2006,2007,2008 Free Software Foundation, Inc.
4 
5    Written by Sergey Poznyakoff
6 
7    GNU Radius is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    GNU Radius is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GNU Radius; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 
21 #define LOG_EMPTY_USERNAME
22 
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26 
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <sys/file.h>
31 #include <sys/stat.h>
32 #include <netinet/in.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <netdb.h>
36 #include <pwd.h>
37 #include <time.h>
38 #include <ctype.h>
39 #include <unistd.h>
40 #include <signal.h>
41 #include <errno.h>
42 #include <sys/wait.h>
43 #include <fcntl.h>
44 
45 #include <radiusd.h>
46 #include <radius/radutmp.h>
47 #include <rewrite.h>
48 
49 int     doradwtmp = 1;
50 
51 static int write_wtmp(struct radutmp *ut);
52 static int write_nas_restart(int status, grad_uint32_t addr);
53 static int check_ts(struct radutmp *ut);
54 
55 int rad_acct_system(radiusd_request_t *radreq, int dowtmp);
56 int rad_acct_db(radiusd_request_t *radreq, int authtype);
57 int rad_acct_ext(radiusd_request_t *radreq);
58 
59 
60 /* Zap a user, or all users on a NAS, from the radutmp file. */
61 int
radzap(grad_uint32_t nasaddr,int port,char * user,time_t t)62 radzap(grad_uint32_t nasaddr, int port, char *user, time_t t)
63 {
64         struct radutmp  *up;
65         radut_file_t    file;
66         grad_uint32_t           netaddr;
67 
68         if (t == 0) time(&t);
69         netaddr = htonl(nasaddr);
70 
71         if (file = grad_ut_setent(grad_utmp_file, 0)) {
72                 /* Find the entry for this NAS / portno combination. */
73                 while (up = grad_ut_getent(file)) {
74                         if (((nasaddr != 0 && netaddr != up->nas_address) ||
75                              (port >= 0   && port    != up->nas_port) ||
76                              (user != NULL && strcmp(up->login, user) != 0) ||
77                              up->type != P_LOGIN))
78                                 continue;
79                         /* Zap the entry */
80                         up->type = P_IDLE;
81                         up->time = t;
82                         grad_ut_putent(file, up);
83                         /* Add a logout entry to the wtmp file. */
84                         write_wtmp(up);
85                 }
86                 grad_ut_endent(file);
87         }
88 
89         return 0;
90 }
91 
92 static void
store_session_id(char * buffer,int len,char * id,int idlen)93 store_session_id(char *buffer, int len, char *id, int idlen)
94 {
95         int off = idlen - len;
96         if (off < 0)
97                 off = 0;
98         memcpy(buffer, id + off, len);
99         buffer[len-1] = 0;
100 }
101 
102 int
write_wtmp(struct radutmp * ut)103 write_wtmp(struct radutmp *ut)
104 {
105         return grad_radwtmp_putent(grad_wtmp_file, ut);
106 }
107 
108 void
backslashify(char * dst,char * src,int len)109 backslashify(char *dst, char *src, int len)
110 {
111 #define CHECK(l,m) \
112  if (l <= m) goto end; else l -= m
113 
114 #define ESCAPE(c)\
115  CHECK(len,2);\
116  src++;\
117  *dst++ = '\\';\
118  *dst++ = c
119 
120         while (*src && len > 1) {
121                 switch (*src) {
122                 case '\\':
123                         ESCAPE('\\');
124                         break;
125                 case '\a':
126                         ESCAPE('a');
127                         break;
128                 case '\b':
129                         ESCAPE('b');
130                         break;
131                 case '\f':
132                         ESCAPE('f');
133                         break;
134                 case '\n':
135                         ESCAPE('n');
136                         break;
137                 case '\r':
138                         ESCAPE('r');
139                         break;
140                 case '\t':
141                         ESCAPE('t');
142                         break;
143                 default:
144                         *dst++ = *src++;
145                         len--;
146                 }
147         }
148 
149 end:
150         *dst = 0;
151 }
152 
153 int
check_attribute(grad_avp_t * check_pairs,int pair_attr,int pair_value,int def)154 check_attribute(grad_avp_t *check_pairs, int pair_attr,
155 		int pair_value, int def)
156 {
157         grad_avp_t *pair;
158 
159         if ((pair = grad_avl_find(check_pairs, pair_attr)) == NULL)
160                 return def;
161         do {
162                 if (pair->avp_lvalue == pair_value)
163                         return 1;
164                 check_pairs = pair->next;
165         } while (check_pairs
166 		 && (pair = grad_avl_find(check_pairs, pair_attr)));
167         return 0;
168 }
169 
170 #ifdef DA_ACCT_TYPE
171 # define ACCT_TYPE(req,t) check_attribute(req, DA_ACCT_TYPE, t, 1)
172 #else
173 # define ACCT_TYPE(req,t) 1
174 #endif
175 
176 
177 /*  Store logins in the RADIUS utmp file. */
178 int
rad_acct_system(radiusd_request_t * radreq,int dowtmp)179 rad_acct_system(radiusd_request_t *radreq, int dowtmp)
180 {
181         struct radutmp  ut;
182         grad_avp_t *vp;
183         int status = -1;
184         int nas_address = 0;
185         int protocol = -1;
186         time_t t;
187         int ret = 0, rc;
188         int port_seen = 0;
189         char buf[GRAD_MAX_LONGNAME];
190 
191 	/* Do not do anything if system accounting is not requested */
192 	if (!acct_system)
193 		return 0;
194 
195         /* A packet should have Acct-Status-Type attribute */
196         if ((vp = grad_avl_find(radreq->request->avlist, DA_ACCT_STATUS_TYPE))
197 	        == NULL) {
198                 grad_log_req(GRAD_LOG_ERR, radreq->request,
199                              _("no Acct-Status-Type attribute"));
200                 return -1;
201         }
202 
203         status = vp->avp_lvalue;
204 
205         time(&t);
206         memset(&ut, 0, sizeof(ut));
207         ut.porttype = -1; /* Unknown so far */
208 
209         if (radreq->realm) {
210 		grad_server_t *server =
211 			grad_list_item(radreq->realm->queue->servers,
212 				       radreq->server_no);
213 		if (server)
214 			ut.realm_address = server->addr;
215         }
216 
217         /* Fill in radutmp structure */
218         for (vp = radreq->request->avlist; vp; vp = vp->next) {
219                 switch (vp->attribute) {
220                 case DA_USER_NAME:
221                         backslashify(ut.login, vp->avp_strvalue, RUT_NAMESIZE);
222                         break;
223 
224                 case DA_ORIG_USER_NAME:
225                         backslashify(ut.orig_login, vp->avp_strvalue, RUT_NAMESIZE);
226                         break;
227 
228                 case DA_LOGIN_IP_HOST:
229                 case DA_FRAMED_IP_ADDRESS:
230                         ut.framed_address = htonl(vp->avp_lvalue);
231                         break;
232 
233                 case DA_FRAMED_PROTOCOL:
234                         protocol = vp->avp_lvalue;
235                         break;
236 
237                 case DA_NAS_IP_ADDRESS:
238                         nas_address = vp->avp_lvalue;
239                         ut.nas_address = htonl(vp->avp_lvalue);
240                         break;
241 
242                 case DA_NAS_PORT_ID:
243                         ut.nas_port = vp->avp_lvalue;
244                         port_seen = 1;
245                         break;
246 
247                 case DA_ACCT_DELAY_TIME:
248                         ut.delay = vp->avp_lvalue;
249                         break;
250 
251                 case DA_CALLING_STATION_ID:
252                         store_session_id(ut.caller_id,
253                                          sizeof(ut.caller_id),
254                                          vp->avp_strvalue,
255                                          vp->avp_strlength);
256                         break;
257 
258                 case DA_CALLED_STATION_ID:
259                         break;
260 
261                 case DA_ACCT_SESSION_ID:
262                         store_session_id(ut.session_id,
263                                          sizeof(ut.session_id),
264                                          vp->avp_strvalue,
265                                          vp->avp_strlength);
266                         break;
267 
268                 case DA_NAS_PORT_TYPE:
269 			ut.porttype = vp->avp_lvalue;
270                         break;
271                 }
272         }
273 
274         if (ut.orig_login[0] == 0)
275                 strncpy(ut.orig_login, ut.login, sizeof(ut.orig_login));
276 
277         /* If we didn't find out the NAS address, use the originator's
278            IP address. */
279         if (nas_address == 0) {
280                 nas_address = radreq->request->ipaddr;
281                 ut.nas_address = htonl(nas_address);
282         }
283 
284 #ifdef LOG_EMPTY_USERNAME
285         if (ut.login[0] == 0 && ut.caller_id[0] != 0) {
286                 ut.login[0] = '#';
287                 store_session_id(ut.login+1,
288                                  RUT_NAMESIZE-2,
289                                  ut.caller_id,
290                                  strlen(ut.caller_id));
291         }
292 #endif
293 
294         ut.proto = protocol;
295         ut.time = t - ut.delay;
296 
297         /* Process Accounting-On/Off records */
298         if (status == DV_ACCT_STATUS_TYPE_ACCOUNTING_ON && nas_address) {
299                 grad_log(GRAD_LOG_NOTICE,
300                          _("NAS %s started (Accounting-On packet seen)"),
301                          grad_nas_ip_to_name(nas_address, buf, sizeof buf));
302                 radzap(nas_address, -1, NULL, ut.time);
303                 write_nas_restart(status, ut.nas_address);
304                 return 0;
305         }
306         if (status == DV_ACCT_STATUS_TYPE_ACCOUNTING_OFF && nas_address) {
307                 grad_log(GRAD_LOG_NOTICE,
308                          _("NAS %s shut down (Accounting-Off packet seen)"),
309                          grad_nas_ip_to_name(nas_address, buf, sizeof buf));
310                 radzap(nas_address, -1, NULL, ut.time);
311                 write_nas_restart(status, ut.nas_address);
312                 return 0;
313         }
314 
315         /* If we don't know the type of entry pretend we succeeded. */
316         if (status != DV_ACCT_STATUS_TYPE_START &&
317             status != DV_ACCT_STATUS_TYPE_STOP &&
318             status != DV_ACCT_STATUS_TYPE_ALIVE) {
319                 grad_log_req(GRAD_LOG_NOTICE,
320                              radreq->request, _("unknown packet type (%d)"),
321                              status);
322                 return 0;
323         } else if (status == DV_ACCT_STATUS_TYPE_START ||
324                    status == DV_ACCT_STATUS_TYPE_STOP) {
325                 GRAD_DEBUG7(1,
326                     "%s: User %s at NAS %s port %d session %-*.*s",
327                      status == DV_ACCT_STATUS_TYPE_START ? "start" : "stop",
328                      ut.login,
329                      grad_nas_ip_to_name(nas_address, buf, sizeof buf),
330                      ut.nas_port,
331                      sizeof(ut.session_id),
332                      sizeof(ut.session_id),
333                      ut.session_id);
334         }
335 
336         /* Decide if we should store this record into radutmp/radwtmp.
337            We skip records:
338 
339                 - if NAS-Port-Id attribute is absent
340                 - if request has one or more Acct-Type attributes
341                   and no one of them requires system accounting.
342                   (The Acct-Type pairs can be inserted only via
343                    raddb/hints  */
344         if (!port_seen)
345                 return 0;
346 
347         if (!ACCT_TYPE(radreq->request->avlist, DV_ACCT_TYPE_SYSTEM)) {
348                 GRAD_DEBUG1(1,"Acct type system disabled for %s", ut.login);
349                 return 0;
350         }
351 
352         /* Update radutmp file. */
353         rc = grad_utmp_putent(grad_utmp_file, &ut, status);
354         GRAD_DEBUG3(1, "grad_utmp_putent=%d for %s/%s",
355                     rc, ut.login, ut.session_id);
356 
357         /* Don't write wtmp if we don't have a username, or
358            if this is an update record and the original record
359            was already written. */
360         if ((status != DV_ACCT_STATUS_TYPE_STOP && ut.login[0] == 0) ||
361             rc == PUTENT_UPDATE)
362                 dowtmp = 0;
363 
364         /* Write a RADIUS wtmp log file. */
365         if (dowtmp) {
366                 stat_update(&ut, status);
367                 write_wtmp(&ut);
368         } else if (rc == PUTENT_UPDATE) {
369                 stat_update(&ut, status);
370         } else {
371                 ret = -1;
372                 stat_inc(acct, radreq->request->ipaddr, num_norecords);
373                 grad_log_req(GRAD_LOG_NOTICE, radreq->request,
374 			     _("NOT writing wtmp record"));
375         }
376         return ret;
377 }
378 
379 static void
disable_system_acct()380 disable_system_acct()
381 {
382         radut_file_t file;
383 	struct radutmp *up;
384 	int written = 0;
385 
386         if ((file = grad_ut_setent(grad_utmp_file, 0)) == NULL)
387                 return;
388 
389         while (up = grad_ut_getent(file)) {
390                 switch (up->type) {
391 		case P_LOGIN:
392                         up->type = P_IDLE;
393                         time(&up->time);
394                         grad_ut_putent(file, up);
395                         /* Add a logout entry to the wtmp file. */
396                         write_wtmp(up);
397 			break;
398 
399 		case P_ACCT_ENABLED:
400 			time(&up->time);
401 			up->type = P_ACCT_DISABLED;
402 			grad_ut_putent(file, up);
403 			write_wtmp(up);
404 			written = 1;
405 			break;
406 
407 		case P_ACCT_DISABLED:
408 			written = 1;
409 			break;
410                 }
411 	}
412 
413 	if (!written) {
414 		struct radutmp ut;
415 
416 		memset(&ut, 0, sizeof ut);
417 		time(&ut.time);
418 		ut.type = P_ACCT_DISABLED;
419 		grad_ut_putent(file, &ut);
420 	}
421 	grad_ut_endent(file);
422 	grad_log(GRAD_LOG_INFO, _("System accounting is disabled"));
423 }
424 
425 static void
enable_system_acct()426 enable_system_acct()
427 {
428         radut_file_t file;
429 	struct radutmp *up, ut;
430 
431         if ((file = grad_ut_setent(grad_utmp_file, 0)) == NULL)
432                 return;
433 
434         while (up = grad_ut_getent(file)) {
435                 if (up->type == P_ACCT_DISABLED) {
436                         up->type = P_ACCT_ENABLED;
437                         time(&up->time);
438                         grad_ut_putent(file, up);
439                         /* Add an entry to the wtmp file. */
440                         write_wtmp(up);
441                 }
442 	}
443 	grad_ut_endent(file);
444 }
445 
446 void
system_acct_init()447 system_acct_init()
448 {
449 	if (acct_system)
450 		enable_system_acct();
451 	else
452 		disable_system_acct();
453 }
454 
455 int
mkdir_path(char * path,int perms)456 mkdir_path(char *path, int perms)
457 {
458 	struct stat st;
459 
460 	if (stat(path, &st)) {
461 		char *p;
462 
463 		if (errno != ENOENT) {
464 			grad_log(GRAD_LOG_ERR|GRAD_LOG_PERROR,
465 				 _("Cannot stat path component: %s"),
466 				 path);
467 			return 1;
468 		}
469 
470 		p = strrchr(path, '/');
471 		if (p && p > path) {
472 			int rc;
473 			*p = 0;
474 			rc = mkdir_path(path, perms);
475 			*p = '/';
476 			if (rc)
477 				return 1;
478 		}
479 
480 		if (mkdir(path, perms)) {
481 			grad_log(GRAD_LOG_ERR|GRAD_LOG_PERROR,
482 				 _("Cannot create directory %s"),
483 				 path);
484 			return 1;
485 		}
486 	} else if (!S_ISDIR(st.st_mode)) {
487 		grad_log(GRAD_LOG_ERR,
488 			 _("Path component is not a directory: %s"),
489 			 path);
490 		return 1;
491 	}
492 	return 0;
493 }
494 
495 static int
check_acct_dir()496 check_acct_dir()
497 {
498         struct stat st;
499 
500 	if (stat(grad_acct_dir, &st) == 0) {
501 		if (S_ISDIR(st.st_mode)) {
502 			if (access(grad_acct_dir, W_OK)) {
503 				grad_log(GRAD_LOG_ERR,
504 					 _("%s: directory not writable"),
505 					 grad_acct_dir);
506 				return 1;
507 			}
508 			return 0;
509 		} else {
510 			grad_log(GRAD_LOG_ERR, _("%s: not a directory"),
511 				 grad_acct_dir);
512 			return 1;
513 		}
514 	}
515 
516 	if (mkdir_path(grad_acct_dir, 0755))
517                 return 1;
518         return 0;
519 }
520 
521 static int acct_dir_status;
522 
523 static void
acct_after_config_hook(void * arg ARG_UNUSED,void * data ARG_UNUSED)524 acct_after_config_hook(void *arg ARG_UNUSED, void *data ARG_UNUSED)
525 {
526 	if (auth_detail || acct_detail) {
527 		acct_dir_status = check_acct_dir();
528 		if (acct_dir_status) {
529 			grad_log(GRAD_LOG_NOTICE,
530 			         _("Detailed accounting is disabled"));
531 			auth_detail = acct_detail = 0;
532 		}
533 	}
534 }
535 
536 void
acct_init()537 acct_init()
538 {
539 	radiusd_set_postconfig_hook(acct_after_config_hook, NULL, 0);
540 }
541 
542 static char *
make_legacy_detail_filename(radiusd_request_t * radreq,char * default_filename)543 make_legacy_detail_filename(radiusd_request_t *radreq, char *default_filename)
544 {
545 	char nasname[GRAD_MAX_LONGNAME];
546 	grad_nas_t *cl;
547 	grad_uint32_t ip;
548 	grad_avp_t *pair;
549 
550         /* Find out the name of this terminal server. We try to find
551            the DA_NAS_IP_ADDRESS in the naslist file. If that fails,
552            we look for the originating address.
553            Only if that fails we resort to a name lookup. */
554 
555         cl = NULL;
556         ip = radreq->request->ipaddr;
557         if ((pair = grad_avl_find(radreq->request->avlist, DA_NAS_IP_ADDRESS)) != NULL)
558                 ip = pair->avp_lvalue;
559 
560         if (radreq->realm) {
561 		grad_server_t *server =
562 			grad_list_item(radreq->realm->queue->servers,
563 				       radreq->server_no);
564 		if (server)
565 			ip = server->addr;
566 	}
567 
568         if ((cl = grad_nas_lookup_ip(ip)) != NULL) {
569                 if (cl->shortname[0])
570                         strcpy(nasname, cl->shortname);
571                 else
572                         strcpy(nasname, cl->longname);
573         }
574 
575         if (cl == NULL)
576                 grad_ip_gethostname(ip, nasname, sizeof(nasname));
577 
578 	return grad_mkfilename(nasname, default_filename);
579 }
580 
581 static char *
make_detail_filename(radiusd_request_t * req,char * template,char * default_filename)582 make_detail_filename(radiusd_request_t *req, char *template,
583 		     char *default_filename)
584 {
585 	if (!template) {
586 		return make_legacy_detail_filename(req, default_filename);
587 	} else if (template[0] == '=') {
588 		grad_value_t val;
589 		/*FIXME: Should be compiled!*/
590 		if (rewrite_interpret(template+1, req->request, &val))
591 			return NULL;
592 		if (val.type != String) {
593 			grad_log(GRAD_LOG_ERR, "%s: %s",
594 			         template+1, _("wrong return type"));
595 			/* Nothing to free in val */
596 			return NULL;
597 		}
598 		return val.datum.sval.data;
599 	} else {
600 		struct obstack stk;
601 		char *ptr;
602 
603 		obstack_init(&stk);
604 		ptr = radius_xlate(&stk, template, req->request, NULL);
605 		if (ptr)
606 			ptr = grad_estrdup(ptr);
607 		obstack_free(&stk, NULL);
608 		return ptr;
609 	}
610 }
611 
612 static int
make_path_to_file(char * filename,int perms)613 make_path_to_file(char *filename, int perms)
614 {
615 	char *p = strrchr(filename, '/');
616 	if (p) {
617 		int rc;
618 		*p = 0;
619 		rc = mkdir_path(filename, perms);
620 		*p = '/';
621 		return rc;
622 	}
623 	return 0;
624 }
625 
626 int
write_detail(radiusd_request_t * radreq,int authtype,int rtype)627 write_detail(radiusd_request_t *radreq, int authtype, int rtype)
628 {
629         FILE *outfd;
630         char *save;
631         grad_avp_t *pair;
632         time_t curtime;
633         int ret = 0;
634 	char *filename;
635 	char *template;
636 	char *deffilename;
637 
638 	if (acct_dir_status)
639 		return 1;
640 
641 	curtime = time(0);
642 
643 	switch (rtype) {
644 	case R_ACCT:
645 		template = acct_detail_template;
646 		deffilename = "detail";
647 		break;
648 
649 	case R_AUTH:
650 		template = auth_detail_template;
651 		deffilename = "detail.auth";
652 		break;
653 
654 	default:
655 		return 1;
656 	}
657 
658         filename = make_detail_filename(radreq, template, deffilename);
659 	if (!filename)
660 		return 1;
661 
662 	/* Change to the accounting directory */
663 	if (chdir(grad_acct_dir)) {
664 		grad_free(filename);
665 		return 1;
666 	}
667 
668         /* Create a directory for this nas. */
669         make_path_to_file(filename, 0755);
670 
671         /* Write Detail file. */
672         if ((outfd = fopen(filename, "a")) == NULL) {
673                 grad_log(GRAD_LOG_ERR|GRAD_LOG_PERROR,
674                          _("can't open %s"), filename);
675                 ret = 1;
676         } else {
677 
678                 /* Post a timestamp */
679                 fprintf(outfd, "%s", ctime(&curtime));
680 
681                 /* Decide which username to log */
682                 if (!strip_names) {
683                         /* user wants a full (non-stripped) name to appear
684                            in detail */
685 
686                         pair = grad_avl_find(radreq->request->avlist,
687 					     DA_ORIG_USER_NAME);
688                         if (pair)
689                                 pair->name = "User-Name";
690                         else
691                                 pair = grad_avl_find(radreq->request->avlist,
692 						     DA_USER_NAME);
693                         if (pair) {
694                                 fprintf(outfd, "\t%s\n",
695                                         grad_format_pair(pair, 0, &save));
696                                 free(save);
697                         }
698                 }
699 
700                 /* Write each attribute/value to the log file */
701                 for (pair = radreq->request->avlist; pair; pair = pair->next) {
702 			if (pair->prop & GRAD_AP_INTERNAL)
703 				continue;
704                         switch (pair->attribute) {
705                         case DA_USER_PASSWORD:
706                                 break;
707                         case DA_USER_NAME:
708                         case DA_ORIG_USER_NAME:
709                                 if (!strip_names)
710                                         break;
711                         default:
712                                 fprintf(outfd, "\t%s\n",
713                                         grad_format_pair(pair, 0, &save));
714                                 free(save);
715                         }
716                 }
717 
718                 /* Add non-protocol attibutes. */
719                 fprintf(outfd, "\tTimestamp = %ld\n", curtime);
720                 switch (authtype) {
721 		case REQ_AUTH_OK:
722 			fprintf(outfd, "\tRequest-Authenticator = Verified\n");
723                         break;
724 		case REQ_AUTH_ZERO:
725                         fprintf(outfd, "\tRequest-Authenticator = None\n");
726                         break;
727 		case REQ_AUTH_BAD:
728                         fprintf(outfd, "\tRequest-Authenticator = Unverified\n");
729                         break;
730 		default:
731 			fprintf(outfd, "\tRequest-Authenticator = %d\n",
732 				authtype);
733                         break;
734                 }
735                 fprintf(outfd, "\n");
736                 fclose(outfd);
737                 ret = 0;
738         }
739 
740         grad_free(filename);
741         chdir("/");
742         return ret;
743 }
744 
745 int
rad_acct_db(radiusd_request_t * radreq,int authtype)746 rad_acct_db(radiusd_request_t *radreq, int authtype)
747 {
748         int rc = 0;
749 
750         if (acct_detail
751 	    && ACCT_TYPE(radreq->request->avlist, DV_ACCT_TYPE_DETAIL))
752                 rc = write_detail(radreq, authtype, R_ACCT);
753         if (ACCT_TYPE(radreq->request->avlist, DV_ACCT_TYPE_SQL))
754                 radiusd_sql_acct(radreq);
755         return rc;
756 }
757 
758 int
rad_acct_ext(radiusd_request_t * radreq)759 rad_acct_ext(radiusd_request_t *radreq)
760 {
761         grad_avp_t *p;
762 	int rc = 0;
763 
764 #ifdef USE_SERVER_GUILE
765         for (p = grad_avl_find(radreq->request->avlist, DA_SCHEME_ACCT_PROCEDURE);
766 	     p;
767 	     p = grad_avl_find(p->next, DA_SCHEME_ACCT_PROCEDURE))
768                 scheme_acct(p->avp_strvalue, radreq);
769 #endif
770         for (p = grad_avl_find(radreq->request->avlist, DA_ACCT_EXT_PROGRAM);
771 	     p;
772 	     p = grad_avl_find(p->next, DA_ACCT_EXT_PROGRAM)) {
773 		radius_eval_avp(radreq, p, NULL, 1);
774     		switch (p->avp_strvalue[0]) {
775 		case '/':
776                 	rc = radius_exec_program(p->avp_strvalue, radreq, NULL,
777 						 1);
778 			break;
779 		case '|':
780                 	filter_acct(p->avp_strvalue+1, radreq);
781                 }
782         }
783         return rc;
784 }
785 
786 /* run accounting modules */
787 int
rad_accounting(radiusd_request_t * radreq,int activefd,int verified)788 rad_accounting(radiusd_request_t *radreq, int activefd, int verified)
789 {
790 	log_open(GRAD_LOG_ACCT);
791 
792         huntgroup_access(radreq, NULL);
793 
794 #if defined(RT_ASCEND_EVENT_REQUEST) && defined(RT_ASCEND_EVENT_RESPONSE)
795         /* Special handling for Ascend-Event-Request */
796         if (radreq->request->code == RT_ASCEND_EVENT_REQUEST) {
797                 write_detail(radreq, verified, R_ACCT);
798                 radius_send_reply(RT_ASCEND_EVENT_RESPONSE,
799                                   radreq, NULL, NULL, activefd);
800                 stat_inc(acct, radreq->request->ipaddr, num_resp);
801                 return 0;
802         }
803 #endif
804 
805         if (rad_acct_system(radreq, doradwtmp) == 0 &&
806             rad_acct_db(radreq, verified) == 0 &&
807             rad_acct_ext(radreq) == 0) {
808                 /* Now send back an ACK to the NAS. */
809                 radius_send_reply(RT_ACCOUNTING_RESPONSE,
810                                radreq, NULL, NULL, activefd);
811                 stat_inc(acct, radreq->request->ipaddr, num_resp);
812                 return 0;
813         }
814 
815         return -1;
816 }
817 
818 int
write_nas_restart(int status,grad_uint32_t addr)819 write_nas_restart(int status, grad_uint32_t addr)
820 {
821         struct radutmp ut;
822 
823         memset(&ut, 0, sizeof(ut));
824         if (status == DV_ACCT_STATUS_TYPE_ACCOUNTING_ON)
825                 ut.type = P_NAS_START;
826         else
827                 ut.type = P_NAS_SHUTDOWN;
828         ut.nas_address = addr;
829         time(&ut.time);
830         return write_wtmp(&ut);
831 }
832 
833 
834 /* Multiple login checking */
835 
836 int
radutmp_mlc_collect_user(char * name,radiusd_request_t * request,grad_list_t ** sess_list)837 radutmp_mlc_collect_user(char *name, radiusd_request_t *request,
838 			 grad_list_t **sess_list)
839 {
840         radut_file_t file;
841 	struct radutmp *up;
842 
843         if ((file = grad_ut_setent(grad_utmp_file, 0)) == NULL)
844                 return 1;
845 
846         while (up = grad_ut_getent(file)) {
847                 if (strncmp(name, up->login, RUT_NAMESIZE) == 0 &&
848                     up->type == P_LOGIN) {
849 			struct radutmp *tmp;
850 
851 			if (*sess_list == NULL)
852 				*sess_list = grad_list_create();
853 			tmp = grad_emalloc(sizeof(*tmp));
854 			memcpy(tmp, up, sizeof(*tmp));
855 			grad_list_append(*sess_list, tmp);
856                 }
857 	}
858 	grad_ut_endent(file);
859 	return 0;
860 }
861 
862 int
radutmp_mlc_collect_realm(radiusd_request_t * request,grad_list_t ** sess_list)863 radutmp_mlc_collect_realm(radiusd_request_t *request, grad_list_t **sess_list)
864 {
865         radut_file_t file;
866 	struct radutmp *up;
867 
868         if ((file = grad_ut_setent(grad_utmp_file, 0)) == NULL)
869                 return 1;
870 
871         while (up = grad_ut_getent(file)) {
872                 if (up->type == P_LOGIN
873 		    && grad_realm_verify_ip(request->realm, up->realm_address)) {
874 			struct radutmp *tmp;
875 
876 			if (*sess_list == NULL)
877 				*sess_list = grad_list_create();
878 			tmp = grad_emalloc(sizeof(*tmp));
879 			memcpy(tmp, up, sizeof(*tmp));
880 			grad_list_append(*sess_list, tmp);
881                 }
882 	}
883 	grad_ut_endent(file);
884 	return 0;
885 }
886 
887 void
radutmp_mlc_close(struct radutmp * up)888 radutmp_mlc_close(struct radutmp *up)
889 {
890 	up->type = P_IDLE;
891 	up->time = time(NULL);
892 	grad_utmp_putent(grad_utmp_file, up, DV_ACCT_STATUS_TYPE_STOP);
893 }
894 
895 int
radutmp_mlc_enabled_p()896 radutmp_mlc_enabled_p()
897 {
898 	return acct_system;
899 }
900 
901 
902 
903 
904 
905 
906 
907 
908 
909 
910