#include #include #include #include "radiusconf.h" #include "radiusconf.m" #include "rc_parser.h" #include "rc_tools.h" #include /* remove (and detroy the objects) from a specified range from given_vitems */ void remove_del_range(VIEWITEMS &given_vitems, int begins_at, int ends_at) { int my_counter; my_counter=ends_at-begins_at + 1; // total of lines to delete while(my_counter--) given_vitems.remove_del(begins_at); } /* insert a line in a given_vitems, in a where_to_insert position. if where_to_insert does not exist (or is -1) the line will be added at the end of given_vitems list */ void smart_line_insert(VIEWITEMS &given_vitems, int where_to_insert, const char *given_str_data) { if((given_vitems.getnb() <= where_to_insert)||(where_to_insert==-1)){ // line does not exist given_vitems.add(new VIEWITEM(given_str_data)); }else{ given_vitems.insert(where_to_insert, new VIEWITEM(given_str_data)); } } /* returns !=0 if the provided string has a trailing comma (ignores trailing spaces), ==0 if hasn't */ int has_trailing_comma(const char *given_string) { SSTRING my_temp; const char *last_char; int my_strlen; cut_surrounding_spaces(given_string, my_temp); if(!(my_strlen=strlen(my_temp.get()))) return(0); last_char=my_temp.get()+(my_strlen-1); if(*last_char==',') return(1); return(0); } /* returns the pointer to the same string, just after the first word found (separated by spaces, tabs, etc) */ const char *skip_first_word(const char *given_string) { const char *my_pos; my_pos=given_string; while(*my_pos && (*my_pos < 33)) my_pos++; while(*my_pos > 32) my_pos++; return(my_pos); } /* adds the items (provided in an string) as independent SSTRINGs entries in a provided SSTRINGS.. these items are separated each other by ',' */ /* returns the number of items added (0 or more) */ int add_items_to_sstrings(const char *provided_line, SSTRINGS &dump_them_here) { SSTRING my_temp_place, adjusted_string; int my_counter=0; while(gimme_word_from_string_bchar(provided_line, my_temp_place, my_counter++, ',')){ cut_surrounding_spaces(my_temp_place.get(), adjusted_string); if(!is_empty_string(adjusted_string.get())) dump_them_here.add(new SSTRING(adjusted_string.get())); } return(my_counter-1); } /* much like add_items_to_sstrings() but it's specific for the first line in group, where the group name is present */ /* returns the number of items added (0 or more) */ int process_first_line(const char *provided_line, SSTRINGS &dump_them_here, SSTRING &dump_groupname_here) { const char *groupname_skipped; /* picks groupname */ gimme_word_from_string(provided_line, dump_groupname_here, 0); /* picks items after groupname */ groupname_skipped=skip_first_word(provided_line); return(add_items_to_sstrings(groupname_skipped, dump_them_here)); } /* 'medium' level parsing routines */ /* returns the total of lines of the pointed group (provided line assumed as being the first line of the group) */ /* invalid line number may be provided (returns 0 in this case) */ int how_many_lines_this_group(VIEWITEMS &given_vitems, int line_number) { int total_items; int my_counter; int end_of_list=0; total_items=given_vitems.getnb(); if(line_number >= total_items) return(0); my_counter=line_number; while((my_counter < total_items)&&(end_of_list<2)){ if(!has_trailing_comma(given_vitems.getitem(my_counter)->line.get())){ end_of_list++; /* is the line to be part of the second group does not look like that (has no \t or space as first character) assumes that the group finished. this is for the case of the groups with just one line, like those ones found in huntgroups file */ if((my_counter+1) < total_items){ if(*(given_vitems.getitem(my_counter+1)->line.get())>' '){ end_of_list++; }else{ if(is_empty_string(given_vitems.getitem(my_counter+1)->line.get())) end_of_list++; } } } my_counter++; } return(my_counter-line_number); } /* returns the first and last lines of the group number N. returns the total of lines in this group (0 = group does not exist, so the other vars have undefined data) */ /* begins_at MAY be equal to ends_at ! */ int identifies_group_limits(VIEWITEMS &given_vitems, int group_number, int &begins_at, int &ends_at) { int my_step, my_position=0; int group_counter=0; int how_many_lines; int total_elements; total_elements=given_vitems.getnb(); // skip empty lines if(my_positionline.get()))&&((my_position+1)line.get()))&&((my_position+1)line.get())) return(0); return(how_many_lines); } } return(0); } /* returns true is given string is an assignment for the given varname */ /* varname is case insensitive */ int is_this_var(const char *given_string, const char *given_varname, const char given_separator) { SSTRING stripped_varname, adjusted_varname; if(gimme_word_from_string_bchar(given_string, stripped_varname, 0, given_separator)){ cut_surrounding_spaces(stripped_varname.get(), adjusted_varname); if(!ci_strcmp(given_varname, adjusted_varname.get())) return(1); } return(0); } /* returns a pointer to given_string from the point it is considered data (after the '=') */ /* it does not filter the "", if present */ /* returns !=0 is data found, ==0 if not ('=' not present) */ int return_var_data_part(const char *given_string, SSTRING &dump_here) { const char *where_it_starts; if((where_it_starts=strchr(given_string, '='))){ where_it_starts++; cut_surrounding_spaces(where_it_starts, dump_here); return(1); } return(0); } /* returns the line where the variable is assigned (in provided sstrings variable) or -1 if this variable is not found */ int locate_var_in_sstrings(SSTRINGS &given_sstrings, const char *given_varname) { int howmany, loopy=0; howmany=given_sstrings.getnb(); while(loopy < howmany){ if(is_this_var(given_sstrings.getitem(loopy)->get(), given_varname, '=')) return(loopy); loopy++; } return(-1); } /* 'high' level parsing routines */ // struct t_loaded_group{ // SSTRING groupname; // SSTRINGS matches; /* the first bunch of properties */ // SSTRINGS changes; /* the second bunch of properties */ // int begins_at, ends_at; /* the lines in viewitems where the group begins/ends */ // }; /* load group data into the t_loaded_group variable. returns ==0 if nothing loaded, !=0 is successful */ int load_group_data(VIEWITEMS &given_vitems, int which_group, t_loaded_group &where_to_dump) { int begins_at, ends_at; int my_loop; const char *current_line; int step=0; /* 0=processing first bunch, 1=second bunch */ if(identifies_group_limits(given_vitems, which_group, begins_at, ends_at)){ where_to_dump.begins_at=begins_at; where_to_dump.ends_at=ends_at; my_loop=begins_at; current_line=given_vitems.getitem(my_loop)->line.get(); process_first_line(current_line, where_to_dump.matches, where_to_dump.groupname); my_loop++; if(!has_trailing_comma(current_line)) step++; while(my_loop <= ends_at){ current_line=given_vitems.getitem(my_loop)->line.get(); if(!step){ add_items_to_sstrings(current_line, where_to_dump.matches); }else{ add_items_to_sstrings(current_line, where_to_dump.changes); } if(!has_trailing_comma(current_line)) step++; my_loop++; } return(1); } return(0); } /* insert the group data from a given t_loaded_group in a specified point of given_vitems */ /* if insert_empty_line!=0 an empty line will be added after the group is written */ /* returns how many lines were inserted */ int insert_t_loaded_group_data(VIEWITEMS &given_vitems, t_loaded_group &given_groupdata, int line_where_to_insert, int insert_empty_line) { int my_linecount; SSTRING my_temp, line_to_dump; int how_many=0; my_linecount=line_where_to_insert; /* creates first line in the group */ { int total_lines, m_counter=0; const char *current_line_data; total_lines=given_groupdata.matches.getnb(); my_temp.setfrom(""); while(m_counterget(); if(m_counter++){ my_temp.appendf(", %s", current_line_data); }else{ my_temp.append(current_line_data); } } } line_to_dump.setfromf("%s\t%s", given_groupdata.groupname.get(), my_temp.get()); smart_line_insert(given_vitems, my_linecount++, line_to_dump.get()); how_many++; /* now create the other lines in the group */ { int total_lines, c_counter=0; const char *current_line_data; total_lines=given_groupdata.changes.getnb(); my_temp.setfrom(""); while(c_counterget(); if(++c_counter==total_lines){ line_to_dump.setfromf("\t%s", current_line_data); }else{ line_to_dump.setfromf("\t%s,", current_line_data); } smart_line_insert(given_vitems, my_linecount++, line_to_dump.get()); how_many++; } } if(insert_empty_line) smart_line_insert(given_vitems, my_linecount++, ""); return(how_many); } /* 'very high' level routines (used directly by the main code) */ /* same as load_var_data() but removes surrounding quotes from readen data */ int load_var_data_quoted(VIEWITEMS &given_vitems, int which_group, const char *given_varname, int varlevel, SSTRING &where_to_dump) { SSTRING my_temp; const char *readen_one; int return_code; if((return_code=load_var_data(given_vitems, which_group, given_varname, varlevel, my_temp))){ readen_one=my_temp.get(); if(strlen(readen_one)>1){ my_temp.truncate(strlen(readen_one)-1); where_to_dump.setfrom(readen_one+1); } } return(return_code); } /* loads a specified variable from a specified group. repetitive brute-force approach, bugless but cpu intensive. (load_group_data() should be cached instead of this) */ /* varlevel may be 0 (first group) or 1 (second group) -- look at Radius config files in order to get the idea */ /* returns !=0 if successful, ==0 if failed (var or group not found) */ int load_var_data(VIEWITEMS &given_vitems, int which_group, const char *given_varname, int varlevel, SSTRING &where_to_dump) { t_loaded_group store_group_here; int at_line_number; SSTRINGS *sstrings_to_use; where_to_dump.setfrom(""); if(!varlevel){ sstrings_to_use=&(store_group_here.matches); }else{ sstrings_to_use=&(store_group_here.changes); } if(load_group_data(given_vitems, which_group, store_group_here)){ at_line_number=locate_var_in_sstrings(*sstrings_to_use, given_varname); if(at_line_number!=-1){ // var found, great! return(return_var_data_part(sstrings_to_use->getitem(at_line_number)->get(), where_to_dump)); } } return(0); } /* same as load_var_data() but takes simultaneously all the definitions for the same variable (what happens in the huntgroups file) */ int load_multiline_var_data(VIEWITEMS &given_vitems, int which_group, const char *given_varname, int varlevel, SSTRING &where_to_dump) { t_loaded_group store_group_here; SSTRINGS *sstrings_to_use; where_to_dump.setfrom(""); if(!varlevel){ sstrings_to_use=&(store_group_here.matches); }else{ sstrings_to_use=&(store_group_here.changes); } if(load_group_data(given_vitems, which_group, store_group_here)){ int howmany, loopy=0; SSTRING my_temp; howmany=sstrings_to_use->getnb(); while(loopy < howmany){ if(is_this_var(sstrings_to_use->getitem(loopy)->get(), given_varname, '=')){ return_var_data_part(sstrings_to_use->getitem(loopy)->get(), my_temp); where_to_dump.appendf("%s\n", my_temp.get()); } loopy++; } if(!is_empty_string(where_to_dump.get())) return(1); } return(0); } /* same as write_var_data() but adds surrounding quoted to the var data */ int write_var_data_quoted(VIEWITEMS &given_vitems, int which_group, const char *given_varname, int varlevel, const char *given_vardata) { SSTRING my_temp; if(is_empty_string(given_vardata)){ my_temp.setfrom(""); }else{ my_temp.setfromf("\"%s\"", given_vardata); } return(write_var_data(given_vitems, which_group, given_varname, varlevel, my_temp.get())); } /* writes a specified variable in a specified group. if var doesn't exist, create it. as brute force as load_var_data() */ /* varlevel may be 0 (first group) or 1 (second group) -- look at Radius config files in order to get the idea */ /* EMPTY vardata will delete existing variable */ /* returns !=0 if successful, ==0 if failed (group not found) */ int write_var_data(VIEWITEMS &given_vitems, int which_group, const char *given_varname, int varlevel, const char *given_vardata) { t_loaded_group store_group_here; int at_line_number; SSTRINGS *sstrings_to_use; if(!varlevel){ sstrings_to_use=&(store_group_here.matches); }else{ sstrings_to_use=&(store_group_here.changes); } if(load_group_data(given_vitems, which_group, store_group_here)){ SSTRING *edit_this_one; at_line_number=locate_var_in_sstrings(*sstrings_to_use, given_varname); if(*given_vardata){ if(at_line_number==-1){ // uh oh, var not found! needs to create an entry for this variable sstrings_to_use->add(new SSTRING()); at_line_number=sstrings_to_use->getnb() - 1; } edit_this_one=sstrings_to_use->getitem(at_line_number); edit_this_one->setfromf("%s = %s", given_varname, given_vardata); }else{ if(at_line_number!=-1) // var exists but must be deleted (empty given_vardata) sstrings_to_use->remove_del(at_line_number); } /* allright, let's write store_group_here back to given_vitems */ { int how_many_lines; // insert renewed group just after the old group how_many_lines=insert_t_loaded_group_data(given_vitems, store_group_here, store_group_here.begins_at, 0); // remove the old group remove_del_range(given_vitems, store_group_here.begins_at+how_many_lines, store_group_here.ends_at+how_many_lines); } return(1); } return(0); } /* same as write_var_data() but treats simultaneously all the definitions for the same variable (what happens in the huntgroups file) */ int write_multiline_var_data(VIEWITEMS &given_vitems, int which_group, const char *given_varname, int varlevel, const char *given_vardata) { t_loaded_group store_group_here; SSTRINGS *sstrings_to_use; if(!varlevel){ sstrings_to_use=&(store_group_here.matches); }else{ sstrings_to_use=&(store_group_here.changes); } if(load_group_data(given_vitems, which_group, store_group_here)){ /* remove all the lines having the varname= assignment */ { int howmany, loopy=0; howmany=sstrings_to_use->getnb(); while(loopy < howmany){ if(is_this_var(sstrings_to_use->getitem(loopy)->get(), given_varname, '=')){ sstrings_to_use->remove_del(loopy); howmany--; }else{ loopy++; } } } /* generate now how many assignments as needed */ { int loopy=0; SSTRING my_temp, my_temp2; while(gimme_word_from_string(given_vardata, my_temp, loopy++)){ my_temp2.setfromf("%s = %s", given_varname, my_temp.get()); sstrings_to_use->add(new SSTRING(my_temp2.get())); } } /* allright, let's write store_group_here back to given_vitems */ { int how_many_lines; // insert renewed group just after the old group how_many_lines=insert_t_loaded_group_data(given_vitems, store_group_here, store_group_here.begins_at, 0); // remove the old group remove_del_range(given_vitems, store_group_here.begins_at+how_many_lines, store_group_here.ends_at+how_many_lines); } return(1); } return(0); } /* remove a specified group (0=first one) returns !=0 if ok, ==0 if error (group not found) */ int delete_whole_group(VIEWITEMS &given_vitems, int which_group) { t_loaded_group store_group_here; if(load_group_data(given_vitems, which_group, store_group_here)){ remove_del_range(given_vitems, store_group_here.begins_at, store_group_here.ends_at); return(1); } return(0); } /* create a new (empty, or almost empty) group */ void create_new_group(VIEWITEMS &given_vitems, const char *text1) { create_new_group(given_vitems, text1, NULL); } /* create a new (empty, or almost empty) group */ void create_new_group(VIEWITEMS &given_vitems, const char *text1, const char *text2) { smart_line_insert(given_vitems, -1, ""); smart_line_insert(given_vitems, -1, text1); // "DEFAULT" if(text2) smart_line_insert(given_vitems, -1, text2); // "Service-Type = Shell-User" } /* move group from a position to another (will shift down the group which has the same number as move_to, so 0 will put the group as the first in the list) */ void move_group(VIEWITEMS &given_vitems, int group_to_move, int move_to) { t_loaded_group store_group_here, other_group; if(move_to==group_to_move) return; if(load_group_data(given_vitems, group_to_move, store_group_here)){ if(load_group_data(given_vitems, move_to, other_group)){ // puts group data in a new place insert_t_loaded_group_data(given_vitems, store_group_here, other_group.begins_at, 1); // remove the old group data if(move_toget()); loopy++; } return(1); } return(0); } /* changes group title (ofted defined as 'DEFAULT') */ /* returns !=0 if successful, ==0 if failed (group not found) */ int write_group_title(VIEWITEMS &given_vitems, int which_group, const char *given_group_title) { t_loaded_group store_group_here; if(load_group_data(given_vitems, which_group, store_group_here)){ store_group_here.groupname.setfrom(given_group_title); /* allright, let's write store_group_here back to given_vitems */ { int how_many_lines; // insert renewed group just after the old group how_many_lines=insert_t_loaded_group_data(given_vitems, store_group_here, store_group_here.begins_at, 0); // remove the old group remove_del_range(given_vitems, store_group_here.begins_at+how_many_lines, store_group_here.ends_at+how_many_lines); } return(1); } return(0); } /* returns !=0 if ok, ==0 if group not found */ int read_group_title(VIEWITEMS &given_vitems, int group_number, SSTRING &title_group) { SSTRING useless_junk; return(returns_data_for_list(given_vitems, group_number, useless_junk, title_group)); } /* returns how many groups are there */ int how_many_groups_are(VIEWITEMS &given_vitems) { int my_counter=0; SSTRING trash1, trash2; while(returns_data_for_list(given_vitems, my_counter, trash1, trash2)) my_counter++; return(my_counter); }