示例#1
0
/**
 * @brief Print data as string, if possible.
 *
 * If attribute "Foo" is defined as "octets" it will normally
 * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
 * expand to "\n\n\n"
 */
static size_t xlat_string(UNUSED void *instance, REQUEST *request,
			  const char *fmt, char *out, size_t outlen)
{
	int len;
	VALUE_PAIR *vp;

	while (isspace((int) *fmt)) fmt++;

	if (outlen < 3) {
	nothing:
		*out = '\0';
		return 0;
	}

	if (!radius_get_vp(request, fmt, &vp)) goto nothing;

	if (!vp) goto nothing;

	if (vp->type != PW_TYPE_OCTETS) goto nothing;

	len = fr_print_string(vp->vp_strvalue, vp->length, out, outlen);
	out[len] = '\0';

	return len;
}
示例#2
0
/** Print data as string, if possible.
 *
 * If attribute "Foo" is defined as "octets" it will normally
 * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
 * expand to "\n\n\n"
 */
static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
			   char const *fmt, char *out, size_t outlen)
{
	size_t len;
	ssize_t ret;
	VALUE_PAIR *vp;
	uint8_t const *p;

	while (isspace((int) *fmt)) fmt++;
	if (*fmt == '&') fmt++;

	if (outlen < 3) {
	nothing:
		*out = '\0';
		return 0;
	}

	if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;

	ret = rad_vp2data(&p, vp);
	if (ret < 0) {
		return ret;
	}

	switch (vp->da->type) {
		case PW_TYPE_OCTETS:
			len = fr_print_string((char const *) p, vp->length, out, outlen);
			break;

		case PW_TYPE_STRING:
			len = strlcpy(out, vp->vp_strvalue, outlen);
			break;

		default:
			len = fr_print_string((char const *) p, ret, out, outlen);
			break;
	}

	return len;
}
示例#3
0
/*
 *	Main program
 */
int main(int argc, char **argv)
{
	CONF_SECTION *maincs, *cs;
	FILE *fp;
	struct radutmp rt;
	char othername[256];
	char nasname[1024];
	char session_id[sizeof(rt.session_id)+1];
	int hideshell = 0;
	int showsid = 0;
	int rawoutput = 0;
	int radiusoutput = 0;	/* Radius attributes */
	char const *portind;
	int c;
	unsigned int portno;
	char buffer[2048];
	char const *user = NULL;
	int user_cmp = 0;
	time_t now = 0;
	uint32_t nas_port = ~0;
	uint32_t nas_ip_address = INADDR_NONE;
	int zap = 0;

	raddb_dir = RADIUS_DIR;

#ifndef NDEBUG
	if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
		fr_perror("radwho");
		exit(EXIT_FAILURE);
	}
#endif

	talloc_set_log_stderr();

	while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) {
		case 'd':
			raddb_dir = optarg;
			break;
		case 'F':
			radutmp_file = optarg;
			break;
		case 'h':
			usage(0);
			break;
		case 'S':
			hideshell = 1;
			break;
		case 'n':
			showname = 0;
			break;
		case 'N':
			if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) {
				usage(1);
			}
			break;
		case 's':
			showname = 1;
			break;
		case 'i':
			showsid = 1;
			break;
		case 'p':
			showptype = 1;
			break;
		case 'P':
			nas_port = atoi(optarg);
			break;
		case 'c':
			showcid = 1;
			showname = 1;
			break;
		case 'r':
			rawoutput = 1;
			break;
		case 'R':
			radiusoutput = 1;
			now = time(NULL);
			break;
		case 'u':
			user = optarg;
			user_cmp = 0;
			break;
		case 'U':
			user = optarg;
			user_cmp = 1;
			break;
		case 'Z':
			zap = 1;
			break;
		default:
			usage(1);
			break;
	}

	/*
	 *	Mismatch between the binary and the libraries it depends on
	 */
	if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
		fr_perror("radwho");
		return 1;
	}

	/*
	 *	Be safe.
	 */
	if (zap && !radiusoutput) zap = 0;

	/*
	 *	zap EVERYONE, but only on this nas
	 */
	if (zap && !user && (~nas_port == 0)) {
		/*
		 *	We need to know which NAS to zap users in.
		 */
		if (nas_ip_address == INADDR_NONE) usage(1);

		printf("Acct-Status-Type = Accounting-Off\n");
		printf("NAS-IP-Address = %s\n",
		       hostname(buffer, sizeof(buffer), nas_ip_address));
		printf("Acct-Delay-Time = 0\n");
		exit(0);	/* don't bother printing anything else */
	}

	if (radutmp_file) goto have_radutmp;

	/*
	 *	Initialize main_config
	 */
	memset(&main_config, 0, sizeof(main_config));

	/* Read radiusd.conf */
	snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir);
	maincs = cf_file_read(buffer);
	if (!maincs) {
		fprintf(stderr, "%s: Error reading or parsing radiusd.conf\n", argv[0]);
		exit(1);
	}

	cs = cf_section_sub_find(maincs, "modules");
	if (!cs) {
		fprintf(stderr, "%s: No modules section found in radiusd.conf\n", argv[0]);
		exit(1);
	}
	/* Read the radutmp section of radiusd.conf */
	cs = cf_section_sub_find_name2(cs, "radutmp", NULL);
	if (!cs) {
		fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf\n", argv[0]);
		exit(1);
	}

	cf_section_parse(cs, NULL, module_config);

	/* Assign the correct path for the radutmp file */
	radutmp_file = radutmpconfig.radutmp_fn;

 have_radutmp:
	if (showname < 0) showname = 1;

	/*
	 *	Show the users logged in on the terminal server(s).
	 */
	if ((fp = fopen(radutmp_file, "r")) == NULL) {
		fprintf(stderr, "%s: Error reading %s: %s\n",
			progname, radutmp_file, fr_syserror(errno));
		return 0;
	}

	/*
	 *	Don't print the headers if raw or RADIUS
	 */
	if (!rawoutput && !radiusoutput) {
		fputs(showname ? hdr1 : hdr2, stdout);
		fputs(eol, stdout);
	}

	/*
	 *	Read the file, printing out active entries.
	 */
	while (fread(&rt, sizeof(rt), 1, fp) == 1) {
		char name[sizeof(rt.login) + 1];

		if (rt.type != P_LOGIN) continue; /* hide logout sessions */

		/*
		 *	We don't show shell users if we are
		 *	fingerd, as we have done that above.
		 */
		if (hideshell && !strchr("PCS", rt.proto))
			continue;

		/*
		 *	Print out sessions only for the given user.
		 */
		if (user) {	/* only for a particular user */
			if (((user_cmp == 0) &&
			     (strncasecmp(rt.login, user, strlen(user)) != 0)) ||
			    ((user_cmp == 1) &&
			     (strncmp(rt.login, user, strlen(user)) != 0))) {
				continue;
			}
		}

		/*
		 *	Print out only for the given NAS port.
		 */
		if (~nas_port != 0) {
			if (rt.nas_port != nas_port) continue;
		}

		/*
		 *	Print out only for the given NAS IP address
		 */
		if (nas_ip_address != INADDR_NONE) {
			if (rt.nas_address != nas_ip_address) continue;
		}

		memcpy(session_id, rt.session_id, sizeof(rt.session_id));
		session_id[sizeof(rt.session_id)] = 0;

		if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) {
			portind = ">";
			portno = (showname ? 999 : 99999);
		} else {
			portind = "S";
			portno = rt.nas_port;
		}

		/*
		 *	Print output as RADIUS attributes
		 */
		if (radiusoutput) {
			memcpy(nasname, rt.login, sizeof(rt.login));
			nasname[sizeof(rt.login)] = '\0';

			fr_print_string(nasname, 0, buffer,
					 sizeof(buffer));
			printf("User-Name = \"%s\"\n", buffer);

			fr_print_string(session_id, 0, buffer,
					 sizeof(buffer));
			printf("Acct-Session-Id = \"%s\"\n", buffer);

			if (zap) printf("Acct-Status-Type = Stop\n");

			printf("NAS-IP-Address = %s\n",
			       hostname(buffer, sizeof(buffer),
					rt.nas_address));
			printf("NAS-Port = %u\n", rt.nas_port);

			switch (rt.proto) {
			case 'S':
				printf("Service-Type = Framed-User\n");
				printf("Framed-Protocol = SLIP\n");
				break;

			case 'P':
				printf("Service-Type = Framed-User\n");
				printf("Framed-Protocol = PPP\n");
				break;

			default:
				printf("Service-type = Login-User\n");
				break;
			}
			if (rt.framed_address != INADDR_NONE) {
				printf("Framed-IP-Address = %s\n",
				       hostname(buffer, sizeof(buffer),
						rt.framed_address));
			}

			/*
			 *	Some sanity checks on the time
			 */
			if ((rt.time <= now) &&
			    (now - rt.time) <= (86400 * 365)) {
				printf("Acct-Session-Time = %" PRId64 "\n", (int64_t) (now - rt.time));
			}

			if (rt.caller_id[0] != '\0') {
				memcpy(nasname, rt.caller_id,
				       sizeof(rt.caller_id));
				nasname[sizeof(rt.caller_id)] = '\0';

				fr_print_string(nasname, 0, buffer,
						 sizeof(buffer));
				printf("Calling-Station-Id = \"%s\"\n", buffer);
			}

			printf("\n"); /* separate entries with a blank line */
			continue;
		}

		/*
		 *	Show the fill name, or not.
		 */
		memcpy(name, rt.login, sizeof(rt.login));
		name[sizeof(rt.login)] = '\0';

		if (showname) {
			if (rawoutput == 0) {
				printf("%-10.10s %-17.17s %-5.5s %s%-3u %-9.9s %-15.15s %-.19s%s",
				       name,
				       showcid ? rt.caller_id :
				       (showsid? session_id : fullname(rt.login)),
				       proto(rt.proto, rt.porttype),
				       portind, portno,
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address), eol);
			} else {
				printf("%s,%s,%s,%s%u,%s,%s,%s%s",
				       name,
				       showcid ? rt.caller_id :
				       (showsid? session_id : fullname(rt.login)),
				       proto(rt.proto, rt.porttype),
				       portind, portno,
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address), eol);
			}
		} else {
			if (rawoutput == 0) {
				printf("%-10.10s %s%-5u  %-6.6s %-13.13s %-15.15s %-.28s%s",
				       name,
				       portind, portno,
				       proto(rt.proto, rt.porttype),
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address),
				       eol);
			} else {
				printf("%s,%s%u,%s,%s,%s,%s%s",
				       name,
				       portind, portno,
				       proto(rt.proto, rt.porttype),
				       dotime(rt.time),
				       hostname(nasname, sizeof(nasname), rt.nas_address),
				       hostname(othername, sizeof(othername), rt.framed_address),
				       eol);
			}
		}
	}
	fclose(fp);

	return 0;
}
示例#4
0
/*
 *	Main program, either pmwho or fingerd.
 */
int main(int argc, char **argv)
{
	CONF_SECTION *maincs, *cs;
	FILE *fp;
	struct radutmp rt;
	char inbuf[128];
	char othername[256];
	char nasname[1024];
	char session_id[sizeof(rt.session_id)+1];
	int fingerd = 0;
	int hideshell = 0;
	int showsid = 0;
	int rawoutput = 0;
	int radiusoutput = 0;	/* Radius attributes */
	char *p, *q;
	const char *portind;
	int c;
	unsigned int portno;
	char buffer[2048];
	const char *user = NULL;
	int user_cmp = 0;
	time_t now = 0;
	uint32_t nas_port = ~0;
	uint32_t nas_ip_address = INADDR_NONE;
	int zap = 0;

	raddb_dir = RADIUS_DIR;

	while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) {
		case 'd':
			raddb_dir = optarg;
			break;
		case 'f':
			fingerd++;
			showname = 0;
			break;
		case 'F':
			radutmp_file = optarg;
			break;
		case 'h':
			usage(0);
			break;
		case 'S':
			hideshell = 1;
			break;
		case 'n':
			showname = 0;
			break;
		case 'N':
			if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) {
				usage(1);
			}
			break;
		case 's':
			showname = 1;
			break;
		case 'i':
			showsid = 1;
			break;
		case 'p':
			showptype = 1;
			break;
		case 'P':
			nas_port = atoi(optarg);
			break;
		case 'c':
			showcid = 1;
			showname = 1;
			break;
		case 'r':
			rawoutput = 1;
			break;
		case 'R':
			radiusoutput = 1;
			now = time(NULL);
			break;
		case 'u':
			user = optarg;
			user_cmp = 0;
			break;
		case 'U':
			user = optarg;
			user_cmp = 1;
			break;
		case 'Z':
			zap = 1;
			break;
		default:
			usage(1);
			break;
	}

	/*
	 *	Be safe.
	 */
	if (zap && !radiusoutput) zap = 0;

	/*
	 *	zap EVERYONE, but only on this nas
	 */
	if (zap && !user && (~nas_port == 0)) {
		/*
		 *	We need to know which NAS to zap users in.
		 */
		if (nas_ip_address == INADDR_NONE) usage(1);

		printf("Acct-Status-Type = Accounting-Off\n");
		printf("NAS-IP-Address = %s\n",
		       hostname(buffer, sizeof(buffer), nas_ip_address));
		printf("Acct-Delay-Time = 0\n");
		exit(0);	/* don't bother printing anything else */
	}

	if (radutmp_file) goto have_radutmp;

	/*
	 *	Initialize mainconfig
	 */
	memset(&mainconfig, 0, sizeof(mainconfig));
	mainconfig.radlog_dest = RADLOG_STDOUT;

        /* Read radiusd.conf */
	snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir);
	maincs = cf_file_read(buffer);
	if (!maincs) {
		fprintf(stderr, "%s: Error reading or parsing radiusd.conf.\n", argv[0]);
		exit(1);
	}

        /* Read the radutmp section of radiusd.conf */
        cs = cf_section_find_name2(cf_section_sub_find(maincs, "modules"), "radutmp", NULL);
        if(!cs) {
                fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf!\n",
                        argv[0]);
                exit(1);
        }

	cf_section_parse(cs, NULL, module_config);

	/* Assign the correct path for the radutmp file */
	radutmp_file = radutmpconfig.radutmp_fn;

 have_radutmp:
	/*
	 *	See if we are "fingerd".
	 */
	if (strstr(argv[0], "fingerd")) {
		fingerd++;
		eol = "\r\n";
		if (showname < 0) showname = 0;
	}
	if (showname < 0) showname = 1;

	if (fingerd) {
		/*
		 *	Read first line of the input.
		 */
		fgets(inbuf, 128, stdin);
		p = inbuf;
		while(*p == ' ' || *p == '\t') p++;
		if (*p == '/' && *(p + 1)) p += 2;
		while(*p == ' ' || *p == '\t') p++;
		for(q = p; *q && *q != '\r' && *q != '\n'; q++)
			;
		*q = 0;

		/*
		 *	See if we fingered a specific user.
		 */
		ffile("header");
		if (*p) sys_finger(p);
	}

	/*
	 *	Show the users logged in on the terminal server(s).
	 */
	if ((fp = fopen(radutmp_file, "r")) == NULL) {
		fprintf(stderr, "%s: Error reading %s: %s\n",
			progname, radutmp_file, strerror(errno));
		return 0;
	}

	/*
	 *	Don't print the headers if raw or RADIUS
	 */
	if (!rawoutput && !radiusoutput) {
		fputs(showname ? hdr1 : hdr2, stdout);
		fputs(eol, stdout);
	}

	/*
	 *	Read the file, printing out active entries.
	 */
	while (fread(&rt, sizeof(rt), 1, fp) == 1) {
		if (rt.type != P_LOGIN) continue; /* hide logout sessions */

		/*
		 *	We don't show shell users if we are
		 *	fingerd, as we have done that above.
		 */
		if (hideshell && !strchr("PCS", rt.proto))
			continue;

		/*
		 *	Print out sessions only for the given user.
		 */
		if (user) {	/* only for a particular user */
			if (((user_cmp == 0) &&
			     (strncasecmp(rt.login, user, strlen(user)) != 0)) ||
			    ((user_cmp == 1) &&
			     (strncmp(rt.login, user, strlen(user)) != 0))) {
				continue;
			}
		}

		/*
		 *	Print out only for the given NAS port.
		 */
		if (~nas_port != 0) {
			if (rt.nas_port != nas_port) continue;
		}

		/*
		 *	Print out only for the given NAS IP address
		 */
		if (nas_ip_address != INADDR_NONE) {
			if (rt.nas_address != nas_ip_address) continue;
		}

		memcpy(session_id, rt.session_id, sizeof(rt.session_id));
		session_id[sizeof(rt.session_id)] = 0;

		if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) {
			portind = ">";
			portno = (showname ? 999 : 99999);
		} else {
			portind = "S";
			portno = rt.nas_port;
		}

		/*
		 *	Print output as RADIUS attributes
		 */
		if (radiusoutput) {
			memcpy(nasname, rt.login, sizeof(rt.login));
			nasname[sizeof(rt.login)] = '\0';

			fr_print_string(nasname, 0, buffer,
					 sizeof(buffer));
			printf("User-Name = \"%s\"\n", buffer);

			fr_print_string(session_id, 0, buffer,
					 sizeof(buffer));
			printf("Acct-Session-Id = \"%s\"\n", buffer);

			if (zap) printf("Acct-Status-Type = Stop\n");

			printf("NAS-IP-Address = %s\n",
			       hostname(buffer, sizeof(buffer),
					rt.nas_address));
			printf("NAS-Port = %u\n", rt.nas_port);

			switch (rt.proto) {
				case 'S':
					printf("Service-Type = Framed-User\n");
					printf("Framed-Protocol = SLIP\n");
					break;
				case 'P':
					printf("Service-Type = Framed-User\n");
					printf("Framed-Protocol = PPP\n");
					break;
				default:
					printf("Service-type = Login-User\n");
					break;
			}
			if (rt.framed_address != INADDR_NONE) {
				printf("Framed-IP-Address = %s\n",
				       hostname(buffer, sizeof(buffer),
						rt.framed_address));
			}

			/*
			 *	Some sanity checks on the time
			 */
			if ((rt.time <= now) &&
			    (now - rt.time) <= (86400 * 365)) {
				printf("Acct-Session-Time = %ld\n",
				       now - rt.time);
			}

			if (rt.caller_id[0] != '\0') {
				memcpy(nasname, rt.caller_id,
				       sizeof(rt.caller_id));
				nasname[sizeof(rt.caller_id)] = '\0';

				fr_print_string(nasname, 0, buffer,
						 sizeof(buffer));
				printf("Calling-Station-Id = \"%s\"\n", buffer);
			}

			printf("\n"); /* separate entries with a blank line */
			continue;
		}

		/*
		 *	Show the fill name, or not.
		 */
		if (showname) {
			printf((rawoutput == 0? rfmt1: rfmt1r),
			       rt.login,
			       showcid ? rt.caller_id :
			       (showsid? session_id : fullname(rt.login)),
			       proto(rt.proto, rt.porttype),
			       portind, portno,
			       dotime(rt.time),
			       hostname(nasname, sizeof(nasname), rt.nas_address),
			       hostname(othername, sizeof(othername), rt.framed_address), eol);
		} else {
			printf((rawoutput == 0? rfmt2: rfmt2r),
			       rt.login,
			       portind, portno,
			       proto(rt.proto, rt.porttype),
			       dotime(rt.time),
			       hostname(nasname, sizeof(nasname), rt.nas_address),
			       hostname(othername, sizeof(othername), rt.framed_address),
			       eol);
		}
	}
	fclose(fp);

	return 0;
}
示例#5
0
文件: auth.c 项目: ebichu/dd-wrt
/*
 * Make sure user/pass are clean
 * and then log them
 */
static int rad_authlog(const char *msg, REQUEST *request, int goodpass)
{
	int logit;
	const char *extra_msg = NULL;
	char clean_password[1024];
	char clean_username[1024];
	char buf[1024];
	char extra[1024];
	VALUE_PAIR *username = NULL;

	if (!request->root->log_auth) {
		return 0;
	}

	/*
	 * Get the correct username based on the configured value
	 */
	if (log_stripped_names == 0) {
		username = pairfind(request->packet->vps, PW_USER_NAME);
	} else {
		username = request->username;
	}

	/*
	 *	Clean up the username
	 */
	if (username == NULL) {
		strcpy(clean_username, "<no User-Name attribute>");
	} else {
		fr_print_string((char *)username->vp_strvalue,
				username->length,
				clean_username, sizeof(clean_username));
	}

	/*
	 *	Clean up the password
	 */
	if (request->root->log_auth_badpass || request->root->log_auth_goodpass) {
		if (!request->password) {
			VALUE_PAIR *auth_type;

			auth_type = pairfind(request->config_items,
					     PW_AUTH_TYPE);
			if (auth_type) {
				snprintf(clean_password, sizeof(clean_password),
					 "<via Auth-Type = %s>",
					 dict_valnamebyattr(PW_AUTH_TYPE,
							    auth_type->vp_integer));
			} else {
				strcpy(clean_password, "<no User-Password attribute>");
			}
		} else if (pairfind(request->packet->vps, PW_CHAP_PASSWORD)) {
			strcpy(clean_password, "<CHAP-Password>");
		} else {
			fr_print_string((char *)request->password->vp_strvalue,
					 request->password->length,
					 clean_password, sizeof(clean_password));
		}
	}

	if (goodpass) {
		logit = request->root->log_auth_goodpass;
		extra_msg = request->root->auth_goodpass_msg;
	} else {
		logit = request->root->log_auth_badpass;
		extra_msg = request->root->auth_badpass_msg;
	}

	if (extra_msg) {
		extra[0] = ' ';
		radius_xlat(extra + 1, sizeof(extra) - 1, extra_msg, request,
			    NULL);
	} else {
		*extra = '\0';
	}

	radlog_request(L_AUTH, 0, request, "%s: [%s%s%s] (%s)%s",
		       msg,
		       clean_username,
		       logit ? "/" : "",
		       logit ? clean_password : "",
		       auth_name(buf, sizeof(buf), request, 1),
		       extra);

	return 0;
}
示例#6
0
/*
 *  Print one value into a string.
 *  delimitst will define if strings and dates will be delimited by '"'
 */
int vp_prints_value(char * out, size_t outlen, VALUE_PAIR *vp, int delimitst)
{
	DICT_VALUE  *v;
	char        buf[1024];
	const char  *a = NULL;
	size_t      len;
	time_t      t;
	struct tm   s_tm;

	out[0] = '\0';
	if (!vp) return 0;

	switch (vp->type) {
		case PW_TYPE_STRING:
			if ((delimitst == 1) && vp->flags.has_tag) {
				/* Tagged attribute: print delimter and ignore tag */
				buf[0] = '"';
				fr_print_string(vp->vp_strvalue,
						 vp->length, buf + 1, sizeof(buf) - 2);
				strcat(buf, "\"");
			} else if (delimitst == 1) {
				/* Non-tagged attribute: print delimter */
				buf[0] = '"';
				fr_print_string(vp->vp_strvalue,
						 vp->length, buf + 1, sizeof(buf) - 2);
				strcat(buf, "\"");

			} else if (delimitst < 0) { /* xlat.c */
				strlcpy(out, vp->vp_strvalue, outlen);
				return strlen(out);

			} else {
				/* Non-tagged attribute: no delimiter */
				fr_print_string(vp->vp_strvalue,
						 vp->length, buf, sizeof(buf));
			}
			a = buf;
			break;
		case PW_TYPE_INTEGER:
		        if ( vp->flags.has_tag ) {
			        /* Attribute value has a tag, need to ignore it */
			        if ((v = dict_valbyattr(vp->attribute, (vp->vp_integer & 0xffffff)))
				    != NULL)
				        a = v->name;
				else {
				        snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff));
				        a = buf;
				}
			} else {
		case PW_TYPE_BYTE:
		case PW_TYPE_SHORT:
			        /* Normal, non-tagged attribute */
			        if ((v = dict_valbyattr(vp->attribute, vp->vp_integer))
				    != NULL)
				        a = v->name;
				else {
				        snprintf(buf, sizeof(buf), "%u", vp->vp_integer);
					a = buf;
				}
			}
			break;
		case PW_TYPE_DATE:
			t = vp->vp_date;
			if (delimitst == 1) {
			  len = strftime(buf, sizeof(buf), "\"%b %e %Y %H:%M:%S %Z\"",
					 localtime_r(&t, &s_tm));
			} else {
			  len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z",
					 localtime_r(&t, &s_tm));
			}
			if (len > 0) a = buf;
			break;
		case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
			snprintf(buf, sizeof(buf), "%d", vp->vp_signed);
			a = buf;
			break;
		case PW_TYPE_IPADDR:
			a = inet_ntop(AF_INET, &(vp->vp_ipaddr),
				      buf, sizeof(buf));
			break;
		case PW_TYPE_ABINARY:
#ifdef ASCEND_BINARY
			a = buf;
			print_abinary(vp, buf, sizeof(buf));
			break;
#else
		  /* FALL THROUGH */
#endif
		case PW_TYPE_OCTETS:
			if (outlen <= (2 * (vp->length + 1))) return 0;

			strcpy(buf, "0x");

			fr_bin2hex(vp->vp_octets, buf + 2, vp->length);
			a = buf;
		  break;

		case PW_TYPE_IFID:
			a = ifid_ntoa(buf, sizeof(buf), vp->vp_octets);
			break;

		case PW_TYPE_IPV6ADDR:
			a = inet_ntop(AF_INET6,
				      (const struct in6_addr *) vp->vp_strvalue,
				      buf, sizeof(buf));
			break;

		case PW_TYPE_IPV6PREFIX:
		{
			struct in6_addr addr;

			/*
			 *	Alignment issues.
			 */
			memcpy(&addr, vp->vp_strvalue + 2, sizeof(addr));

			a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
			if (a) {
				char *p = buf + strlen(buf);
				snprintf(p, buf + sizeof(buf) - p - 1, "/%u",
					 (unsigned int) vp->vp_octets[1]);
			}
		}
			break;

		case PW_TYPE_ETHERNET:
			snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
				 vp->vp_ether[0], vp->vp_ether[1],
				 vp->vp_ether[2], vp->vp_ether[3],
				 vp->vp_ether[4], vp->vp_ether[5]);
			a = buf;
			break;

		case PW_TYPE_TLV:
			if (outlen <= (2 * (vp->length + 1))) return 0;

			strcpy(buf, "0x");

			fr_bin2hex(vp->vp_tlv, buf + 2, vp->length);
			a = buf;
		  break;

		default:
			a = "UNKNOWN-TYPE";
			break;
	}

	if (a != NULL) strlcpy(out, a, outlen);

	return strlen(out);
}