/* ***************************************************************************** * * Copyright 1989,1990 Xylogics, Inc. ALL RIGHTS RESERVED. * * ALL RIGHTS RESERVED. Licensed Material - Property of Xylogics, Inc. * This software is made available solely pursuant to the terms of a * software license agreement which governs its use. * Unauthorized duplication, distribution or sale are strictly prohibited. * * File description: ACP user profile Support routines * * Original Author: Richard G. Bockenek Created on: 2/22/93 * **************************************************************************** */ /* **************************************************************************** * * * NOTES * * * Lexical Analysis * * An ACP token is a string ending in any of the following separators: * " \t,{}\\\r\n" * * The '\' quote character does the usual thing. A single '\' is removed * from the token and the next character is not. Two consecutive quotes * results in a single '\' in the token. Tokens can span input lines by * quoting the EOL characters '\r' or '\n'. Note, however, that the EOL * itself is discarded and *not* included in the token string. The '#' * comment character causes the profile reader to discard all characters * to the end of the line, including any continuation lines. The reason { * and } are included is to allow users to take advantage of editor * block-sensitivity. * * * Parsing * * The ACP parser views its input as a token stream with no constraints * on typographical format. This stream is read sequentually until the * end of file is reached. Each token is fed through an FSM-based parser * which generates an action and a state transition. * * Within constructed objects (user, access and atzone), command/argument * pairs may arrive in any order or be omitted entirely. Also command * names need not be prohibited for use as argument values -- the parser * distinquishes commands from arguments based on state. * * Well-formed user records are compiled into user profile structs and * added to the database. Parser warnings are issued if a syntactically * correct but otherwise dubious or duplicate user record is encountered. * Parser errors are issued if a syntax error is encountered. In the case * of error, the parser continues compiling in order to report additional * errors, but a database is not generated. * * * Notes on the following parser FSM: * * - The token means any token not listed as an expected token * in the given state. * * - The next state means no state transition. * * - The next state means the state previous to the current. * * - The initial state is Idle. * * * FSM * * STATE TOKEN NEXT-STATE DESCRIPTION OF ACTION * * Idle user User Start a new user profile record, * the next token is the username. * * pool Pool Start a new port pool record, * the next token is the poolname. * * %include filename Open up an included file and continue * * Recover Start error recovery * * User accesscode Acc Start a new accesscode record, * the next token is the access code * * at_callback The following token is an at * callback number * * at_passwd The following token is an ARAP * password * * at_zone Zone Start a new atzone record * * at_connect_time The following token is the connect * time in minutes. * * blacklist The following token is blacklist * `max value' * * climask Climask Start a new cli mask record * * clicmd Clicmd Start a new cli cmd record * * filter Filter Start a new filter definition * * route Route Start a static route definition * * local_address The following token is the local * IP address of the slip or ppp link. * * mp_max_links The following token is the maximum * number of links within an MP bundle. * * remote_address The following token is the remote * IP address of the slip or ppp link. * * subnet_mask The following token is the subnet * mask of the interface. * * %include filename Open up an included file and continue * * end End of user record * * Recover Start error recovery * * Access in_pool The following token is an input * pool name * * out_pool The following token is an output * pool name * * phone_no The following token is a callback * number * * job Job Start of job record * * %include filename Open up an included file and continue * * end End of access record * * Recover Start error recovery * * Job end End of job record * * Job token * * Zone end End of at zone * * Zone token * * Climask end End of climask state * * cli mask token * * Clicmd end End of clicmd state * * cli cmd token * * Filter end End of filter state * * cli cmd token * * %include filename Open up and included file and continue * * Route end End of route state * * %include filename Open up and included file and continue * * cli cmd token * * Pool ports Portset Start of new port set record * * annex The next token is a hostname or * host ip address in `dot' notation * * %include filename Open up and included file and continue * * end End of pool record * * Recover Start error recovery * * Portset end End of port set * * %include filename Open up and included file and continue * * Port number or range * * Recover end End of recovery state * * Ignored * * Note that commands are case insensitive. Note additionally that in * each state commands can be abbreviated to the shorted unambiguous * initial string in their name. * * * Database Additions and Searches * * The ACP user profiler uses the standard hash-table support routines * hcreate(3C) and hsearch(3C). These routines are based on Knuth 6.4 * Algorithm D. They are not necessarily the most efficient, but they * are reliable and supported in virtually all POSIX compliant user * development environments. * * * Implementation Notes * * The implementation of the database add/find routines do not use the * hcreate/hsearch routines due to severe limitations in these routines. * Viz, they support only one static database whereas we have currently * to support user and port pool databases, and many others in the * future unless nobody wants to extend this code, which seems to be the * ad hoc way things are implemented around here. * **************************************************************************** */ /* * included headers */ #include "../inc/config.h" #include "../inc/port/port.h" #include #ifndef _WIN32 #include #include #include #include #include #include #else #include "../inc/rom/syslog.h" #endif /* !_WIN32 */ #include #include #include #include #include #include #include #include "../inc/erpc/nerpcd.h" #include "acp.h" #include "getacpuser.h" #include "acp_group.h" #include "acp_policy.h" #include "environment.h" /* * Routines for creating group lists for group= entries in * userinfo database. */ static int create_group_list_4_env(); static int is_group_member_4_env(); int extract_ports(); #ifdef _WIN32 void NTCreateGroupList(); #endif /* * global vars. */ static int database_count = 0; /*userinfo database count*/ /* * Class member function forward references */ static int token_new(); static int token_open(); static int token_close(); static int token_read(); static char *token_get(); static int database_new(); static int database_add(); static int database_find(); static void database_free(); static int parser_event(); static int stack_new(); static int stack_push(); static int stack_pop(); static void errlog(); static int get_user_profile(); static int get_user_profile_by_env(); void release_cmd_list(); /* * action routine forward references -- by state */ static int user_begin(), pool_begin(), idle_error(); static int access_begin(), climask_begin(), deny_user(), clicmd_begin(), blacklist(), filter_begin(), route_begin(), atzone_begin(),atpasswd(), atconnect_time(), atcallback(), local_addr(), remote_addr(), subnet_mask(), dyndial_passwd(), chap_secret(), mp_max_links(), max_logon_time(), user_end(), user_error(); static int phone_no(), in_pool_name(), out_pool_name(), job_begin(), access_end(), access_error(); static int zone_end(), zone(); static int nve_begin(), nve_filter(), nve_include(), nve_exclude(), nve_end(); static int job_end(), job(); static int climask_end(), climask(); static int clicmd_end(), clicmd(); static int filter_end(), filter(); static int route_end(), route(); static int portnum(), portset(), hostname(), pool_end(), pool_error(); static int portset_end(), portmem(); static int recover_end(), recover(); static int open_include_file(); /* * action routine vectors -- by state */ static ifp idle_fn[] = { open_include_file, user_begin, pool_begin, idle_error }; static ifp user_fn[] = { open_include_file, access_begin, climask_begin, deny_user, clicmd_begin, filter_begin, route_begin, blacklist,atzone_begin, atpasswd, atconnect_time, atcallback, local_addr, remote_addr, subnet_mask, nve_begin, dyndial_passwd, chap_secret, mp_max_links, max_logon_time, user_end, user_error }; static ifp access_fn[] = { open_include_file, phone_no, in_pool_name, out_pool_name, job_begin, access_end, access_error }; static ifp job_fn[] = { job_end, job }; static ifp zone_fn[] = { zone_end, zone }; static ifp nve_fn[] = { open_include_file, nve_include, nve_exclude, nve_end, nve_filter }; static ifp climask_fn[]= { climask_end, climask }; static ifp clicmd_fn[] = { clicmd_end, clicmd }; static ifp filter_fn[] = { open_include_file, filter_end, filter }; static ifp route_fn[] = { open_include_file, route_end, route }; static ifp pool_fn[] = { open_include_file, portnum, portset, hostname, pool_end, pool_error }; static ifp port_fn[] = { open_include_file, portset_end, portmem }; static ifp recover_fn[]= { recover_end, recover }; static ifp include_fn[]= { open_include_file }; /* * keywords -- by state */ static char *idle_kw[] = { "%include", "user", "pool" }; static char *user_kw[] = { "%include", "accesscode", "climask", "deny", "clicmd", "filter", "route", "blacklist", "at_zone", "at_passwd", "at_connect_time", "at_callback", "local_address","remote_address", "subnet_mask", "at_nve_filter","dyndial_passwd", "chap_secret", "mp_max_links", "max_logon", "end" }; static char *access_kw[]= { "%include", "phone_no", "in_pool_name", "out_pool_name", "job", "end" }; static char *zone_kw[] = { "end" }; static char *nve_kw[] = { "%include", "include", "exclude", "end" }; static char *job_kw[] = { "end" }; static char *climask_kw[] = { "end" }; static char *clicmd_kw[] = { "end" }; static char *filter_kw[] = { "%include", "end" }; static char *route_kw[] = { "%include", "end" }; static char *pool_kw[] = { "%include", "ports", "__place_holder__", "annex", "end" }; static char *port_kw[] = { "%include", "end" } ; static char *recover_kw[] = { "end" }; static char *include_kw[] = { "__place_holder__" }; /* * parse vector size -- by state */ #define MAX_IDLE (sizeof(idle_kw) / sizeof(char *)) #define MAX_USER (sizeof(user_kw) / sizeof(char *)) #define MAX_ACCESS (sizeof(access_kw) / sizeof(char *)) #define MAX_ZONE (sizeof(zone_kw) / sizeof(char *)) #define MAX_NVE (sizeof(nve_kw) / sizeof(char *)) #define MAX_JOB (sizeof(job_kw) / sizeof(char *)) #define MAX_CLIMASK (sizeof(climask_kw) / sizeof(char *)) #define MAX_CLICMD (sizeof(clicmd_kw) / sizeof(char *)) #define MAX_FILTER (sizeof(filter_kw) / sizeof(char *)) #define MAX_ROUTE (sizeof(route_kw) / sizeof(char *)) #define MAX_POOL (sizeof(pool_kw) / sizeof(char *)) #define MAX_PORT (sizeof(port_kw) / sizeof(char *)) #define MAX_RECOVER (sizeof(recover_kw) / sizeof(char *)) #define MAX_INCLUDE (sizeof(include_kw) / sizeof(char *)) #define MAX_LOGON 1440 /* in minutes (comes out to be 24 Hr) */ /* * parser state table */ static ParserEntry parse_table[] = { { MAX_IDLE, idle_kw, idle_fn }, { MAX_USER, user_kw, user_fn }, { MAX_ACCESS, access_kw, access_fn }, { MAX_ZONE, zone_kw, zone_fn }, { MAX_JOB, job_kw, job_fn }, { MAX_NVE, nve_kw, nve_fn }, { MAX_CLIMASK, climask_kw, climask_fn }, { MAX_CLICMD, clicmd_kw, clicmd_fn }, { MAX_FILTER, filter_kw, filter_fn }, { MAX_ROUTE, route_kw, route_fn }, { MAX_POOL, pool_kw, pool_fn }, { MAX_PORT, port_kw, port_fn }, { MAX_RECOVER, recover_kw, recover_fn }, { MAX_INCLUDE, include_kw, include_fn } }; static Uprof *uprof; /* Current user profile */ static int illegal_uprof; /* user profile is legal */ static int print_user_name = 0; /* record name is not printed */ static unsigned print_mode = 0; /* print mode (-u option) */ static Access *current_access; static Pool *pool; static PoolEntry *pool_entry; static char *severity[] = { "unspecified", "fatal", "error", "warning" }; /* * Objects */ static Database users; static Database pools; static Stack state; static Token token, sub_token; static Token *active_token; /* * Defines to indicate the type of database being acted upon by database_free */ #define NO_DATABASE 0 #define USER_DATABASE 1 #define POOL_DATABASE 2 #define Mlint (print_mode & M_LINT) #define Mdebug (print_mode & M_DEBUG) /* #define DEBUG_ORA 1 */ /* **************************************************************************** * * NAME: * open_user_profile_file - open the ACP user profile file * * SYNOPSIS: * int open_user_profile_file(const char *filename) * * DESCRIPTION: * * EXCEPTIONS: * **************************************************************************** */ int open_user_profile_file (filename) char *filename; { int status; status = pre_open_user_profile_file (filename, &token); if (status == ACPU_ESUCCESS) { if (token_new(&token, &sub_token, filename) != ACPU_ESUCCESS) { errlog(Warning, "Could not initialize Token"); print_mode = 0; return(ACPU_ERROR); } } else if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; return (status); } /* **************************************************************************** * * NAME: * close_user_profile_file - close the ACP user profile file * * SYNOPSIS: * int close_user_profile_file() * * DESCRIPTION: * * EXCEPTIONS: * **************************************************************************** */ int close_user_profile_file () { int status; status = pre_close_user_profile_file(); if (status == ACPU_ESUCCESS) { if ((status = token_close(&token)) != ACPU_ESUCCESS) return (status); } else if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; return (status); } /* **************************************************************************** * * NAME: * * initialize_user_profile_file - read the ACP user profile file into memory * * * SYNOPSIS: * * int initialize_user_profile_file(unsigned mode); * * * DESCRIPTION: * * initialize_user_profile_file creates an in-core database of user profiles by * reading user profile records from `filename'. If `filename' * is NULL, then stdin is used. `Mode' is a bit mask interpreted as follows: * * Symbol Bit Value Description * * M_INCR CURRENTLY UNIMPLEMENTED * 1 1 the existing database is incrementally updated with * user profiles in `filename'. * * 0 the current database is discarded and a new * database is generated from scratch. * * M_LINT 2 1 `filename' is syntax checked only and database * generation is suppressed (overrides M_INCR). * * M_TEE CURRENTLY UNIMPLEMENTED * 4 1 the user profiles are printed on stdout as they * are added to database. * * M_DEBUG 8 1 print debug info on stdout. Works only if this * file is compiled with -DDEBUG. * * * initialize_user_profile_file returns ACPU_ESUCCESS on success and error codes * on error conditions. * * * EXCEPTIONS: * * Upon detecting an operational error, such as not enought memory or * file oper error, initialize_user_profile_file prints a message on stderr and * returns an error code to caller. * * Upon detecting an parsing error, initialize_user_profile_file prints a * message on stderr. The message contains the filename, line number, * severity and description. If severity is Error, then database * generation is suppressed but the parser continues in order to detect * and report additional syntax errors. If severity is Warning, the * parser prints the message but adds the user profile to the database. * If the warning condition warrants, the user should fix the acp * user profile source and rehup the profile reader. * * **************************************************************************** */ int initialize_user_profile_file(mode) unsigned mode; { char *word = NULL; int status = ACPU_ESUCCESS; print_mode = mode; /* it makes life much easier */ active_token = &token; if ((status = pre_init_user_profile_file ()) == ACPU_ESUCCESS) { /* * make new objects */ if (Mdebug) printf("initialize_user_profile_file: making objects\n"); if (database_new(&users, sizeof(Uprof)) != ACPU_ESUCCESS) { errlog(Fatal, "Insufficient memory for Uprofs"); print_mode = 0; return(ACPU_ERROR); } if (database_new(&pools, sizeof(Pool)) != ACPU_ESUCCESS) { errlog(Fatal, "Insufficient memory for Pools"); print_mode = 0; return(ACPU_ERROR); } if (stack_new(&state, Idle) != ACPU_ESUCCESS) { errlog(Fatal, "Could not initialize Stack"); print_mode = 0; return(ACPU_ERROR); } /* * main loop */ main_loop: while (word = token_get(active_token)) { if (Mdebug) printf("initialize_user_profile_file: got token \"%s\"\n", word); status = parser_event(word); if (Mdebug) printf("initialize_user_profile_file: parse status %d\n", status); if (status != ACPU_ESUCCESS) break; } if (Mlint) { if (status == ACPU_ESUCCESS) { printf("initialize_user_profile_file: parsed %d users\n", database_entries(&users)); if(sub_token.t_fp) { token_free(&sub_token); bzero((caddr_t)&sub_token, sizeof(Token)); active_token = &token; goto main_loop; } } else printf("initialize_user_profile_file: parse failed\n"); print_mode = 0; return(ACPU_ERROR); } if (status == ACPU_ESUCCESS) { if(sub_token.t_fp) { token_free(&sub_token); bzero((caddr_t)&sub_token, sizeof(Token)); active_token = &token; goto main_loop; } database_ready(&users); database_ready(&pools); } else { database_free(&users,USER_DATABASE); database_free(&pools,POOL_DATABASE); } /* * done with this object */ token_free(&token); if(sub_token.t_fp) token_free(&sub_token); } else if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; print_mode = 0; return(status); } /* **************************************************************************** * * NAME: * * clear_user_profile_info - clear out the old ACP user profile info * * * SYNOPSIS: * * #include "acp_uprof.h" * * void clear_user_profile_info(); * * * DESCRIPTION: * * Clears the old user profile information in preparation for re-reading * the database. Called on SIGUSR1. * * * **************************************************************************** */ void clear_user_profile_info() { int status; Uprof *up, *up_prev; Access *acc, *acc_prev; struct _phone *ph, *ph_prev; Pool *pool, *pool_prev; PoolEntry *pe, *pe_prev; status = pre_clear_user_profile_info(); if (status == ACPU_ESUCCESS) { /* users.db_list and pools.db_list are declared to be of type * DatabaseEntry, but they are in reality Uprof and Pool structs, * both of whom have DatabaseEntry structs as their first members, * so they can be manipulated by database_add() etc. as DatabaseEntry * structs. */ up = (Uprof *)users.db_list; while (up != NULL) { acc = up->up_accesslist; while (acc != NULL) { ph = acc->ac_phone_list; while (ph != NULL) { ph_prev = ph; ph = ph->next; ph_prev->next = NULL; free(ph_prev); } acc_prev = acc; acc = acc->ac_next; acc_prev->ac_next = NULL; free(acc_prev); } if (up->up_cmd_list) release_cmd_list(up->up_cmd_list); if (up->up_filter_list) release_cmd_list(up->up_filter_list); if (up->up_route_list) release_cmd_list(up->up_route_list); if (up->up_values_p) free(up->up_values_p); up_prev = up; up = (Uprof *)up->up_de.de_next; up_prev->up_de.de_next = NULL; bzero(up_prev, sizeof(Uprof)); free(up_prev); } pool = (Pool *)pools.db_list; while (pool != NULL) { pe = pool->po_list; while (pe != NULL) { pe_prev = pe; pe = pe->pe_next; pe_prev->pe_next = NULL; free(pe_prev); } pool_prev = pool; pool = (Pool *)pool->po_de.de_next; pool_prev->po_de.de_next = NULL; free(pool_prev); } } database_count = 0; } /***************************************************************************** * * NAME: get_user_profile_entry * * DESCRIPTION: Returns the first matched entry for a user from the userinfo * database. * This routine makes two calls to userinfo database. Both * calls search the database linearly from the very beginning. * First call (get_user_profile) searches the database for * pre per-user entries such as: * * user net-surfer * at_passwd xyz * at_zone 38net 39net end * chat_secret surf1 * end * * where as the 2nd call (get_user_profile_by_env) looks * for entries with the per-user profile criteria. For eg. * * user username=net-surfer;time="Saturday";annex=whatever * climask telnet, who end * at_zone 38net 39net end * chap_secret surf1 * end * * Whichever entry is first in the database, it is used for * user's connection environment. If the first call returns * with success, the 2nd call uses the entry index no. of the * entry found. This makes sure that 2nd call doesn't go beyond * the first match found (by the first call) and saves on frivolous * lookups. If the first call is unsuccessful, 2nd calls gets a * very large entry index no. and searches the entire database for * user's entry. * * ARGUMENTS: * Uprof *up - OUTPUT userinfo entry structs * ACP_LSTRING Name - INPUT username * struct environment_spec **env - INPUT user's environment information * struct gr_file *file_etc - INPUT group file information * * * RETURN VALUE: * ACPU_ESUCCESS if successful * ACPU_ENOUSER on failure * * * RESOURCE HANDLING: * * SIDE EFFECTS: * * EXCEPTIONS: * * ASSUMPTIONS: * */ int get_user_profile_entry(up, Name, env, file_etc) Uprof *up; /*userinfo entry struct*/ #ifndef _WIN32 ACP_LSTRING Name; /*username */ #else /* defined _WIN32 */ ACP_USTRING Name; #endif /* defined _WIN32 */ struct environment_spec **env; /*user's environment information*/ struct gr_file *file_etc; /*group file information */ { int status; int error = -1; int error_by_env = -1; Uprof up_call1, up_call2; status = pre_get_user_profile_entry (up, Name, env, file_etc); if (status == ACPU_ESUCCESS) { bzero (&up_call1, sizeof(Uprof)); bzero (&up_call2, sizeof(Uprof)); error = get_user_profile(Name, &up_call1); if (error == ACPU_ESUCCESS) { file_etc->count = up_call1.up_de.de_entry_num; error_by_env = get_user_profile_by_env(env, &up_call2, file_etc); } else { file_etc->count = 0xfffffff; error_by_env = get_user_profile_by_env(env, &up_call2, file_etc); } file_etc->count = 0; if(error == ACPU_ESUCCESS || error_by_env == ACPU_ESUCCESS) status = ACPU_ESUCCESS; else status = ACPU_ENOUSER; /* * Choosing the first match of the two * calls. Both calls could be successful * since the database is read from the very * beginning. * "error" is the error value from the first call. * "error_by_env" is the error value from the 2nd call. * Copy information from the successful entry. If no * success, return ACPU_ENOUSER */ if ((error_by_env == ACPU_ESUCCESS) && ((error == ACPU_ESUCCESS)||(error == ACPU_ENOUSER))) bcopy (&up_call2, up, sizeof(Uprof)); else if (error == ACPU_ESUCCESS) bcopy (&up_call1, up, sizeof(Uprof)); } else if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; return (status); } /* **************************************************************************** * * NAME: * * get_user_profile - get user profile information by username * * SYNOPSIS: * static int get_user_profile(const char *username, Uprof *profile); * * DESCRIPTION: * Get_user_profile returns user profile information for a specified * user. `Username' is the search key. The user profile data is copied * into the uprof structure provided in `profile'. * * Get_user_profile returns an integer value interpreted as follows: * * ACPU_ESUCCESS Normal return, username found. * * ACPU_ENOACP The user profile database does not exist. * * ACPU_EINPROG The user profile database is in the process of being update, * try again later. * * ACPU_ENOUSER A user profile for `username' does not exist. * **************************************************************************** */ static int get_user_profile(username, uprof) char *username; Uprof *uprof; { /* * check if database exists */ if ((database_flags(&users) & DF_OPEN) == 0) return ACPU_ENOACP; /* * check if database is ready */ if ((database_flags(&users) & DF_READY) == 0) return ACPU_EINPROG; /* * search database for username */ if (database_find(&users, username, uprof) != ACPU_ESUCCESS) return ACPU_ENOUSER; /* * normal return */ return ACPU_ESUCCESS; } /* **************************************************************************** * * NAME: * get_user_profile_by_env - get user profile information by username * * * SYNOPSIS: * int get_user_profile_by_env(struct environment_spec **env_p, * Uprof *entry, struct gr_file *file_info); * * DESCRIPTION: * * get_user_profile_by_env returns user profile information for a specified * user which matches the environment description provided in `env_p'. * * Get_user_profile returns an integer value interpreted as follows: * * ACPU_ESUCCESS Normal return, match found. * * ACPU_ENOUSER A user profile matching the environment does not exist * **************************************************************************** */ static int get_user_profile_by_env(env_p,entry, file_info) struct environment_spec **env_p; Uprof *entry; struct gr_file *file_info; { struct environment_spec *temp=*env_p; struct environment_values *user_temp=NULL; DatabaseEntry *target; int i = 1; int list_already_created = FALSE; for (target = users.db_list; target && i < file_info->count; i++, target = target->de_next) { if (!(((Uprof *)target)->up_values_p)) continue; if(isalpha(((Uprof *)target)->up_values_p->groupname[0])) { if (!list_already_created) { if(create_group_list_4_env(&(temp->group_list), temp->username, file_info) == FALSE) { /* Failed to create a group list */ /* deny access */ return(ACPU_ENOUSER); } } list_already_created = TRUE; } user_temp = (struct environment_values *)malloc(sizeof(struct environment_values)); bzero(user_temp, sizeof(struct environment_values)); bcopy(((Uprof *)target)->up_values_p, user_temp, sizeof(struct environment_values)); if (match_env_options(*env_p, user_temp)) { bcopy((caddr_t)target, (caddr_t)entry, users.db_sizeof); file_info->count = i; free(user_temp); return(ACPU_ESUCCESS); } free(user_temp); } return(ACPU_ENOUSER); } /* **************************************************************************** * * NAME: * * get_user_access - get access information by username * * * SYNOPSIS: * * #include "acp_uprof.h" * * int get_user_access(const char *username, * const char *accesscode, * Access *accessptr); * struct env_gr_info *envinfo); * * * DESCRIPTION: * * Get_user_access returns user access information for a specified * user and access. `Username' is the search key for the user profile * and `accesscode' is the search key for an access code defined within * the user profile. The user access data is copied into the access * structure provided in `access'. * * Get_user_access returns an integer value interpreted as follows: * * ACPU_ESUCCESS Normal return, access code found. * * ACPU_ENOACP The user profile database does not exist. * * ACPU_EINPROG The user profile database is in the process of being update, * try again later. * * ACPU_ENOUSER A user profile for `username' does not exist. * * ACPU_ENOACC A access block for 'accesscode' does not exist. * **************************************************************************** */ int get_user_access(username, accesscode, accessptr, envinfo) char *username; char *accesscode; Access *accessptr; struct env_gr_info *envinfo; { Uprof uprof; Access *acp = NULL; int status; bzero (&uprof, sizeof(Uprof)); /* * search database for user */ if((status = get_user_profile_entry(&uprof, username, envinfo->env, envinfo->gr_info)) != ACPU_ESUCCESS) { release_uprof(&uprof); return (status); } if ((status = pre_get_user_access (username, accesscode, accessptr, envinfo)) != ACPU_ESUCCESS) { if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; release_uprof(&uprof); return (status); } /* * if pointer to access code is null, do not return * the access code, just check if there is one defined. * return ACPU_ENOACC if no access codes are defined. */ if (accesscode == 0) { if(uprof.up_accesslist == 0) /* no access codes defined */ status = ACPU_ENOACC; else /* access codes are defined but pointer is null */ status = ACPU_EACCESSCODE; release_uprof(&uprof); return(status); } /* * search accesscode list for access code */ for (acp = uprof.up_accesslist; acp; acp = acp->ac_next) { if (!strcmp(acp->ac_code, accesscode)) break; } if (!acp) status = ACPU_ENOACC; if ((acp != NULL) && (accessptr != NULL) && (status == ACPU_ESUCCESS)) bcopy((caddr_t)acp, (caddr_t)accessptr, sizeof(Access)); release_uprof(&uprof); return (status); } /* **************************************************************************** * * NAME: * * get_port_pool - get port pool information by poolname * * * SYNOPSIS: * * #include "acp_uprof.h" * * int get_port_pool(const char *poolname, PoolEntry *pool_entry); * * * DESCRIPTION: * * Get_port_pool returns port pool information for a specified * poolname. `Poolname' is the search key for the port pool. * The pool data is copied into the pool structure provided in * `pool_entry'. * * Get_port_pool returns an integer value interpreted as follows: * * ACPU_ESUCCESS Normal return, port pool found. * * ACPU_ENOACP The user profile database does not exist. * * ACPU_EINPROG The user profile database is in the process of being update, * try again later. * * ACPU_ENOPOOL A port pool for `poolname' does not exist. * * ACPU_ENOPOOLENT The named pool has no pool entries. * **************************************************************************** */ int get_port_pool(poolname, pool_entry) char *poolname; PoolEntry *pool_entry; { Pool pool; int status; if ((status = pre_get_port_pool(poolname, pool_entry)) != ACPU_ESUCCESS) { if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; return (status); } /* * check if database exists */ if ((database_flags(&pools) & DF_OPEN) == 0) status = ACPU_ENOACP; /* * check if database is ready */ else if ((database_flags(&pools) & DF_READY) == 0) status = ACPU_EINPROG; /* * search database for username */ else if (database_find(&pools, poolname, &pool) != ACPU_ESUCCESS) status = ACPU_ENOPOOL; /* * check for first pool entry */ else if (pool.po_count == 0) status = ACPU_ENOPOOLENT; bcopy((caddr_t)pool.po_list, (caddr_t)pool_entry, sizeof(PoolEntry)); return (status); } /* **************************************************************************** * * NAME: * * get_next_pool_entry - get the next pool entry * * * SYNOPSIS: * * #include "acp_uprof.h" * * int get_next_pool_entry(PoolEntry *pool_entry); * * * DESCRIPTION: * * Get_next_pool_entry returns pool information for the next pool entry * in a poolname. `pool_entry' is the address of a pool entry returned by * a call to get_port_pool or get_next_pool_entry. The pool data is copied * into the pool structure provided in `pool_entry'. * * Get_port_pool returns an integer value interpreted as follows: * * ACPU_ESUCCESS Normal return, port pool found. * * ACPU_ENOACP The user profile database does not exist. * * ACPU_EINPROG The user profile database is in the process of being update, * try again later. * * ACPU_EBADGEN Since the last get_next_pool_entry call, the pools database * has been changed. * ACPU_ENOPOOL A port pool for `poolname' does not exist. * * ACPU_ENOPOOLENT There are no more pool entries in this pool. * **************************************************************************** */ int get_next_pool_entry(pool_entry) PoolEntry *pool_entry; { PoolEntry *next_entry = pool_entry->pe_next; int status; if ((status = pre_get_next_pool_entry(pool_entry)) != ACPU_ESUCCESS) { if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; return (status); } /* * check if database exists */ if ((database_flags(&pools) & DF_OPEN) == 0) status = ACPU_ENOACP; /* * check if database is ready */ else if ((database_flags(&pools) & DF_READY) == 0) status = ACPU_EINPROG; /* * check database generation to make sure * that it hasn't been re-cached since last * get_next_pool_entry call. */ else if (pool_entry->pe_gen != pools.db_gen) status = ACPU_EBADGEN; /* * check for next pool entry */ else if (next_entry == 0) { status = ACPU_ENOPOOLENT; return (status); } bcopy((caddr_t)next_entry, (caddr_t)pool_entry, sizeof(PoolEntry)); return (status); } /* **************************************************************************** * * NAME: * * get_pool_entry_by_addr - get a pool entry * * * SYNOPSIS: * * #include "acp_uprof.h" * * int get_pool_entry_by_addr(const char *poolname, const u_long hostaddr, * const int portnum); * * * DESCRIPTION: * * `Poolname' is the name of a port pool. If NULL, all pools in the pools * database are searched. `Hostaddr' is the address of the Annex in network * byte order. `Portnum' is a port number of a serial port. * * Get_pool_entry_by_addr returns an integer value interpreted as follows: * * ACPU_ESUCCESS Normal return, port pool found. * * ACPU_ENOACP The user profile database does not exist. * * ACPU_EINPROG The user profile database is in the process of being update, * try again later. * * ACPU_ENOPOOL A port pool for `poolname' does not exist. * * ACPU_ENOPOOLENT There are no more pool entries in this pool. * **************************************************************************** */ int get_pool_entry_by_addr(poolname, hostaddr, portnum, ptype) char *poolname; INT32 hostaddr; int portnum,ptype; { Pool *pool; PoolEntry *pool_entry; int n = (portnum - 1)/8; int bmask = 1 << ((portnum-1) % 8); int status; if ((status = pre_get_pool_entry_by_addr(poolname, hostaddr, portnum, ptype)) != ACPU_ESUCCESS) { if (status == ACPU_ESKIP) status = ACPU_ESUCCESS; return (status); } /* * check if database exists */ if ((database_flags(&pools) & DF_OPEN) == 0) status = ACPU_ENOACP; /* * check if database is ready */ else if ((database_flags(&pools) & DF_READY) == 0) status = ACPU_EINPROG; /* * Do range check on the port number. * On Annex3's port MAX_SERIAL_PORTS+1 is the first vcli port number. * pe_portmap[] is MAX_SERIAL_PORTS-bit wide and must not be exceeded. */ else if (portnum > MAX_PORTS) status = ACPU_ENOPOOLENT; /* * search pools database for pool entry */ else { status=ACPU_ENOPOOLENT; for (pool = (Pool*)pools.db_list; pool; pool = (Pool*)pool->po_next) { /* * restrict search to named pool */ if (poolname && strcmp(poolname, pool->po_poolname)) continue; /* * search pool entries on this pool for match */ for (pool_entry = pool->po_list; pool_entry; pool_entry = pool_entry->pe_next) { if ((hostaddr == pool_entry->pe_hostaddr) && (pool_entry->pe_ports[ptype][n] & bmask)) { status = ACPU_ESUCCESS; break; } } } } /* end else */ if (status == ACPU_ESUCCESS) return ACPU_ESUCCESS; else return ACPU_ENOPOOLENT; } /* **************************************************************************** * * class member functions * **************************************************************************** */ static int token_new(this, sub_this, filename) Token *this, *sub_this; char *filename; { bzero((caddr_t)this, sizeof(Token)); bzero((caddr_t)sub_this, sizeof(Token)); if (token_open(this, filename) == ACPU_ERROR) return ACPU_ERROR; return token_read(this); } static int token_open(this, filename) Token *this; char *filename; { if (filename) { strncpy(this->t_filename,filename, sizeof(this->t_filename)-1); this->t_filename[sizeof(this->t_filename)-1] = '\0'; if ((this->t_fp = fopen(filename, "r")) == NULL) return ACPU_ERROR; } else { strcpy(this->t_filename, "stdin"); this->t_fp = stdin; } return ACPU_ESUCCESS; } static int token_close(this) Token *this; { if (this->t_fp != NULL) { if (fclose (this->t_fp)) return ACPU_ERROR; } return ACPU_ESUCCESS; } static int token_read(this) Token *this; { register char *bp = this->t_buf; register int len = sizeof this->t_buf, i = 0; again: this->t_buf[0] = '\0'; this->t_bp = this->t_buf; while (i < len) { if (!fgets(bp, len - i, this->t_fp)) return ACPU_ERROR; this->t_line++; i += strlen(bp) - 1; if (i == 0) goto again; if (!(memchr("\n\r", this->t_buf[i], 2) && this->t_buf[i-1] == '\\')) return ACPU_ESUCCESS; bp = &this->t_buf[--i]; } errlog(Error, "line too long"); return ACPU_ERROR; } static char * token_get(this) Token *this; { register char *start, *middle, *end; char temp[TOKBUFLEN + 1]; int current_state = state.s_stack[state.s_index]; /* * return ungotten word, if any */ if (this->t_ungotten) { start = this->t_ungotten; this->t_ungotten = NULL; return start; } more: /* * read more if real or virtual eol */ if (*this->t_bp == '\0' || *this->t_bp == '#') { if (token_read(this) != ACPU_ESUCCESS) return NULL; goto more; } start = this->t_bp + strspn(this->t_bp, SEPARATORS); if (*start == '\0' || *start == '#') { if (token_read(this) != ACPU_ESUCCESS) return NULL; goto more; } /* We want to start at the beginning backslash if first char is a backslash */ if((start > this->t_bp) && ((*(start-1)) == '\\')) start -= 1; /* * find token end */ middle = start; again: /* When looking for the end of the token, we need to * look not only for separator characters, but quote * characters, which we must handle specially. */ end = middle + strcspn(middle, SEPARATORS_W_QUOTES); /* If we got a quote character, skip up to the closing * quote and move forward. */ /* Be certain to check that the * preceding character was not a backslash, quoting the * quote. This involves looking back *two* characters, * as the backslash might itself be quoted! */ if (*end == '\"') { int close_found = FALSE; int x = 1; int nquotes = 0; /* Loop to look for closing quote - we must be certain * the quote we find is not a quoted quote within a * string. */ while (1) { /* Find the closing quote */ if ((end = (char *)strchr(end+1, '\"')) == NULL) { errlog(Error, "Unclosed quote in token"); return NULL; } /* Make sure it's not a quoted quote by counting * up the number of contiguous backslashes that * immediately precede it. If it's an odd number, * one of them goes with the quote character. */ for (x = 1, nquotes = 0; ((end - x) >= start) && (*(end - x) == '\\'); x++) nquotes++; /* Reset "middle" to point to the character following * the quote. */ middle = end + 1; /* If it's an even number of quotes, this quote * wasn't quoted. Get out. Otherwise, we go * through the loop again, looking for the next quote. */ if(!(nquotes % 2)) break; } /* Finished processing the quote - go back and get * the rest of the token. */ goto again; } else if (*end == '\\') { int c; if (isxdigit(*(end+1)) && isxdigit(*(end+2))) { strncpy(temp, end+1, 2); temp[2] = '\0'; /* null terminate */ c = strtol(temp,0,16); if (c == 0) { errlog(Error, "Illegal embedded NULL(\\00)"); return NULL; } *temp = (unsigned char)c; strcpy(temp+1, end+3); strcpy(end, temp); middle = end +1; goto again; } strcpy(temp, end+1); strcpy(end, temp); middle = end + 1; goto again; } /* * if last token in buf, * set bp to point to '\0' so that next * call to token_get does a token_read; * else * set bp to point 1 char past end of token; */ this->t_bp = (*end == '\0' || *end == '#') ? end : end + 1; /* * terminate token */ *end = '\0'; /* disallow wildcard prefixes in username. This should be remmoved later and then put in to the apt. place*/ if((current_state == Idle) && strchr(start, '*') &&(!strchr(start, '='))){ errlog(Error, "* is invalid as username in non-profile entries"); return NULL; } return (*start ? start : NULL); } static int parser_event(word) char *word; { int i, j, status; int s = state.s_stack[state.s_index]; ParserEntry *pe = &parse_table[s - 1]; int n = pe->pe_num_events; char **keywords = pe->pe_keywords; int (**fns)() = pe->pe_funcs; if (Mdebug) fprintf(stderr, "parser_event: passed \"%s\" in state %d\n", word, s); for (i = 0; i < n; i++) { if (strncasecmp(keywords[i], word, strlen(word)) == 0) break; } for (j = i + 1; j < n; j++) { if (strncasecmp(keywords[j], word, strlen(word)) == 0) break; } if (j < n) { if (Mlint) fprintf(stderr, "%s: line %d: error: \"%s\" is ambiguous\n", active_token->t_filename, active_token->t_line, word); return(stack_push(&state, Recover)); } /* * If keyword, pass action routine the next word (ie, * the argument) else pass action routine this word. */ if (i < n) word = token_get(active_token); if (Mdebug) fprintf(stderr, "parser_event: passing \"%s\" to handler\n", (word == NULL)?"NULL":word); status = (*fns[i])(word); return status; } static int database_new(this, entry_len) Database *this; int entry_len; { int gen = this->db_gen; bzero((caddr_t)this, sizeof(Database)); this->db_flags = DF_OPEN; this->db_sizeof = entry_len; this->db_listp = &this->db_list; this->db_gen = gen + 1; return ACPU_ESUCCESS; } static int database_add(this, new_entry) Database *this; DatabaseEntry *new_entry; { *this->db_listp = new_entry; this->db_listp = &new_entry->de_next; this->db_entries++; return ACPU_ESUCCESS; } static int database_find(this, key, entry) Database *this; char *key; DatabaseEntry *entry; { DatabaseEntry *target; for (target = this->db_list; target; target = target->de_next) if (!strcmp(key, target->de_key)) break; if (!target) return ACPU_ERROR; bcopy((caddr_t)target, (caddr_t)entry, this->db_sizeof); return ACPU_ESUCCESS; } static void database_free(this,db_type) Database *this; int db_type; { DatabaseEntry *curr, *next; next = this->db_list; while (curr = next) { next = curr->de_next; /* Free anything from user environment and clicmd list */ if (db_type == USER_DATABASE) { if (((Uprof *)curr)->up_cmd_list) release_cmd_list(((Uprof *)curr)->up_cmd_list); if (((Uprof *)curr)->up_filter_list) release_cmd_list(((Uprof *)curr)->up_filter_list); if (((Uprof *)curr)->up_route_list) release_cmd_list(((Uprof *)curr)->up_route_list); if (((Uprof *)curr)->up_values_p) free(((Uprof *)curr)->up_values_p); } free(curr); } (void)database_new(this, this->db_sizeof); } static int stack_new(this, init_entry) Stack *this; int init_entry; { bzero((caddr_t)this, sizeof(Stack)); this->s_stack[0] = init_entry; return ACPU_ESUCCESS; } static int stack_push(this, new_entry) Stack *this; int new_entry; { if (this->s_index >= MAXSTKENT) return ACPU_ERROR; /* stack overflow */ this->s_stack[++this->s_index] = new_entry; return ACPU_ESUCCESS; } static int stack_pop(this) Stack *this; { if (this->s_index < 1) return ACPU_ERROR; /* stack underflow */ this->s_stack[this->s_index--]; return ACPU_ESUCCESS; } static void errlog(level, msg) Severity level; char *msg; { int syslev; char buf[256]; switch (level) { case Warning: syslev = LOG_WARNING; break; case Error: syslev = LOG_ERR; break; default: if (Mlint) fprintf(stderr, "errlog: *** bad level coded ***\n"); case Fatal: syslev = LOG_CRIT; break; } if (Mlint) fprintf(stderr, "%s: line %d: %s: %s %s\n", (active_token) ? active_token->t_filename : "", (active_token) ? active_token->t_line : 0, severity[(int)level], msg, (print_user_name && uprof) ? uprof->up_username : ""); else { sprintf(buf, "%s: line %d: %s: %s %s\n", (active_token) ? active_token->t_filename : "", (active_token) ? active_token->t_line : 0, severity[(int)level], msg, (print_user_name && uprof) ? uprof->up_username : ""); syslog(syslev, buf); } } /* ***************************************************************************** * * parse table action routines * ***************************************************************************** */ static int user_begin(word) char *word; { int env_parse = 0; char *temp=NULL; ACP_USTRING check_word; if (Mdebug) fprintf(stderr, "user_begin: called with \"%s\"\n", word); if (word == NULL) { errlog(Error, "user_begin: called with no username"); return(ACPU_ERROR); } if ((uprof = (Uprof *)malloc(sizeof(Uprof))) == NULL) { errlog(Fatal, "user_begin: insufficient memory"); return(ACPU_ERROR); } bzero(uprof, sizeof(Uprof)); strncpy(check_word, word, ACP_MAXUSTRING); check_word[ACP_MAXUSTRING] = '\0'; temp = check_word; /* if profile criteria keyword, we just use count, spr 6259 */ /* tokens screw everything up. */ if (strstr(word, "="))sprintf(temp, "%d", database_count+1); fill_field(&temp, uprof->up_username, ACP_MAXUSTRING + 1); if (database_find(&users, uprof->up_username, uprof) == ACPU_ESUCCESS) { print_user_name = 1; errlog(Warning, "record exists for user"); print_user_name = 0; bzero(uprof, sizeof(Uprof)); illegal_uprof = 1; } else print_user_name = illegal_uprof = 0; database_count++; uprof->up_de.de_entry_num = database_count; /* Check if this is an environment string */ while (strstr(word, "=")) { if (uprof->up_values_p == (struct environment_values *)NULL) { uprof->up_values_p = (struct environment_values *)malloc(sizeof(struct environment_values)); if (uprof->up_values_p == (struct environment_values *)NULL) { /* print_user_name = 1; */ errlog(Warning, "insufficient memory for environment"); print_user_name = 0; bzero(uprof, sizeof(Uprof)); illegal_uprof = 1; break; } else { bzero(uprof->up_values_p, sizeof(struct environment_values)); } } /* Parse the environemt string */ if (env_keyword_routine(word,uprof->up_values_p) == TRUE) { /* Get the next token (maybe environment token) */ if ((word = token_get(active_token)) == NULL) break; else env_parse = 1; } else { /* Parsing failed setup for cleanup */ /* print_user_name = 1; */ errlog(Warning, "failed parsing environment"); print_user_name = 0; bzero(uprof, sizeof(Uprof)); illegal_uprof = 1; break; } } if (env_parse) { /* Push the unused token back on the stream */ token_unget(active_token, word); } return stack_push(&state, User); } static int pool_begin(word) char *word; { if ((pool = (Pool *)malloc(sizeof(Pool))) == NULL) { errlog(Fatal, "not enough memory for pool"); return ACPU_ERROR; } bzero(pool, sizeof(Pool)); pool->po_listp = &pool->po_list; if (strlen(word) > NAMLEN) { errlog(Warning, "poolname truncated to 64 characters"); word[NAMLEN] = '\0'; } strcpy(pool->po_poolname, word); pool_entry = (PoolEntry *)malloc(sizeof(PoolEntry)); if (!pool_entry) { errlog(Fatal, "not enough memory for pool entry"); return ACPU_ERROR; } bzero(pool_entry, sizeof(PoolEntry)); pool_entry->pe_gen = pools.db_gen; return stack_push(&state, Portpool); } static int idle_error(word) char *word; { errlog(Warning, "expected \"user\""); return stack_push(&state, Recover); } static int access_begin(word) char *word; { register Access **acpp; acpp = &uprof->up_accesslist; while (current_access = *acpp) { *acpp = current_access; acpp = ¤t_access->ac_next; } current_access = (Access *)malloc(sizeof(Access)); if (!current_access) { errlog(Fatal, "not enough memory"); return ACPU_ERROR; } bzero(current_access, sizeof(Access)); *acpp = current_access; if (strlen(word) > NAMLEN) { errlog(Warning, "accesscode truncated to 64 characters"); word[NAMLEN] = '\0'; } strcpy(current_access->ac_code, word); return stack_push(&state, Acc); } static int climask_begin(word) char *word; { if (Mdebug) fprintf(stderr, "climask_begin: entered\n"); if (uprof->up_climask) { errlog(Error, "multiply defined climask"); return stack_push(&state, Recover); } climask(word); return stack_push(&state, Climask); } static int climask(word) char *word; { register i, j; /* NOTE, these must be in the same order as the MASK_* definitions */ static char *cli_names[] = { "bg", "call", "fg", "hangup", "help", "hosts", "jobs", "kill", "netstat", "rlogin", "stats","stty", "telnet", "who", "lock", "su", "slip", "connect", "services", "ppp", "arap", "ipx", "dec", "lat", "ping", "none" }; #define MAXCLINAM (sizeof(cli_names) / sizeof (char *)) if (Mdebug) fprintf(stderr, "climask: entered\n"); for (i = 0; i < MAXCLINAM; i++) { if (!strncasecmp(cli_names[i], word, strlen(word))) break; } for (j = i + 1; j < MAXCLINAM; j++) { if (!strncasecmp(cli_names[j], word, strlen(word))) break; } if (i == MAXCLINAM) { errlog(Warning, "unsupported cli command name found"); return stack_push(&state, Recover); } else if (j < MAXCLINAM) { errlog(Warning, "ambiguous cli command name found"); return stack_push(&state, Recover); } else if (i == MAXCLINAM -1) uprof->up_climask = MASK_NONE; else uprof->up_climask |= 1 << i; return ACPU_ESUCCESS; } static int climask_end(word) char *word; { if (Mdebug) fprintf(stderr, "climask_end: entered\n"); token_unget(active_token, word); return stack_pop(&state); } static int deny_user(word) char *word; { if (Mdebug) fprintf(stderr, "deny_user: entered\n"); token_unget(active_token, word); uprof->up_deny = TRUE; return ACPU_ESUCCESS; } /********************************************************************** * * The release_cmd_list function is used to release clicmd, filter * and route lists from the Uprof structure * **********************************************************************/ void release_cmd_list(head_p) struct cli_cmd_list *head_p; { struct cli_cmd_list *entry_p; while(head_p) { entry_p = head_p; head_p = head_p->next; free(entry_p); } } /********************************************************************** * * The clicmd_begin, clicmd, and clicmd_end functions parse a * clicmd entry in acp_userinfo * */ static int clicmd_begin(word) char *word; { register struct cli_cmd_list *entp; struct cli_cmd_list *new_entp; if (Mdebug) fprintf(stderr, "clicmd_begin: entered\n"); new_entp = (struct cli_cmd_list *)malloc(sizeof(struct cli_cmd_list)); if ((new_entp == NULL) || (strlen(word) > MAX_CLI_CMD)) { errlog(Error, "cannot allocate space for clicmd entry"); return(stack_push(&state, Recover)); /* Clear out the list */ } bzero(new_entp, sizeof(struct cli_cmd_list)); new_entp->next = NULL; if (strcmp("...", word) != 0) /* look for special indicator */ strcpy(new_entp->clicmd, word); /* this must be a real command */ else *new_entp->clicmd = '\0'; /* indicates not to kill the cli */ if (uprof->up_cmd_list == NULL) uprof->up_cmd_list = new_entp; else { for (entp = uprof->up_cmd_list; entp->next != NULL; entp = entp->next); entp->next = new_entp; } return(stack_push(&state, Clicmd)); } static int clicmd(word) char *word; { register struct cli_cmd_list *entp; if (Mdebug) fprintf(stderr, "clicmd: entered\n"); for (entp = uprof->up_cmd_list; entp->next != NULL; entp = entp->next); if ((strlen(entp->clicmd) + strlen(word) + 2) > MAX_CLI_CMD) { errlog(Error, "clicmd \"%20s ...\" - length greater than %d\n", entp->clicmd, MAX_CLI_CMD); return(stack_push(&state, Recover)); /* Clear out the list ??? */ } strcat(entp->clicmd, " "); strcat(entp->clicmd, word); return(ACPU_ESUCCESS); } static int clicmd_end(word) char *word; { if (Mdebug) fprintf(stderr, "clicmd_end: entered\n"); token_unget(active_token, word); return stack_pop(&state); } /********************************************************************** * * The filter_begin, filter, and filter_end functions parse a * filter entry in acp_userinfo * */ static int filter_begin(word) char *word; { register struct cli_cmd_list *entp; struct cli_cmd_list *new_entp; if (Mdebug) fprintf(stderr, "filter_begin: entered\n"); new_entp = (struct cli_cmd_list *)malloc(sizeof(struct cli_cmd_list)); if ((new_entp == NULL) || (strlen(word) > MAX_CLI_CMD)) { errlog(Error, "cannot allocate space for filter entry"); return(stack_push(&state, Recover)); /* Clear out the list */ } bzero(new_entp, sizeof(struct cli_cmd_list)); new_entp->next = NULL; strcpy(new_entp->clicmd, word); if (uprof->up_filter_list == NULL) uprof->up_filter_list = new_entp; else { for (entp = uprof->up_filter_list; entp->next != NULL; entp = entp->next); entp->next = new_entp; } return(stack_push(&state, Filter)); } static int filter(word) char *word; { register struct cli_cmd_list *entp; if (Mdebug) fprintf(stderr, "filter: entered\n"); for (entp = uprof->up_filter_list; entp->next != NULL; entp = entp->next); if ((strlen(entp->clicmd) + strlen(word) + 2) > MAX_CLI_CMD) { errlog(Error, "filter \"%20s ...\" - length greater than %d\n", entp->clicmd, MAX_CLI_CMD); return(stack_push(&state, Recover)); /* Clear out the list ??? */ } strcat(entp->clicmd, " "); strcat(entp->clicmd, word); return(ACPU_ESUCCESS); } static int filter_end(word) char *word; { if (Mdebug) fprintf(stderr, "filter_end: entered\n"); token_unget(active_token, word); return stack_pop(&state); } /********************************************************************** * * The route_begin, route, and route_end functions parse a * route entry in acp_userinfo * */ static int route_begin(word) char *word; { register struct cli_cmd_list *entp; struct cli_cmd_list *new_entp; if (Mdebug) fprintf(stderr, "route_begin: entered\n"); new_entp = (struct cli_cmd_list *)malloc(sizeof(struct cli_cmd_list)); if ((new_entp == NULL) || (strlen(word) > MAX_CLI_CMD)) { errlog(Error, "cannot allocate space for route entry"); return(stack_push(&state, Recover)); /* Clear out the list */ } bzero(new_entp, sizeof(struct cli_cmd_list)); new_entp->next = NULL; strcpy(new_entp->clicmd, word); if (uprof->up_route_list == NULL) uprof->up_route_list = new_entp; else { for (entp = uprof->up_route_list; entp->next != NULL; entp = entp->next); entp->next = new_entp; } return(stack_push(&state, Route)); } static int route(word) char *word; { register struct cli_cmd_list *entp; if (Mdebug) fprintf(stderr, "route: entered\n"); for (entp = uprof->up_route_list; entp->next != NULL; entp = entp->next); if ((strlen(entp->clicmd) + strlen(word) + 2) > MAX_CLI_CMD) { errlog(Error, "route \"%20s ...\" - length greater than %d\n", entp->clicmd, MAX_CLI_CMD); return(stack_push(&state, Recover)); /* Clear out the list */ } strcat(entp->clicmd, " "); strcat(entp->clicmd, word); return(ACPU_ESUCCESS); } static int route_end(word) char *word; { if (Mdebug) fprintf(stderr, "route_end: entered\n"); token_unget(active_token, word); return stack_pop(&state); } static int blacklist(word) char *word; { int n; if (Mdebug) fprintf(stderr, "blacklist: entered\n"); n = atoi(word); if (n > 0) uprof->up_blacklist = n; else errlog(Warning, "expected blacklist arg > 0"); return ACPU_ESUCCESS; } static int user_error(word) char *word; { errlog(Error, "expected user keyword"); /*return stack_push(&state, Recover);*/ return ACPU_ERROR; } static int atzone_begin(word) char *word; { token_unget(active_token, word); uprof->up_at.at_zones = 0; return stack_push(&state, Zone); } static int atpasswd(word) char *word; { register i, n = strlen(word); char c; for (i = 0; i < n; i++) { c = word[i]; if (c == ' ') { errlog(Warning, "illegal blank in at_passwd"); illegal_uprof = 1; return ACPU_ESUCCESS; } if (!isalnum(c) && !ispunct(c)) { errlog(Warning, "illegal character in at_passwd"); illegal_uprof = 1; return ACPU_ESUCCESS; } } if (n > PWDLEN) { errlog(Warning, "passwd truncated to 8 characters"); illegal_uprof = 1; word[PWDLEN] = '\0'; n = PWDLEN; } strcpy(uprof->up_at.at_passwd, word); return ACPU_ESUCCESS; } static int dyndial_passwd(word) char *word; { register i, n = strlen(word); char c; for (i = 0; i < n; i++) { c = word[i]; if (c == ' ') { errlog(Warning, "illegal blank in dyndial_passwd"); return ACPU_ESUCCESS; } if (!isalnum(c) && !ispunct(c)) { errlog(Warning, "illegal character in dyndial_passwd"); return ACPU_ESUCCESS; } } if (n >= ACP_MAXSTRING) { errlog(Warning, "dyndial passwd truncated to 31 characters"); word[ACP_MAXSTRING] = '\0'; n = ACP_MAXSTRING - 1; } strcpy(uprof->user_index, word); return ACPU_ESUCCESS; } static int chap_secret(word) char *word; { register i, n = strlen(word); char c; for (i = 0; i < n; i++) { c = word[i]; if (c == ' ') { errlog(Warning, "illegal blank in chap_secret"); return ACPU_ESUCCESS; } if (!isalnum(c) && !ispunct(c)) { errlog(Warning, "illegal character in chap_secret"); return ACPU_ESUCCESS; } } if (n >= ACP_MAXSTRING) { errlog(Warning, "chap secret truncated to 31 characters"); word[ACP_MAXSTRING] = '\0'; n = ACP_MAXSTRING - 1; } strcpy(uprof->up_secret, word); return ACPU_ESUCCESS; } static int max_logon_time(word) char *word; { uprof->up_max_logon = atoi(word); /* -1 value means log this user off immediately. */ if (((uprof->up_max_logon < 0) && (uprof->up_max_logon != -1)) || (uprof->up_max_logon > MAX_LOGON) || (uprof->up_max_logon == 0)){ errlog(Warning,"Illegal max_logon argument"); return stack_push(&state, Recover); } else return ACPU_ESUCCESS; } static int atconnect_time(word) char *word; { register int n; int i; int max = strlen(word); char *p = word; for(i=0; iup_at.at_connect_time = n; return ACPU_ESUCCESS; } static int atcallback(word) char *word; { if (strlen(word) > DIALEN) { errlog(Warning, "phone num truncated to 32 characters"); illegal_uprof = 1; word[DIALEN] = '\0'; } strcpy(uprof->up_at.at_callback, word); return ACPU_ESUCCESS; } static int local_addr(word) char *word; { struct hostent *hostent; uprof->up_local_addr = inet_addr(word); if (uprof->up_local_addr == -1) { if ((hostent = gethostbyname(word)) == 0) { errlog(Warning, "unknown local hostname"); return stack_push(&state, Recover); } bcopy(hostent->h_addr, &uprof->up_local_addr, hostent->h_length); } return ACPU_ESUCCESS; } static int mp_max_links(word) char *word; { register int n; int i; int max = strlen(word); char *p = word; for(i=0; iup_mp_max_links = n; return ACPU_ESUCCESS; } static int remote_addr(word) char *word; { struct hostent *hostent; uprof->up_remote_addr = inet_addr(word); if (uprof->up_remote_addr == -1) { if ((hostent = gethostbyname(word)) == 0) { errlog(Warning, "unknown remote hostname"); return stack_push(&state, Recover); } bcopy(hostent->h_addr, &uprof->up_remote_addr, hostent->h_length); } return ACPU_ESUCCESS; } static int subnet_mask(word) char *word; { struct hostent *hostent; uprof->up_subnet_mask = inet_addr(word); if (uprof->up_subnet_mask == -1) { if ((hostent = gethostbyname(word)) == 0) { errlog(Warning, "unknown subnet mask"); return stack_push(&state, Recover); } bcopy(hostent->h_addr, &uprof->up_subnet_mask, hostent->h_length); } return ACPU_ESUCCESS; } static int user_end(word) char *word; { char *env_print_values(); token_unget(active_token, word); if (illegal_uprof == 0) { if (Mlint) { if(uprof->up_values_p != (struct environment_values *) 0) (void) fprintf(stderr, "Security profile criteria %s added\n", env_print_values(uprof->up_values_p)); else (void) fprintf(stderr, "user %s added\n", uprof->up_username); } database_add(&users, uprof); } else { print_user_name = 1; errlog(Warning, "record not loaded for user"); print_user_name = 0; free(uprof); uprof = (Uprof *) 0; } illegal_uprof = 0; return stack_pop(&state); } static int phone_no(word) char *word; { #define ca_phone_list current_access->ac_phone_list #define ca_phone current_access->ac_phone_list->ac_phone #define ca_code current_access->ac_code int is_ipx = !strcmp(ca_code, IPX_ACCESS_CODE_TOK); struct _phone **ll_head_ptr = 0; char *phone_ptr = 0; if (strlen(word) > DIALEN) { errlog(Warning, "phone no truncated to 32 characters"); word[DIALEN] = '\0'; } if (!ca_phone_list) { ll_head_ptr = &ca_phone_list; } else { if (is_ipx) { /* * For ipx, go to the back of the list. */ struct _phone *mark, *last; for (mark = ca_phone_list; mark; mark = mark->next) { last = mark; } phone_ptr = last->ac_phone; ll_head_ptr = &(last->next); /* * If the last phone number is the * charge_back token, then this * phone number just read is * meaningless. */ if (phone_ptr && !strcmp(phone_ptr, IPX_CHARGE_BACK_TOK)) return ACPU_ESUCCESS; } else { /* * For cli dialback security, there's * only one phone number in the list, * i.e. at the head. */ phone_ptr = ca_phone; } } if (ll_head_ptr) { (*ll_head_ptr) =(struct _phone *)malloc(sizeof(struct _phone)); if (!(*ll_head_ptr)) { errlog(Fatal, "not enough memory"); return ACPU_ERROR; } bzero(*ll_head_ptr, sizeof(struct _phone)); phone_ptr = (*ll_head_ptr)->ac_phone; } strcpy(phone_ptr, word); return ACPU_ESUCCESS; } static int in_pool_name(word) char *word; { if (strlen(word) > NAMLEN) { errlog(Warning, "pool name no truncated to 64 characters"); word[NAMLEN] = '\0'; } strcpy(current_access->ac_inpool, word); return ACPU_ESUCCESS; } static int out_pool_name(word) char *word; { if (strlen(word) > NAMLEN) { errlog(Warning, "poll name truncated to 64 characters"); word[NAMLEN] = '\0'; } strcpy(current_access->ac_outpool, word); return ACPU_ESUCCESS; } static int job_begin(word) char *word; { Acjob *acjob = ¤t_access->ac_job; if (acjob->j_length) { errlog(Error, "multiply defined jobs"); return stack_push(&state, Recover); } acjob->j_length = strlen(word); if (acjob->j_length > JOBLEN) { errlog(Error, "job string too long"); return stack_push(&state, Recover); } strcpy(acjob->j_string, word); acjob->j_count = 1; return stack_push(&state, Job); } static int job(word) char *word; { Acjob *acjob = ¤t_access->ac_job; int i = strlen(word); if ((i + acjob->j_length + 1) > JOBLEN) { errlog(Error, "job string too long"); return stack_push(&state, Recover); } acjob->j_string[acjob->j_length++] = ' '; strcpy(&acjob->j_string[acjob->j_length], word); acjob->j_length += i; acjob->j_count++; return ACPU_ESUCCESS; } static int job_end(word) char *word; { token_unget(active_token, word); return stack_pop(&state); } static int access_end(word) char *word; { token_unget(active_token, word); #ifdef DEBUG_PHONE_LIST { struct _phone *x; if ((x = current_access->ac_phone_list)) { printf("Phone numbers for accescode %s:\n\t", ca_code); for (;x; x = x->next) { printf("%s ", x->ac_phone); } printf("\n"); } } #endif return stack_pop(&state); } static int access_error(word) char *word; { errlog(Error, "expected access keyword"); return stack_push(&state, Recover); } static int zone_end(word) char *word; { token_unget(active_token, word); return stack_pop(&state); } static int zone(word) char *word; { At *atp = &uprof->up_at; register int i, n = strlen(word); char c; for (i = 0; i < n; i++) { c = word[i]; #if 0 if (c == ' ') { errlog(Warning, "illegal blank in zone"); return ACPU_ESUCCESS; } #endif if (!isalnum(c) && !ispunct(c) && !isspace(c)) { errlog(Warning, "illegal character in zone"); illegal_uprof = 1; return ACPU_ESUCCESS; } } if (n > ZONLEN) { errlog(Warning, "zone truncated to 33 characters"); illegal_uprof = 1; word[ZONLEN] = '\0'; n = ZONLEN; } if (atp->at_zone_combined + 1 + n > MAXNUMZON) { errlog(Warning, "too many at_zone characters, ignored"); illegal_uprof = 1; } else { atp->at_zonelist[atp->at_zone_combined++] = (u_char)n; strcpy(&atp->at_zonelist[atp->at_zone_combined],word); atp->at_zone_combined += n; atp->at_zones++; } return ACPU_ESUCCESS; } static int portnum(word) char *word; { if (pool_entry->pe_flags & PF_PORT) { if ((pool_entry->pe_flags & PF_ADDR) == 0) errlog(Warning, "unspecified address identifier"); *pool->po_listp = pool_entry; pool->po_listp = &pool_entry->pe_next; pool_entry = (PoolEntry *)malloc(sizeof(PoolEntry)); if (!pool_entry) { errlog(Fatal, "not enough memory for pool entry"); return ACPU_ERROR; } bzero(pool_entry, sizeof(PoolEntry)); pool_entry->pe_gen = pools.db_gen; pool->po_count++; } return portmem(word); } #define PORTS 1 #define HOSTNAME 2 #define ERROR_STATE 3 #define DONE 4 static int portmem(word) char *word; { char *cp=0, *pp=0; char buffp[ACP_MAXSTRING]; int done=FALSE; int rv=TRUE; int state=PORTS; pool_entry->pe_flags |= PF_PORT; /* * This fxn. gets a pool port string of following * syntax: * * pool-port := * port-string := * port-expr := {} | ,[ | ] * port-range := * port-range-expr := - * hostname := @ * ip := #.#.#.# | name * port := annex port#s * * is parsed by calling extract_ports() * fxn. in env_parser.c file. is parsed by calling * hostname() . */ while(!done) { switch(state) { /* parse */ case PORTS: strncpy(buffp, word, strcspn(word, "@")); /* copy to buff */ buffp[strcspn(word, "@")]='\0'; pp = buffp; cp=strstr(word, "@"); /* call extract_port_list() to parse */ if(rv = extract_port_list(&pp,pool_entry->pe_ports)) state = HOSTNAME; else state = ERROR_STATE; break; /* parse */ case HOSTNAME: if (*cp != '@') { state = ERROR_STATE; break; } *cp++ = '\0'; /* call hostname() to parse */ if (hostname(cp) != ACPU_ESUCCESS) state = ERROR_STATE; else state = DONE; break; /* error out */ case ERROR_STATE: done = TRUE; rv = ACPU_ERROR; break; /* end parsing */ case DONE: default: done = TRUE; rv = ACPU_ESUCCESS; break; } } if (*cp) return stack_pop(&state); return(rv); } static int portset(word) char *word; { token_unget(active_token, word); if (pool_entry->pe_flags & PF_PORT) { if ((pool_entry->pe_flags & PF_ADDR) == 0) errlog(Warning, "unspecified Annex identifier"); *pool->po_listp = pool_entry; pool->po_listp = &pool_entry->pe_next; pool_entry = (PoolEntry *)malloc(sizeof(PoolEntry)); if (!pool_entry) { errlog(Fatal, "not enough memory for pool entry"); return ACPU_ERROR; } bzero(pool_entry, sizeof(PoolEntry)); pool_entry->pe_gen = pools.db_gen; pool->po_count++; } return stack_push(&state, Portset); } static int portset_end(word) char *word; { token_unget(active_token, word); return stack_pop(&state); } static int pool_end(word) char *word; { token_unget(active_token, word); *pool->po_listp = pool_entry; pool->po_listp = &pool_entry->pe_next; pool->po_count++; database_add(&pools, pool); return stack_pop(&state); } static int pool_error(word) char *word; { errlog(Warning, "expected pool keyword"); return stack_push(&state, Recover); } static int hostname(word) char *word; { struct hostent *hostent; if (pool_entry->pe_flags & PF_ADDR) { if ((pool_entry->pe_flags & PF_PORT) == 0) errlog(Warning, "unspecified port identifier"); *pool->po_listp = pool_entry; pool->po_listp = &pool_entry->pe_next; pool_entry = (PoolEntry *)malloc(sizeof(PoolEntry)); if (!pool_entry) { errlog(Fatal, "not enough memory for pool entry"); return ACPU_ERROR; } bzero(pool_entry, sizeof(PoolEntry)); pool_entry->pe_gen = pools.db_gen; pool->po_count++; } pool_entry->pe_flags |= PF_ADDR; if (strlen(word) > NAMLEN) { errlog(Warning, "truncating hostname to 64 characters"); word[NAMLEN] = '\0'; } strcpy(pool_entry->pe_hostname, word); pool_entry->pe_hostaddr = inet_addr(word); if (pool_entry->pe_hostaddr == -1) { if ((hostent = gethostbyname(word)) == 0) { errlog(Warning, "unknown hostname"); return stack_push(&state, Recover); } bcopy(hostent->h_addr, &pool_entry->pe_hostaddr, hostent->h_length); } return ACPU_ESUCCESS; } static int recover_end(word) char *word; { token_unget(active_token, word); return stack_pop(&state); } static int recover(word) char *word; { return ACPU_ESUCCESS; } static int nve_begin(word) char *word; { token_unget(active_token, word); return stack_push(&state, Nve); } static int test_nve( word , len) char *word; int len; { int wild = 0; int esc = 0; char *p = word; if (len == 0) { errlog(Error, "Zero length entity"); return ( ACPU_ERROR ); } if (len > ZONLEN) { errlog(Warning, "Entity truncated to 32 characters"); word[ZONLEN] = '\0'; len = ZONLEN; return ACPU_ERROR; } while ( len ) { if ( *p == '*' ) wild++; if ( wild > 1 ) { errlog(Error, "Too Many wildcards in NVE"); return(ACPU_ERROR); } p++; len--; } return (ACPU_ESUCCESS); } static int nve_filter(word) char *word; { int n; int indx; char *p; At *atp = &uprof->up_at; indx = atp->at_nve_combined; if ((p = (char *)index ( word, ':')) == (char *)0) { errlog(Error, "Missing colon (:) in NVE filter"); illegal_uprof = 1; return(ACPU_ESUCCESS); } else { n = p - word; if (test_nve(word, n) == ACPU_ERROR) { illegal_uprof = 1; return(ACPU_ESUCCESS); } atp->at_nve[indx++] = (char)n; strncpy(&atp->at_nve[indx],word, n); indx += n; word = p+1; } if ((p = (char *)index(word, '@')) == (char *)0) { errlog(Error, "Missing at sign (@) in NVE filter"); illegal_uprof = 1; return(ACPU_ESUCCESS); } else { n = p - word; if (test_nve(word , n) == ACPU_ERROR) { illegal_uprof = 1; return(ACPU_ESUCCESS); } atp->at_nve[indx++] = (char)n; strncpy(&atp->at_nve[indx],word, n); indx += n; word = p+1; } if (*word) { n = strlen ( word ); if (test_nve(word, n ) == ACPU_ERROR) { illegal_uprof = 1; return(ACPU_ESUCCESS); } atp->at_nve[indx++] = (char)n; strncpy(&atp->at_nve[indx],word, n); indx += n; atp->at_nve_combined = indx; atp->at_nves += 3; } else { errlog(Error, "Missing zone in NVE filter"); illegal_uprof = 1; return(ACPU_ESUCCESS); } if (atp->at_nve_combined + 1 + n > MAXNUMNVE) { atp->at_nve_combined = MAXNUMNVE; errlog(Warning, "Too many at_nve_filter characters, ignored"); illegal_uprof = 1; } return ACPU_ESUCCESS; } static int nve_include(word) char *word; { token_unget(active_token, word); return ACPU_ESUCCESS; } static int nve_exclude(word) char *word; { At *atp = &uprof->up_at; atp -> at_nve_exclude = 1; token_unget(active_token, word); return ACPU_ESUCCESS; } static int nve_end(word) char *word; { At *atp = &uprof->up_at; token_unget(active_token, word); if ((atp -> at_nves == 0) || ((atp -> at_nves % 3) != 0)) { atp -> at_nves = 0; atp -> at_nve_combined = 0; atp -> at_nve_exclude = 0; return stack_pop(&state); } return stack_pop(&state); } #define GROUP_FIELD_DELIMITERS ":,\t\n " #define DISALLOW_GROUP '-' /****************************************************************************** * * create_group_list_4_env * * This is function creates a list of groups that have the specified user * as a member. This function opens the file specified by group_file. This * function reads entries from the group file until EOF is encountered. If * the file cannot be opened, then the event is logged (syslog), group_list * is set to NULL and FALSE is returned. * * The group entry is parsed into its components. This implementation is only * concerned with the group and user list components, the other components are * discarded. The function is_group_member() is called with the user list and * the username. d to is_group_member(). If is_group_member() returns TRUE, * then this function allocates space for the group_entry structure, copies the * group name to the structure and adds this entry to the group list. If this * function has been unable to allocate memory for the group_entry structure, * then this event is logged (syslog), any allocated entries are released, * group_list is set to NULL and FALSE is returned. This process is repeated * until EOF is encountered. When EOF is encountered and the group list created, * then group_list is to the head of the list and TRUE is returned. Otherwise * group_list is set to NULL and FALSE returned. * * Arguments: * struct group_entry **group_list; * char *username; * Return Value: * TRUE - The group is valid and the user is associated with the group or * user doesn't belong to any groups. * FALSE - acp_group exists but is not readible. acp_group doesn't exist * and so does /etc/group. Also if /etc/group exists but is not * readible. M_ALI 8/7/96. * Side Effects: None. * Exceptions: If one of the error conditions described in Return Value has * occurred, then an error message will be logged. * Assumptions: None. ******************************************************************************/ static int create_group_list_4_env(group_list,username, file_info) struct group_entry **group_list; char *username; struct gr_file *file_info; { #ifdef _WIN32 NTCreateGroupList(group_list,username); return TRUE; #else /* _WIN32 */ FILE *grp; struct group_entry *head, *entry; struct group *grp_entry; #if defined (ULTRIX) || defined (FREEBSD) || defined (BSDI) struct group *getgrent(); #else struct group *fgetgrent(); #endif int retv = FALSE,field; struct stat buff_stat; head = (struct group_entry *)NULL; errno = 0; /* checking to see if acp_group */ /* exists M_ALI 8/7/95. */ #if (!(defined (ULTRIX) || defined (FREEBSD) || defined (BSDI))) if ((stat(file_info->group_f, &buff_stat)) == 0) { if((grp = fopen(file_info->group_f, "r")) == NULL){ syslog(LOG_CRIT, "erpcd: failed to open acp_group file"); return(retv); } } /* since acp_group doesn't exist, */ /* /etc/group must exist. else it */ /* is an error M_ALI 8/7/95 */ else #endif if ((errno == ENOENT || errno==0) && (stat (DEFAULT_GROUP, &buff_stat)) == 0) { if ((buff_stat.st_mode & S_IRUSR)) grp = fopen(DEFAULT_GROUP,"r"); else { syslog(LOG_CRIT, "erpcd: failed to open %s", DEFAULT_GROUP); return(retv); } } /* Both acp_group and /etc/group */ /* are not available. This is an */ /* error. retv=FALSE M_ALI 8/7/95 */ if(grp == NULL){ syslog(LOG_CRIT, "erpcd: failed to open either of the group files"); return retv; } /* retv can only be FALSE when there */ /* is an error calloc'ng. M_ALI 8/7/95 */ retv = TRUE; /* get a line from the group file */ #if defined (ULTRIX) || defined (FREEBSD) || defined (BSDI) setgrent(); while(grp_entry = getgrent()) #else while((grp_entry = fgetgrent(grp))) #endif { /* Get the group name */ if (*(grp_entry->gr_name) == DISALLOW_GROUP) continue; if (is_group_member_4_env(grp_entry->gr_mem, username)) { if (entry = (struct group_entry *)malloc(sizeof(struct group_entry))){ bzero(entry, sizeof(struct group_entry)); strcpy(entry->groupname,grp_entry->gr_name); /* Place entry at the head of the list */ entry->next = head; head = entry; } else { /* Unable to create a link list - return FALSE */ retv = FALSE; syslog(LOG_ERR,"acp_group.c: insufficient memory for group entry"); while(head) { entry = head; head = head->next; free(entry); } break; } /* End if malloc OK */ } /* End if is group member */ } /* End for all acp_group entries */ *group_list = head; fclose(grp); return(retv); #endif /* _WIN32 */ } /****************************************************************************** * * is_group_member_4_env * * This is function searches for the user_list for the specified user. * The users are parsed from the list and compared with username. If a * match is found, then TRUE is returned. Otherwise the process is repeated. * The process is repeated until the end of the user_list is encountered. When * the end of the user_list is encountered, FALSE is returned. * * Arguments: * char *user_list; * char *username * Return Value: * TRUE - The group is valid and the user is associated with the group. * FALSE - Either the group file cannot be opened or the group is invalid * or the user name is invalid or the user is not associated with * the group. * Side Effects: None. * Exceptions: If one of the error conditions described in Return Value has * occurred, then an error message will be logged (acp_log and syslog). * Assumptions: None. ******************************************************************************/ static int is_group_member_4_env(user_list,user) char **user_list; char *user; { for(; *user_list; user_list++) if (strcasecmp(*user_list, user) == 0) return(TRUE); return(FALSE); } static int open_include_file(word) char *word; { char temp_name[256]; int status; if(sub_token.t_fp) { /* not allowed to nest include files */ errlog (Error, "Include files cannot be nested - Ignored"); return ACPU_ESUCCESS; } sprintf(temp_name,"%s/%s",install_dir,word); if ((status = token_open(&sub_token, temp_name)) != ACPU_ESUCCESS) return (status); active_token = &sub_token; return token_read(active_token); }