static void check_pair(REQUEST *request, VALUE_PAIR *check_item, VALUE_PAIR *reply_item, int *pass, int *fail) { int compare; if (check_item->op == T_OP_SET) return; compare = paircmp(check_item, reply_item); if (compare < 0) { REDEBUG("Comparison failed: %s", fr_strerror()); } if (compare == 1) { ++*(pass); } else { ++*(fail); } if (RDEBUG_ENABLED3) { char rule[1024], pair[1024]; vp_prints(rule, sizeof(rule), check_item); vp_prints(pair, sizeof(pair), reply_item); RDEBUG3("%s %s %s", pair, compare == 1 ? "allowed by" : "disallowed by", rule); } return; }
static int addlinetocontent(VALUE_PAIR *vp) { int outlen = sizeof(content) - concntr - 1; int lendiv; if ( outlen < 4 ) return -1; if ( vp == NULL ) { /* add empty line */ content[concntr++] = '\n'; content[concntr] = '\0'; } else { while ( vp != NULL ){ lendiv = vp_prints(&content[concntr],outlen,vp); if ( lendiv > 0 ) { outlen -= lendiv; if (outlen > 3) { strcat(content,", "); concntr += lendiv + 2; outlen -= 2; } else { concntr = 0; return -1; } } vp = vp -> next; } if ( concntr > 2 ) { /* remove trailing ',' */ content[--concntr] = '\0'; content[concntr - 1] = '\n'; } } return 0; }
/** Print one attribute and value to FP * * Complete string with '\\t' and '\\n' is written to buffer before printing to * avoid issues when running with multiple threads. * * @param fp to output to. * @param vp to print. */ void vp_print(FILE *fp, VALUE_PAIR const *vp) { char buf[1024]; char *p = buf; size_t len; VERIFY_VP(vp); *p++ = '\t'; len = vp_prints(p, sizeof(buf) - 1, vp); if (!len) { return; } p += len; /* * Deal with truncation gracefully */ if (((size_t) (p - buf)) >= (sizeof(buf) - 2)) { p = buf + (sizeof(buf) - 2); } *p++ = '\n'; *p = '\0'; fputs(buf, fp); }
/* * Print one attribute and value. */ void vp_print(FILE *fp, VALUE_PAIR *vp) { char buf[1024]; vp_prints(buf, sizeof(buf), vp); fputs(buf, fp); }
/** Print a list of valuepairs to the request list. * * @param[in] level Debug level (1-4). * @param[in] request to read logging params from. * @param[in] vp to print. */ void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp) { vp_cursor_t cursor; char buffer[256]; if (!vp || !request || !request->log.func) return; if (!radlog_debug_enabled(L_DBG, level, request)) return; for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); fr_log_talloc_report(vp); rad_assert(0); } vp_prints(buffer, sizeof(buffer), vp); RDEBUGX(level, "\t%s", buffer); } }
/* * Dump a whole list of attributes to DEBUG2 */ void vp_listdebug(VALUE_PAIR *vp) { char tmpPair[70]; for (; vp; vp = vp->next) { vp_prints(tmpPair, sizeof(tmpPair), vp); DEBUG2(" %s", tmpPair); } }
/* * Dump a whole list of attributes to DEBUG2 */ void vp_listdebug(VALUE_PAIR *vp) { vp_cursor_t cursor; char tmpPair[70]; for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) { vp_prints(tmpPair, sizeof(tmpPair), vp); DEBUG2(" %s", tmpPair); } }
/** Print a list of valuepairs to the request list. * * @param[in] level Debug level (1-4). * @param[in] request to read logging params from. * @param[in] vp to print. */ void rdebug_pair_list(int level, REQUEST *request, VALUE_PAIR *vp) { char buffer[256]; if (!vp || !request || !request->radlog) return; while (vp) { vp_prints(buffer, sizeof(buffer), vp); request->radlog(L_DBG, level, request, "\t%s", buffer); vp = vp->next; } }
static void debug_packet(RADIUS_PACKET *packet, int direction) { VALUE_PAIR *vp; char buffer[1024]; const char *received, *from; const fr_ipaddr_t *ip; int port; if (!packet) return; if (direction == 0) { received = "Received"; from = "from"; /* what else? */ ip = &packet->src_ipaddr; port = packet->src_port; } else { received = "Sending"; from = "to"; /* hah! */ ip = &packet->dst_ipaddr; port = packet->dst_port; } /* * Client-specific debugging re-prints the input * packet into the client log. * * This really belongs in a utility library */ if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) { printf("%s %s packet %s host %s port %d, id=%d, length=%d\n", received, fr_packet_codes[packet->code], from, inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)), port, packet->id, packet->data_len); } else { printf("%s packet %s host %s port %d code=%d, id=%d, length=%d\n", received, from, inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)), port, packet->code, packet->id, packet->data_len); } for (vp = packet->vps; vp != NULL; vp = vp->next) { vp_prints(buffer, sizeof(buffer), vp); printf("\t%s\n", buffer); } fflush(stdout); }
/** * @brief Replace %whatever in a string. * * See 'doc/variables.txt' for more information. * * @param out output buffer * @param outlen size of output buffer * @param fmt string to expand * @param request current request * @param func function to escape final value e.g. SQL quoting * @return length of string written @bug should really have -1 for failure */ int radius_xlat(char *out, int outlen, const char *fmt, REQUEST *request, RADIUS_ESCAPE_STRING func, void *funcarg) { int c, len, freespace; const char *p; char *q; char *nl; VALUE_PAIR *tmp; struct tm *TM, s_TM; char tmpdt[40]; /* For temporary storing of dates */ /* * Catch bad modules. */ if (!fmt || !out || !request) return 0; q = out; p = fmt; while (*p) { /* Calculate freespace in output */ freespace = outlen - (q - out); if (freespace <= 1) break; c = *p; if ((c != '%') && (c != '$') && (c != '\\')) { /* * We check if we're inside an open brace. If we are * then we assume this brace is NOT literal, but is * a closing brace and apply it */ *q++ = *p++; continue; } /* * There's nothing after this character, copy * the last '%' or "$' or '\\' over to the output * buffer, and exit. */ if (*++p == '\0') { *q++ = c; break; } if (c == '\\') { switch(*p) { case '\\': *q++ = *p; break; case 't': *q++ = '\t'; break; case 'n': *q++ = '\n'; break; default: *q++ = c; *q++ = *p; break; } p++; } else if (c == '%') switch(*p) { case '{': p--; if (decode_attribute(&p, &q, freespace, request, func, funcarg) < 0) return 0; break; case '%': *q++ = *p++; break; case 'd': /* request day */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%d", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'l': /* request timestamp */ snprintf(tmpdt, sizeof(tmpdt), "%lu", (unsigned long) request->timestamp); strlcpy(q,tmpdt,freespace); q += strlen(q); p++; break; case 'm': /* request month */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%m", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 't': /* request timestamp */ CTIME_R(&request->timestamp, tmpdt, sizeof(tmpdt)); nl = strchr(tmpdt, '\n'); if (nl) *nl = '\0'; strlcpy(q, tmpdt, freespace); q += strlen(q); p++; break; case 'C': /* ClientName */ strlcpy(q,request->client->shortname,freespace); q += strlen(q); p++; break; case 'D': /* request date */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y%m%d", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'G': /* request minute */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%M", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'H': /* request hour */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%H", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'I': /* Request ID */ snprintf(tmpdt, sizeof(tmpdt), "%i", request->packet->id); strlcpy(q, tmpdt, freespace); q += strlen(q); p++; break; case 'S': /* request timestamp in SQL format*/ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d %H:%M:%S", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'T': /* request timestamp */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d-%H.%M.%S.000000", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'V': /* Request-Authenticator */ strlcpy(q,"Verified",freespace); q += strlen(q); p++; break; case 'Y': /* request year */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'Z': /* Full request pairs except password */ tmp = request->packet->vps; while (tmp && (freespace > 3)) { if (tmp->attribute != PW_USER_PASSWORD) { *q++ = '\t'; len = vp_prints(q, freespace - 2, tmp); q += len; freespace -= (len + 2); *q++ = '\n'; } tmp = tmp->next; } p++; break; default: RDEBUG2("WARNING: Unknown variable '%%%c': See 'doc/variables.txt'", *p); if (freespace > 2) { *q++ = '%'; *q++ = *p++; } break; } } *q = '\0'; RDEBUG2("\texpand: %s -> %s", fmt, out); return strlen(out); }
/** * @brief Replace %whatever in a string. * * See 'doc/variables.txt' for more information. * * @param out output buffer * @param outlen size of output buffer * @param fmt string to expand * @param request current request * @param func function to escape final value e.g. SQL quoting * @return length of string written @bug should really have -1 for failure */ int radius_xlat(char *out, int outlen, const char *fmt, REQUEST *request, RADIUS_ESCAPE_STRING func) { int c, len, freespace; const char *p; char *q; char *nl; VALUE_PAIR *tmp; struct tm *TM, s_TM; char tmpdt[40]; /* For temporary storing of dates */ int openbraces=0; /* * Catch bad modules. */ if (!fmt || !out || !request) return 0; /* * Ensure that we always have an escaping function. */ if (func == NULL) { func = xlat_copy; } q = out; p = fmt; while (*p) { /* Calculate freespace in output */ freespace = outlen - (q - out); if (freespace <= 1) break; c = *p; if ((c != '%') && (c != '$') && (c != '\\')) { /* * We check if we're inside an open brace. If we are * then we assume this brace is NOT literal, but is * a closing brace and apply it */ if ((c == '}') && openbraces) { openbraces--; p++; /* skip it */ continue; } *q++ = *p++; continue; } /* * There's nothing after this character, copy * the last '%' or "$' or '\\' over to the output * buffer, and exit. */ if (*++p == '\0') { *q++ = c; break; } if (c == '\\') { switch(*p) { case '\\': *q++ = *p; break; case 't': *q++ = '\t'; break; case 'n': *q++ = '\n'; break; default: *q++ = c; *q++ = *p; break; } p++; } else if (c == '%') switch(*p) { case '{': p--; if (decode_attribute(&p, &q, freespace, request, func) < 0) return 0; break; case '%': *q++ = *p++; break; case 'a': /* Protocol: */ q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_PROTOCOL, 0),PW_TYPE_INTEGER, func); p++; break; case 'c': /* Callback-Number */ q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_CALLBACK_NUMBER, 0),PW_TYPE_STRING, func); p++; break; case 'd': /* request day */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%d", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'f': /* Framed IP address */ q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_IP_ADDRESS, 0),PW_TYPE_IPADDR, func); p++; break; case 'i': /* Calling station ID */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CALLING_STATION_ID, 0),PW_TYPE_STRING, func); p++; break; case 'l': /* request timestamp */ snprintf(tmpdt, sizeof(tmpdt), "%lu", (unsigned long) request->timestamp); strlcpy(q,tmpdt,freespace); q += strlen(q); p++; break; case 'm': /* request month */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%m", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'n': /* NAS IP address */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_IP_ADDRESS, 0),PW_TYPE_IPADDR, func); p++; break; case 'p': /* Port number */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_PORT, 0),PW_TYPE_INTEGER, func); p++; break; case 's': /* Speed */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO, 0),PW_TYPE_STRING, func); p++; break; case 't': /* request timestamp */ CTIME_R(&request->timestamp, tmpdt, sizeof(tmpdt)); nl = strchr(tmpdt, '\n'); if (nl) *nl = '\0'; strlcpy(q, tmpdt, freespace); q += strlen(q); p++; break; case 'u': /* User name */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME, 0),PW_TYPE_STRING, func); p++; break; case 'A': /* radacct_dir */ strlcpy(q,radacct_dir,freespace); q += strlen(q); p++; break; case 'C': /* ClientName */ strlcpy(q,request->client->shortname,freespace); q += strlen(q); p++; break; case 'D': /* request date */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y%m%d", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'H': /* request hour */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%H", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'L': /* radlog_dir */ strlcpy(q,radlog_dir,freespace); q += strlen(q); p++; break; case 'M': /* MTU */ q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU, 0),PW_TYPE_INTEGER, func); p++; break; case 'R': /* radius_dir */ strlcpy(q,radius_dir,freespace); q += strlen(q); p++; break; case 'S': /* request timestamp in SQL format*/ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d %H:%M:%S", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'T': /* request timestamp */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d-%H.%M.%S.000000", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'U': /* Stripped User name */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_STRIPPED_USER_NAME, 0),PW_TYPE_STRING, func); p++; break; case 'V': /* Request-Authenticator */ strlcpy(q,"Verified",freespace); q += strlen(q); p++; break; case 'Y': /* request year */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y", TM); if (len > 0) { strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'Z': /* Full request pairs except password */ tmp = request->packet->vps; while (tmp && (freespace > 3)) { if (tmp->attribute != PW_USER_PASSWORD) { *q++ = '\t'; len = vp_prints(q, freespace - 2, tmp); q += len; freespace -= (len + 2); *q++ = '\n'; } tmp = tmp->next; } p++; break; default: RDEBUG2("WARNING: Unknown variable '%%%c': See 'doc/variables.txt'", *p); if (freespace > 2) { *q++ = '%'; *q++ = *p++; } break; } } *q = '\0'; RDEBUG2("\texpand: %s -> %s", fmt, out); return strlen(out); }
/* * Cache the reply items and the Auth-Type */ static int caching_postauth(void *instance, REQUEST *request) { rlm_caching_t *data = (rlm_caching_t *)instance; char key[MAX_STRING_LEN]; datum key_datum; datum data_datum; VALUE_PAIR *reply_vp; VALUE_PAIR *auth_type; rlm_caching_data cache_data; int count = 0; int ret = 0; int size = 0; int rcode = 0; if (pairfind(request->packet->vps, PW_CACHE_NO_CACHING, 0) != NULL){ DEBUG("rlm_caching: Cache-No-Caching is set. Returning NOOP"); return RLM_MODULE_NOOP; } if ((auth_type = pairfind(request->config_items, PW_AUTH_TYPE, 0)) != NULL){ DEBUG("rlm_caching: Found Auth-Type, value: '%s'",auth_type->vp_strvalue); if (strcmp(auth_type->vp_strvalue,"Reject") == 0 && data->cache_rejects == 0){ DEBUG("rlm_caching: No caching of Rejects. Returning NOOP"); return RLM_MODULE_NOOP; } if (strlen(auth_type->vp_strvalue) > MAX_AUTH_TYPE - 1){ DEBUG("rlm_caching: Auth-Type value too large"); return RLM_MODULE_NOOP; } } else{ DEBUG("rlm_caching: No Auth-Type found. Returning NOOP"); return RLM_MODULE_NOOP; } reply_vp = request->reply->vps; if (reply_vp == NULL) { DEBUG("rlm_caching: The Request does not contain any reply attributes"); return RLM_MODULE_NOOP; } if (!radius_xlat(key,sizeof(key), data->key, request, NULL)){ radlog(L_ERR, "rlm_caching: xlat on key '%s' failed.",data->key); return RLM_MODULE_FAIL; } memset(&cache_data,0,sizeof(rlm_caching_data)); cache_data.creation = time(NULL); strcpy(cache_data.auth_type,auth_type->vp_strvalue); size = MAX_RECORD_LEN; while(reply_vp) { if (size <= 1){ DEBUG("rlm_caching: Not enough space."); return RLM_MODULE_NOOP; } ret = vp_prints(cache_data.data + count,size,reply_vp); if (ret == 0) { DEBUG("rlm_caching: Record is too large, will not store it."); return RLM_MODULE_NOOP; } count += (ret + 1); size -= (ret + 1); DEBUG("rlm_caching: VP=%s,VALUE=%s,length=%d,cache record length=%d, space left=%d", reply_vp->name,reply_vp->vp_strvalue,ret,count,size); reply_vp = reply_vp->next; } cache_data.len = count; DEBUG("rlm_caching: Storing cache for Key='%s'",key); data_datum.dptr = (rlm_caching_data *) &cache_data; data_datum.dsize = sizeof(rlm_caching_data); key_datum.dptr = (char *) key; key_datum.dsize = strlen(key); pthread_mutex_lock(&data->mutex); rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE); pthread_mutex_unlock(&data->mutex); if (rcode < 0) { radlog(L_ERR, "rlm_caching: Failed storing data to %s: %s", data->filename, gdbm_strerror(gdbm_errno)); return RLM_MODULE_FAIL; } DEBUG("rlm_caching: New value stored successfully."); return RLM_MODULE_OK; }
/* * Write accounting information to this modules database. */ static int xmlrpc_accounting(void *instance, REQUEST * request) { rlm_xmlrpc_t *inst = instance; rlm_xmlrpc_client_t *client; VALUE_PAIR *vps = request->packet->vps; xmlrpc_value *array_param; xmlrpc_value *array_string; xmlrpc_value *resultP; char *const methodName = inst->method; int error; VALUE_PAIR *status_type_pair; if ((status_type_pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) { radlog(L_ERR, "rlm_xmlrpc: No Accounting-Status-Type record."); return RLM_MODULE_NOOP; } client = get_client(instance); /* * Xmlrpc wants method params in an array, so we build an array * with a pointer in index 0. This pointer contains a sub array * filled whith strings each one for packet attributes. */ array_param = xmlrpc_array_new(&client->env); error = check_error(&client->env); if (error != RLM_MODULE_OK) return error; array_string = xmlrpc_array_new(&client->env); error = check_error(&client->env); if (error != RLM_MODULE_OK) return error; /* * The array of strings is built whit vp_prints */ VALUE_PAIR *vp = vps; for (; vp; vp = vp->next) { char buf[1024]; vp_prints(buf, sizeof(buf), vp); xmlrpc_array_append_item(&client->env, array_string, xmlrpc_string_new(&client->env, buf)); int error = check_error(&client->env); if (error != RLM_MODULE_OK) return error; } xmlrpc_array_append_item(&client->env, array_param, array_string); error = check_error(&client->env); if (error != RLM_MODULE_OK) return error; xmlrpc_client_call2(&client->env, client->clientP, client->serverInfoP, methodName, array_param, &resultP); error = check_error(&client->env); if (error != RLM_MODULE_OK) return error; /* * We don't check for method return value. If an accounting packet is * dispatched without errors, it should be processed by server * without any further notification. */ xmlrpc_DECREF(resultP); xmlrpc_DECREF(array_param); xmlrpc_DECREF(array_string); return RLM_MODULE_OK; }