Path: blob/main/crypto/krb5/src/kadmin/cli/keytab.c
34914 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/*2* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.3*4* $Id$5* $Source$6*/78/*9* Copyright (C) 1998 by the FundsXpress, INC.10*11* All rights reserved.12*13* Export of this software from the United States of America may require14* a specific license from the United States Government. It is the15* responsibility of any person or organization contemplating export to16* obtain such a license before exporting.17*18* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and19* distribute this software and its documentation for any purpose and20* without fee is hereby granted, provided that the above copyright21* notice appear in all copies and that both that copyright notice and22* this permission notice appear in supporting documentation, and that23* the name of FundsXpress. not be used in advertising or publicity pertaining24* to distribution of the software without specific, written prior25* permission. FundsXpress makes no representations about the suitability of26* this software for any purpose. It is provided "as is" without express27* or implied warranty.28*29* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR30* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED31* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.32*/3334#include "k5-int.h"35#include <kadm5/admin.h>36#include <adm_proto.h>37#include "kadmin.h"3839static void add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,40krb5_boolean keepold,41int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,42char *princ_str);43static void remove_principal(char *keytab_str, krb5_keytab keytab,44char *princ_str, char *kvno_str);45static char *etype_string(krb5_enctype enctype);4647static int quiet;4849static int norandkey;5051static void52add_usage(void)53{54fprintf(stderr, _("Usage: ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] "55"[-norandkey] [principal | -glob princ-exp] [...]\n"));56}5758static void59rem_usage(void)60{61fprintf(stderr, _("Usage: ktremove [-k[eytab] keytab] [-q] principal "62"[kvno|\"all\"|\"old\"]\n"));63}6465static int66process_keytab(krb5_context my_context, char **keytab_str,67krb5_keytab *keytab)68{69int code;70char *name = *keytab_str;7172if (name == NULL) {73name = malloc(BUFSIZ);74if (!name) {75com_err(whoami, ENOMEM, _("while creating keytab name"));76return 1;77}78code = krb5_kt_default(my_context, keytab);79if (code != 0) {80com_err(whoami, code, _("while opening default keytab"));81free(name);82return 1;83}84code = krb5_kt_get_name(my_context, *keytab, name, BUFSIZ);85if (code != 0) {86com_err(whoami, code, _("while getting keytab name"));87free(name);88return 1;89}90} else {91if (strchr(name, ':') != NULL)92name = strdup(name);93else if (asprintf(&name, "WRFILE:%s", name) < 0)94name = NULL;95if (name == NULL) {96com_err(whoami, ENOMEM, _("while creating keytab name"));97return 1;98}99100code = krb5_kt_resolve(my_context, name, keytab);101if (code != 0) {102com_err(whoami, code, _("while resolving keytab %s"), name);103free(name);104return 1;105}106}107108*keytab_str = name;109return 0;110}111112void113kadmin_keytab_add(int argc, char **argv, int sci_idx, void *info_ptr)114{115krb5_keytab keytab = 0;116char *keytab_str = NULL, **princs;117int code, num, i;118krb5_error_code retval;119int n_ks_tuple = 0;120krb5_boolean keepold = FALSE;121krb5_key_salt_tuple *ks_tuple = NULL;122123argc--; argv++;124quiet = 0;125norandkey = 0;126while (argc) {127if (strncmp(*argv, "-k", 2) == 0) {128argc--; argv++;129if (!argc || keytab_str) {130add_usage();131return;132}133keytab_str = *argv;134} else if (strcmp(*argv, "-q") == 0) {135quiet++;136} else if (strcmp(*argv, "-norandkey") == 0) {137norandkey++;138} else if (strcmp(*argv, "-e") == 0) {139argc--;140if (argc < 1) {141add_usage();142return;143}144retval = krb5_string_to_keysalts(*++argv, NULL, NULL, 0,145&ks_tuple, &n_ks_tuple);146if (retval) {147com_err("ktadd", retval, _("while parsing keysalts %s"),148*argv);149150return;151}152} else153break;154argc--; argv++;155}156157if (argc == 0) {158add_usage();159return;160}161162if (norandkey && ks_tuple) {163fprintf(stderr,164_("cannot specify keysaltlist when not changing key\n"));165return;166}167168if (process_keytab(context, &keytab_str, &keytab))169return;170171while (*argv) {172if (strcmp(*argv, "-glob") == 0) {173if (*++argv == NULL) {174add_usage();175break;176}177178code = kadm5_get_principals(handle, *argv, &princs, &num);179if (code) {180com_err(whoami, code, _("while expanding expression \"%s\"."),181*argv);182argv++;183continue;184}185186for (i = 0; i < num; i++)187add_principal(handle, keytab_str, keytab, keepold,188n_ks_tuple, ks_tuple, princs[i]);189kadm5_free_name_list(handle, princs, num);190} else {191add_principal(handle, keytab_str, keytab, keepold,192n_ks_tuple, ks_tuple, *argv);193argv++;194}195}196197code = krb5_kt_close(context, keytab);198if (code != 0)199com_err(whoami, code, _("while closing keytab"));200201free(keytab_str);202}203204void205kadmin_keytab_remove(int argc, char **argv, int sci_idx, void *info_ptr)206{207krb5_keytab keytab = 0;208char *keytab_str = NULL;209int code;210211argc--; argv++;212quiet = 0;213while (argc) {214if (strncmp(*argv, "-k", 2) == 0) {215argc--; argv++;216if (!argc || keytab_str) {217rem_usage();218return;219}220keytab_str = *argv;221} else if (strcmp(*argv, "-q") == 0) {222quiet++;223} else224break;225argc--; argv++;226}227228if (argc != 1 && argc != 2) {229rem_usage();230return;231}232if (process_keytab(context, &keytab_str, &keytab))233return;234235remove_principal(keytab_str, keytab, argv[0], argv[1]);236237code = krb5_kt_close(context, keytab);238if (code != 0)239com_err(whoami, code, _("while closing keytab"));240241free(keytab_str);242}243244/* Generate new random keys for princ, and convert them into a kadm5_key_data245* array (with no salt information). */246static krb5_error_code247fetch_new_keys(void *lhandle, krb5_principal princ, krb5_boolean keepold,248int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,249kadm5_key_data **key_data_out, int *nkeys_out)250{251krb5_error_code code;252kadm5_key_data *key_data;253kadm5_principal_ent_rec princ_rec;254krb5_keyblock *keys = NULL;255int i, nkeys = 0;256257*key_data_out = NULL;258*nkeys_out = 0;259memset(&princ_rec, 0, sizeof(princ_rec));260261/* Generate new random keys. */262code = randkey_princ(lhandle, princ, keepold, n_ks_tuple, ks_tuple,263&keys, &nkeys);264if (code)265goto cleanup;266267/* Get the principal entry to find the kvno of the new keys. (This is not268* atomic, but randkey doesn't report the new kvno.) */269code = kadm5_get_principal(lhandle, princ, &princ_rec,270KADM5_PRINCIPAL_NORMAL_MASK);271if (code)272goto cleanup;273274key_data = k5calloc(nkeys, sizeof(*key_data), &code);275if (key_data == NULL)276goto cleanup;277278/* Transfer the keyblocks and free the container array. */279for (i = 0; i < nkeys; i++) {280key_data[i].key = keys[i];281key_data[i].kvno = princ_rec.kvno;282}283*key_data_out = key_data;284*nkeys_out = nkeys;285free(keys);286keys = NULL;287nkeys = 0;288289cleanup:290for (i = 0; i < nkeys; i++)291krb5_free_keyblock_contents(context, &keys[i]);292free(keys);293kadm5_free_principal_ent(lhandle, &princ_rec);294return code;295}296297static void298add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,299krb5_boolean keepold, int n_ks_tuple,300krb5_key_salt_tuple *ks_tuple, char *princ_str)301{302krb5_principal princ = NULL;303krb5_keytab_entry new_entry;304kadm5_key_data *key_data;305int code, nkeys, i;306307princ = NULL;308key_data = NULL;309nkeys = 0;310311code = krb5_parse_name(context, princ_str, &princ);312if (code != 0) {313com_err(whoami, code, _("while parsing -add principal name %s"),314princ_str);315goto cleanup;316}317318if (norandkey) {319code = kadm5_get_principal_keys(handle, princ, 0, &key_data, &nkeys);320} else {321code = fetch_new_keys(handle, princ, keepold, n_ks_tuple, ks_tuple,322&key_data, &nkeys);323}324325if (code != 0) {326if (code == KADM5_UNK_PRINC) {327fprintf(stderr, _("%s: Principal %s does not exist.\n"),328whoami, princ_str);329} else330com_err(whoami, code, _("while changing %s's key"), princ_str);331goto cleanup;332}333334for (i = 0; i < nkeys; i++) {335memset(&new_entry, 0, sizeof(new_entry));336new_entry.principal = princ;337new_entry.key = key_data[i].key;338new_entry.vno = key_data[i].kvno;339340code = krb5_kt_add_entry(context, keytab, &new_entry);341if (code != 0) {342com_err(whoami, code, _("while adding key to keytab"));343goto cleanup;344}345346if (!quiet) {347printf(_("Entry for principal %s with kvno %d, "348"encryption type %s added to keytab %s.\n"),349princ_str, key_data[i].kvno,350etype_string(key_data[i].key.enctype), keytab_str);351}352}353354cleanup:355kadm5_free_kadm5_key_data(context, nkeys, key_data);356krb5_free_principal(context, princ);357}358359static void360remove_principal(char *keytab_str, krb5_keytab keytab,361char *princ_str, char *kvno_str)362{363krb5_principal princ = NULL;364krb5_keytab_entry entry;365krb5_kt_cursor cursor = NULL;366enum { UNDEF, SPEC, HIGH, ALL, OLD } mode;367int code, did_something;368krb5_kvno kvno;369370code = krb5_parse_name(context, princ_str, &princ);371if (code != 0) {372com_err(whoami, code, _("while parsing principal name %s"), princ_str);373goto cleanup;374}375376mode = UNDEF;377if (kvno_str == NULL) {378mode = HIGH;379kvno = 0;380} else if (strcmp(kvno_str, "all") == 0) {381mode = ALL;382kvno = 0;383} else if (strcmp(kvno_str, "old") == 0) {384mode = OLD;385kvno = 0;386} else {387mode = SPEC;388kvno = atoi(kvno_str);389}390391/* kvno is set to specified value for SPEC, 0 otherwise */392code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry);393if (code != 0) {394if (code == ENOENT) {395fprintf(stderr, _("%s: Keytab %s does not exist.\n"),396whoami, keytab_str);397} else if (code == KRB5_KT_NOTFOUND) {398if (mode != SPEC) {399fprintf(stderr, _("%s: No entry for principal %s exists in "400"keytab %s\n"),401whoami, princ_str, keytab_str);402} else {403fprintf(stderr, _("%s: No entry for principal %s with kvno %d "404"exists in keytab %s\n"),405whoami, princ_str, kvno, keytab_str);406}407} else {408com_err(whoami, code,409_("while retrieving highest kvno from keytab"));410}411goto cleanup;412}413414/* set kvno to spec'ed value for SPEC, highest kvno otherwise */415if (mode != SPEC)416kvno = entry.vno;417krb5_kt_free_entry(context, &entry);418419code = krb5_kt_start_seq_get(context, keytab, &cursor);420if (code != 0) {421com_err(whoami, code, _("while starting keytab scan"));422goto cleanup;423}424425did_something = 0;426while ((code = krb5_kt_next_entry(context, keytab, &entry,427&cursor)) == 0) {428if (krb5_principal_compare(context, princ, entry.principal) &&429((mode == ALL) ||430(mode == SPEC && entry.vno == kvno) ||431(mode == OLD && entry.vno != kvno) ||432(mode == HIGH && entry.vno == kvno))) {433434/*435* Ack! What a kludge... the scanning functions lock436* the keytab so entries cannot be removed while they437* are operating.438*/439code = krb5_kt_end_seq_get(context, keytab, &cursor);440if (code != 0) {441com_err(whoami, code,442_("while temporarily ending keytab scan"));443goto cleanup;444}445cursor = NULL;446code = krb5_kt_remove_entry(context, keytab, &entry);447if (code != 0) {448com_err(whoami, code, _("while deleting entry from keytab"));449goto cleanup;450}451code = krb5_kt_start_seq_get(context, keytab, &cursor);452if (code != 0) {453com_err(whoami, code, _("while restarting keytab scan"));454goto cleanup;455}456457did_something++;458if (!quiet) {459printf(_("Entry for principal %s with kvno %d removed from "460"keytab %s.\n"), princ_str, entry.vno, keytab_str);461}462}463krb5_kt_free_entry(context, &entry);464}465if (code && code != KRB5_KT_END) {466com_err(whoami, code, _("while scanning keytab"));467goto cleanup;468}469code = krb5_kt_end_seq_get(context, keytab, &cursor);470if (code) {471com_err(whoami, code, _("while ending keytab scan"));472goto cleanup;473}474cursor = NULL;475476/*477* If !did_someting then mode must be OLD or we would have478* already returned with an error. But check it anyway just to479* prevent unexpected error messages...480*/481if (!did_something && mode == OLD) {482fprintf(stderr, _("%s: There is only one entry for principal %s in "483"keytab %s\n"), whoami, princ_str, keytab_str);484}485486cleanup:487if (cursor != NULL)488(void)krb5_kt_end_seq_get(context, keytab, &cursor);489krb5_free_principal(context, princ);490}491492/*493* etype_string(enctype): return a string representation of the494* encryption type. XXX copied from klist.c; this should be a495* library function, or perhaps just #defines496*/497static char *498etype_string(krb5_enctype enctype)499{500static char buf[100];501krb5_error_code ret;502503ret = krb5_enctype_to_name(enctype, FALSE, buf, sizeof(buf));504if (ret)505snprintf(buf, sizeof(buf), "etype %d", enctype);506507return buf;508}509510511