Path: blob/main/crypto/heimdal/appl/gssmask/gssmaestro.c
34879 views
/*1* Copyright (c) 2006 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of KTH nor the names of its contributors may be17* used to endorse or promote products derived from this software without18* specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY21* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR23* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR27* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,28* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR29* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF30* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.31*/3233#include <common.h>34RCSID("$Id$");3536static FILE *logfile;3738/*39*40*/4142struct client {43char *name;44struct sockaddr *sa;45socklen_t salen;46krb5_storage *sock;47int32_t capabilities;48char *target_name;49char *moniker;50krb5_storage *logsock;51int have_log;52#ifdef ENABLE_PTHREAD_SUPPORT53pthread_t thr;54#else55pid_t child;56#endif57};5859static struct client **clients;60static int num_clients;6162static int63init_sec_context(struct client *client,64int32_t *hContext, int32_t *hCred,65int32_t flags,66const char *targetname,67const krb5_data *itoken, krb5_data *otoken)68{69int32_t val;70krb5_data_zero(otoken);71put32(client, eInitContext);72put32(client, *hContext);73put32(client, *hCred);74put32(client, flags);75putstring(client, targetname);76putdata(client, *itoken);77ret32(client, *hContext);78ret32(client, val);79retdata(client, *otoken);80return val;81}8283static int84accept_sec_context(struct client *client,85int32_t *hContext,86int32_t flags,87const krb5_data *itoken,88krb5_data *otoken,89int32_t *hDelegCred)90{91int32_t val;92krb5_data_zero(otoken);93put32(client, eAcceptContext);94put32(client, *hContext);95put32(client, flags);96putdata(client, *itoken);97ret32(client, *hContext);98ret32(client, val);99retdata(client, *otoken);100ret32(client, *hDelegCred);101return val;102}103104static int105acquire_cred(struct client *client,106const char *username,107const char *password,108int32_t flags,109int32_t *hCred)110{111int32_t val;112put32(client, eAcquireCreds);113putstring(client, username);114putstring(client, password);115put32(client, flags);116ret32(client, val);117ret32(client, *hCred);118return val;119}120121static int122toast_resource(struct client *client,123int32_t hCred)124{125int32_t val;126put32(client, eToastResource);127put32(client, hCred);128ret32(client, val);129return val;130}131132static int133goodbye(struct client *client)134{135put32(client, eGoodBye);136return GSMERR_OK;137}138139static int140get_targetname(struct client *client,141char **target)142{143put32(client, eGetTargetName);144retstring(client, *target);145return GSMERR_OK;146}147148static int32_t149encrypt_token(struct client *client, int32_t hContext, int32_t flags,150krb5_data *in, krb5_data *out)151{152int32_t val;153put32(client, eEncrypt);154put32(client, hContext);155put32(client, flags);156put32(client, 0);157putdata(client, *in);158ret32(client, val);159retdata(client, *out);160return val;161}162163static int32_t164decrypt_token(struct client *client, int32_t hContext, int flags,165krb5_data *in, krb5_data *out)166{167int32_t val;168put32(client, eDecrypt);169put32(client, hContext);170put32(client, flags);171put32(client, 0);172putdata(client, *in);173ret32(client, val);174retdata(client, *out);175return val;176}177178static int32_t179wrap_token_ext(struct client *client, int32_t hContext, int32_t flags,180int32_t bflags, krb5_data *header, krb5_data *in, krb5_data *trailer,181krb5_data *out)182{183int32_t val;184put32(client, eWrapExt);185put32(client, hContext);186put32(client, flags);187put32(client, bflags);188putdata(client, *header);189putdata(client, *in);190putdata(client, *trailer);191ret32(client, val);192retdata(client, *out);193return val;194}195196static int32_t197unwrap_token_ext(struct client *client, int32_t hContext, int32_t flags,198int32_t bflags, krb5_data *header, krb5_data *in, krb5_data *trailer,199krb5_data *out)200{201int32_t val;202put32(client, eUnwrapExt);203put32(client, hContext);204put32(client, flags);205put32(client, bflags);206putdata(client, *header);207putdata(client, *in);208putdata(client, *trailer);209ret32(client, val);210retdata(client, *out);211return val;212}213214static int32_t215get_mic(struct client *client, int32_t hContext,216krb5_data *in, krb5_data *mic)217{218int32_t val;219put32(client, eSign);220put32(client, hContext);221put32(client, 0);222put32(client, 0);223putdata(client, *in);224ret32(client, val);225retdata(client, *mic);226return val;227}228229static int32_t230verify_mic(struct client *client, int32_t hContext,231krb5_data *in, krb5_data *mic)232{233int32_t val;234put32(client, eVerify);235put32(client, hContext);236put32(client, 0);237put32(client, 0);238putdata(client, *in);239putdata(client, *mic);240ret32(client, val);241return val;242}243244245static int32_t246get_version_capa(struct client *client,247int32_t *version, int32_t *capa,248char **version_str)249{250put32(client, eGetVersionAndCapabilities);251ret32(client, *version);252ret32(client, *capa);253retstring(client, *version_str);254return GSMERR_OK;255}256257static int32_t258get_moniker(struct client *client,259char **moniker)260{261put32(client, eGetMoniker);262retstring(client, *moniker);263return GSMERR_OK;264}265266static int267wait_log(struct client *c)268{269int32_t port;270struct sockaddr_storage sast;271socklen_t salen = sizeof(sast);272int fd, fd2, ret;273274memset(&sast, 0, sizeof(sast));275276assert(sizeof(sast) >= c->salen);277278fd = socket(c->sa->sa_family, SOCK_STREAM, 0);279if (fd < 0)280err(1, "failed to build socket for %s's logging port", c->moniker);281282((struct sockaddr *)&sast)->sa_family = c->sa->sa_family;283ret = bind(fd, (struct sockaddr *)&sast, c->salen);284if (ret < 0)285err(1, "failed to bind %s's logging port", c->moniker);286287if (listen(fd, SOMAXCONN) < 0)288err(1, "failed to listen %s's logging port", c->moniker);289290salen = sizeof(sast);291ret = getsockname(fd, (struct sockaddr *)&sast, &salen);292if (ret < 0)293err(1, "failed to get address of local socket for %s", c->moniker);294295port = socket_get_port((struct sockaddr *)&sast);296297put32(c, eSetLoggingSocket);298put32(c, ntohs(port));299300salen = sizeof(sast);301fd2 = accept(fd, (struct sockaddr *)&sast, &salen);302if (fd2 < 0)303err(1, "failed to accept local socket for %s", c->moniker);304close(fd);305306return fd2;307}308309310311312static int313build_context(struct client *ipeer, struct client *apeer,314int32_t flags, int32_t hCred,315int32_t *iContext, int32_t *aContext, int32_t *hDelegCred)316{317int32_t val = GSMERR_ERROR, ic = 0, ac = 0, deleg = 0;318krb5_data itoken, otoken;319int iDone = 0, aDone = 0;320int step = 0;321int first_call = 0x80;322323if (apeer->target_name == NULL)324errx(1, "apeer %s have no target name", apeer->name);325326krb5_data_zero(&itoken);327328while (!iDone || !aDone) {329330if (iDone) {331warnx("iPeer already done, aPeer want extra rtt");332val = GSMERR_ERROR;333goto out;334}335336val = init_sec_context(ipeer, &ic, &hCred, flags|first_call,337apeer->target_name, &itoken, &otoken);338step++;339switch(val) {340case GSMERR_OK:341iDone = 1;342if (aDone)343continue;344break;345case GSMERR_CONTINUE_NEEDED:346break;347default:348warnx("iPeer %s failed with %d (step %d)",349ipeer->name, (int)val, step);350goto out;351}352353if (aDone) {354warnx("aPeer already done, iPeer want extra rtt");355val = GSMERR_ERROR;356goto out;357}358359val = accept_sec_context(apeer, &ac, flags|first_call,360&otoken, &itoken, &deleg);361step++;362switch(val) {363case GSMERR_OK:364aDone = 1;365if (iDone)366continue;367break;368case GSMERR_CONTINUE_NEEDED:369break;370default:371warnx("aPeer %s failed with %d (step %d)",372apeer->name, (int)val, step);373val = GSMERR_ERROR;374goto out;375}376first_call = 0;377val = GSMERR_OK;378}379380if (iContext == NULL || val != GSMERR_OK) {381if (ic)382toast_resource(ipeer, ic);383if (iContext)384*iContext = 0;385} else386*iContext = ic;387388if (aContext == NULL || val != GSMERR_OK) {389if (ac)390toast_resource(apeer, ac);391if (aContext)392*aContext = 0;393} else394*aContext = ac;395396if (hDelegCred == NULL || val != GSMERR_OK) {397if (deleg)398toast_resource(apeer, deleg);399if (hDelegCred)400*hDelegCred = 0;401} else402*hDelegCred = deleg;403404out:405return val;406}407408static void409test_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2)410{411krb5_data msg, mic;412int32_t val;413414msg.data = "foo";415msg.length = 3;416417krb5_data_zero(&mic);418419val = get_mic(c1, hc1, &msg, &mic);420if (val)421errx(1, "get_mic failed to host: %s", c1->moniker);422val = verify_mic(c2, hc2, &msg, &mic);423if (val)424errx(1, "verify_mic failed to host: %s", c2->moniker);425426krb5_data_free(&mic);427}428429static int32_t430test_wrap(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,431int conf)432{433krb5_data msg, wrapped, out;434int32_t val;435436msg.data = "foo";437msg.length = 3;438439krb5_data_zero(&wrapped);440krb5_data_zero(&out);441442val = encrypt_token(c1, hc1, conf, &msg, &wrapped);443if (val) {444warnx("encrypt_token failed to host: %s", c1->moniker);445return val;446}447val = decrypt_token(c2, hc2, conf, &wrapped, &out);448if (val) {449krb5_data_free(&wrapped);450warnx("decrypt_token failed to host: %s", c2->moniker);451return val;452}453454if (msg.length != out.length) {455warnx("decrypted'ed token have wrong length (%lu != %lu)",456(unsigned long)msg.length, (unsigned long)out.length);457val = GSMERR_ERROR;458} else if (memcmp(msg.data, out.data, msg.length) != 0) {459warnx("decryptd'ed token have wrong data");460val = GSMERR_ERROR;461}462463krb5_data_free(&wrapped);464krb5_data_free(&out);465return val;466}467468static int32_t469test_wrap_ext(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,470int conf, int bflags)471{472krb5_data header, msg, trailer, wrapped, out;473int32_t val;474475header.data = "header";476header.length = 6;477478msg.data = "0123456789abcdef"; /* padded for most enctypes */479msg.length = 32;480481trailer.data = "trailer";482trailer.length = 7;483484krb5_data_zero(&wrapped);485krb5_data_zero(&out);486487val = wrap_token_ext(c1, hc1, conf, bflags, &header, &msg, &trailer, &wrapped);488if (val) {489warnx("encrypt_token failed to host: %s", c1->moniker);490return val;491}492val = unwrap_token_ext(c2, hc2, conf, bflags, &header, &wrapped, &trailer, &out);493if (val) {494krb5_data_free(&wrapped);495warnx("decrypt_token failed to host: %s", c2->moniker);496return val;497}498499if (msg.length != out.length) {500warnx("decrypted'ed token have wrong length (%lu != %lu)",501(unsigned long)msg.length, (unsigned long)out.length);502val = GSMERR_ERROR;503} else if (memcmp(msg.data, out.data, msg.length) != 0) {504warnx("decryptd'ed token have wrong data");505val = GSMERR_ERROR;506}507508krb5_data_free(&wrapped);509krb5_data_free(&out);510return val;511}512513514static int32_t515test_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, int wrap_ext)516{517int32_t val;518int i;519520for (i = 0; i < 10; i++) {521/* mic */522test_mic(c1, hc1, c2, hc2);523test_mic(c2, hc2, c1, hc1);524525/* wrap */526val = test_wrap(c1, hc1, c2, hc2, 0);527if (val) return val;528val = test_wrap(c2, hc2, c1, hc1, 0);529if (val) return val;530531val = test_wrap(c1, hc1, c2, hc2, 1);532if (val) return val;533val = test_wrap(c2, hc2, c1, hc1, 1);534if (val) return val;535536if (wrap_ext) {537/* wrap ext */538val = test_wrap_ext(c1, hc1, c2, hc2, 1, 0);539if (val) return val;540val = test_wrap_ext(c2, hc2, c1, hc1, 1, 0);541if (val) return val;542543val = test_wrap_ext(c1, hc1, c2, hc2, 1, 1);544if (val) return val;545val = test_wrap_ext(c2, hc2, c1, hc1, 1, 1);546if (val) return val;547548val = test_wrap_ext(c1, hc1, c2, hc2, 0, 0);549if (val) return val;550val = test_wrap_ext(c2, hc2, c1, hc1, 0, 0);551if (val) return val;552553val = test_wrap_ext(c1, hc1, c2, hc2, 0, 1);554if (val) return val;555val = test_wrap_ext(c2, hc2, c1, hc1, 0, 1);556if (val) return val;557}558}559return GSMERR_OK;560}561562static int563log_function(void *ptr)564{565struct client *c = ptr;566int32_t cmd, line;567char *file, *string;568569while (1) {570if (krb5_ret_int32(c->logsock, &cmd))571goto out;572573switch (cmd) {574case eLogSetMoniker:575if (krb5_ret_string(c->logsock, &file))576goto out;577free(file);578break;579case eLogInfo:580case eLogFailure:581if (krb5_ret_string(c->logsock, &file))582goto out;583if (krb5_ret_int32(c->logsock, &line))584goto out;585if (krb5_ret_string(c->logsock, &string))586goto out;587printf("%s:%lu: %s\n",588file, (unsigned long)line, string);589fprintf(logfile, "%s:%lu: %s\n",590file, (unsigned long)line, string);591fflush(logfile);592free(file);593free(string);594if (krb5_store_int32(c->logsock, 0))595goto out;596break;597default:598errx(1, "client send bad log command: %d", (int)cmd);599}600}601out:602603return 0;604}605606static void607connect_client(const char *slave)608{609char *name, *port;610struct client *c = ecalloc(1, sizeof(*c));611struct addrinfo hints, *res0, *res;612int ret, fd;613614name = estrdup(slave);615port = strchr(name, ':');616if (port == NULL)617errx(1, "port missing from %s", name);618*port++ = 0;619620c->name = estrdup(slave);621622memset(&hints, 0, sizeof(hints));623hints.ai_family = PF_UNSPEC;624hints.ai_socktype = SOCK_STREAM;625626ret = getaddrinfo(name, port, &hints, &res0);627if (ret)628errx(1, "error resolving %s", name);629630for (res = res0, fd = -1; res; res = res->ai_next) {631fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);632if (fd < 0)633continue;634if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {635close(fd);636fd = -1;637continue;638}639c->sa = ecalloc(1, res->ai_addrlen);640memcpy(c->sa, res->ai_addr, res->ai_addrlen);641c->salen = res->ai_addrlen;642break; /* okay we got one */643}644if (fd < 0)645err(1, "connect to host: %s", name);646freeaddrinfo(res);647648c->sock = krb5_storage_from_fd(fd);649close(fd);650if (c->sock == NULL)651errx(1, "krb5_storage_from_fd");652653{654int32_t version;655char *str = NULL;656get_version_capa(c, &version, &c->capabilities, &str);657if (str) {658free(str);659}660if (c->capabilities & HAS_MONIKER)661get_moniker(c, &c->moniker);662else663c->moniker = c->name;664if (c->capabilities & ISSERVER)665get_targetname(c, &c->target_name);666}667668if (logfile) {669int fd;670671printf("starting log socket to client %s\n", c->moniker);672673fd = wait_log(c);674675c->logsock = krb5_storage_from_fd(fd);676close(fd);677if (c->logsock == NULL)678errx(1, "failed to create log krb5_storage");679#ifdef ENABLE_PTHREAD_SUPPORT680pthread_create(&c->thr, NULL, log_function, c);681#else682c->child = fork();683if (c->child == -1)684errx(1, "failed to fork");685else if (c->child == 0) {686log_function(c);687fclose(logfile);688exit(0);689}690#endif691}692693694clients = erealloc(clients, (num_clients + 1) * sizeof(*clients));695696clients[num_clients] = c;697num_clients++;698699free(name);700}701702static struct client *703get_client(const char *slave)704{705size_t i;706for (i = 0; i < num_clients; i++)707if (strcmp(slave, clients[i]->name) == 0)708return clients[i];709errx(1, "failed to find client %s", slave);710}711712/*713*714*/715716static int version_flag;717static int help_flag;718static int wrap_ext = 0;719static char *logfile_str;720static getarg_strings principals;721static getarg_strings slaves;722723struct getargs args[] = {724{ "principals", 0, arg_strings, &principals, "Test principal",725NULL },726{ "slaves", 0, arg_strings, &slaves, "Slaves",727NULL },728{ "log-file", 0, arg_string, &logfile_str, "Logfile",729NULL },730{ "wrap-ext", 0, arg_flag, &wrap_ext, "test wrap extended",731NULL },732{ "version", 0, arg_flag, &version_flag, "Print version",733NULL },734{ "help", 0, arg_flag, &help_flag, NULL,735NULL }736};737738static void739usage(int ret)740{741arg_printusage (args,742sizeof(args) / sizeof(args[0]),743NULL,744"");745exit (ret);746}747748int749main(int argc, char **argv)750{751int optidx= 0;752char *user;753char *password;754char ***list, **p;755size_t num_list, i, j, k;756int failed = 0;757758setprogname (argv[0]);759760if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))761usage (1);762763if (help_flag)764usage (0);765766if (version_flag) {767print_version (NULL);768return 0;769}770771if (optidx != argc)772usage (1);773774if (principals.num_strings == 0)775errx(1, "no principals");776777user = estrdup(principals.strings[0]);778password = strchr(user, ':');779if (password == NULL)780errx(1, "password missing from %s", user);781*password++ = 0;782783if (slaves.num_strings == 0)784errx(1, "no principals");785786if (logfile_str) {787printf("open logfile %s\n", logfile_str);788logfile = fopen(logfile_str, "w+");789if (logfile == NULL)790err(1, "failed to open: %s", logfile_str);791}792793/*794*795*/796797list = permutate_all(&slaves, &num_list);798799/*800* Set up connection to all clients801*/802803printf("Connecting to slaves\n");804for (i = 0; i < slaves.num_strings; i++)805connect_client(slaves.strings[i]);806807/*808* Test acquire credentials809*/810811printf("Test acquire credentials\n");812for (i = 0; i < slaves.num_strings; i++) {813int32_t hCred, val;814815val = acquire_cred(clients[i], user, password, 1, &hCred);816if (val != GSMERR_OK) {817warnx("Failed to acquire_cred on host %s: %d",818clients[i]->moniker, (int)val);819failed = 1;820} else821toast_resource(clients[i], hCred);822}823824if (failed)825goto out;826827/*828* First test if all slaves can build context to them-self.829*/830831printf("Self context tests\n");832for (i = 0; i < num_clients; i++) {833int32_t hCred, val, delegCred;834int32_t clientC, serverC;835struct client *c = clients[i];836837if (c->target_name == NULL)838continue;839840printf("%s connects to self using %s\n",841c->moniker, c->target_name);842843val = acquire_cred(c, user, password, 1, &hCred);844if (val != GSMERR_OK)845errx(1, "failed to acquire_cred: %d", (int)val);846847val = build_context(c, c,848GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|849GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|850GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,851hCred, &clientC, &serverC, &delegCred);852if (val == GSMERR_OK) {853test_token(c, clientC, c, serverC, wrap_ext);854toast_resource(c, clientC);855toast_resource(c, serverC);856if (delegCred)857toast_resource(c, delegCred);858} else {859warnx("build_context failed: %d", (int)val);860}861/*862*863*/864865val = build_context(c, c,866GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG,867hCred, &clientC, &serverC, &delegCred);868if (val == GSMERR_OK) {869test_token(c, clientC, c, serverC, wrap_ext);870toast_resource(c, clientC);871toast_resource(c, serverC);872if (delegCred)873toast_resource(c, delegCred);874} else {875warnx("build_context failed: %d", (int)val);876}877878toast_resource(c, hCred);879}880/*881* Build contexts though all entries in each lists, including the882* step from the last entry to the first, ie treat the list as a883* circle.884*885* Only follow the delegated credential, but test "all"886* flags. (XXX only do deleg|mutual right now.887*/888889printf("\"All\" permutation tests\n");890891for (i = 0; i < num_list; i++) {892int32_t hCred, val, delegCred = 0;893int32_t clientC = 0, serverC = 0;894struct client *client, *server;895896p = list[i];897898client = get_client(p[0]);899900val = acquire_cred(client, user, password, 1, &hCred);901if (val != GSMERR_OK)902errx(1, "failed to acquire_cred: %d", (int)val);903904for (j = 1; j < num_clients + 1; j++) {905server = get_client(p[j % num_clients]);906907if (server->target_name == NULL)908break;909910for (k = 1; k < j; k++)911printf("\t");912printf("%s -> %s\n", client->moniker, server->moniker);913914val = build_context(client, server,915GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|916GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|917GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,918hCred, &clientC, &serverC, &delegCred);919if (val != GSMERR_OK) {920warnx("build_context failed: %d", (int)val);921break;922}923924val = test_token(client, clientC, server, serverC, wrap_ext);925if (val)926break;927928toast_resource(client, clientC);929toast_resource(server, serverC);930if (!delegCred) {931warnx("no delegated cred on %s", server->moniker);932break;933}934toast_resource(client, hCred);935hCred = delegCred;936client = server;937}938if (hCred)939toast_resource(client, hCred);940}941942/*943* Close all connections to clients944*/945946out:947printf("sending goodbye and waiting for log sockets\n");948for (i = 0; i < num_clients; i++) {949goodbye(clients[i]);950if (clients[i]->logsock) {951#ifdef ENABLE_PTHREAD_SUPPORT952pthread_join(&clients[i]->thr, NULL);953#else954waitpid(clients[i]->child, NULL, 0);955#endif956}957}958959printf("done\n");960961return 0;962}963964965