int main(int argc, char **argv) { PAIRLIST *list; DBUG_PUSH("d:t"); if(!(list = pairlist_init(&compare_string_ci_eq, &compare_string_ci_eq))) { fprintf(stderr, "Couldn't init pairlist\n"); return 1; } pairlist_add(list, "name", "Jeremy Cole"); pairlist_add(list, "age", "23"); pairlist_add(list, "height", "6'1\""); printf("name=%s age=%s height=%s\n", pairlist_get_value(list, "name"), pairlist_get_value(list, "age"), pairlist_get_value(list, "height")); pairlist_dump(list); pairlist_free(list); return 0; }
/* * Clean up. */ static int attr_filter_detach(void *instance) { struct attr_filter_instance *inst = instance; pairlist_free(&inst->attrs); free(inst->attrsfile); free(inst); return 0; }
int rad_load_credentials(TALLOC_CTX *ctx, ikev2_ctx *i2,char *filename,char *authtype_name) { rad_assert(i2 && filename && authtype_name); int authtype; authtype=AuthtypeFromName(authtype_name); if(authtype==-1) { ERROR(IKEv2_LOG_PREFIX "Unsupported 'default_auth_type' value (%s), using both",authtype_name); authtype=IKEv2_AUTH_BOTH; } PAIR_LIST *users=NULL; if(getusersfile(ctx, filename,&users,"no")!=0) { ERROR(IKEv2_LOG_PREFIX "Error while loading %s userfile",filename); return -1; } PAIR_LIST *tusers=users; while(tusers) { if(strcmp(tusers->name,"DEFAULT")) { rad_update_shared_seclist(&i2->sslist,tusers->name,tusers->check,authtype); } tusers=tusers->next; } pairlist_free(&users); //print sslist // struct sharedSecList *sslist=i2->sslist; // while(sslist) { // ERROR("sslist:id=%s",sslist->id); // ERROR("sslist:idlen=%d",sslist->idlen); // ERROR("sslist:pwd=%s",sslist->pwd); // ERROR("sslist:pwdlen=%d",sslist->pwdlen); // ERROR("sslist:idtype= %d",sslist->idtype); // ERROR("sslist:authtype=%d",sslist->authtype); // sslist=sslist->next; // } return 0; }
static int getusersfile(TALLOC_CTX *ctx, char const *filename, fr_hash_table_t **pht, char *compat_mode_str) { int rcode; PAIR_LIST *users = NULL; PAIR_LIST *entry, *next; fr_hash_table_t *ht, *tailht; int order = 0; if (!filename) { *pht = NULL; return 0; } rcode = pairlist_read(ctx, filename, &users, 1); if (rcode < 0) { return -1; } /* * Walk through the 'users' file list, if we're debugging, * or if we're in compat_mode. */ if ((debug_flag) || (strcmp(compat_mode_str, "cistron") == 0)) { VALUE_PAIR *vp; int compat_mode = false; if (strcmp(compat_mode_str, "cistron") == 0) { compat_mode = true; } entry = users; while (entry) { vp_cursor_t cursor; if (compat_mode) { DEBUG("[%s]:%d Cistron compatibility checks for entry %s ...", filename, entry->lineno, entry->name); } /* * Look for improper use of '=' in the * check items. They should be using * '==' for on-the-wire RADIUS attributes, * and probably ':=' for server * configuration items. */ for (vp = paircursor(&cursor, &entry->check); vp; vp = pairnext(&cursor)) { /* * Ignore attributes which are set * properly. */ if (vp->op != T_OP_EQ) { continue; } /* * If it's a vendor attribute, * or it's a wire protocol, * ensure it has '=='. */ if ((vp->da->vendor != 0) || (vp->da->attr < 0x100)) { if (!compat_mode) { WDEBUG("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s", filename, entry->lineno, vp->da->name, vp->da->name, entry->name); } else { DEBUG("\tChanging '%s =' to '%s =='", vp->da->name, vp->da->name); } vp->op = T_OP_CMP_EQ; continue; } /* * Cistron Compatibility mode. * * Re-write selected attributes * to be '+=', instead of '='. * * All others get set to '==' */ if (compat_mode) { /* * Non-wire attributes become += * * On the write attributes * become == */ if ((vp->da->attr >= 0x100) && (vp->da->attr <= 0xffff) && (vp->da->attr != PW_HINT) && (vp->da->attr != PW_HUNTGROUP_NAME)) { DEBUG("\tChanging '%s =' to '%s +='", vp->da->name, vp->da->name); vp->op = T_OP_ADD; } else { DEBUG("\tChanging '%s =' to '%s =='", vp->da->name, vp->da->name); vp->op = T_OP_CMP_EQ; } } } /* end of loop over check items */ /* * Look for server configuration items * in the reply list. * * It's a common enough mistake, that it's * worth doing. */ for (vp = paircursor(&cursor, &entry->reply); vp; vp = pairnext(&cursor)) { /* * If it's NOT a vendor attribute, * and it's NOT a wire protocol * and we ignore Fall-Through, * then bitch about it, giving a * good warning message. */ if ((vp->da->vendor == 0) && (vp->da->attr > 0xff) && (vp->da->attr > 1000)) { WDEBUG("[%s]:%d Check item \"%s\"\n" "\tfound in reply item list for user \"%s\".\n" "\tThis attribute MUST go on the first line" " with the other check items", filename, entry->lineno, vp->da->name, entry->name); } } entry = entry->next; } } ht = fr_hash_table_create(pairlist_hash, pairlist_cmp, my_pairlist_free); if (!ht) { pairlist_free(&users); return -1; } tailht = fr_hash_table_create(pairlist_hash, pairlist_cmp, NULL); if (!tailht) { fr_hash_table_free(ht); pairlist_free(&users); return -1; } /* * Now that we've read it in, put the entries into a hash * for faster access. */ for (entry = users; entry != NULL; entry = next) { PAIR_LIST *tail; next = entry->next; entry->next = NULL; entry->order = order++; /* * Insert it into the hash table, and remember * the tail of the linked list. */ tail = fr_hash_table_finddata(tailht, entry); if (!tail) { /* * Insert it into the head & tail. */ if (!fr_hash_table_insert(ht, entry) || !fr_hash_table_insert(tailht, entry)) { pairlist_free(&next); fr_hash_table_free(ht); fr_hash_table_free(tailht); return -1; } } else { tail->next = entry; if (!fr_hash_table_replace(tailht, entry)) { pairlist_free(&next); fr_hash_table_free(ht); fr_hash_table_free(tailht); return -1; } } } fr_hash_table_free(tailht); *pht = ht; return 0; }
static void my_pairlist_free(void *data) { PAIR_LIST *pl = data; pairlist_free(&pl); }
/* * Read the users, huntgroups or hints file. * Return a PAIR_LIST. */ int pairlist_read(TALLOC_CTX *ctx, char const *file, PAIR_LIST **list, int complain) { FILE *fp; int mode = FIND_MODE_NAME; char entry[256]; char buffer[8192]; char const *ptr; VALUE_PAIR *check_tmp; VALUE_PAIR *reply_tmp; PAIR_LIST *pl = NULL, *t; PAIR_LIST **last = &pl; int lineno = 0; int old_lineno = 0; FR_TOKEN parsecode; char newfile[8192]; DEBUG2("reading pairlist file %s", file); /* * Open the file. The error message should be a little * more useful... */ if ((fp = fopen(file, "r")) == NULL) { if (!complain) return -1; ERROR("Couldn't open %s for reading: %s", file, fr_syserror(errno)); return -1; } parsecode = T_EOL; /* * Read the entire file into memory for speed. */ while(fgets(buffer, sizeof(buffer), fp) != NULL) { lineno++; if (!feof(fp) && (strchr(buffer, '\n') == NULL)) { fclose(fp); ERROR("%s[%d]: line too long", file, lineno); pairlist_free(&pl); return -1; } if (buffer[0] == '#' || buffer[0] == '\n') continue; /* * If the line contains nothing but whitespace, * ignore it. */ ptr = buffer; while (isspace((int) *ptr)) ptr++; if (*ptr == '\0') continue; parse_again: if(mode == FIND_MODE_NAME) { /* * Find the entry starting with the users name */ if (isspace((int) buffer[0])) { if (parsecode != T_EOL) { ERROR("%s[%d]: Unexpected trailing comma for entry %s", file, lineno, entry); fclose(fp); return -1; } continue; } ptr = buffer; getword(&ptr, entry, sizeof(entry)); /* * Include another file if we see * $INCLUDE filename */ if (strcasecmp(entry, "$INCLUDE") == 0) { while(isspace((int) *ptr)) ptr++; /* * If it's an absolute pathname, * then use it verbatim. * * If not, then make the $include * files *relative* to the current * file. */ if (FR_DIR_IS_RELATIVE(ptr)) { char *p; strlcpy(newfile, file, sizeof(newfile)); p = strrchr(newfile, FR_DIR_SEP); if (!p) { p = newfile + strlen(newfile); *p = FR_DIR_SEP; } getword(&ptr, p + 1, sizeof(newfile) - 1 - (p - newfile)); } else { getword(&ptr, newfile, sizeof(newfile)); } t = NULL; if (pairlist_read(ctx, newfile, &t, 0) != 0) { pairlist_free(&pl); ERROR("%s[%d]: Could not open included file %s: %s", file, lineno, newfile, fr_syserror(errno)); fclose(fp); return -1; } *last = t; /* * t may be NULL, it may have one * entry, or it may be a linked list * of entries. Go to the end of the * list. */ while (*last) last = &((*last)->next); continue; } /* * Parse the check values */ check_tmp = NULL; reply_tmp = NULL; old_lineno = lineno; parsecode = userparse(ctx, ptr, &check_tmp); if (parsecode == T_OP_INVALID) { pairlist_free(&pl); ERROR("%s[%d]: Parse error (check) for entry %s: %s", file, lineno, entry, fr_strerror()); fclose(fp); return -1; } else if (parsecode == T_COMMA) { ERROR("%s[%d]: Unexpected trailing comma in check item list for entry %s", file, lineno, entry); fclose(fp); return -1; } mode = FIND_MODE_REPLY; parsecode = T_COMMA; } else { if(*buffer == ' ' || *buffer == '\t') { if (parsecode != T_COMMA) { ERROR("%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s", file, lineno, entry); fclose(fp); return -1; } /* * Parse the reply values */ parsecode = userparse(ctx, buffer, &reply_tmp); /* valid tokens are 1 or greater */ if (parsecode < 1) { pairlist_free(&pl); ERROR("%s[%d]: Parse error (reply) for entry %s: %s", file, lineno, entry, fr_strerror()); fclose(fp); return -1; } } else { /* * Done with this entry... */ MEM(t = talloc_zero(ctx, PAIR_LIST)); t->check = check_tmp; t->reply = reply_tmp; t->lineno = old_lineno; check_tmp = NULL; reply_tmp = NULL; t->name = talloc_typed_strdup(t, entry); *last = t; last = &(t->next); mode = FIND_MODE_NAME; if (buffer[0] != 0) goto parse_again; } } } /* * Make sure that we also read the last line of the file! */ if (mode == FIND_MODE_REPLY) { buffer[0] = 0; goto parse_again; } fclose(fp); *list = pl; return 0; }
/* * Read the users, huntgroups or hints file. * Return a PAIR_LIST. */ int pairlist_read(TALLOC_CTX *ctx, char const *file, PAIR_LIST **list, int complain) { FILE *fp; int mode = FIND_MODE_NAME; char entry[256]; char buffer[8192]; char const *ptr; VALUE_PAIR *check_tmp = NULL; VALUE_PAIR *reply_tmp = NULL; PAIR_LIST *pl = NULL, *t; PAIR_LIST **last = &pl; int lineno = 0; int entry_lineno = 0; FR_TOKEN parsecode; #ifdef HAVE_REGEX_H VALUE_PAIR *vp; vp_cursor_t cursor; #endif char newfile[8192]; DEBUG2("reading pairlist file %s", file); /* * Open the file. The error message should be a little * more useful... */ if ((fp = fopen(file, "r")) == NULL) { if (!complain) return -1; ERROR("Couldn't open %s for reading: %s", file, fr_syserror(errno)); return -1; } /* * Read the entire file into memory for speed. */ while (fgets(buffer, sizeof(buffer), fp) != NULL) { lineno++; if (!feof(fp) && (strchr(buffer, '\n') == NULL)) { fclose(fp); ERROR("%s[%d]: line too long", file, lineno); pairlist_free(&pl); return -1; } /* * If the line contains nothing but whitespace, * ignore it. */ ptr = buffer; while (isspace((int) *ptr)) ptr++; if (*ptr == '#' || *ptr == '\n' || !*ptr) continue; parse_again: if (mode == FIND_MODE_NAME) { /* * The user's name MUST be the first text on the line. */ if (isspace((int) buffer[0])) { ERROR("%s[%d]: Entry does not begin with a user name", file, lineno); fclose(fp); return -1; } /* * Get the name. */ ptr = buffer; getword(&ptr, entry, sizeof(entry), false); entry_lineno = lineno; /* * Include another file if we see * $INCLUDE filename */ if (strcasecmp(entry, "$INCLUDE") == 0) { while (isspace((int) *ptr)) ptr++; /* * If it's an absolute pathname, * then use it verbatim. * * If not, then make the $include * files *relative* to the current * file. */ if (FR_DIR_IS_RELATIVE(ptr)) { char *p; strlcpy(newfile, file, sizeof(newfile)); p = strrchr(newfile, FR_DIR_SEP); if (!p) { p = newfile + strlen(newfile); *p = FR_DIR_SEP; } getword(&ptr, p + 1, sizeof(newfile) - 1 - (p - newfile), false); } else { getword(&ptr, newfile, sizeof(newfile), false); } t = NULL; if (pairlist_read(ctx, newfile, &t, 0) != 0) { pairlist_free(&pl); ERROR("%s[%d]: Could not open included file %s: %s", file, lineno, newfile, fr_syserror(errno)); fclose(fp); return -1; } *last = t; /* * t may be NULL, it may have one * entry, or it may be a linked list * of entries. Go to the end of the * list. */ while (*last) last = &((*last)->next); continue; } /* $INCLUDE ... */ /* * Parse the check values */ rad_assert(check_tmp == NULL); rad_assert(reply_tmp == NULL); parsecode = fr_pair_list_afrom_str(ctx, ptr, &check_tmp); if (parsecode == T_INVALID) { pairlist_free(&pl); ERROR("%s[%d]: Parse error (check) for entry %s: %s", file, lineno, entry, fr_strerror()); fclose(fp); return -1; } if (parsecode != T_EOL) { pairlist_free(&pl); talloc_free(check_tmp); ERROR("%s[%d]: Invalid text after check attributes for entry %s", file, lineno, entry); fclose(fp); return -1; } #ifdef HAVE_REGEX_H /* * Do some more sanity checks. */ for (vp = fr_cursor_init(&cursor, &check_tmp); vp; vp = fr_cursor_next(&cursor)) { if (((vp->op == T_OP_REG_EQ) || (vp->op == T_OP_REG_NE)) && (vp->da->type != PW_TYPE_STRING)) { pairlist_free(&pl); talloc_free(check_tmp); ERROR("%s[%d]: Cannot use regular expressions for non-string attributes in entry %s", file, lineno, entry); fclose(fp); return -1; } } #endif /* * The reply MUST be on a new line. */ mode = FIND_MODE_WANT_REPLY; continue; } /* * We COULD have a reply, OR we could have a new entry. */ if (mode == FIND_MODE_WANT_REPLY) { if (!isspace((int) buffer[0])) goto create_entry; mode = FIND_MODE_HAVE_REPLY; } /* * mode == FIND_MODE_HAVE_REPLY */ /* * The previous line ended with a comma, and then * we have the start of a new entry! */ if (!isspace((int) buffer[0])) { trailing_comma: pairlist_free(&pl); talloc_free(check_tmp); talloc_free(reply_tmp); ERROR("%s[%d]: Invalid comma after the reply attributes. Please delete it.", file, lineno); fclose(fp); return -1; } /* * Parse the reply values. If there's a trailing * comma, keep parsing the reply values. */ parsecode = fr_pair_list_afrom_str(ctx, buffer, &reply_tmp); if (parsecode == T_COMMA) { continue; } /* * We expect an EOL. Anything else is an error. */ if (parsecode != T_EOL) { pairlist_free(&pl); talloc_free(check_tmp); talloc_free(reply_tmp); ERROR("%s[%d]: Parse error (reply) for entry %s: %s", file, lineno, entry, fr_strerror()); fclose(fp); return -1; } create_entry: /* * Done with this entry... */ MEM(t = talloc_zero(ctx, PAIR_LIST)); if (check_tmp) fr_pair_steal(t, check_tmp); if (reply_tmp) fr_pair_steal(t, reply_tmp); t->check = check_tmp; t->reply = reply_tmp; t->lineno = entry_lineno; check_tmp = NULL; reply_tmp = NULL; t->name = talloc_typed_strdup(t, entry); *last = t; last = &(t->next); /* * Look for a name. If we came here because * there were no reply attributes, then re-parse * the current line, instead of reading another one. */ mode = FIND_MODE_NAME; if (feof(fp)) break; if (!isspace((int) buffer[0])) goto parse_again; } /* * We're at EOF. If we're supposed to read more, that's * an error. */ if (mode == FIND_MODE_HAVE_REPLY) goto trailing_comma; /* * We had an entry, but no reply attributes. That's OK. */ if (mode == FIND_MODE_WANT_REPLY) goto create_entry; /* * Else we were looking for an entry. We didn't get one * because we were at EOF, so that's OK. */ fclose(fp); *list = pl; return 0; }
static int getusersfile(TALLOC_CTX *ctx, char const *filename, rbtree_t **ptree) { int rcode; VALUE_PAIR *vp; PAIR_LIST *users = NULL; PAIR_LIST *entry, *next; PAIR_LIST *user_list, *default_list, **default_tail; rbtree_t *tree; if (!filename) { *ptree = NULL; return 0; } rcode = pairlist_read(ctx, dict_radius, filename, &users, 1); if (rcode < 0) { return -1; } /* * Walk through the 'users' file list */ entry = users; while (entry) { fr_cursor_t cursor; /* * Look for improper use of '=' in the * check items. They should be using * '==' for on-the-wire RADIUS attributes, * and probably ':=' for server * configuration items. */ for (vp = fr_cursor_init(&cursor, &entry->check); vp; vp = fr_cursor_next(&cursor)) { /* * Ignore attributes which are set * properly. */ if (vp->op != T_OP_EQ) { continue; } /* * If it's a vendor attribute, * or it's a wire protocol, * ensure it has '=='. */ if ((fr_dict_vendor_num_by_da(vp->da) != 0) || (vp->da->attr < 0x100)) { WARN("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s", filename, entry->lineno, vp->da->name, vp->da->name, entry->name); vp->op = T_OP_CMP_EQ; continue; } } /* end of loop over check items */ /* * Look for server configuration items * in the reply list. * * It's a common enough mistake, that it's * worth doing. */ for (vp = fr_cursor_init(&cursor, &entry->reply); vp; vp = fr_cursor_next(&cursor)) { /* * If it's NOT a vendor attribute, * and it's NOT a wire protocol * and we ignore Fall-Through, * then bitch about it, giving a * good warning message. */ if (fr_dict_attr_is_top_level(vp->da) && (vp->da->attr > 1000)) { WARN("[%s]:%d Check item \"%s\"\n" "\tfound in reply item list for user \"%s\".\n" "\tThis attribute MUST go on the first line" " with the other check items", filename, entry->lineno, vp->da->name, entry->name); } } entry = entry->next; } tree = rbtree_create(ctx, pairlist_cmp, NULL, RBTREE_FLAG_NONE); if (!tree) { pairlist_free(&users); return -1; } default_list = NULL; default_tail = &default_list; /* * We've read the entries in linearly, but putting them * into an indexed data structure would be much faster. * Let's go fix that now. */ for (entry = users; entry != NULL; entry = next) { /* * Remove this entry from the input list. */ next = entry->next; entry->next = NULL; /* * DEFAULT entries get their own list. */ if (strcmp(entry->name, "DEFAULT") == 0) { if (!default_list) { default_list = entry; /* * Insert the first DEFAULT into the tree. */ if (!rbtree_insert(tree, entry)) { error: pairlist_free(&entry); pairlist_free(&next); talloc_free(tree); return -1; } } else { /* * Tack this entry onto the tail * of the DEFAULT list. */ *default_tail = entry; } default_tail = &entry->next; continue; } /* * Not DEFAULT, must be a normal user. */ user_list = rbtree_finddata(tree, entry); if (!user_list) { /* * Insert the first one. */ if (!rbtree_insert(tree, entry)) goto error; } else { /* * Find the tail of this list, and add it * there. */ while (user_list->next) user_list = user_list->next; user_list->next = entry; } } *ptree = tree; return 0; }