2 * valuepair.c Functions to handle VALUE_PAIRs
8 static const char rcsid[] = "$Id$";
12 #include <sys/types.h>
21 #include "libradius.h"
29 static char *months[] = {
30 "jan", "feb", "mar", "apr", "may", "jun",
31 "jul", "aug", "sep", "oct", "nov", "dec" };
35 * Create a new valuepair.
37 VALUE_PAIR *paircreate(int attr, int type)
42 if ((vp = malloc(sizeof(VALUE_PAIR))) == NULL)
44 memset(vp, 0, sizeof(VALUE_PAIR));
47 if ((da = dict_attrbyvalue(attr)) != NULL)
48 strcpy(vp->name, da->name);
50 sprintf(vp->name, "Attr-%d", attr);
66 * Release the memory used by a list of attribute-value
69 void pairfree(VALUE_PAIR *pair)
82 * Find the pair with the matching attribute
84 VALUE_PAIR * pairfind(VALUE_PAIR *first, int attr)
86 while(first && first->attribute != attr)
93 * Delete the pair(s) with the matching attribute
95 void pairdelete(VALUE_PAIR **first, int attr)
97 VALUE_PAIR *i, *next, *last = NULL;
99 for(i = *first; i; i = next) {
101 if (i->attribute == attr) {
113 * Add a pair at the end of a VALUE_PAIR list.
115 void pairadd(VALUE_PAIR **first, VALUE_PAIR *new)
120 if (*first == NULL) {
124 for(i = *first; i->next; i = i->next)
130 * Copy just a certain type of pairs.
132 VALUE_PAIR *paircopy2(VALUE_PAIR *vp, int attr)
134 VALUE_PAIR *first, *n, *last;
140 if (attr >= 0 && vp->attribute != attr) {
144 if ((n = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL)
146 memcpy(n, vp, sizeof(VALUE_PAIR));
162 VALUE_PAIR *paircopy(VALUE_PAIR *vp)
164 return paircopy2(vp, -1);
169 * Move attributes from one list to the other
170 * if not already present.
172 void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
174 VALUE_PAIR *tailto, *i, *next;
175 VALUE_PAIR *tailfrom = NULL;
176 int has_password = 0;
185 * First, see if there are any passwords here, and
186 * point "tailto" to the end of the "to" list.
189 for(i = *to; i; i = i->next) {
190 if (i->attribute == PW_PASSWORD ||
192 * FIXME: this seems to be needed with PAM support
193 * to keep it around the Auth-Type = Pam stuff.
194 * Perhaps we should only do this if Auth-Type = Pam?
197 i->attribute == PAM_AUTH_ATTR ||
199 i->attribute == PW_CRYPT_PASSWORD)
205 * Loop over the "from" list.
207 for(i = *from; i; i = next) {
210 * If there was a password in the "to" list,
211 * do not move any other password from the
212 * "from" to the "to" list.
215 (i->attribute == PW_PASSWORD ||
217 i->attribute == PAM_AUTH_ATTR ||
219 i->attribute == PW_CRYPT_PASSWORD)) {
224 * If the attribute is already present in "to",
225 * do not move it from "from" to "to". We make
226 * an exception for "Hint" which can appear multiple
227 * times, and we never move "Fall-Through".
229 if (i->attribute == PW_FALL_THROUGH ||
230 (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE
231 && pairfind(*to, i->attribute) != 0)) {
236 tailfrom->next = next;
246 * Move one kind of attributes from one list to the other
248 void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr)
250 VALUE_PAIR *to_tail, *i, *next;
251 VALUE_PAIR *iprev = NULL;
254 * Find the last pair in the "to" list and put it in "to_tail".
258 for(i = *to; i; i = i->next)
263 for(i = *from; i; i = next) {
266 if (i->attribute != attr) {
272 * Remove the attribute from the "from" list.
280 * Add the attribute to the "to" list.
293 * Sort of strtok/strsep function.
295 static char *mystrtok(char **ptr, char *sep)
301 while (**ptr && strchr(sep, **ptr))
306 while (**ptr && strchr(sep, **ptr) == NULL)
314 * Turn printable string into time_t
316 static time_t gettime(char *valstr)
328 strncpy(buf, valstr, sizeof(buf));
329 buf[sizeof(buf) - 1] = 0;
330 for (p = buf; *p; p++)
331 if (isupper(*p)) *p = tolower(*p);
334 d = mystrtok(&p, " \t");
335 m = mystrtok(&p, " \t");
336 y = mystrtok(&p, " \t");
337 if (!y || !m || !d) return 0;
339 for (i = 0; i < 12; i++) {
340 if (strncmp(months[i], y, 3) == 0) {
345 tm->tm_mday = atoi(m);
346 tm->tm_year = atoi(y);
347 if (tm->tm_year >= 1900) tm->tm_year -= 1900;
353 * Create a VALUE_PAIR from an ASCII attribute and value.
355 VALUE_PAIR *pairmake(char *attribute, char *value, int operator)
362 if ((da = dict_attrbyname(attribute)) == NULL) {
363 librad_log("unknown attribute %s", attribute);
367 if ((vp = (VALUE_PAIR *)malloc(sizeof(VALUE_PAIR))) == NULL) {
368 librad_log("out of memory");
372 memset(vp, 0, sizeof(VALUE_PAIR));
373 vp->attribute = da->attr;
375 vp->operator = (operator == 0) ? T_OP_EQ : operator;
376 strcpy(vp->name, da->name);
379 * Even for integers, dates and ip addresses we
380 * keep the original string in vp->strvalue.
382 strncpy(vp->strvalue, value, MAX_STRING_LEN);
383 vp->strvalue[MAX_STRING_LEN - 1] = 0;
387 vp->length = strlen(value);
388 if (vp->length >= MAX_STRING_LEN) {
389 vp->length = MAX_STRING_LEN - 1;
394 * FIXME: complain if hostname
395 * cannot be resolved, or resolve later!
397 if ((p = strrchr(value, '+')) != NULL && !p[1]) {
402 vp->lvalue = librad_dodns ? ip_getaddr(value) :
407 case PW_TYPE_INTEGER:
409 * For PW_NAS_PORT_ID, allow a
410 * port range instead of just a port.
412 if (vp->attribute == PW_NAS_PORT_ID) {
413 for(s = value; *s; s++)
414 if (!isdigit(*s)) break;
416 vp->type = PW_TYPE_STRING;
417 vp->length = strlen(value);
421 if (isdigit(*value)) {
422 vp->lvalue = atoi(value);
425 else if ((dval = dict_valbyname(value)) == NULL) {
427 librad_log("unknown value %s", value);
431 vp->lvalue = dval->value;
437 if ((vp->lvalue = gettime(value)) == (time_t)-1) {
439 librad_log("failed to get time");
444 case PW_TYPE_ABINARY:
447 * special case to convert filter to binary
449 if ( filterBinary( vp, value ) < 0 ) {
450 librad_log("failed to parse Ascend binary attribute: %s",
458 /* raw octets: 0x01020304... */
461 if (strncasecmp(value, "0x", 2) == 0) {
464 while (*p && vp->length < MAX_STRING_LEN) {
467 if (sscanf(p, "%02x", &tmp) != 1) break;
478 librad_log("unknown attribute type %d", da->type);
485 * Read a valuepair from a buffer, and advance pointer.
486 * Sets *eol to 1 if end of line was encountered.
488 VALUE_PAIR *pairread(char **ptr, int *eol)
499 gettoken(ptr, attr, sizeof(attr));
501 librad_log("No token read");
505 /* Now we should have an '=' here. */
506 token = gettoken(ptr, buf, sizeof(buf));
507 if (token < T_EQSTART || token > T_EQEND) {
508 librad_log("expecting '='");
513 gettoken(ptr, value, sizeof(value));
515 librad_log("failed to get value");
520 * Peek at the next token. Must be T_EOL or T_COMMA.
523 t = gettoken(&p, buf, sizeof(buf));
524 if (t != T_EOL && t != T_COMMA) {
525 librad_log("Expected end of line or comma");
532 * HACK: should peek again, taking shortcut :)
540 return pairmake(attr, value, token);
544 * Read one line of attribute/value pairs. This might contain
545 * multiple pairs seperated by comma's.
547 int userparse(char *buffer, VALUE_PAIR **first_pair)
554 * We allow an empty line.
561 if ((vp = pairread(&p, &eol)) == NULL)
563 pairadd(first_pair, vp);