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