1 /* Copyright (c) 2019, SWITCH */
2 /* See LICENSE for licensing information. */
3 
4 #include <ctype.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <regex.h>
8 #include <arpa/inet.h>
9 #include "debug.h"
10 #include "gconfig.h"
11 #include "hash.h"
12 #include "list.h"
13 #include "radmsg.h"
14 #include "rewrite.h"
15 #include "util.h"
16 
17 static struct hash *rewriteconfs;
18 
19 /** Extract attributes from string NAMEVAL, create a struct tlv and
20  * return the tlv.  If VENDOR_FLAG, NAMEVAL is on the form
21  * "<vendor>:<name>:<val>" and otherwise it's "<name>:<val>".  Return
22  * NULL if fields are missing or if conversion fails.
23  *
24  * FIXME: Should accept both names and numeric values, only numeric
25  * right now */
extractattr(char * nameval,char vendor_flag)26 struct tlv *extractattr(char *nameval, char vendor_flag) {
27     int len, name = 0;
28     int vendor = 0;	    /* Vendor 0 is reserved, see RFC 1700.  */
29     uint32_t ival=0;
30     char *s, *s2;
31     struct tlv *a;
32 
33     s = strchr(nameval, ':');
34     if (!s)
35         return NULL;
36     name = atoi(nameval);
37 
38     if (vendor_flag) {
39         s2 = strchr(s + 1, ':');
40         if (!s2)
41             return NULL;
42         vendor = name;
43         name = atoi(s + 1);
44         s = s2;
45     }
46 
47     s++;
48     if (isdigit(*s)) {
49         ival = atoi(s);
50         ival = htonl(ival);
51         len = 4;
52         s = (char *)&ival;
53     } else {
54         if (*s == '\'')
55             s++;
56 
57         len = unhex(s,1);
58         if (len > 253)
59             return NULL;
60     }
61 
62     if (name < 1 || name > 255)
63         return NULL;
64     a = malloc(sizeof(struct tlv));
65     if (!a)
66         return NULL;
67 
68     a->v = (uint8_t *)stringcopy(s, len);
69     if (!a->v) {
70         free(a);
71         return NULL;
72     }
73     a->t = name;
74     a->l = len;
75 
76     if (vendor_flag)
77         a = makevendortlv(vendor, a);
78 
79     return a;
80 }
81 
82 /* should accept both names and numeric values, only numeric right now */
extractmodattr(char * nameval)83 struct modattr *extractmodattr(char *nameval) {
84     int name = 0;
85     char *s, *t;
86     struct modattr *m;
87 
88     if (!strncasecmp(nameval, "User-Name:/", 11)) {
89         s = nameval + 11;
90         name = 1;
91     } else {
92         s = strchr(nameval, ':');
93         name = atoi(nameval);
94         if (!s || name < 1 || name > 255 || s[1] != '/')
95             return NULL;
96         s += 2;
97     }
98     /* regexp, remove optional trailing / if present */
99     if (s[strlen(s) - 1] == '/')
100         s[strlen(s) - 1] = '\0';
101 
102     for (t = strchr(s, '/'); t; t = strchr(t+1, '/'))
103         if (t == s || t[-1] != '\\')
104             break;
105     if (!t)
106         return NULL;
107     *t = '\0';
108     t++;
109 
110     m = malloc(sizeof(struct modattr));
111     if (!m) {
112         debug(DBG_ERR, "malloc failed");
113         return NULL;
114     }
115     m->t = name;
116 
117     m->replacement = stringcopy(t, 0);
118     if (!m->replacement) {
119         free(m);
120         debug(DBG_ERR, "malloc failed");
121         return NULL;
122     }
123 
124     m->regex = malloc(sizeof(regex_t));
125     if (!m->regex) {
126         free(m->replacement);
127         free(m);
128         debug(DBG_ERR, "malloc failed");
129         return NULL;
130     }
131 
132     if (regcomp(m->regex, s, REG_ICASE | REG_EXTENDED)) {
133         free(m->regex);
134         free(m->replacement);
135         free(m);
136         debug(DBG_ERR, "failed to compile regular expression %s", s);
137         return NULL;
138     }
139 
140     return m;
141 }
142 
extractmodvattr(char * nameval)143 struct modattr *extractmodvattr(char *nameval) {
144     uint32_t vendor;
145     char *s;
146     struct modattr *modvattr;
147 
148     s = strchr(nameval, ':');
149     vendor = atoi(nameval);
150     if (!s || !vendor || !strchr(s+1,':'))
151         return NULL;
152     modvattr = extractmodattr(s+1);
153     if (modvattr)
154         modvattr ->vendor = vendor;
155     return modvattr;
156 }
157 
addrewrite(char * value,uint8_t whitelist_mode,char ** rmattrs,char ** rmvattrs,char ** addattrs,char ** addvattrs,char ** modattrs,char ** modvattrs,char ** supattrs,char ** supvattrs)158 void addrewrite(char *value, uint8_t whitelist_mode, char **rmattrs, char **rmvattrs, char **addattrs,
159                 char **addvattrs, char **modattrs, char **modvattrs, char **supattrs, char** supvattrs)
160 {
161     struct rewrite *rewrite = NULL;
162     int i, n;
163     uint8_t *rma = NULL;
164     uint32_t *p, *rmva = NULL;
165     struct list *adda = NULL, *moda = NULL, *modva = NULL, *supa = NULL;
166     struct tlv *a;
167     struct modattr *m;
168 
169     if (rmattrs) {
170         for (n = 0; rmattrs[n]; n++);
171         rma = calloc(n + 1, sizeof(uint8_t));
172         if (!rma)
173             debugx(1, DBG_ERR, "malloc failed");
174 
175         for (i = 0; i < n; i++)
176             if (!(rma[i] = attrname2val(rmattrs[i])))
177                 debugx(1, DBG_ERR, "addrewrite: removing invalid attribute %s", rmattrs[i]);
178         freegconfmstr(rmattrs);
179         rma[i] = 0;
180     }
181 
182     if (rmvattrs) {
183         for (n = 0; rmvattrs[n]; n++);
184         rmva = calloc(2 * n + 1, sizeof(uint32_t));
185         if (!rmva)
186             debugx(1, DBG_ERR, "malloc failed");
187 
188         for (p = rmva, i = 0; i < n; i++, p += 2)
189             if (!vattrname2val(rmvattrs[i], p, p + 1))
190                 debugx(1, DBG_ERR, "addrewrite: removing invalid vendor attribute %s", rmvattrs[i]);
191         freegconfmstr(rmvattrs);
192         *p = 0;
193     }
194 
195     if (addattrs) {
196         adda = list_create();
197         if (!adda)
198             debugx(1, DBG_ERR, "malloc failed");
199         for (i = 0; addattrs[i]; i++) {
200             a = extractattr(addattrs[i], 0);
201             if (!a)
202                 debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", addattrs[i]);
203             if (!list_push(adda, a))
204                 debugx(1, DBG_ERR, "malloc failed");
205         }
206         freegconfmstr(addattrs);
207     }
208 
209     if (addvattrs) {
210         if (!adda)
211             adda = list_create();
212         if (!adda)
213             debugx(1, DBG_ERR, "malloc failed");
214         for (i = 0; addvattrs[i]; i++) {
215             a = extractattr(addvattrs[i], 1);
216             if (!a)
217                 debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", addvattrs[i]);
218             if (!list_push(adda, a))
219                 debugx(1, DBG_ERR, "malloc failed");
220         }
221         freegconfmstr(addvattrs);
222     }
223 
224     if (modattrs) {
225         moda = list_create();
226         if (!moda)
227             debugx(1, DBG_ERR, "malloc failed");
228         for (i = 0; modattrs[i]; i++) {
229             m = extractmodattr(modattrs[i]);
230             if (!m)
231                 debugx(1, DBG_ERR, "addrewrite: modifying invalid attribute %s", modattrs[i]);
232             if (!list_push(moda, m))
233                 debugx(1, DBG_ERR, "malloc failed");
234         }
235         freegconfmstr(modattrs);
236     }
237 
238     if (modvattrs) {
239         modva = list_create();
240         if (!modva)
241             debugx(1, DBG_ERR, "malloc failed");
242         for (i = 0; modvattrs[i]; i++) {
243             m = extractmodvattr(modvattrs[i]);
244             if (!m)
245                 debugx(1, DBG_ERR, "addrewrite: modifying invalid vendor attribute %s", modvattrs[i]);
246             if (!list_push(modva, m))
247                 debugx(1, DBG_ERR, "malloc failed");
248         }
249         freegconfmstr(modvattrs);
250     }
251 
252     if (supattrs) {
253         supa = list_create();
254         if (!supa)
255             debugx(1, DBG_ERR, "malloc failed");
256         for (i = 0; supattrs[i]; i++) {
257             a = extractattr(supattrs[i], 0);
258             if (!a)
259                 debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", supattrs[i]);
260             if (!list_push(supa, a))
261                 debugx(1, DBG_ERR, "malloc failed");
262         }
263         freegconfmstr(supattrs);
264     }
265 
266     if (supvattrs) {
267         if (!supa)
268             supa = list_create();
269         if (!supa)
270             debugx(1, DBG_ERR, "malloc failed");
271         for (i = 0; supvattrs[i]; i++) {
272             a = extractattr(supvattrs[i], 1);
273             if (!a)
274                 debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", supvattrs[i]);
275             if (!list_push(supa, a))
276                 debugx(1, DBG_ERR, "malloc failed");
277         }
278         freegconfmstr(supvattrs);
279     }
280 
281     if (rma || rmva || adda || moda || modva || supa) {
282         rewrite = malloc(sizeof(struct rewrite));
283         if (!rewrite)
284             debugx(1, DBG_ERR, "malloc failed");
285         rewrite->whitelist_mode = whitelist_mode;
286         rewrite->removeattrs = rma;
287         rewrite->removevendorattrs = rmva;
288         rewrite->addattrs = adda;
289         rewrite->modattrs = moda;
290         rewrite->modvattrs = modva;
291         rewrite->supattrs = supa;
292     }
293 
294     if (!rewriteconfs)
295         rewriteconfs = hash_create();
296     if (!hash_insert(rewriteconfs, value, strlen(value), rewrite))
297         debugx(1, DBG_ERR, "malloc failed");
298     debug(DBG_DBG, "addrewrite: added rewrite block %s", value);
299 }
300 
getrewrite(char * alt1,char * alt2)301 struct rewrite *getrewrite(char *alt1, char *alt2) {
302     struct rewrite *r;
303 
304     if (alt1)
305         if ((r = hash_read(rewriteconfs,  alt1, strlen(alt1))))
306             return r;
307     if (alt2)
308         if ((r = hash_read(rewriteconfs,  alt2, strlen(alt2))))
309             return r;
310     return NULL;
311 }
312 
findvendorsubattr(uint32_t * attrs,uint32_t vendor,uint32_t subattr)313 int findvendorsubattr(uint32_t *attrs, uint32_t vendor, uint32_t subattr) {
314     if (!attrs)
315         return 0;
316 
317     for (; attrs[0]; attrs += 2)
318         if (attrs[0] == vendor && attrs[1] == subattr)
319             return 1;
320     return 0;
321 }
322 
323 /* returns 1 if entire element is to be removed, else 0 */
dovendorrewriterm(struct tlv * attr,uint32_t * removevendorattrs,int inverted)324 int dovendorrewriterm(struct tlv *attr, uint32_t *removevendorattrs, int inverted) {
325     uint8_t alen, sublen;
326     uint32_t vendor;
327     uint8_t *subattrs;
328 
329     if (!removevendorattrs || attr->l <= 4)
330         return 0;
331 
332     memcpy(&vendor, attr->v, 4);
333     vendor = ntohl(vendor);
334     while (*removevendorattrs && *removevendorattrs != vendor)
335         removevendorattrs += 2;
336             if (!*removevendorattrs)
337                 return 0;
338 
339     if (findvendorsubattr(removevendorattrs, vendor, 256))
340         return 1; /* remove entire vendor attribute */
341 
342     sublen = attr->l - 4;
343     subattrs = attr->v + 4;
344 
345     if (!attrvalidate(subattrs, sublen)) {
346         debug(DBG_INFO, "dovendorrewrite: vendor attribute validation failed, no rewrite");
347         return 0;
348     }
349 
350     while (sublen > 1) {
351         alen = ATTRLEN(subattrs);
352         sublen -= alen;
353         if (!!findvendorsubattr(removevendorattrs, vendor, ATTRTYPE(subattrs)) != !!inverted) {
354             memmove(subattrs, subattrs + alen, sublen);
355             attr->l -= alen;
356         } else
357             subattrs += alen;
358     }
359     if ((attr->l <= 4) != !!inverted)
360         return 1;
361     return 0;
362 }
363 
364 /*if inverted is true, remove all attributes except those listed */
dorewriterm(struct radmsg * msg,uint8_t * rmattrs,uint32_t * rmvattrs,int inverted)365 void dorewriterm(struct radmsg *msg, uint8_t *rmattrs, uint32_t *rmvattrs, int inverted) {
366     struct list_node *n, *p;
367     struct tlv *attr;
368 
369     p = NULL;
370     n = list_first(msg->attrs);
371     while (n) {
372         attr = (struct tlv *)n->data;
373         if (((rmattrs && strchr((char *)rmattrs, attr->t)) ||
374             (rmvattrs && attr->t == RAD_Attr_Vendor_Specific && dovendorrewriterm(attr, rmvattrs, inverted))) != !!inverted) {
375             list_removedata(msg->attrs, attr);
376             freetlv(attr);
377             n = p ? list_next(p) : list_first(msg->attrs);
378         } else {
379             p = n;
380             n = list_next(n);
381         }
382     }
383 }
384 
dorewritemodattr(struct tlv * attr,struct modattr * modattr)385 int dorewritemodattr(struct tlv *attr, struct modattr *modattr) {
386     size_t nmatch = 10, reslen = 0, start = 0;
387     regmatch_t pmatch[10], *pfield;
388     int i;
389     char *in, *out;
390 
391     in = stringcopy((char *)attr->v, attr->l);
392     if (!in)
393         return 0;
394 
395     if (regexec(modattr->regex, in, nmatch, pmatch, 0)) {
396         free(in);
397         return 1;
398     }
399 
400     out = modattr->replacement;
401 
402     for (i = start; out[i]; i++) {
403         if (out[i] == '\\' && out[i + 1] >= '1' && out[i + 1] <= '9') {
404             pfield = &pmatch[out[i + 1] - '0'];
405             if (pfield->rm_so >= 0) {
406                 reslen += i - start + pfield->rm_eo - pfield->rm_so;
407                 start = i + 2;
408             }
409         i++;
410         }
411     }
412     reslen += i - start;
413     if (!resizeattr(attr, reslen)) {
414         debug(DBG_INFO, "rewritten attribute to length %d failed, discarding message", reslen);
415         free(in);
416         return 0;
417     }
418 
419     start = 0;
420     reslen = 0;
421     for (i = start; out[i]; i++) {
422         if (out[i] == '\\' && out[i + 1] >= '1' && out[i + 1] <= '9') {
423             pfield = &pmatch[out[i + 1] - '0'];
424             if (pfield->rm_so >= 0) {
425                 memcpy(attr->v + reslen, out + start, i - start);
426                 reslen += i - start;
427                 memcpy(attr->v + reslen, in + pfield->rm_so, pfield->rm_eo - pfield->rm_so);
428                 reslen += pfield->rm_eo - pfield->rm_so;
429                 start = i + 2;
430             }
431         i++;
432         }
433     }
434     free(in);
435 
436     memcpy(attr->v + reslen, out + start, i - start);
437     return 1;
438 }
439 
replacesubtlv(struct tlv * vendortlv,uint8_t * p,struct tlv * newtlv)440 int replacesubtlv(struct tlv *vendortlv, uint8_t *p, struct tlv *newtlv) {
441     int size_diff;
442     uint8_t rem_size, *next_attr;
443 
444     size_diff = newtlv->l - ATTRLEN(p);
445     next_attr = p+ATTRLEN(p);
446     rem_size = (vendortlv->v + vendortlv->l) - next_attr;
447 
448     if (size_diff < 0)
449         memmove(next_attr + size_diff, next_attr, rem_size);
450     if (!resizeattr(vendortlv, vendortlv->l+size_diff))
451         return 0;
452     if (size_diff > 0)
453         memmove(next_attr + size_diff, next_attr, rem_size);
454 
455     tlv2buf(p, newtlv);
456     return 1;
457 }
458 
dorewritemodvattr(struct tlv * vendortlv,struct modattr * modvattr)459 int dorewritemodvattr(struct tlv *vendortlv, struct modattr *modvattr) {
460     struct tlv *tmpattr;
461     int offset;
462 
463     if (vendortlv->l <= 4 || !attrvalidate(vendortlv->v+4, vendortlv->l-4))
464         return 0;
465     for (offset = 4; offset < vendortlv->l; offset += ATTRLEN(vendortlv->v+offset)) {
466         if (ATTRTYPE(vendortlv->v+offset) == modvattr->t) {
467             tmpattr = maketlv(ATTRTYPE(vendortlv->v+offset), ATTRVALLEN(vendortlv->v+offset), ATTRVAL(vendortlv->v+offset));
468             if (!tmpattr)
469                 return 0;
470             if (dorewritemodattr(tmpattr, modvattr)) {
471                 int size_diff = tmpattr->l - ATTRVALLEN(vendortlv->v+offset);
472                 int rem_size = vendortlv->l - offset - ATTRLEN(vendortlv->v+offset);
473                 uint8_t *next;
474 
475                 if (size_diff > 0)
476                     if (!resizeattr(vendortlv, vendortlv->l+size_diff)) {
477                         freetlv(tmpattr);
478                         return 0;
479                     }
480                 next = vendortlv->v + offset + ATTRLEN(vendortlv->v+offset);
481                 memmove(next + size_diff, next, rem_size);
482                 if (size_diff < 0)
483                     if (!resizeattr(vendortlv, vendortlv->l+size_diff)) {
484                         freetlv(tmpattr);
485                         return 0;
486                     }
487 
488                 tlv2buf(vendortlv->v+offset, tmpattr);
489             } else {
490                 freetlv(tmpattr);
491                 return 0;
492             }
493             freetlv(tmpattr);
494         }
495     }
496     return 1;
497 }
498 
dorewritemod(struct radmsg * msg,struct list * modattrs,struct list * modvattrs)499 int dorewritemod(struct radmsg *msg, struct list *modattrs, struct list *modvattrs) {
500     struct list_node *n, *m;
501     uint32_t vendor;
502 
503     for (n = list_first(msg->attrs); n; n = list_next(n)) {
504         struct tlv *attr = (struct tlv *)n->data;
505         if (attr->t == RAD_Attr_Vendor_Specific) {
506             memcpy(&vendor, attr->v, 4);
507             vendor = ntohl(vendor);
508             for (m = list_first(modvattrs); m; m = list_next(m)) {
509                 if (vendor == ((struct modattr *)m->data)->vendor &&
510                     !dorewritemodvattr(attr, (struct modattr*)m->data))
511                     return 0;
512             }
513         } else {
514             for (m = list_first(modattrs); m; m = list_next(m))
515                 if (((struct tlv *)n->data)->t == ((struct modattr *)m->data)->t &&
516                     !dorewritemodattr((struct tlv *)n->data, (struct modattr *)m->data))
517                     return 0;
518         }
519     }
520     return 1;
521 }
522 
dorewriteadd(struct radmsg * msg,struct list * addattrs)523 int dorewriteadd(struct radmsg *msg, struct list *addattrs) {
524     struct list_node *n;
525     struct tlv *a;
526 
527     for (n = list_first(addattrs); n; n = list_next(n)) {
528         a = copytlv((struct tlv *)n->data);
529         if (!a)
530             return 0;
531         if (!radmsg_add(msg, a)) {
532             freetlv(a);
533             return 0;
534         }
535     }
536     return 1;
537 }
538 
dorewritesup(struct radmsg * msg,struct list * supattrs)539 int dorewritesup(struct radmsg *msg, struct list *supattrs) {
540     struct list_node *n, *p;
541     struct tlv *attr, *supattr;
542     uint8_t exist, *vendortype, *v;;
543 
544     for (n = list_first(supattrs); n; n = list_next(n)) {
545         supattr = (struct tlv *)n->data;
546         exist = 0;
547         for(p = list_first(msg->attrs); p; p = list_next(p)) {
548             attr = (struct tlv *)p->data;
549             if (attr->t == supattr->t && attr->t != RAD_Attr_Vendor_Specific) {
550                 exist = 1;
551                 break;
552             } else if (supattr->t == RAD_Attr_Vendor_Specific && attr->t == RAD_Attr_Vendor_Specific &&
553                         memcmp (supattr->v, attr->v, 4)==0) {
554                 if (!attrvalidate(attr->v+4, attr->l-4)) {
555                     debug(DBG_INFO, "dorewritesup: vendor attribute validation failed, no rewrite");
556                     return 0;
557                 }
558                 vendortype = (uint8_t *)supattr->v+4;
559                 for (v=attr->v+4; v < attr->v + attr->l; v += *(v+1)){
560                     if (*v == *vendortype) {
561                         exist = 1;
562                         break;
563                     }
564                 }
565                 if (exist) break;
566             }
567         }
568         if (!exist) {
569             supattr = copytlv(supattr);
570             if (!supattr)
571                 return 0;
572             if (!radmsg_add(msg, supattr)) {
573                 freetlv(supattr);
574                 return 0;
575             }
576         }
577     }
578     return 1;
579 }
580 
dorewrite(struct radmsg * msg,struct rewrite * rewrite)581 int dorewrite(struct radmsg *msg, struct rewrite *rewrite) {
582     int rv = 1;			/* Success.  */
583 
584     if (rewrite) {
585         if (rewrite->removeattrs || rewrite->removevendorattrs)
586             dorewriterm(msg, rewrite->removeattrs, rewrite->removevendorattrs, rewrite->whitelist_mode);
587         if (rewrite->modattrs || rewrite->modvattrs)
588             if (!dorewritemod(msg, rewrite->modattrs, rewrite->modvattrs))
589                 rv = 0;
590         if (rewrite->supattrs)
591             if (!dorewritesup(msg, rewrite->supattrs))
592                 rv = 0;
593         if (rewrite->addattrs)
594             if (!dorewriteadd(msg, rewrite->addattrs))
595                 rv = 0;
596     }
597     return rv;
598 }
599 
600 /** Ad vendor attribute with VENDOR + ATTR and push it on MSG.  ATTR
601  * is consumed.  */
addvendorattr(struct radmsg * msg,uint32_t vendor,struct tlv * attr)602 int addvendorattr(struct radmsg *msg, uint32_t vendor, struct tlv *attr) {
603     struct tlv *vattr;
604 
605     vattr = makevendortlv(vendor, attr);
606     if (!vattr) {
607         freetlv(attr);
608         return 0;
609     }
610     if (!radmsg_add(msg, vattr)) {
611         freetlv(vattr);
612         return 0;
613     }
614     return 1;
615 }
616 
617 /* Local Variables: */
618 /* c-file-style: "stroustrup" */
619 /* End: */
620