📄 xlat.c
字号:
int spaces = FALSE; p = *from; q = *to; pa = &xlat_name[0]; *q = '\0'; /* * Skip the '{' at the front of 'p' * Increment open braces */ p++; openbraces++; if (*p == '#') { p++; do_length = 1; } /* * Handle %{%{foo}:-%{bar}}, which is useful, too. * * Did I mention that this parser is garbage? */ if ((p[0] == '%') && (p[1] == '{')) { /* * This is really bad, but it works. */ int len1, len2; size_t mylen = strlen(p); char *first = rad_malloc(mylen); char *second = rad_malloc(mylen); int expand2 = FALSE; len1 = rad_copy_variable(first, p); if (len1 < 0) { DEBUG2("Badly formatted variable: %s", p); goto free_and_done; } if ((p[len1] != ':') || (p[len1 + 1] != '-')) { DEBUG2("No trailing :- after variable at %s", p); goto free_and_done; } p += len1 + 2; if ((p[0] == '%') && (p[1] == '{')) { len2 = rad_copy_variable(second, p); expand2 = TRUE; if (len2 < 0) { DEBUG2("Invalid text after :- at %s", p); goto free_and_done; } p += len2; } else if ((p[0] == '"') || p[0] == '\'') { getstring(&p, second, mylen); } else { char *s = second; while (*p && (*p != '}')) { *(s++) = *(p++); } *s = '\0'; } if (*p != '}') { DEBUG2("Failed to find trailing '}' in string"); goto free_and_done; } mylen = radius_xlat(q, freespace, first, request, func); if (mylen) { q += mylen; goto free_and_done; } if (!expand2) { strlcpy(q, second, freespace); q += strlen(q); } else { mylen = radius_xlat(q, freespace, second, request, func); if (mylen) { q += mylen; goto free_and_done; } } /* * Else the output is an empty string. */ free_and_done: free(first); free(second); goto done; } /* * First, copy the xlat key name to one buffer */ while (*p && (*p != '}') && (*p != ':')) { *pa++ = *p++; if (pa >= (xlat_name + sizeof(xlat_name) - 1)) { /* * Skip to the end of the input */ p += strlen(p); DEBUG("xlat: Module name is too long in string %%%s", *from); goto done; } } *pa = '\0'; if (!*p) { DEBUG("xlat: Invalid syntax in %s", *from); /* * %{name} is a simple attribute reference, * or regex reference. */ } else if (*p == '}') { openbraces--; rad_assert(openbraces == *open_p); p++; xlat_string = xlat_name; goto do_xlat; } else if ((p[0] == ':') && (p[1] == '-')) { /* handle ':- */ DEBUG2("WARNING: Deprecated conditional expansion \":-\". See \"man unlang\" for details"); p += 2; xlat_string = xlat_name; goto do_xlat; } else { /* module name, followed by per-module string */ int stop = 0; int delimitbrace = *open_p; rad_assert(*p == ':'); p++; /* skip the ':' */ /* * If there's a brace immediately following the colon, * then we've chosen to delimite the per-module string, * so keep track of that. */ if (*p == '{') { delimitbrace = openbraces; openbraces++; p++; } xlat_string = rad_malloc(strlen(p) + 1); /* always returns */ free_xlat_string = TRUE; pa = xlat_string; /* * Copy over the rest of the string, which is per-module * data. */ while (*p && !stop) { switch(*p) { /* * What the heck is this supposed * to be doing? */ case '\\': p++; /* skip it */ *pa++ = *p++; break; case ':': if (!spaces && p[1] == '-') { p += 2; stop = 1; break; } *pa++ = *p++; break; /* * This is pretty hokey... we * should use the functions in * util.c */ case '{': openbraces++; *pa++ = *p++; break; case '}': openbraces--; if (openbraces == delimitbrace) { p++; stop=1; } else { *pa++ = *p++; } break; case ' ': case '\t': spaces = TRUE; /* FALL-THROUGH */ default: *pa++ = *p++; break; } } *pa = '\0'; /* * Now check to see if we're at the end of the string * we were sent. If we're not, check for :- */ if (openbraces == delimitbrace) { if (p[0] == ':' && p[1] == '-') { p += 2; } } /* * Look up almost everything in the new tree of xlat * functions. This makes it a little quicker... */ do_xlat: if ((c = xlat_find(xlat_name)) != NULL) { if (!c->internal) DEBUG3("radius_xlat: Running registered xlat function of module %s for string \'%s\'", c->module, xlat_string); retlen = c->do_xlat(c->instance, request, xlat_string, q, freespace, func); /* If retlen is 0, treat it as not found */ if (retlen > 0) found = 1;#ifndef NDEBUG } else { /* * No attribute by that name, return an error. */ DEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", xlat_name, *from);#endif } } /* * Skip to last '}' if attr is found * The rest of the stuff within the braces is * useless if we found what we need */ if (found) { if (do_length) { snprintf(q, freespace, "%d", retlen); retlen = strlen(q); } q += retlen; while((*p != '\0') && (openbraces > *open_p)) { /* * Handle escapes outside of the loop. */ if (*p == '\\') { p++; if (!*p) break; p++; /* get & ignore next character */ continue; } switch (*p) { default: break; /* * Bare brace */ case '{': openbraces++; break; case '}': openbraces--; break; } p++; /* skip the character */ } } done: if (free_xlat_string) free(xlat_string); *open_p = openbraces; *from = p; *to = q;}/* * If the caller doesn't pass xlat an escape function, then * we use this one. It simplifies the coding, as the check for * func == NULL only happens once. */static size_t xlat_copy(char *out, size_t outlen, const char *in){ int freespace = outlen; rad_assert(outlen > 0); while ((*in) && (freespace > 1)) { /* * Copy data. * * FIXME: Do escaping of bad stuff! */ *(out++) = *(in++); freespace--; } *out = '\0'; return (outlen - freespace); /* count does not include NUL */}/* * Replace %<whatever> in a string. * * See 'doc/variables.txt' for more information. */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 '{': decode_attribute(&p, &q, freespace, &openbraces, request, func); break; case '%': *q++ = *p++; break; case 'a': /* Protocol: */ q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_PROTOCOL),PW_TYPE_INTEGER, func); p++; break; case 'c': /* Callback-Number */ q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_CALLBACK_NUMBER),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),PW_TYPE_IPADDR, func); p++; break; case 'i': /* Calling station ID */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CALLING_STATION_ID),PW_TYPE_STRING, func); p++; break; case 'l': /* request timestamp */ snprintf(tmpdt, sizeof(tmpdt), "%lu", (unsigned long) request->received.tv_sec); 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),PW_TYPE_IPADDR, func); p++; break; case 'p': /* Port number */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_PORT),PW_TYPE_INTEGER, func); p++; break; case 's': /* Speed */ q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO),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),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),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),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: DEBUG2("WARNING: Unknown variable '%%%c': See 'doc/variables.txt'", *p); if (freespace > 2) { *q++ = '%'; *q++ = *p++; } break; } } *q = '\0'; DEBUG2("\texpand: %s -> %s", fmt, out); return strlen(out);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -