📄 valuepair.c
字号:
/* * valuepair.c Functions to handle VALUE_PAIRs * * Version: $Id: valuepair.c,v 1.141 2008/04/18 14:09:56 aland Exp $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000,2006 The FreeRADIUS server project */#include <freeradius-devel/ident.h>RCSID("$Id: valuepair.c,v 1.141 2008/04/18 14:09:56 aland Exp $")#include <freeradius-devel/libradius.h>#include <ctype.h>#ifdef HAVE_MALLOC_H# include <malloc.h>#endif#ifdef HAVE_REGEX_H# include <regex.h>#endifstatic const char *months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };/* * This padding is necessary only for attributes that are NOT * in the dictionary, and then only because the rest of the * code accesses vp->name directly, rather than through an * accessor function. * * The name padding only has to large enough for: * * Vendor-65535-Attr-65535 * * i.e. 23 characters, plus a zero. We add another 8 bytes for * padding, because the VALUE_PAIR structure may be un-aligned. * * The result is that for the normal case, the server uses a less * memory (36 bytes * number of VALUE_PAIRs). */#define FR_VP_NAME_PAD (32)#define FR_VP_NAME_LEN (24)VALUE_PAIR *pairalloc(DICT_ATTR *da){ size_t name_len = 0; VALUE_PAIR *vp; /* * Not in the dictionary: the name is allocated AFTER * the VALUE_PAIR struct. */ if (!da) name_len = FR_VP_NAME_PAD; vp = malloc(sizeof(*vp) + name_len); if (!vp) return NULL; memset(vp, 0, sizeof(*vp)); if (da) { vp->attribute = da->attr; vp->vendor = da->vendor; vp->type = da->type; vp->name = da->name; vp->flags = da->flags; } else { vp->attribute = 0; vp->vendor = 0; vp->type = PW_TYPE_OCTETS; vp->name = NULL; memset(&vp->flags, 0, sizeof(vp->flags)); vp->flags.unknown_attr = 1; } switch (vp->type) { case PW_TYPE_BYTE: vp->length = 1; break; case PW_TYPE_SHORT: vp->length = 2; break; case PW_TYPE_INTEGER: case PW_TYPE_IPADDR: case PW_TYPE_DATE: vp->length = 4; break; case PW_TYPE_IFID: vp->length = sizeof(vp->vp_ifid); break; case PW_TYPE_IPV6ADDR: vp->length = sizeof(vp->vp_ipv6addr); break; case PW_TYPE_IPV6PREFIX: vp->length = sizeof(vp->vp_ipv6prefix); break; case PW_TYPE_ETHERNET: vp->length = sizeof(vp->vp_ether); break; default: vp->length = 0; break; } return vp;}/* * Create a new valuepair. */VALUE_PAIR *paircreate(int attr, int type){ VALUE_PAIR *vp; DICT_ATTR *da; da = dict_attrbyvalue(attr); if ((vp = pairalloc(da)) == NULL) { librad_log("out of memory"); return NULL; } vp->operator = T_OP_EQ; /* * It isn't in the dictionary: update the name. */ if (!da) { char *p = (char *) (vp + 1); vp->vendor = VENDOR(attr); vp->attribute = attr; vp->name = p; vp->type = type; /* be forgiving */ if (!vp_print_name(p, FR_VP_NAME_LEN, vp->attribute)) { free(vp); return NULL; } } return vp;}/* * release the memory used by a single attribute-value pair * just a wrapper around free() for now. */void pairbasicfree(VALUE_PAIR *pair){ /* clear the memory here */ memset(pair, 0, sizeof(*pair)); free(pair);}/* * Release the memory used by a list of attribute-value * pairs, and sets the pair pointer to NULL. */void pairfree(VALUE_PAIR **pair_ptr){ VALUE_PAIR *next, *pair; if (!pair_ptr) return; pair = *pair_ptr; while (pair != NULL) { next = pair->next; pairbasicfree(pair); pair = next; } *pair_ptr = NULL;}/* * Find the pair with the matching attribute */VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr){ while(first && first->attribute != attr) first = first->next; return first;}/* * Delete the pair(s) with the matching attribute */void pairdelete(VALUE_PAIR **first, int attr){ VALUE_PAIR *i, *next; VALUE_PAIR **last = first; for(i = *first; i; i = next) { next = i->next; if (i->attribute == attr) { *last = next; pairbasicfree(i); } else { last = &i->next; } }}/* * Add a pair at the end of a VALUE_PAIR list. */void pairadd(VALUE_PAIR **first, VALUE_PAIR *add){ VALUE_PAIR *i; if (!add) return; if (*first == NULL) { *first = add; return; } for(i = *first; i->next; i = i->next) ; i->next = add;}/* * Add or replace a pair at the end of a VALUE_PAIR list. */void pairreplace(VALUE_PAIR **first, VALUE_PAIR *replace){ VALUE_PAIR *i, *next; VALUE_PAIR **prev = first; if (*first == NULL) { *first = replace; return; } /* * Not an empty list, so find item if it is there, and * replace it. Note, we always replace the first one, and * we ignore any others that might exist. */ for(i = *first; i; i = next) { next = i->next; /* * Found the first attribute, replace it, * and return. */ if (i->attribute == replace->attribute) { *prev = replace; /* * Should really assert that replace->next == NULL */ replace->next = next; pairbasicfree(i); return; } /* * Point to where the attribute should go. */ prev = &i->next; } /* * If we got here, we didn't find anything to replace, so * stopped at the last item, which we just append to. */ *prev = replace;}/* * Copy just one VP. */VALUE_PAIR *paircopyvp(const VALUE_PAIR *vp){ size_t name_len; VALUE_PAIR *n; if (!vp->flags.unknown_attr) { name_len = 0; } else { name_len = FR_VP_NAME_PAD; } if ((n = malloc(sizeof(*n) + name_len)) == NULL) { librad_log("out of memory"); return NULL; } memcpy(n, vp, sizeof(*n) + name_len); n->next = NULL; return n;}/* * Copy just a certain type of pairs. */VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr){ VALUE_PAIR *first, *n, **last; first = NULL; last = &first; while (vp) { if (attr >= 0 && vp->attribute != attr) { vp = vp->next; continue; } n = paircopyvp(vp); if (!n) return first; *last = n; last = &n->next; vp = vp->next; } return first;}/* * Copy a pairlist. */VALUE_PAIR *paircopy(VALUE_PAIR *vp){ return paircopy2(vp, -1);}/* * Move attributes from one list to the other * if not already present. */void pairmove(VALUE_PAIR **to, VALUE_PAIR **from){ VALUE_PAIR **tailto, *i, *j, *next; VALUE_PAIR *tailfrom = NULL; VALUE_PAIR *found; int has_password = 0; /* * First, see if there are any passwords here, and * point "tailto" to the end of the "to" list. */ tailto = to; for(i = *to; i; i = i->next) { if (i->attribute == PW_USER_PASSWORD || i->attribute == PW_CRYPT_PASSWORD) has_password = 1; tailto = &i->next; } /* * Loop over the "from" list. */ for(i = *from; i; i = next) { next = i->next; /* * If there was a password in the "to" list, * do not move any other password from the * "from" to the "to" list. */ if (has_password && (i->attribute == PW_USER_PASSWORD || i->attribute == PW_CRYPT_PASSWORD)) { tailfrom = i; continue; } switch (i->operator) { /* * These are COMPARISON attributes * from a check list, and are not * supposed to be copied! */ case T_OP_NE: case T_OP_GE: case T_OP_GT: case T_OP_LE: case T_OP_LT: case T_OP_CMP_TRUE: case T_OP_CMP_FALSE: case T_OP_CMP_EQ: tailfrom = i; continue; default: break; } /* * If the attribute is already present in "to", * do not move it from "from" to "to". We make * an exception for "Hint" which can appear multiple * times, and we never move "Fall-Through". */ if (i->attribute == PW_FALL_THROUGH || (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) { found = pairfind(*to, i->attribute); switch (i->operator) { /* * If matching attributes are found, * delete them. */ case T_OP_SUB: /* -= */ if (found) { if (!i->vp_strvalue[0] || (strcmp((char *)found->vp_strvalue, (char *)i->vp_strvalue) == 0)){ pairdelete(to, found->attribute); /* * 'tailto' may have been * deleted... */ tailto = to; for(j = *to; j; j = j->next) { tailto = &j->next; } } } tailfrom = i; continue; break;/* really HAVE_REGEX_H */#if 0 /* * Attr-Name =~ "s/find/replace/" * * Very bad code. Barely working, * if at all. */ case T_OP_REG_EQ: if (found && (i->vp_strvalue[0] == 's')) { regex_t reg; regmatch_t match[1]; char *str; char *p, *q; p = i->vp_strvalue + 1; q = strchr(p + 1, *p); if (!q || (q[strlen(q) - 1] != *p)) { tailfrom = i; continue; } str = strdup(i->vp_strvalue + 2); q = strchr(str, *p); *(q++) = '\0'; q[strlen(q) - 1] = '\0'; regcomp(®, str, 0); if (regexec(®, found->vp_strvalue, 1, match, 0) == 0) { fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n", found->vp_strvalue, match[0].rm_so, match[0].rm_eo, q); } regfree(®); free(str); } tailfrom = i; /* don't copy it over */ continue; break;#endif case T_OP_EQ: /* = */ /* * FIXME: Tunnel attributes with * different tags are different * attributes. */ if (found) { tailfrom = i; continue; /* with the loop */ } break; /* * If a similar attribute is found, * replace it with the new one. Otherwise, * add the new one to the list. */ case T_OP_SET: /* := */ if (found) { VALUE_PAIR *mynext = found->next; /* * Do NOT call pairdelete() * here, due to issues with * re-writing "request->username". * * Everybody calls pairmove, * and expects it to work. * We can't update request->username * here, so instead we over-write * the vp that it's pointing to. */ memcpy(found, i, sizeof(*found)); found->next = mynext; pairdelete(&found->next, found->attribute); /* * 'tailto' may have been * deleted... */ for(j = found; j; j = j->next) { tailto = &j->next; } continue; } break; /* * Add the new element to the list, even * if similar ones already exist. */ default: case T_OP_ADD: /* += */ break; } } if (tailfrom) tailfrom->next = next; else *from = next; /* * If ALL of the 'to' attributes have been deleted, * then ensure that the 'tail' is updated to point * to the head. */ if (!*to) { tailto = to; } *tailto = i; if (i) { i->next = NULL; tailto = &i->next; } }}/* * Move one kind of attributes from one list to the other */void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr){ VALUE_PAIR *to_tail, *i, *next; VALUE_PAIR *iprev = NULL; /* * Find the last pair in the "to" list and put it in "to_tail". */ if (*to != NULL) { to_tail = *to; for(i = *to; i; i = i->next) to_tail = i; } else to_tail = NULL; for(i = *from; i; i = next) { next = i->next; /* * If the attribute to move is NOT a VSA, then it * ignores any attributes which do not match exactly. */ if ((attr != PW_VENDOR_SPECIFIC) && (i->attribute != attr)) { iprev = i; continue; } /* * If the attribute to move IS a VSA, then it ignores * any non-VSA attribute. */ if ((attr == PW_VENDOR_SPECIFIC) && (VENDOR(i->attribute) == 0)) { iprev = i; continue; } /* * Remove the attribute from the "from" list. */ if (iprev) iprev->next = next; else *from = next; /* * Add the attribute to the "to" list. */ if (to_tail) to_tail->next = i; else *to = i; to_tail = i; i->next = NULL; }}/* * Sort of strtok/strsep function. */static char *mystrtok(char **ptr, const char *sep){ char *res; if (**ptr == 0) return NULL; while (**ptr && strchr(sep, **ptr)) (*ptr)++; if (**ptr == 0) return NULL; res = *ptr; while (**ptr && strchr(sep, **ptr) == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -