Path: blob/main/crypto/krb5/src/clients/klist/klist.c
34914 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* clients/klist/klist.c - List contents of credential cache or keytab */2/*3* Copyright 1990 by the Massachusetts Institute of Technology.4* All Rights Reserved.5*6* Export of this software from the United States of America may7* require a specific license from the United States Government.8* It is the responsibility of any person or organization contemplating9* export to obtain such a license before exporting.10*11* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and12* distribute this software and its documentation for any purpose and13* without fee is hereby granted, provided that the above copyright14* notice appear in all copies and that both that copyright notice and15* this permission notice appear in supporting documentation, and that16* the name of M.I.T. not be used in advertising or publicity pertaining17* to distribution of the software without specific, written prior18* permission. Furthermore if you modify this software you must label19* your software as modified software and not distribute it in such a20* fashion that it might be confused with the original M.I.T. software.21* M.I.T. makes no representations about the suitability of22* this software for any purpose. It is provided "as is" without express23* or implied warranty.24*/2526#include "k5-int.h"27#include <krb5.h>28#include <com_err.h>29#include <locale.h>30#include <stdlib.h>31#include <string.h>32#include <stdio.h>33#include <time.h>3435/* Need definition of INET6 before network headers, for IRIX. */36#if defined(HAVE_ARPA_INET_H)37#include <arpa/inet.h>38#endif3940#ifndef _WIN3241#define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/') + 1 : (x))42#else43#define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))44#endif4546#ifndef _WIN3247#include <sys/socket.h>48#include <netdb.h>49#endif5051int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;52int show_etype = 0, show_addresses = 0, no_resolve = 0, print_version = 0;53int show_adtype = 0, show_all = 0, list_all = 0, use_client_keytab = 0;54int show_config = 0;55char *progname;56krb5_timestamp now;57unsigned int timestamp_width;5859krb5_context context;6061static krb5_boolean is_local_tgt(krb5_principal princ, krb5_data *realm);62static char *etype_string(krb5_enctype );63static void show_credential(krb5_creds *, const char *);6465static void list_all_ccaches(void);66static int list_ccache(krb5_ccache);67static void show_all_ccaches(void);68static void do_ccache(void);69static int show_ccache(krb5_ccache);70static int check_ccache(krb5_ccache);71static void do_keytab(const char *);72static void printtime(krb5_timestamp);73static void one_addr(krb5_address *);74static void fillit(FILE *, unsigned int, int);7576#define DEFAULT 077#define CCACHE 178#define KEYTAB 27980static void81usage(void)82{83fprintf(stderr, _("Usage: %s [-e] [-V] [[-c] [-l] [-A] [-d] [-f] [-s] "84"[-a [-n]]] [-k [-i] [-t] [-K]] [-C] [name]\n"),85progname);86fprintf(stderr, _("\t-c specifies credentials cache\n"));87fprintf(stderr, _("\t-k specifies keytab\n"));88fprintf(stderr, _("\t (Default is credentials cache)\n"));89fprintf(stderr, _("\t-i uses default client keytab if no name given\n"));90fprintf(stderr, _("\t-l lists credential caches in collection\n"));91fprintf(stderr, _("\t-A shows content of all credential caches\n"));92fprintf(stderr, _("\t-e shows the encryption type\n"));93fprintf(stderr, _("\t-V shows the Kerberos version and exits\n"));94fprintf(stderr, _("\toptions for credential caches:\n"));95fprintf(stderr, _("\t\t-d shows the submitted authorization data "96"types\n"));97fprintf(stderr, _("\t\t-f shows credentials flags\n"));98fprintf(stderr, _("\t\t-s sets exit status based on valid tgt "99"existence\n"));100fprintf(stderr, _("\t\t-a displays the address list\n"));101fprintf(stderr, _("\t\t\t-n do not reverse-resolve\n"));102fprintf(stderr, _("\toptions for keytabs:\n"));103fprintf(stderr, _("\t\t-t shows keytab entry timestamps\n"));104fprintf(stderr, _("\t\t-K shows keytab entry keys\n"));105fprintf(stderr, _("\t\t-C includes configuration data entries\n"));106exit(1);107}108109static void110extended_com_err_fn(const char *prog, errcode_t code, const char *fmt,111va_list args)112{113const char *msg;114115msg = krb5_get_error_message(context, code);116fprintf(stderr, "%s: %s%s", prog, msg, (*fmt == '\0') ? "" : " ");117krb5_free_error_message(context, msg);118vfprintf(stderr, fmt, args);119fprintf(stderr, "\n");120}121122int123main(int argc, char *argv[])124{125krb5_error_code ret;126char *name, tmp[BUFSIZ];127int c, mode;128129setlocale(LC_ALL, "");130progname = GET_PROGNAME(argv[0]);131set_com_err_hook(extended_com_err_fn);132133name = NULL;134mode = DEFAULT;135/* V = version so v can be used for verbose later if desired. */136while ((c = getopt(argc, argv, "dfetKsnacki45lAVC")) != -1) {137switch (c) {138case 'd':139show_adtype = 1;140break;141case 'f':142show_flags = 1;143break;144case 'e':145show_etype = 1;146break;147case 't':148show_time = 1;149break;150case 'K':151show_keys = 1;152break;153case 's':154status_only = 1;155break;156case 'n':157no_resolve = 1;158break;159case 'a':160show_addresses = 1;161break;162case 'c':163if (mode != DEFAULT)164usage();165mode = CCACHE;166break;167case 'k':168if (mode != DEFAULT)169usage();170mode = KEYTAB;171break;172case 'i':173use_client_keytab = 1;174break;175case '4':176fprintf(stderr, _("Kerberos 4 is no longer supported\n"));177exit(3);178break;179case '5':180break;181case 'l':182list_all = 1;183break;184case 'A':185show_all = 1;186break;187case 'C':188show_config = 1;189break;190case 'V':191print_version = 1;192break;193default:194usage();195break;196}197}198199if (no_resolve && !show_addresses)200usage();201202if (mode == DEFAULT || mode == CCACHE) {203if (show_time || show_keys)204usage();205if ((show_all && list_all) || (status_only && list_all))206usage();207} else {208if (show_flags || status_only || show_addresses ||209show_all || list_all)210usage();211}212213if (argc - optind > 1) {214fprintf(stderr, _("Extra arguments (starting with \"%s\").\n"),215argv[optind + 1]);216usage();217}218219if (print_version) {220#ifdef _WIN32 /* No access to autoconf vars; fix somehow. */221printf("Kerberos for Windows\n");222#else223printf(_("%s version %s\n"), PACKAGE_NAME, PACKAGE_VERSION);224#endif225exit(0);226}227228name = (optind == argc - 1) ? argv[optind] : NULL;229now = time(0);230231if (!krb5_timestamp_to_sfstring(now, tmp, 20, NULL) ||232!krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), NULL))233timestamp_width = (int)strlen(tmp);234else235timestamp_width = 15;236237ret = krb5_init_context(&context);238if (ret) {239com_err(progname, ret, _("while initializing krb5"));240exit(1);241}242243if (name != NULL && mode != KEYTAB) {244ret = krb5_cc_set_default_name(context, name);245if (ret) {246com_err(progname, ret, _("while setting default cache name"));247exit(1);248}249}250251if (list_all)252list_all_ccaches();253else if (show_all)254show_all_ccaches();255else if (mode == DEFAULT || mode == CCACHE)256do_ccache();257else258do_keytab(name);259return 0;260}261262static void263do_keytab(const char *name)264{265krb5_error_code ret;266krb5_keytab kt;267krb5_keytab_entry entry;268krb5_kt_cursor cursor;269unsigned int i;270char buf[BUFSIZ]; /* Hopefully large enough for any type */271char *pname;272273if (name == NULL && use_client_keytab) {274ret = krb5_kt_client_default(context, &kt);275if (ret) {276com_err(progname, ret, _("while getting default client keytab"));277exit(1);278}279} else if (name == NULL) {280ret = krb5_kt_default(context, &kt);281if (ret) {282com_err(progname, ret, _("while getting default keytab"));283exit(1);284}285} else {286ret = krb5_kt_resolve(context, name, &kt);287if (ret) {288com_err(progname, ret, _("while resolving keytab %s"), name);289exit(1);290}291}292293ret = krb5_kt_get_name(context, kt, buf, BUFSIZ);294if (ret) {295com_err(progname, ret, _("while getting keytab name"));296exit(1);297}298299printf("Keytab name: %s\n", buf);300301ret = krb5_kt_start_seq_get(context, kt, &cursor);302if (ret) {303com_err(progname, ret, _("while starting keytab scan"));304exit(1);305}306307/* XXX Translating would disturb table alignment; skip for now. */308if (show_time) {309printf("KVNO Timestamp");310fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' ');311printf("Principal\n");312printf("---- ");313fillit(stdout, timestamp_width, (int) '-');314printf(" ");315fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-');316printf("\n");317} else {318printf("KVNO Principal\n");319printf("---- ------------------------------------------------"320"--------------------------\n");321}322323while ((ret = krb5_kt_next_entry(context, kt, &entry, &cursor)) == 0) {324ret = krb5_unparse_name(context, entry.principal, &pname);325if (ret) {326com_err(progname, ret, _("while unparsing principal name"));327exit(1);328}329printf("%4d ", entry.vno);330if (show_time) {331printtime(entry.timestamp);332printf(" ");333}334printf("%s", pname);335if (show_etype)336printf(" (%s) " , etype_string(entry.key.enctype));337if (show_keys) {338printf(" (0x");339for (i = 0; i < entry.key.length; i++)340printf("%02x", entry.key.contents[i]);341printf(")");342}343printf("\n");344krb5_free_unparsed_name(context, pname);345krb5_free_keytab_entry_contents(context, &entry);346}347if (ret && ret != KRB5_KT_END) {348com_err(progname, ret, _("while scanning keytab"));349exit(1);350}351ret = krb5_kt_end_seq_get(context, kt, &cursor);352if (ret) {353com_err(progname, ret, _("while ending keytab scan"));354exit(1);355}356exit(0);357}358359static void360list_all_ccaches(void)361{362krb5_error_code ret;363krb5_ccache cache;364krb5_cccol_cursor cursor;365int exit_status;366367ret = krb5_cccol_cursor_new(context, &cursor);368if (ret) {369if (!status_only)370com_err(progname, ret, _("while listing ccache collection"));371exit(1);372}373374/* XXX Translating would disturb table alignment; skip for now. */375printf("%-30s %s\n", "Principal name", "Cache name");376printf("%-30s %s\n", "--------------", "----------");377exit_status = 1;378while ((ret = krb5_cccol_cursor_next(context, cursor, &cache)) == 0 &&379cache != NULL) {380exit_status = list_ccache(cache) && exit_status;381krb5_cc_close(context, cache);382}383krb5_cccol_cursor_free(context, &cursor);384exit(exit_status);385}386387static int388list_ccache(krb5_ccache cache)389{390krb5_error_code ret;391krb5_principal princ = NULL;392char *princname = NULL, *ccname = NULL;393int expired, status = 1;394395ret = krb5_cc_get_principal(context, cache, &princ);396if (ret) /* Uninitialized cache file, probably. */397goto cleanup;398ret = krb5_unparse_name(context, princ, &princname);399if (ret)400goto cleanup;401ret = krb5_cc_get_full_name(context, cache, &ccname);402if (ret)403goto cleanup;404405expired = check_ccache(cache);406407printf("%-30.30s %s", princname, ccname);408if (expired)409printf(" %s", _("(Expired)"));410printf("\n");411412status = 0;413414cleanup:415krb5_free_principal(context, princ);416krb5_free_unparsed_name(context, princname);417krb5_free_string(context, ccname);418return status;419}420421static void422show_all_ccaches(void)423{424krb5_error_code ret;425krb5_ccache cache;426krb5_cccol_cursor cursor;427krb5_boolean first;428int exit_status, st;429430ret = krb5_cccol_cursor_new(context, &cursor);431if (ret) {432if (!status_only)433com_err(progname, ret, _("while listing ccache collection"));434exit(1);435}436exit_status = 1;437first = TRUE;438while ((ret = krb5_cccol_cursor_next(context, cursor, &cache)) == 0 &&439cache != NULL) {440if (!status_only && !first)441printf("\n");442first = FALSE;443st = status_only ? check_ccache(cache) : show_ccache(cache);444exit_status = st && exit_status;445krb5_cc_close(context, cache);446}447krb5_cccol_cursor_free(context, &cursor);448exit(exit_status);449}450451static void452do_ccache(void)453{454krb5_error_code ret;455krb5_ccache cache;456457ret = krb5_cc_default(context, &cache);458if (ret) {459if (!status_only)460com_err(progname, ret, _("while resolving ccache"));461exit(1);462}463exit(status_only ? check_ccache(cache) : show_ccache(cache));464}465466/* Display the contents of cache. */467static int468show_ccache(krb5_ccache cache)469{470krb5_cc_cursor cur = NULL;471krb5_creds creds;472krb5_principal princ = NULL;473krb5_error_code ret;474char *defname = NULL;475int status = 1;476477ret = krb5_cc_get_principal(context, cache, &princ);478if (ret) {479com_err(progname, ret, "");480goto cleanup;481}482ret = krb5_unparse_name(context, princ, &defname);483if (ret) {484com_err(progname, ret, _("while unparsing principal name"));485goto cleanup;486}487488printf(_("Ticket cache: %s:%s\nDefault principal: %s\n\n"),489krb5_cc_get_type(context, cache), krb5_cc_get_name(context, cache),490defname);491/* XXX Translating would disturb table alignment; skip for now. */492fputs("Valid starting", stdout);493fillit(stdout, timestamp_width - sizeof("Valid starting") + 3, (int) ' ');494fputs("Expires", stdout);495fillit(stdout, timestamp_width - sizeof("Expires") + 3, (int) ' ');496fputs("Service principal\n", stdout);497498ret = krb5_cc_start_seq_get(context, cache, &cur);499if (ret) {500com_err(progname, ret, _("while starting to retrieve tickets"));501goto cleanup;502}503while ((ret = krb5_cc_next_cred(context, cache, &cur, &creds)) == 0) {504if (show_config || !krb5_is_config_principal(context, creds.server))505show_credential(&creds, defname);506krb5_free_cred_contents(context, &creds);507}508if (ret == KRB5_CC_END) {509ret = krb5_cc_end_seq_get(context, cache, &cur);510cur = NULL;511if (ret) {512com_err(progname, ret, _("while finishing ticket retrieval"));513goto cleanup;514}515} else {516com_err(progname, ret, _("while retrieving a ticket"));517goto cleanup;518}519520status = 0;521522cleanup:523if (cur != NULL)524(void)krb5_cc_end_seq_get(context, cache, &cur);525krb5_free_principal(context, princ);526krb5_free_unparsed_name(context, defname);527return status;528}529530/* Return 0 if cache is accessible, present, and unexpired; return 1 if not. */531static int532check_ccache(krb5_ccache cache)533{534krb5_error_code ret;535krb5_cc_cursor cur = NULL;536krb5_creds creds;537krb5_principal princ = NULL;538krb5_boolean found_tgt = FALSE, found_current_tgt = FALSE;539krb5_boolean found_current_cred = FALSE;540541ret = krb5_cc_get_principal(context, cache, &princ);542if (ret)543goto cleanup;544ret = krb5_cc_start_seq_get(context, cache, &cur);545if (ret)546goto cleanup;547found_tgt = found_current_tgt = found_current_cred = FALSE;548while ((ret = krb5_cc_next_cred(context, cache, &cur, &creds)) == 0) {549if (is_local_tgt(creds.server, &princ->realm)) {550found_tgt = TRUE;551if (ts_after(creds.times.endtime, now))552found_current_tgt = TRUE;553} else if (!krb5_is_config_principal(context, creds.server) &&554ts_after(creds.times.endtime, now)) {555found_current_cred = TRUE;556}557krb5_free_cred_contents(context, &creds);558}559if (ret != KRB5_CC_END)560goto cleanup;561ret = krb5_cc_end_seq_get(context, cache, &cur);562cur = NULL;563564cleanup:565if (cur != NULL)566(void)krb5_cc_end_seq_get(context, cache, &cur);567krb5_free_principal(context, princ);568if (ret)569return 1;570/* If the cache contains at least one local TGT, require that it be571* current. Otherwise accept any current cred. */572if (found_tgt)573return found_current_tgt ? 0 : 1;574return found_current_cred ? 0 : 1;575}576577/* Return true if princ is the local krbtgt principal for local_realm. */578static krb5_boolean579is_local_tgt(krb5_principal princ, krb5_data *realm)580{581return princ->length == 2 && data_eq(princ->realm, *realm) &&582data_eq_string(princ->data[0], KRB5_TGS_NAME) &&583data_eq(princ->data[1], *realm);584}585586static char *587etype_string(krb5_enctype enctype)588{589static char buf[100];590char *bp = buf;591size_t deplen, buflen = sizeof(buf);592593if (krb5int_c_deprecated_enctype(enctype)) {594deplen = strlcpy(bp, "DEPRECATED:", buflen);595buflen -= deplen;596bp += deplen;597}598599if (krb5_enctype_to_name(enctype, FALSE, bp, buflen))600snprintf(bp, buflen, "etype %d", enctype);601return buf;602}603604static char *605flags_string(krb5_creds *cred)606{607static char buf[32];608int i = 0;609610if (cred->ticket_flags & TKT_FLG_FORWARDABLE)611buf[i++] = 'F';612if (cred->ticket_flags & TKT_FLG_FORWARDED)613buf[i++] = 'f';614if (cred->ticket_flags & TKT_FLG_PROXIABLE)615buf[i++] = 'P';616if (cred->ticket_flags & TKT_FLG_PROXY)617buf[i++] = 'p';618if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)619buf[i++] = 'D';620if (cred->ticket_flags & TKT_FLG_POSTDATED)621buf[i++] = 'd';622if (cred->ticket_flags & TKT_FLG_INVALID)623buf[i++] = 'i';624if (cred->ticket_flags & TKT_FLG_RENEWABLE)625buf[i++] = 'R';626if (cred->ticket_flags & TKT_FLG_INITIAL)627buf[i++] = 'I';628if (cred->ticket_flags & TKT_FLG_HW_AUTH)629buf[i++] = 'H';630if (cred->ticket_flags & TKT_FLG_PRE_AUTH)631buf[i++] = 'A';632if (cred->ticket_flags & TKT_FLG_TRANSIT_POLICY_CHECKED)633buf[i++] = 'T';634if (cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE)635buf[i++] = 'O'; /* D/d are taken. Use short strings? */636if (cred->ticket_flags & TKT_FLG_ANONYMOUS)637buf[i++] = 'a';638buf[i] = '\0';639return buf;640}641642static void643printtime(krb5_timestamp ts)644{645char timestring[BUFSIZ], fill = ' ';646647if (!krb5_timestamp_to_sfstring(ts, timestring, timestamp_width + 1,648&fill))649printf("%s", timestring);650}651652static void653print_config_data(int col, krb5_data *data)654{655unsigned int i;656657for (i = 0; i < data->length; i++) {658while (col < 8) {659putchar(' ');660col++;661}662if (data->data[i] > 0x20 && data->data[i] < 0x7f) {663putchar(data->data[i]);664col++;665} else {666col += printf("\\%03o", (unsigned char)data->data[i]);667}668if (col > 72) {669putchar('\n');670col = 0;671}672}673if (col > 0)674putchar('\n');675}676677static void678show_credential(krb5_creds *cred, const char *defname)679{680krb5_error_code ret;681krb5_ticket *tkt = NULL;682char *name = NULL, *sname = NULL, *tktsname, *flags;683int extra_field = 0, ccol = 0, i, r;684krb5_boolean is_config = krb5_is_config_principal(context, cred->server);685686ret = krb5_unparse_name(context, cred->client, &name);687if (ret) {688com_err(progname, ret, _("while unparsing client name"));689goto cleanup;690}691ret = krb5_unparse_name(context, cred->server, &sname);692if (ret) {693com_err(progname, ret, _("while unparsing server name"));694goto cleanup;695}696if (!is_config)697(void)krb5_decode_ticket(&cred->ticket, &tkt);698if (!cred->times.starttime)699cred->times.starttime = cred->times.authtime;700701if (!is_config) {702printtime(cred->times.starttime);703putchar(' ');704putchar(' ');705printtime(cred->times.endtime);706putchar(' ');707putchar(' ');708printf("%s\n", sname);709} else {710fputs("config: ", stdout);711ccol = 8;712for (i = 1; i < cred->server->length; i++) {713r = printf("%s%.*s%s", i > 1 ? "(" : "",714(int)cred->server->data[i].length,715cred->server->data[i].data, i > 1 ? ")" : "");716if (r >= 0)717ccol += r;718}719fputs(" = ", stdout);720ccol += 3;721}722723if (strcmp(name, defname)) {724printf(_("\tfor client %s"), name);725extra_field++;726}727728if (is_config)729print_config_data(ccol, &cred->ticket);730731if (cred->times.renew_till) {732if (!extra_field)733fputs("\t",stdout);734else735fputs(", ",stdout);736fputs(_("renew until "), stdout);737printtime(cred->times.renew_till);738extra_field += 2;739}740741if (show_flags) {742flags = flags_string(cred);743if (flags && *flags) {744if (!extra_field)745fputs("\t",stdout);746else747fputs(", ",stdout);748printf(_("Flags: %s"), flags);749extra_field++;750}751}752753if (extra_field > 2) {754fputs("\n", stdout);755extra_field = 0;756}757758if (show_etype && tkt != NULL) {759if (!extra_field)760fputs("\t",stdout);761else762fputs(", ",stdout);763printf(_("Etype (skey, tkt): %s, "),764etype_string(cred->keyblock.enctype));765printf("%s ", etype_string(tkt->enc_part.enctype));766extra_field++;767}768769if (show_adtype) {770if (cred->authdata != NULL) {771if (!extra_field)772fputs("\t",stdout);773else774fputs(", ",stdout);775printf(_("AD types: "));776for (i = 0; cred->authdata[i] != NULL; i++) {777if (i)778printf(", ");779printf("%d", cred->authdata[i]->ad_type);780}781extra_field++;782}783}784785/* If any additional info was printed, extra_field is non-zero. */786if (extra_field)787putchar('\n');788789if (show_addresses) {790if (cred->addresses == NULL || cred->addresses[0] == NULL) {791printf(_("\tAddresses: (none)\n"));792} else {793printf(_("\tAddresses: "));794one_addr(cred->addresses[0]);795796for (i = 1; cred->addresses[i] != NULL; i++) {797printf(", ");798one_addr(cred->addresses[i]);799}800801printf("\n");802}803}804805/* Display the ticket server if it is different from the server name the806* entry was cached under (most commonly for referrals). */807if (tkt != NULL &&808!krb5_principal_compare(context, cred->server, tkt->server)) {809ret = krb5_unparse_name(context, tkt->server, &tktsname);810if (ret) {811com_err(progname, ret, _("while unparsing ticket server name"));812goto cleanup;813}814printf(_("\tTicket server: %s\n"), tktsname);815krb5_free_unparsed_name(context, tktsname);816}817818cleanup:819krb5_free_unparsed_name(context, name);820krb5_free_unparsed_name(context, sname);821krb5_free_ticket(context, tkt);822}823824#include "port-sockets.h"825#include "socket-utils.h" /* For ss2sin etc. */826#include "fake-addrinfo.h"827828static void829one_addr(krb5_address *a)830{831struct sockaddr_storage ss;832struct sockaddr_in *sinp;833struct sockaddr_in6 *sin6p;834int err, i;835char namebuf[NI_MAXHOST];836const uint8_t *p;837838memset(&ss, 0, sizeof(ss));839840switch (a->addrtype) {841case ADDRTYPE_INET:842if (a->length != 4) {843printf(_("broken address (type %d length %d)"),844a->addrtype, a->length);845return;846}847sinp = ss2sin(&ss);848sinp->sin_family = AF_INET;849memcpy(&sinp->sin_addr, a->contents, 4);850break;851case ADDRTYPE_INET6:852if (a->length != 16) {853printf(_("broken address (type %d length %d)"),854a->addrtype, a->length);855return;856}857sin6p = ss2sin6(&ss);858sin6p->sin6_family = AF_INET6;859memcpy(&sin6p->sin6_addr, a->contents, 16);860break;861case ADDRTYPE_NETBIOS:862if (a->length != 16) {863printf(_("broken address (type %d length %d)"),864a->addrtype, a->length);865return;866}867p = a->contents;868for (i = 0; i < 15 && p[i] != '\0' && p[i] != ' '; i++)869putchar(p[i]);870return;871default:872printf(_("unknown addrtype %d"), a->addrtype);873return;874}875876namebuf[0] = 0;877err = getnameinfo(ss2sa(&ss), sa_socklen(ss2sa(&ss)), namebuf,878sizeof(namebuf), 0, 0,879no_resolve ? NI_NUMERICHOST : 0U);880if (err) {881printf(_("unprintable address (type %d, error %d %s)"), a->addrtype,882err, gai_strerror(err));883return;884}885printf("%s", namebuf);886}887888static void889fillit(FILE *f, unsigned int num, int c)890{891unsigned int i;892893for (i = 0; i < num; i++)894fputc(c, f);895}896897898