1 /* This file is part of GNU Radius.
2    Copyright (C) 2000,2001,2002,2003,2004,2005,
3    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
18    License along with GNU Radius; if not, write to the Free
19    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301 USA. */
21 
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25 
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <netinet/in.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <netdb.h>
34 #include <pwd.h>
35 #include <ctype.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <sys/stat.h>
40 #include <sys/file.h>
41 #include <pwd.h>
42 #include <grp.h>
43 
44 #include <radlib.h>
45 #include "intprops.h"
46 
47 grad_request_t *
grad_request_alloc()48 grad_request_alloc()
49 {
50         return grad_emalloc(sizeof(grad_request_t));
51 }
52 
53 /* Free a grad_request_t struct.
54  */
55 void
grad_request_free(grad_request_t * radreq)56 grad_request_free(grad_request_t *radreq)
57 {
58         grad_avl_free(radreq->avlist);
59         grad_free(radreq);
60 }
61 
62 /* Turn printable string (dictionary type DATE) into correct tm struct entries
63  */
64 static char *months[] = {
65         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
66         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
67 
68 int
grad_parse_time_string(char * valstr,struct tm * tm)69 grad_parse_time_string(char *valstr, struct tm *tm)
70 {
71         int     i;
72 
73         /* Get the month */
74         for (i = 0; i < 12; i++) {
75                 if (grad_c_strncasecmp(months[i], valstr, 3) == 0) {
76                         tm->tm_mon = i;
77                         break;
78                 }
79         }
80 
81         if (i == 12)
82                 return -1;
83 
84         valstr += 3;
85         while (*valstr && isspace(*valstr))
86                 valstr++;
87 
88         if (!*valstr)
89                 return -1;
90 
91         /* Get the Day */
92         tm->tm_mday = strtol(valstr, &valstr, 10);
93 
94         while (*valstr && isspace(*valstr))
95                 valstr++;
96         if (!*valstr)
97                 return -1;
98 
99         /* Now the year */
100         tm->tm_year = strtol(valstr, &valstr, 10) - 1900;
101 
102         return 0;
103 }
104 
105 /* Lock `size' bytes on the file descriptor `fd' starting from `offset'.
106  * `whence' determines from where the offset is counted (seek-like)
107  */
108 void
grad_lock_file(int fd,size_t size,off_t offset,int whence)109 grad_lock_file(int fd, size_t size, off_t offset, int whence)
110 {
111         struct flock fl;
112 
113         fl.l_type = F_WRLCK;
114         fl.l_whence = whence;
115         fl.l_start = offset;
116         fl.l_len = size;
117         fcntl(fd, F_SETLKW, &fl); /* FIXME: Handle EINTR */
118 }
119 
120 /* Unlock `size' bytes on the file descriptor `fd' starting from `offset'.
121  * `whence' determines from where the offset is counted (seek-like)
122  */
123 void
grad_unlock_file(int fd,size_t size,off_t offset,int whence)124 grad_unlock_file(int fd, size_t size, off_t offset, int whence)
125 {
126         struct flock fl;
127 
128         fl.l_type = F_UNLCK;
129         fl.l_whence = whence;
130         fl.l_start = offset;
131         fl.l_len = size;
132         fcntl(fd, F_SETLKW, &fl);
133 }
134 
135 /* Find a grad_keyword_t matching the given string. Return keyword token
136  * number if found. Otherwise return default value `def'.
137  */
138 int
grad_xlat_keyword(grad_keyword_t * kw,const char * str,int def)139 grad_xlat_keyword(grad_keyword_t *kw, const char *str, int def)
140 {
141         for ( ; kw->name; kw++)
142                 if (strcmp(str, kw->name) == 0)
143                         return kw->tok;
144         return def;
145 }
146 
147 /* compose a full pathname from given path and filename
148  */
149 char *
grad_mkfilename(char * dir,char * name)150 grad_mkfilename(char *dir, char *name)
151 {
152         int len = strlen(dir) + strlen(name);
153         char *p = grad_emalloc(len+2);
154         sprintf(p, "%s/%s", dir, name);
155         return p;
156 }
157 
158 /* compose a full pathname from given path, subdirectory and filename
159  */
160 char *
grad_mkfilename3(char * dir,char * subdir,char * name)161 grad_mkfilename3(char *dir, char *subdir, char *name)
162 {
163         int len = strlen(dir) + strlen(subdir) + strlen(name);
164         char *p = grad_emalloc(len+3); /* two intermediate slashes and
165                                         * terminating zero
166                                         */
167         sprintf(p, "%s/%s/%s", dir, subdir, name);
168         return p;
169 }
170 
171 int
grad_astrcat(char ** pptr,...)172 grad_astrcat(char **pptr, ...)
173 {
174 	va_list ap;
175 	size_t size = 0;
176 	char *s, *p;
177 
178 	va_start(ap, pptr);
179 	while ((s = va_arg(ap, char*)))
180 		size += strlen(s);
181 	va_end(ap);
182 	size++;
183 	p = malloc(size);
184 	if (!p)
185 		return 1;
186 	*p = 0;
187 	va_start(ap, pptr);
188 	while ((s = va_arg(ap, char*)))
189 		strcat(p, s);
190 	va_end(ap);
191 
192 	*pptr = p;
193 	return 0;
194 }
195 
196 /* Convert second character of a backslash sequence to its ASCII
197    value: */
198 int
grad_decode_backslash(int c)199 grad_decode_backslash(int c)
200 {
201         static char transtab[] = "a\ab\bf\fn\nr\rt\t";
202         char *p;
203 
204         for (p = transtab; *p; p += 2) {
205                 if (*p == c)
206                         return p[1];
207         }
208         return c;
209 }
210 
211 void
grad_string_copy(char * d,char * s,int len)212 grad_string_copy(char *d, char *s, int len)
213 {
214         int slen = strlen(s);
215 
216         if (slen > len)
217                 grad_log(GRAD_LOG_ERR, _("string too long: %s"), s);
218         strncpy(d, s, len);
219         d[len] = 0;
220 }
221 
222 char *
grad_op_to_str(enum grad_operator op)223 grad_op_to_str(enum grad_operator op)
224 {
225         switch (op) {
226         case grad_operator_equal:         return "=";
227         case grad_operator_not_equal:     return "!=";
228         case grad_operator_less_than:     return "<";
229         case grad_operator_greater_than:  return ">";
230         case grad_operator_less_equal:    return "<=";
231         case grad_operator_greater_equal: return ">=";
232 	default:
233 		break;
234         }
235         return "?";
236 }
237 
238 enum grad_operator
grad_str_to_op(char * str)239 grad_str_to_op(char *str)
240 {
241         int op = grad_operator_invalid;
242         switch (*str++) {
243         case '=':
244                 op = grad_operator_equal;
245                 break;
246         case '!':
247                 if (*str++ == '=')
248                         op = grad_operator_not_equal;
249                 break;
250         case '<':
251                 if (*str == 0)
252                         op = grad_operator_less_than;
253                 else if (*str++ == '=')
254                         op = grad_operator_less_equal;
255                 break;
256         case '>':
257                 if (*str == 0)
258                         op = grad_operator_greater_than;
259                 else if (*str++ == '=')
260                         op = grad_operator_greater_equal;
261                 break;
262         }
263         if (*str)
264                 op = grad_operator_invalid;
265         return op;
266 }
267 
268 static int
flush_seg(char ** bufp,char * seg,char * ptr,int runlen)269 flush_seg(char **bufp, char *seg, char *ptr, int runlen)
270 {
271         int outbytes = 0;
272         char *buf = *bufp;
273 
274         if (ptr - seg >= runlen) {
275                 outbytes += ptr - seg;
276                 if (buf)
277                         while (seg < ptr)
278                                 *buf++ = *seg++;
279         } else {
280                 outbytes += 4*(ptr - seg);
281                 if (buf)
282                         while (seg < ptr) {
283                                 sprintf(buf, "\\%03o", *(u_char*)seg);
284                                 seg++;
285                                 buf += 4;
286                         }
287         }
288         *bufp = buf;
289         return outbytes;
290 }
291 
292 /* Print LEN characters from STR to buffer BUF. If a sequence of RUNLEN
293    or more printable characters is encountered, it is printed as is,
294    otherwise, each character is printed as a three-digit octal number,
295    preceeded by a backslash (\%03o).
296    Return number of characters, _output_ to BUF. If BUF is NULL, no
297    printing is done, but the number of characters that would be output
298    (not counting null terminator) is returned. */
299 
300 int
grad_format_string_visual(char * buf,int runlen,char * str,int len)301 grad_format_string_visual(char *buf, int runlen, char *str, int len)
302 {
303         char *seg, *ptr;
304         int outbytes = 0;
305 
306         seg = NULL;
307         ptr = str;
308         while (len) {
309                 if (isprint(*ptr)) {
310                         if (!seg)
311                                 seg = ptr;
312                 } else {
313                         if (seg) {
314                                 outbytes += flush_seg(&buf, seg, ptr, runlen);
315                                 seg = NULL;
316                         }
317                         if (buf) {
318                                 sprintf(buf, "\\%03o", *(u_char*)ptr);
319                                 buf += 4;
320                         }
321                         outbytes += 4;
322                 }
323                 len--;
324                 ptr++;
325         }
326         /* Make last segment printable no matter how many chars it contains */
327         if (seg) {
328                 outbytes += ptr - seg;
329                 if (buf)
330                         while (seg < ptr)
331                                 *buf++ = *seg++;
332         }
333         if (buf)
334                 *buf++ = 0;
335         return outbytes;
336 }
337 
338 int
grad_format_vendor_pair(char * buf,grad_avp_t * pair)339 grad_format_vendor_pair(char *buf, grad_avp_t *pair)
340 {
341         int n;
342         grad_uint32_t vendor;
343         u_char *ptr = (u_char*)pair->avp_strvalue;
344         char buf1[64];
345         char *bufp = buf;
346 
347         memcpy(&vendor, ptr, 4);
348         ptr += 4;
349         n = snprintf(buf1, sizeof(buf1), "V%d", (int)ntohl(vendor));
350         if (n < 0)
351                 return -1;
352 
353         if (bufp) {
354                 memcpy(bufp, buf1, n);
355                 bufp += n;
356         }
357 
358         return n + grad_format_string_visual(bufp, 4, ptr,
359 					     pair->avp_strlength - 4);
360 }
361 
362 char *
grad_format_pair(grad_avp_t * pair,int typeflag,char ** savep)363 grad_format_pair(grad_avp_t *pair, int typeflag, char **savep)
364 {
365         char *buf1 = NULL;
366         char *buf2ptr = NULL;
367         char buf2[4*GRAD_STRING_LENGTH+1]; /* Enough to hold longest possible
368                                            string value all converted to
369                                            octal */
370         grad_dict_value_t *dval;
371         struct tm tm;
372         char *type = "";
373 
374         *savep = NULL;
375 
376         switch (pair->eval_type == grad_eval_const ? pair->type : GRAD_TYPE_STRING) {
377         case GRAD_TYPE_STRING:
378                 if (pair->attribute != DA_VENDOR_SPECIFIC) {
379                         int len = strlen (pair->avp_strvalue);
380                         if (len != pair->avp_strlength-1)
381                                 len = pair->avp_strlength;
382                         grad_format_string_visual(buf2, 4,
383 						  pair->avp_strvalue, len);
384                 } else if (pair->avp_strlength < 6)
385                         snprintf(buf2, sizeof(buf2),
386                                  "[invalid length: %d]", pair->avp_strlength);
387                 else {
388                         int len = grad_format_vendor_pair(NULL, pair);
389                         buf2ptr = malloc(len+1);
390                         if (!buf2ptr) {
391                                 grad_log(GRAD_LOG_ERR,
392                                          "%s:%d: can't alloc %d bytes",
393                                          __FILE__, __LINE__, len+1);
394                                 buf2[0] = 0;
395                         } else
396                                 grad_format_vendor_pair(buf2ptr, pair);
397                 }
398                 break;
399 
400         case GRAD_TYPE_INTEGER:
401                 if (pair->name && (pair->prop & GRAD_AP_TRANSLATE))
402                         dval = grad_value_lookup(pair->avp_lvalue, pair->name);
403                 else
404                         dval = NULL;
405 
406                 if (!dval)
407                         snprintf(buf2, sizeof(buf2), "%lu", pair->avp_lvalue);
408                 else
409                         snprintf(buf2, sizeof(buf2), "%s", dval->name);
410                 break;
411 
412         case GRAD_TYPE_IPADDR:
413                 grad_ip_iptostr(pair->avp_lvalue, buf2);
414                 break;
415 
416         case GRAD_TYPE_DATE:
417                 strftime(buf2, sizeof(buf2), "\"%b %e %Y\"",
418                          localtime_r((time_t *)&pair->avp_lvalue, &tm));
419                 break;
420         default:
421                 strncpy(buf2, "[UNKNOWN DATATYPE]", sizeof(buf2));
422         }
423 
424 	if (typeflag) {
425 		switch (pair->type) {
426 		case GRAD_TYPE_STRING:
427 			type = "(STRING) ";
428 			break;
429 
430 		case GRAD_TYPE_INTEGER:
431 			type = "(INTEGER) ";
432 			break;
433 
434 		case GRAD_TYPE_IPADDR:
435 			type = "(IPADDR) ";
436 			break;
437 
438 		case GRAD_TYPE_DATE:
439 			type = "(DATE) ";
440 			break;
441 		}
442 	}
443 
444         if (pair->name)
445 		grad_astrcat(&buf1,
446 			     pair->name, " ",
447 			     grad_op_to_str(pair->operator), " ",
448 			     type,
449 			     buf2ptr ? buf2ptr : buf2,
450 			     NULL);
451         else {
452 		char buf[INT_BUFSIZE_BOUND (int)];
453 
454 		grad_inttostr(pair->attribute, buf, sizeof buf);
455                 grad_astrcat(&buf1,
456 			     buf, " ",
457 			     grad_op_to_str(pair->operator), " ",
458 			     buf2ptr ? buf2ptr : buf2,
459 			     NULL);
460 	}
461 
462         if (buf2ptr)
463                 free(buf2ptr);
464 
465         *savep = buf1;
466         return buf1;
467 }
468 
469 /* Recompute the timeout TVAL taking into account the time elapsed since
470    START */
471 int
grad_recompute_timeout(struct timeval * start,struct timeval * tval)472 grad_recompute_timeout(struct timeval *start, struct timeval *tval)
473 {
474 	struct timeval now, diff;
475 
476 	gettimeofday(&now, NULL);
477 	timersub(&now, start, &diff);
478 	if (timercmp(&diff, tval, <)) {
479 		struct timeval tmp;
480 		timersub(tval, &diff, &tmp);
481 		*tval = tmp;
482 		return 0;
483 	}
484 	return 1;
485 }
486 
487