NSAPI_PUBLIC int ACL_ExprSetDenyWith( NSErr_t *errp, ACLExprHandle_t *expr, char *deny_type, char *deny_response) { int rv; if ( expr->expr_argc == 0 ) { if ( (rv = ACL_ExprAddArg(errp, expr, deny_type)) < 0 ) return(rv); if ( (rv = ACL_ExprAddArg(errp, expr, deny_response)) < 0 ) return(rv); } else if ( expr->expr_argc == 2 ) { if ( deny_type ) { if ( expr->expr_argv[0] ) PERM_FREE(expr->expr_argv[0]); expr->expr_argv[0] = PERM_STRDUP(deny_type); if ( expr->expr_argv[0] == NULL ) return(ACLERRNOMEM); } if ( deny_response ) { if ( expr->expr_argv[1] ) PERM_FREE(expr->expr_argv[1]); expr->expr_argv[1] = PERM_STRDUP(deny_response); if ( expr->expr_argv[0] == NULL ) return(ACLERRNOMEM); } } else { return(ACLERRINTERNAL); } return(0); }
NSAPI_PUBLIC int ACL_ExprAddArg( NSErr_t *errp, ACLExprHandle_t *expr, const char *arg ) { if ( expr == NULL ) return(ACLERRUNDEF); if (expr->expr_argv == NULL) expr->expr_argv = (char **) PERM_MALLOC( 2 * sizeof(char *) ); else expr->expr_argv = (char **) PERM_REALLOC( expr->expr_argv, (expr->expr_argc+2) * sizeof(char *) ); if (expr->expr_argv == NULL) return(ACLERRNOMEM); expr->expr_argv[expr->expr_argc] = PERM_STRDUP( arg ); if (expr->expr_argv[expr->expr_argc] == NULL) return(ACLERRNOMEM); expr->expr_argc++; expr->expr_argv[expr->expr_argc] = NULL; return(0); }
/* * Gets a name list of consisting of all ACL names for input list. * * Input: * acl_list an ACL List handle * name_list pointer to a list of string pointers * Returns: * 0 success * < 0 failure */ NSAPI_PUBLIC int ACL_ListGetNameList(NSErr_t *errp, ACLListHandle_t *acl_list, char ***name_list) { const int block_size = 50; ACLWrapper_t *wrapper; int list_index; int list_size; char **tmp_list; char **local_list; const char *name; if ( acl_list == NULL ) return(ACLERRUNDEF); list_size = block_size; local_list = (char **) PERM_MALLOC(sizeof(char *) * list_size); if ( local_list == NULL ) return(ACLERRNOMEM); list_index = 0; local_list[list_index] = NULL; for ( wrapper = acl_list->acl_list_head; wrapper != NULL; wrapper = wrapper->wrap_next ) { if ( wrapper->acl->tag ) name = wrapper->acl->tag; else name = "noname"; if ( list_index + 2 > list_size ) { list_size += block_size; tmp_list = (char **) PERM_REALLOC(local_list, sizeof(char *) * list_size); if ( tmp_list == NULL ) { ACL_NameListDestroy(errp, local_list); return(ACLERRNOMEM); } local_list = tmp_list; } local_list[list_index] = PERM_STRDUP(name); if ( local_list[list_index] == NULL ) { ACL_NameListDestroy(errp, local_list); return(ACLERRNOMEM); } list_index++; local_list[list_index] = NULL; } *name_list = local_list; return(0); }
NSAPI_PUBLIC ACLHandle_t * ACL_AclNew(NSErr_t *errp, char *tag ) { ACLHandle_t *handle; handle = ( ACLHandle_t * ) PERM_CALLOC ( 1 * sizeof (ACLHandle_t) ); if ( handle && tag ) { handle->tag = PERM_STRDUP( tag ); if ( handle->tag == NULL ) { PERM_FREE(handle); return(NULL); } } return(handle); }
NSAPI_PUBLIC dns_cache_entry_t * dns_cache_insert(char *host, unsigned int ip, unsigned int verified) { dns_cache_entry_t *newentry; if ( !dns_cache || !ip) { return NULL; } if ( (newentry = (dns_cache_entry_t *)PERM_MALLOC(sizeof(dns_cache_entry_t))) == NULL) { ereport(LOG_FAILURE, XP_GetAdminStr(DBT_dnsCacheInsertErrorAllocatingEnt_)); goto error; } if (host) { if ( (newentry->host = PERM_STRDUP(host)) == NULL) { ereport(LOG_FAILURE, XP_GetAdminStr(DBT_dnsCacheInsertMallocFailure_)); goto error; } } else newentry->host = NULL; #ifdef CACHE_DEBUG newentry->cache.magic = CACHE_ENTRY_MAGIC; #endif newentry->ip = ip; newentry->verified = verified; newentry->last_access = ft_time(); if ( cache_insert_p(dns_cache, &(newentry->cache), (void *)&(newentry->ip), (void *)newentry, &dns_cache_entry_functions) < 0) { /* Not a bad error; it just means the cache is full */ goto error; } return newentry; error: if (newentry) { if (newentry->host) PERM_FREE(newentry->host); PERM_FREE(newentry); } return NULL; }
NSAPI_PUBLIC int ACL_AddPermInfo( NSErr_t *errp, ACLHandle_t *acl, char **access_rights, PFlags_t flags, int allow, ACLExprHandle_t *expr, char *tag ) { if ( acl == NULL || expr == NULL ) return(ACLERRUNDEF); expr->expr_flags = flags; expr->expr_argv = (char **) access_rights; expr->expr_tag = PERM_STRDUP( tag ); if ( expr->expr_tag == NULL ) return(ACLERRNOMEM); return(ACL_ExprAppend( errp, acl, expr )); }
static Symbol_t * acl_sym_new(ACLHandle_t *acl) { Symbol_t *sym; /* It's not there, so add it */ sym = (Symbol_t *) PERM_MALLOC(sizeof(Symbol_t)); if ( sym == NULL ) return(NULL); sym->sym_name = PERM_STRDUP(acl->tag); if ( sym->sym_name == NULL ) { PERM_FREE(sym); return(NULL); } sym->sym_type = ACLSYMACL; sym->sym_data = (void *) acl; return(sym); }
static int _fsmutex_create(fsmutex_s *fsm, char *name, int number) { char tn[256]; SYS_FILE lfd; int visible = (fsm->flags & FSMUTEX_VISIBLE ? 1 : 0); util_snprintf(tn, 256, "/tmp/%s.%d", name, number); if(!visible) unlink(tn); if( (lfd = PR_Open(tn, PR_RDWR|PR_CREATE_FILE, 0644)) == NULL) return -1; if(!visible) unlink(tn); else fsm->id = PERM_STRDUP(tn); fsm->mutex = lfd; return 0; }
PR_END_EXTERN_C /* ----------------------------- filter_fill ------------------------------ */ static Filter *filter_fill(const char *name, int order, const FilterMethods *methods, int flags, Filter *filter) { filter->name = PERM_STRDUP(name); filter->flags = flags; filter->order = order & FILTER_MASK; // Reserve topmost bits for future use /* * Setup NSAPI-specific filter methods */ if (methods->insert) { filter->insert = methods->insert; } else { filter->insert = &filtermethod_always_insert; } if (methods->remove) { filter->remove = methods->remove; } else { filter->remove = &filtermethod_default_remove; } if (methods->read) { filter->read = methods->read; } else { filter->read = NULL; } /* * Setup NSPR filter methods */ filter->priomethods = *PR_GetDefaultIOMethods(); filter->priomethods.file_type = PR_DESC_LAYERED; // Assert NSPR IO layer and NSAPI filter binary compatibility PR_ASSERT(sizeof(PRSendFileData) == sizeof(sendfiledata)); PR_ASSERT(sizeof(PRIOVec) == sizeof(NSAPIIOVec)); PR_ASSERT(sizeof(PRStatus) == sizeof(int)); PR_ASSERT(sizeof(PRInt32) == sizeof(int)); PR_ASSERT(sizeof(PRSize) == sizeof(size_t)); filter->priomethods.close = &filtermethod_close; if (methods->flush) { filter->priomethods.fsync = (PRFsyncFN)methods->flush; } else { filter->priomethods.fsync = &filtermethod_default_fsync; } if (methods->read) { filter->priomethods.read = &filtermethod_emulate_read; filter->priomethods.recv = &filtermethod_emulate_recv; } else { filter->priomethods.read = &filtermethod_default_read; filter->priomethods.recv = &filtermethod_default_recv; } if (methods->write) { filter->priomethods.write = (PRWriteFN)methods->write; filter->priomethods.send = (PRSendFN)methods->write; } else { filter->priomethods.write = &filtermethod_default_write; filter->priomethods.send = &filtermethod_default_send; } if (methods->writev) { filter->priomethods.writev = (PRWritevFN)methods->writev; } else if (methods->write) { ereport(LOG_VERBOSE, "Emulating writev for filter %s", filter->name); filter->priomethods.writev = &filtermethod_emulate_writev; } else { filter->priomethods.writev = &filtermethod_default_writev; } if (methods->sendfile) { filter->priomethods.sendfile = (PRSendfileFN)methods->sendfile; } else if (methods->write) { ereport(LOG_VERBOSE, "Emulating sendfile for filter %s", filter->name); filter->priomethods.sendfile = &filtermethod_emulate_sendfile; } else { filter->priomethods.sendfile = &filtermethod_default_sendfile; } /* * Add the filter to the front of the server-wide list */ PR_Lock(_filter_list_lock); filter->next = _filter_list; _filter_list = filter; _filter_hash.remove((void *)filter->name); _filter_hash.insert((void *)filter->name, filter); PR_Unlock(_filter_list_lock); return filter; }
NSAPI_PUBLIC int ACL_ExprTerm( NSErr_t *errp, ACLExprHandle_t *acl_expr, const char *attr_name, CmpOp_t cmp, char *attr_pattern ) { ACLExprEntry_t *expr; ACLExprRaw_t *raw_expr; if ( acl_expr == NULL || acl_expr->expr_arry == NULL ) return(ACLERRUNDEF); if ( acl_expr->expr_term_index >= acl_expr->expr_arry_size ) { acl_expr->expr_arry = ( ACLExprEntry_t *) PERM_REALLOC ( acl_expr->expr_arry, (acl_expr->expr_arry_size + ACL_TERM_BSIZE) * sizeof(ACLExprEntry_t)); if ( acl_expr->expr_arry == NULL ) return(ACLERRNOMEM); acl_expr->expr_arry_size += ACL_TERM_BSIZE; } expr = &acl_expr->expr_arry[acl_expr->expr_term_index]; acl_expr->expr_term_index++; expr->attr_name = PERM_STRDUP(attr_name); if ( expr->attr_name == NULL ) return(ACLERRNOMEM); expr->comparator = cmp; expr->attr_pattern = PERM_STRDUP(attr_pattern); if ( expr->attr_pattern == NULL ) return(ACLERRNOMEM); expr->true_idx = ACL_TRUE_IDX; expr->false_idx = ACL_FALSE_IDX; expr->start_flag = 1; expr->las_cookie = 0; expr->las_eval_func = 0; if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) { acl_expr->expr_raw = ( ACLExprRaw_t *) PERM_REALLOC ( acl_expr->expr_raw, (acl_expr->expr_raw_size + ACL_TERM_BSIZE) * sizeof(ACLExprRaw_t)); if ( acl_expr->expr_raw == NULL ) return(ACLERRNOMEM); acl_expr->expr_raw_size += ACL_TERM_BSIZE; } raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index]; acl_expr->expr_raw_index++; raw_expr->attr_name = expr->attr_name; raw_expr->comparator = cmp; raw_expr->attr_pattern = expr->attr_pattern; raw_expr->logical = (ACLExprOp_t)0; #ifdef DEBUG_LEVEL_2 printf ( "%d: %s %s %s, t=%d, f=%d\n", acl_expr->expr_term_index - 1, expr->attr_name, acl_comp_string( expr->comparator ), expr->attr_pattern, expr->true_idx, expr->false_idx ); #endif return(0); }
/** ************************************************************************** * check-request-limits SAF * * See top of this file for the pb parameters this SAF can consume and the * defaults for each. * * This SAF counts requests per interval for the given monitor/bucket. If * the request/sec in an interval exceeds the max-rps given then it returns * REQ_ABORTED for this and all subsequent matching requests in the current * interval. After the next interval request rate recomputation the request * limiting may be discontinued if the conditions of 'continue' are met. * * Separately, concurrent requests for the same bucket may be limited to * the given number if max-connections is given. * * On the next request after purge_timeout, a purge sweep of the buckets is * done, deleting any entries which have not seen any recomputes in the * purge interval (unless timeout disabled by setting it to zero). * * For more information, refer to the WS7.0 security functional spec at: * http://sac.eng/arc/WSARC/2004/076/ * * For params: http://docs.sun.com/source/817-1835-10/npgmysaf.html#wp14889 * For returns: http://docs.sun.com/source/817-1835-10/npgmysaf.html#wp14969 * * This returns: * REQ_NOACTION: If the request can go on. * REQ_ABORTED: If the request has hit limits and is not to be processed. * Return code is set to 'error' param (default 503). * */ int check_request_limits(pblock *pb, Session *sn, Request *rq) { const char * param; int response = REQ_NOACTION; if (rq->rq_attr.req_restarted) { // Do not count restarted requests as new requests for the // purpose of reqlimit accounting as it is just one client // request. (This is particularly important for // max-connections since processing restarts would cause the // conc counter to increase more than once for a given request // but only decrease once at the end). return response; } time_t time_now = rq->req_start; assert (time_now != NULL); // Get max-rps int max_rps = 0; param = pblock_findval(MAXRPS_PARAM, pb); if (param) { max_rps = atoi(param); } // Get max-connections int conc = 0; param = pblock_findval(CONC_PARAM, pb); if (param) { conc = atoi(param); } // We must have at least max-rps or max-connections, otherwise can't // do anything meaningful here if (!max_rps && !conc) { log_error(LOG_MISCONFIG, "check-request-limits", sn, rq, XP_GetAdminStr(DBT_reqlimitCantWork)); return response; } // Decide bucket name; if none, we use the anonymous bucket anon_bucket bucket_info * bucket = NULL; const char * bucket_name = pblock_findval(MONITOR_PARAM, pb); if (!bucket_name) { bucket = &anon_bucket; } // interval (in seconds), or use default int interval = DEFAULT_INTERVAL; param = pblock_findval(INTERVAL_PARAM, pb); if (param) { interval = atoi(param); } // Check continue, or use default int cont = DEFAULT_CONTINUE; param = pblock_findval(CONTINUE_PARAM, pb); if (param) { if (!strcmp(CONT_THRESHOLD_VAL, param)) { cont = CONT_THRESHOLD; } else if (!strcmp(CONT_SILENCE_VAL, param)) { cont = CONT_SILENCE; } else { // Log config error but continue since we have default log_error(LOG_MISCONFIG, "check-request-limits", sn, rq, XP_GetAdminStr(DBT_reqlimitBadContinue)); } } //----- START_CRIT ------------------------------ crit_enter(reqlimit_crit); if (purge_timeout && (time_now > next_timeout)) { // run purge if needed handle_purge_timeout(time_now); } // If using anon bucket we already have reference to it, otherwise need // to go find it in hashtable (and if not found, create one) if (!bucket) { bucket = (bucket_info *)PL_HashTableLookup(hashtable, bucket_name); if (!bucket) { // Need to create new entry for this one log_error(LOG_VERBOSE, "check-request-limits", sn, rq, "creating new entry for [%s]", bucket_name); bucket = (bucket_info *)PERM_MALLOC(sizeof(bucket_info)); bucket->count = 1; bucket->time = time_now + interval; bucket->state = REQ_NOACTION; bucket->conc = 0; // handle conc case on initial? PL_HashTableAdd(hashtable, (const void *)PERM_STRDUP(bucket_name), (void *)bucket); // Since it is the first request, no need to check more crit_exit(reqlimit_crit); return response; } } // If we are doing max-rps limiting then handle it otherwise don't bother if (max_rps) { bucket->count++; if (time_now > bucket->time) { // Interval or more has passed, time to recompute and recheck int time_interval = time_now - bucket->time + interval; int rps = bucket->count / time_interval; log_error(LOG_VERBOSE, "check-request-limits", sn, rq, "bucket [%s] %d req/s (%d req in %d sec)", bucket_name ? bucket_name: "", rps, bucket->count, time_interval); if (rps > max_rps) { // Start limiting bucket->state = REQ_ABORTED; log_error(LOG_WARN, "check-request-limits", sn, rq, XP_GetAdminStr(DBT_reqlimitAboveMaxRPS), rps, max_rps, bucket_name ? bucket_name: ""); } else { // Reset state if we're under threshhold or if this is first // hit (which means an interval with zero hits has already // passed) if ((cont == CONT_THRESHOLD) || (bucket->count == 1)) { bucket->state = REQ_NOACTION; } } // Prepare for next interval by resetting count and recompute time bucket->count = 0; bucket->time = time_now + interval; } response = bucket->state; } // If decision to reject already done, no need to check or increase conc // since this is not getting processed anyway. Otherwise, do it if needed. if (conc && response != REQ_ABORTED) { if (bucket->conc >= conc) { // Note that this reject is based on conditions at this instant // instead of over an interval, so is independent of bucket->state response = REQ_ABORTED; } else { bucket->conc++; // This queues up a call to fn associated with req_cleanup // (here, reqlimit_conc_done) to be called after request is done request_set_data(rq, req_cleanup, bucket); } } crit_exit(reqlimit_crit); //----- END_CRIT ------------------------------ if (response == REQ_NOACTION) { return REQ_NOACTION; } // abort this request int err = DEFAULT_ERROR; param = pblock_findval(ERROR_PARAM, pb); if (param) { err = atoi(param); } protocol_status(sn, rq, err, NULL); log_error(LOG_VERBOSE, "check-request-limits", sn, rq, "Rejecting request matching bucket [%s] with status %d", bucket_name ? bucket_name: "", err); return response; }