Added tolower function
[freeradius.git] / src / main / xlat.c
index 934b98c..9c32288 100644 (file)
@@ -26,6 +26,7 @@
 RCSID("$Id$")
 
 #include       <freeradius-devel/radiusd.h>
+#include       <freeradius-devel/md5.h>
 #include       <freeradius-devel/rad_assert.h>
 
 #include       <ctype.h>
@@ -158,18 +159,44 @@ static size_t xlat_packet(void *instance, REQUEST *request,
         */
        da = dict_attrbyname(fmt);
        if (!da) {
+               int do_number = FALSE;
                size_t count;
-               const char *p = strchr(fmt, '[');
+               const char *p;
                char buffer[256];
 
-               if (!p) return 0;
                if (strlen(fmt) > sizeof(buffer)) return 0;
 
+               p = strchr(fmt, '[');
+               if (!p) {
+                       p = strchr(fmt, '#');
+                       if (!p) return 0;
+                       do_number = TRUE;
+               }
+
                strlcpy(buffer, fmt, p - fmt + 1);
 
                da = dict_attrbyname(buffer);
                if (!da) return 0;
 
+               if (do_number) {
+                       vp = pairfind(vps, da->attr, 0);
+                       if (!vp) return 0;
+
+                       switch (da->type) {
+                       default:
+                               break;
+
+                       case PW_TYPE_INTEGER:
+                       case PW_TYPE_DATE:
+                       case PW_TYPE_SHORT:
+                       case PW_TYPE_BYTE:
+                               snprintf(out, outlen, "%u", vp->lvalue);
+                               return strlen(out);
+                       }
+
+                       goto just_print;
+               }
+
                /*
                 *      %{Attribute-Name[#]} returns the count of
                 *      attributes of that name in the list.
@@ -177,12 +204,12 @@ static size_t xlat_packet(void *instance, REQUEST *request,
                if ((p[1] == '#') && (p[2] == ']')) {
                        count = 0;
 
-                       for (vp = pairfind(vps, da->attr);
+                       for (vp = pairfind(vps, da->attr, da->vendor);
                             vp != NULL;
-                            vp = pairfind(vp->next, da->attr)) {
+                            vp = pairfind(vp->next, da->attr, da->vendor)) {
                                count++;
                        }
-                       snprintf(out, outlen, "%d", count);
+                       snprintf(out, outlen, "%d", (int) count);
                        return strlen(out);
                }
 
@@ -193,9 +220,9 @@ static size_t xlat_packet(void *instance, REQUEST *request,
                if ((p[1] == '*') && (p[2] == ']')) {
                        int total = 0;
 
-                       for (vp = pairfind(vps, da->attr);
+                       for (vp = pairfind(vps, da->attr, da->vendor);
                             vp != NULL;
-                            vp = pairfind(vp->next, da->attr)) {
+                            vp = pairfind(vp->next, da->attr, da->vendor)) {
                                count = valuepair2str(out, outlen - 1, vp, da->type, func);
                                rad_assert(count <= outlen);
                                total += count + 1;
@@ -225,9 +252,9 @@ static size_t xlat_packet(void *instance, REQUEST *request,
                /*
                 *      Find the N'th value.
                 */
-               for (vp = pairfind(vps, da->attr);
+               for (vp = pairfind(vps, da->attr, da->vendor);
                     vp != NULL;
-                    vp = pairfind(vp->next, da->attr)) {
+                    vp = pairfind(vp->next, da->attr, da->vendor)) {
                        if (count == 0) break;
                        count--;
                }
@@ -236,11 +263,11 @@ static size_t xlat_packet(void *instance, REQUEST *request,
                 *      Non-existent array reference.
                 */
                if (!vp) return 0;
-
+       just_print:
                return valuepair2str(out, outlen, vp, da->type, func);
        }
 
-       vp = pairfind(vps, da->attr);
+       vp = pairfind(vps, da->attr, da->vendor);
        if (!vp) {
                /*
                 *      Some "magic" handlers, which are never in VP's, but
@@ -259,7 +286,7 @@ static size_t xlat_packet(void *instance, REQUEST *request,
                        {
                                DICT_VALUE *dval;
 
-                               dval = dict_valbyattr(da->attr, packet->code);
+                               dval = dict_valbyattr(da->attr, da->vendor, packet->code);
                                if (dval) {
                                        snprintf(out, outlen, "%s", dval->name);
                                } else {
@@ -440,6 +467,68 @@ static size_t xlat_debug(UNUSED void *instance, REQUEST *request,
 
 
 /*
+ *     Calculate the MD5 hash of a string.
+ */
+static size_t xlat_md5(UNUSED void *instance, REQUEST *request,
+                      char *fmt, char *out, size_t outlen,
+                      UNUSED RADIUS_ESCAPE_STRING func)
+{
+       int i;
+       uint8_t digest[16];
+       FR_MD5_CTX ctx;
+       char buffer[1024];
+
+       if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) {
+               *out = '\0';
+               return 0;
+       }
+
+       fr_MD5Init(&ctx);
+       fr_MD5Update(&ctx, (void *) buffer, strlen(buffer));
+       fr_MD5Final(digest, &ctx);
+
+       if (outlen < 33) {
+               snprintf(out, outlen, "md5_overflow");
+               return strlen(out);
+       }
+
+       for (i = 0; i < 16; i++) {
+               snprintf(out + i * 2, 3, "%02x", digest[i]);
+       }
+
+       return strlen(out);
+}
+
+
+/*
+ *     Convert a string to lowercase
+ */
+static size_t xlat_lc(UNUSED void *instance, REQUEST *request,
+                      char *fmt, char *out, size_t outlen,
+                      UNUSED RADIUS_ESCAPE_STRING func)
+{
+       char *p, *q;
+       char buffer[1024];
+
+       if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) {
+               *out = '\0';
+               return 0;
+       }
+
+       for (p = buffer, q = out; *p != '\0'; p++, outlen--) {
+               if (outlen <= 1) break;
+
+               *(q++) = tolower((int) *p);
+       }
+
+       *q = '\0';
+
+       return strlen(out);
+}
+
+
+
+/*
  *     Compare two xlat_t structs, based ONLY on the module name.
  */
 static int xlat_cmp(const void *a, const void *b)
@@ -453,7 +542,6 @@ static int xlat_cmp(const void *a, const void *b)
                      ((const xlat_t *)a)->length);
 }
 
-
 /*
  *     find the appropriate registered xlat function.
  */
@@ -465,7 +553,8 @@ static xlat_t *xlat_find(const char *module)
         *      Look for dictionary attributes first.
         */
        if ((dict_attrbyname(module) != NULL) ||
-           (strchr(module, '[') != NULL)) {
+           (strchr(module, '[') != NULL) ||
+           (strchr(module, '#') != NULL)) {
                module = "request";
        }
 
@@ -544,6 +633,16 @@ int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance)
                c = xlat_find("debug");
                rad_assert(c != NULL);
                c->internal = TRUE;
+
+               xlat_register("md5", xlat_md5, &xlat_inst[0]);
+               c = xlat_find("md5");
+               rad_assert(c != NULL);
+               c->internal = TRUE;
+
+               xlat_register("tolower", xlat_lc, &xlat_inst[0]);
+               c = xlat_find("tolower");
+               rad_assert(c != NULL);
+               c->internal = TRUE;
        }
 
        /*
@@ -616,34 +715,39 @@ void xlat_free(void)
 /*
  *     Decode an attribute name into a string.
  */
-static void decode_attribute(const char **from, char **to, int freespace,
-                            int *open_p, REQUEST *request,
+static int decode_attribute(const char **from, char **to, int freespace,
+                            REQUEST *request,
                             RADIUS_ESCAPE_STRING func)
 {
        int     do_length = 0;
-       char    xlat_name[128];
-       char    *xlat_string = NULL; /* can be large */
-       int     free_xlat_string = FALSE;
-       const char *p;
-       char *q, *pa;
-       int found=0, retlen=0;
-       int openbraces = *open_p;
+       char    *xlat_name, *xlat_string;
+       char *p, *q, *l, *next = NULL;
+       int retlen=0;
        const xlat_t *c;
-       int spaces = FALSE;
+       int varlen;
+       char buffer[8192];
 
-       p = *from;
        q = *to;
-       pa = &xlat_name[0];
 
        *q = '\0';
 
        /*
-        * Skip the '{' at the front of 'p'
-        * Increment open braces
+        *      Copy the input string to an intermediate buffer where
+        *      we can mangle it.
         */
-       p++;
-       openbraces++;
+       varlen = rad_copy_variable(buffer, *from);
+       if (varlen < 0) {
+               RDEBUG2("Badly formatted variable: %s", *from);
+               return -1;
+       }
+       *from += varlen;
 
+       /*
+        *      Kill the %{} around the data we are looking for.
+        */
+       p = buffer;
+       p[varlen - 1] = '\0';   /*  */
+       p += 2;
        if (*p == '#') {
                p++;
                do_length = 1;
@@ -655,284 +759,176 @@ static void decode_attribute(const char **from, char **to, int freespace,
         *      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 + 1);
-               char *second = rad_malloc(mylen + 1);
                int expand2 = FALSE;
 
-               len1 = rad_copy_variable(first, p);
+               /*
+                *      'p' is after the start of 'buffer', so we can
+                *      safely do this.
+                */
+               len1 = rad_copy_variable(buffer, p);
                if (len1 < 0) {
                        RDEBUG2("Badly formatted variable: %s", p);
-                       goto free_and_done;
+                       return -1;
                }
 
+               /*
+                *      They did %{%{foo}}, which is stupid, but allowed.
+                */
+               if (!p[len1]) {
+                       RDEBUG2("Improperly nested variable; %%{%s}", p);
+                       return -1;
+               }
+
+               /*
+                *      It SHOULD be %{%{foo}:-%{bar}}.  If not, it's
+                *      an error.
+                */
                if ((p[len1] != ':') || (p[len1 + 1] != '-')) {
                        RDEBUG2("No trailing :- after variable at %s", p);
-                       goto free_and_done;
+                       return -1;
                }
 
+               /*
+                *      Parse the second bit.  The second bit can be
+                *      either %{foo}, or a string "foo", or a string
+                *      'foo', or just a bare word: foo
+                */
                p += len1 + 2;
+               l = buffer + len1 + 1;
 
                if ((p[0] == '%') && (p[1] == '{')) {
-                       len2 = rad_copy_variable(second, p);
+                       len2 = rad_copy_variable(l, p);
 
-                       expand2 = TRUE;
                        if (len2 < 0) {
                                RDEBUG2("Invalid text after :- at %s", p);
-                               goto free_and_done;
+                               return -1;
                        }
                        p += len2;
+                       expand2 = TRUE;
 
                } else if ((p[0] == '"') || p[0] == '\'') {
-                       getstring(&p, second, mylen);
+                       getstring(&p, l, strlen(l));
 
                } else {
-                       char *s = second;
-
-                       while (*p && (*p != '}')) {
-                               *(s++) = *(p++);
-                       }
-                       *s = '\0';
-               }
-
-               if (*p != '}') {
-                       RDEBUG2("Failed to find trailing '}' in string");
-                       goto free_and_done;
+                       l = p;
                }
 
-               mylen = radius_xlat(q, freespace, first, request, func);
-               if (mylen) {
-                       q += mylen;
-                       goto free_and_done;
+               /*
+                *      Expand the first one.  If we did, exit the
+                *      conditional.
+                */
+               retlen = radius_xlat(q, freespace, buffer, request, func);
+               if (retlen) {
+                       q += retlen;
+                       goto done;
                }
 
-               if (!expand2) {
-                       strlcpy(q, second, freespace);
-                       q += strlen(q);
-               } else {
-                       mylen = radius_xlat(q, freespace, second,
+               RDEBUG2("\t... expanding second conditional");
+               /*
+                *      Expand / copy the second string if required.
+                */
+               if (expand2) {
+                       retlen = radius_xlat(q, freespace, l,
                                            request, func);
-                       if (mylen) {
-                               q += mylen;
-                               goto free_and_done;
+                       if (retlen) {
+                               q += retlen;
                        }
+               } else {
+                       strlcpy(q, l, freespace);
+                       q += strlen(q);
                }
 
                /*
                 *      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
+        *      See if we're supposed to expand a module name.
         */
-       while (*p && (*p != '}') && (*p != ':')) {
-               *pa++ = *p++;
-
-               if (pa >= (xlat_name + sizeof(xlat_name) - 1)) {
-                       /*
-                        *      Skip to the end of the input
-                        */
-                       p += strlen(p);
-                       RDEBUG("xlat: Module name is too long in string %%%s",
-                             *from);
-                       goto done;
+       xlat_name = NULL;
+       for (l = p; *l != '\0'; l++) {
+               if (*l == '\\') {
+                       l++;
+                       continue;
                }
-       }
-       *pa = '\0';
 
-       if (!*p) {
-               RDEBUG("xlat: Invalid syntax in %s", *from);
+               if (*l == ':') {
+                       xlat_name = p; /* start of name */
+                       *l = '\0';
+                       p = l + 1;
+                       break;
+               }
 
                /*
-                *      %{name} is a simple attribute reference,
-                *      or regex reference.
+                *      Module names can't have spaces.
                 */
-       } else if (*p == '}') {
-               openbraces--;
-               rad_assert(openbraces == *open_p);
+               if ((*l == ' ') || (*l == '\t')) break;
+       }
 
-               p++;
-               xlat_string = xlat_name;
+       /*
+        *      %{name} is a simple attribute reference,
+        *      or regex reference.
+        */
+       if (!xlat_name) {
+               xlat_name = xlat_string = p;
                goto do_xlat;
+       }
 
-       } else if ((p[0] == ':') && (p[1] == '-')) { /* handle ':- */
+       /*
+        *      Maybe it's the old-style %{foo:-bar}
+        */
+       if (*p == '-') {
                RDEBUG2("WARNING: Deprecated conditional expansion \":-\".  See \"man unlang\" for details");
-               p += 2;
+               p++;
+
                xlat_string = xlat_name;
+               next = p;
                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) RDEBUG3("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 NRDEBUG
-               } else {
-                       /*
-                        *      No attribute by that name, return an error.
-                        */
-                       RDEBUG2("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
+        *      FIXME: For backwards "WTF" compatibility, check for
+        *      {...}, (after the :), and copy that, too.
         */
-       if (found) {
-               if (do_length) {
-                       snprintf(q, freespace, "%d", retlen);
-                       retlen = strlen(q);
-               }
 
-               q += retlen;
+       /* module name, followed by (possibly) per-module string */
+       xlat_string = p;
+       
+do_xlat:
+       if ((c = xlat_find(xlat_name)) != NULL) {
+               if (!c->internal) RDEBUG3("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 > 0) {
+                       if (do_length) {
+                               snprintf(q, freespace, "%d", retlen);
+                               retlen = strlen(q);
+                       }
 
-               while((*p != '\0') && (openbraces > *open_p)) {
+               } else if (next) {
                        /*
-                        *      Handle escapes outside of the loop.
+                        *      Expand the second bit.
                         */
-                       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 */
+                       RDEBUG2("\t... expanding second conditional");
+                       retlen = radius_xlat(q, freespace, next, request, func);
                }
-       }
+               q += retlen;
 
-       done:
-       if (free_xlat_string) free(xlat_string);
+       } else {
+               /*
+                *      No attribute by that name, return an error.
+                */
+               RDEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", xlat_name, *from);
+               return -1;
+       }
 
-       *open_p = openbraces;
-       *from = p;
+done:
        *to = q;
+       return 0;
 }
 
 /*
@@ -1044,18 +1040,19 @@ int radius_xlat(char *out, int outlen, const char *fmt,
 
                } else if (c == '%') switch(*p) {
                        case '{':
-                               decode_attribute(&p, &q, freespace, &openbraces, request, func);
+                               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),PW_TYPE_INTEGER, func);
+                               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),PW_TYPE_STRING, func);
+                               q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_CALLBACK_NUMBER, 0),PW_TYPE_STRING, func);
                                p++;
                                break;
                        case 'd': /* request day */
@@ -1068,16 +1065,16 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'f': /* Framed IP address */
-                               q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_IP_ADDRESS),PW_TYPE_IPADDR, func);
+                               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),PW_TYPE_STRING, func);
+                               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->received.tv_sec);
+                                        (unsigned long) request->timestamp);
                                strlcpy(q,tmpdt,freespace);
                                q += strlen(q);
                                p++;
@@ -1092,15 +1089,15 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'n': /* NAS IP address */
-                               q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_IP_ADDRESS),PW_TYPE_IPADDR, func);
+                               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),PW_TYPE_INTEGER, func);
+                               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),PW_TYPE_STRING, func);
+                               q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO, 0),PW_TYPE_STRING, func);
                                p++;
                                break;
                        case 't': /* request timestamp */
@@ -1112,7 +1109,7 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'u': /* User name */
-                               q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME),PW_TYPE_STRING, func);
+                               q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME, 0),PW_TYPE_STRING, func);
                                p++;
                                break;
                        case 'A': /* radacct_dir */
@@ -1149,7 +1146,7 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'M': /* MTU */
-                               q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU),PW_TYPE_INTEGER, func);
+                               q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU, 0),PW_TYPE_INTEGER, func);
                                p++;
                                break;
                        case 'R': /* radius_dir */
@@ -1176,7 +1173,7 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'U': /* Stripped User name */
-                               q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_STRIPPED_USER_NAME),PW_TYPE_STRING, func);
+                               q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_STRIPPED_USER_NAME, 0),PW_TYPE_STRING, func);
                                p++;
                                break;
                        case 'V': /* Request-Authenticator */