Path: blob/main/crypto/krb5/src/lib/kadm5/str_conv.c
39536 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* lib/kadm5/str_conv.c */2/*3* Copyright (C) 1995-2015 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* * Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in15* the documentation and/or other materials provided with the16* distribution.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29* OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132/* Convert between strings and Kerberos internal data. */3334#include "k5-int.h"35#include "admin_internal.h"36#include "adm_proto.h"3738#include <ctype.h>3940static const char default_tupleseps[] = ", \t";41static const char default_ksaltseps[] = ":";4243struct flag_table_row {44const char *spec; /* Input specifier string */45krb5_flags flag; /* Flag */46int invert; /* Whether to invert the sense */47};4849static const struct flag_table_row ftbl[] = {50{"allow_postdated", KRB5_KDB_DISALLOW_POSTDATED, 1},51{"postdateable", KRB5_KDB_DISALLOW_POSTDATED, 1},52{"disallow_postdated", KRB5_KDB_DISALLOW_POSTDATED, 0},53{"allow_forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 1},54{"forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 1},55{"disallow_forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 0},56{"allow_tgs_req", KRB5_KDB_DISALLOW_TGT_BASED, 1},57{"tgt_based", KRB5_KDB_DISALLOW_TGT_BASED, 1},58{"disallow_tgt_based", KRB5_KDB_DISALLOW_TGT_BASED, 0},59{"allow_renewable", KRB5_KDB_DISALLOW_RENEWABLE, 1},60{"renewable", KRB5_KDB_DISALLOW_RENEWABLE, 1},61{"disallow_renewable", KRB5_KDB_DISALLOW_RENEWABLE, 0},62{"allow_proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 1},63{"proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 1},64{"disallow_proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 0},65{"allow_dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 1},66{"dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 1},67{"disallow_dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 0},68{"allow_tickets", KRB5_KDB_DISALLOW_ALL_TIX, 1},69{"allow_tix", KRB5_KDB_DISALLOW_ALL_TIX, 1},70{"disallow_all_tix", KRB5_KDB_DISALLOW_ALL_TIX, 0},71{"preauth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},72{"requires_pre_auth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},73{"requires_preauth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},74{"hwauth", KRB5_KDB_REQUIRES_HW_AUTH, 0},75{"requires_hw_auth", KRB5_KDB_REQUIRES_HW_AUTH, 0},76{"requires_hwauth", KRB5_KDB_REQUIRES_HW_AUTH, 0},77{"needchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},78{"pwchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},79{"requires_pwchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},80{"allow_svr", KRB5_KDB_DISALLOW_SVR, 1},81{"service", KRB5_KDB_DISALLOW_SVR, 1},82{"disallow_svr", KRB5_KDB_DISALLOW_SVR, 0},83{"password_changing_service", KRB5_KDB_PWCHANGE_SERVICE, 0},84{"pwchange_service", KRB5_KDB_PWCHANGE_SERVICE, 0},85{"pwservice", KRB5_KDB_PWCHANGE_SERVICE, 0},86{"md5", KRB5_KDB_SUPPORT_DESMD5, 0},87{"support_desmd5", KRB5_KDB_SUPPORT_DESMD5, 0},88{"new_princ", KRB5_KDB_NEW_PRINC, 0},89{"ok_as_delegate", KRB5_KDB_OK_AS_DELEGATE, 0},90{"ok_to_auth_as_delegate", KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 0},91{"no_auth_data_required", KRB5_KDB_NO_AUTH_DATA_REQUIRED, 0},92{"lockdown_keys", KRB5_KDB_LOCKDOWN_KEYS, 0},93};94#define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))9596static const char *outflags[] = {97"DISALLOW_POSTDATED", /* 0x00000001 */98"DISALLOW_FORWARDABLE", /* 0x00000002 */99"DISALLOW_TGT_BASED", /* 0x00000004 */100"DISALLOW_RENEWABLE", /* 0x00000008 */101"DISALLOW_PROXIABLE", /* 0x00000010 */102"DISALLOW_DUP_SKEY", /* 0x00000020 */103"DISALLOW_ALL_TIX", /* 0x00000040 */104"REQUIRES_PRE_AUTH", /* 0x00000080 */105"REQUIRES_HW_AUTH", /* 0x00000100 */106"REQUIRES_PWCHANGE", /* 0x00000200 */107NULL, /* 0x00000400 */108NULL, /* 0x00000800 */109"DISALLOW_SVR", /* 0x00001000 */110"PWCHANGE_SERVICE", /* 0x00002000 */111"SUPPORT_DESMD5", /* 0x00004000 */112"NEW_PRINC", /* 0x00008000 */113NULL, /* 0x00010000 */114NULL, /* 0x00020000 */115NULL, /* 0x00040000 */116NULL, /* 0x00080000 */117"OK_AS_DELEGATE", /* 0x00100000 */118"OK_TO_AUTH_AS_DELEGATE", /* 0x00200000 */119"NO_AUTH_DATA_REQUIRED", /* 0x00400000 */120"LOCKDOWN_KEYS", /* 0x00800000 */121};122#define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))123124/*125* Given s, which is a normalized flagspec with the prefix stripped off, and126* req_neg indicating whether the flagspec is negated, update the toset and127* toclear masks.128*/129static krb5_error_code130raw_flagspec_to_mask(const char *s, int req_neg, krb5_flags *toset,131krb5_flags *toclear)132{133int found = 0, invert = 0;134size_t i;135krb5_flags flag;136unsigned long ul;137138for (i = 0; !found && i < NFTBL; i++) {139if (strcmp(s, ftbl[i].spec) != 0)140continue;141/* Found a match */142found = 1;143invert = ftbl[i].invert;144flag = ftbl[i].flag;145}146/* Accept hexadecimal numbers. */147if (!found && strncmp(s, "0x", 2) == 0) {148/* Assume that krb5_flags are 32 bits long. */149ul = strtoul(s, NULL, 16) & 0xffffffff;150flag = (krb5_flags)ul;151found = 1;152}153if (!found)154return EINVAL;155if (req_neg)156invert = !invert;157if (invert)158*toclear &= ~flag;159else160*toset |= flag;161return 0;162}163164/*165* Update the toset and toclear flag masks according to flag specifier string166* spec, which is of the form {+|-}flagname. toset and toclear can point to167* the same flag word.168*/169krb5_error_code170krb5_flagspec_to_mask(const char *spec, krb5_flags *toset, krb5_flags *toclear)171{172int req_neg = 0;173char *copy, *cp, *s;174krb5_error_code retval;175176s = copy = strdup(spec);177if (s == NULL)178return ENOMEM;179180if (*s == '-') {181req_neg = 1;182s++;183} else if (*s == '+')184s++;185186for (cp = s; *cp != '\0'; cp++) {187/* Transform hyphens to underscores.*/188if (*cp == '-')189*cp = '_';190/* Downcase. */191if (isupper((unsigned char)*cp))192*cp = tolower((unsigned char)*cp);193}194retval = raw_flagspec_to_mask(s, req_neg, toset, toclear);195free(copy);196return retval;197}198199/*200* Copy the flag name of flagnum to outstr. On error, outstr points to a null201* pointer.202*/203krb5_error_code204krb5_flagnum_to_string(int flagnum, char **outstr)205{206const char *s = NULL;207208*outstr = NULL;209if ((unsigned int)flagnum < NOUTFLAGS)210s = outflags[flagnum];211if (s == NULL) {212/* Assume that krb5_flags are 32 bits long. */213if (asprintf(outstr, "0x%08lx", 1UL << flagnum) == -1)214*outstr = NULL;215} else {216*outstr = strdup(s);217}218if (*outstr == NULL)219return ENOMEM;220return 0;221}222223/*224* Create a null-terminated array of string representations of flags. Store a225* null pointer into outarray if there would be no strings.226*/227krb5_error_code228krb5_flags_to_strings(krb5_int32 flags, char ***outarray)229{230char **a = NULL, **a_new = NULL, **ap;231size_t amax = 0, i;232krb5_error_code retval;233234*outarray = NULL;235236/* Assume that krb5_flags are 32 bits long. */237for (i = 0; i < 32; i++) {238if (!(flags & (1UL << i)))239continue;240241a_new = realloc(a, (amax + 2) * sizeof(*a));242if (a_new == NULL) {243retval = ENOMEM;244goto cleanup;245}246a = a_new;247retval = krb5_flagnum_to_string(i, &a[amax++]);248a[amax] = NULL;249if (retval)250goto cleanup;251}252*outarray = a;253return 0;254cleanup:255for (ap = a; ap != NULL && *ap != NULL; ap++) {256free(*ap);257}258free(a);259return retval;260}261262/*263* krb5_keysalt_is_present() - Determine if a key/salt pair is present264* in a list of key/salt tuples.265*266* Salttype may be negative to indicate a search for only a enctype.267*/268krb5_boolean269krb5_keysalt_is_present(krb5_key_salt_tuple *ksaltlist, krb5_int32 nksalts,270krb5_enctype enctype, krb5_int32 salttype)271{272krb5_boolean foundit;273int i;274275foundit = 0;276if (ksaltlist) {277for (i=0; i<nksalts; i++) {278if ((ksaltlist[i].ks_enctype == enctype) &&279((ksaltlist[i].ks_salttype == salttype) ||280(salttype < 0))) {281foundit = 1;282break;283}284}285}286return(foundit);287}288289/* NOTE: This is a destructive parser (writes NULs). */290static krb5_error_code291string_to_keysalt(char *s, const char *ksaltseps,292krb5_enctype *etype, krb5_int32 *stype)293{294char *sp;295const char *ksseps = (ksaltseps != NULL) ? ksaltseps : default_ksaltseps;296krb5_error_code ret = 0;297298sp = strpbrk(s, ksseps);299if (sp != NULL) {300*sp++ = '\0';301}302ret = krb5_string_to_enctype(s, etype);303if (ret)304return ret;305306/* Default to normal salt if omitted. */307*stype = KRB5_KDB_SALTTYPE_NORMAL;308if (sp == NULL)309return 0;310return krb5_string_to_salttype(sp, stype);311}312313/*314* krb5_string_to_keysalts() - Convert a string representation to a list315* of key/salt tuples.316*/317krb5_error_code318krb5_string_to_keysalts(const char *string, const char *tupleseps,319const char *ksaltseps, krb5_boolean dups,320krb5_key_salt_tuple **ksaltp, krb5_int32 *nksaltp)321{322char *copy, *p, *ksp;323char *tlasts = NULL;324const char *tseps = (tupleseps != NULL) ? tupleseps : default_tupleseps;325krb5_int32 nksalts = 0;326krb5_int32 stype;327krb5_enctype etype;328krb5_error_code ret = 0;329krb5_key_salt_tuple *ksalts = NULL, *ksalts_new = NULL;330331*ksaltp = NULL;332*nksaltp = 0;333p = copy = strdup(string);334if (p == NULL)335return ENOMEM;336while ((ksp = strtok_r(p, tseps, &tlasts)) != NULL) {337/* Pass a null pointer to subsequent calls to strtok_r(). */338p = NULL;339340/* Discard unrecognized keysalts. */341if (string_to_keysalt(ksp, ksaltseps, &etype, &stype) != 0)342continue;343344/* Ignore duplicate keysalts if caller asks. */345if (!dups && krb5_keysalt_is_present(ksalts, nksalts, etype, stype))346continue;347348ksalts_new = realloc(ksalts, (nksalts + 1) * sizeof(*ksalts));349if (ksalts_new == NULL) {350ret = ENOMEM;351goto cleanup;352}353ksalts = ksalts_new;354ksalts[nksalts].ks_enctype = etype;355ksalts[nksalts].ks_salttype = stype;356nksalts++;357}358*ksaltp = ksalts;359*nksaltp = nksalts;360cleanup:361if (ret)362free(ksalts);363free(copy);364return ret;365}366367/*368* krb5_keysalt_iterate() - Do something for each unique key/salt369* combination.370*371* If ignoresalt set, then salttype is ignored.372*/373krb5_error_code374krb5_keysalt_iterate(krb5_key_salt_tuple *ksaltlist, krb5_int32 nksalt,375krb5_boolean ignoresalt,376krb5_error_code (*iterator)(krb5_key_salt_tuple *,377void *),378void *arg)379{380int i;381krb5_error_code kret;382krb5_key_salt_tuple scratch;383384kret = 0;385for (i=0; i<nksalt; i++) {386scratch.ks_enctype = ksaltlist[i].ks_enctype;387scratch.ks_salttype = (ignoresalt) ? -1 : ksaltlist[i].ks_salttype;388if (!krb5_keysalt_is_present(ksaltlist,389i,390scratch.ks_enctype,391scratch.ks_salttype)) {392kret = (*iterator)(&scratch, arg);393if (kret)394break;395}396}397return(kret);398}399400401