1*eabc0478Schristos /* $NetBSD: authkeys.c,v 1.14 2024/08/18 20:47:13 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * authkeys.c - routines to manage the storage of authentication keys 5abb0f93cSkardel */ 6abb0f93cSkardel #ifdef HAVE_CONFIG_H 7abb0f93cSkardel # include <config.h> 8abb0f93cSkardel #endif 9abb0f93cSkardel 102950cc38Schristos #include <math.h> 11abb0f93cSkardel #include <stdio.h> 12abb0f93cSkardel 13abb0f93cSkardel #include "ntp.h" 142950cc38Schristos #include "ntp_fp.h" 15abb0f93cSkardel #include "ntpd.h" 162950cc38Schristos #include "ntp_lists.h" 17abb0f93cSkardel #include "ntp_string.h" 18abb0f93cSkardel #include "ntp_malloc.h" 19abb0f93cSkardel #include "ntp_stdlib.h" 2068dbbb44Schristos #include "ntp_keyacc.h" 21abb0f93cSkardel 22abb0f93cSkardel /* 23abb0f93cSkardel * Structure to store keys in in the hash table. 24abb0f93cSkardel */ 252950cc38Schristos typedef struct savekey symkey; 262950cc38Schristos 27abb0f93cSkardel struct savekey { 282950cc38Schristos symkey * hlink; /* next in hash bucket */ 292950cc38Schristos DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */ 302950cc38Schristos u_char * secret; /* shared secret */ 3168dbbb44Schristos KeyAccT * keyacclist; /* Private key access list */ 32abb0f93cSkardel u_long lifetime; /* remaining lifetime */ 332950cc38Schristos keyid_t keyid; /* key identifier */ 342950cc38Schristos u_short type; /* OpenSSL digest NID */ 3568dbbb44Schristos size_t secretsize; /* secret octets */ 362950cc38Schristos u_short flags; /* KEY_ flags that wave */ 37abb0f93cSkardel }; 38abb0f93cSkardel 392950cc38Schristos /* define the payload region of symkey beyond the list pointers */ 402950cc38Schristos #define symkey_payload secret 412950cc38Schristos 42abb0f93cSkardel #define KEY_TRUSTED 0x001 /* this key is trusted */ 43abb0f93cSkardel 442950cc38Schristos #ifdef DEBUG 452950cc38Schristos typedef struct symkey_alloc_tag symkey_alloc; 462950cc38Schristos 472950cc38Schristos struct symkey_alloc_tag { 482950cc38Schristos symkey_alloc * link; 492950cc38Schristos void * mem; /* enable free() atexit */ 502950cc38Schristos }; 512950cc38Schristos 522950cc38Schristos symkey_alloc * authallocs; 532950cc38Schristos #endif /* DEBUG */ 542950cc38Schristos 5568dbbb44Schristos static u_short auth_log2(size_t); 562950cc38Schristos static void auth_resize_hashtable(void); 5768dbbb44Schristos static void allocsymkey(keyid_t, u_short, 5868dbbb44Schristos u_short, u_long, size_t, u_char *, KeyAccT *); 5968dbbb44Schristos static void freesymkey(symkey *); 602950cc38Schristos #ifdef DEBUG 612950cc38Schristos static void free_auth_mem(void); 622950cc38Schristos #endif 632950cc38Schristos 642950cc38Schristos symkey key_listhead; /* list of all in-use keys */; 65abb0f93cSkardel /* 66abb0f93cSkardel * The hash table. This is indexed by the low order bits of the 67abb0f93cSkardel * keyid. We make this fairly big for potentially busy servers. 68abb0f93cSkardel */ 692950cc38Schristos #define DEF_AUTHHASHSIZE 64 708b8da087Schristos /*#define HASHMASK ((HASHSIZE)-1)*/ 712950cc38Schristos #define KEYHASH(keyid) ((keyid) & authhashmask) 72abb0f93cSkardel 732950cc38Schristos int authhashdisabled; 742950cc38Schristos u_short authhashbuckets = DEF_AUTHHASHSIZE; 752950cc38Schristos u_short authhashmask = DEF_AUTHHASHSIZE - 1; 762950cc38Schristos symkey **key_hash; 77abb0f93cSkardel 78abb0f93cSkardel u_long authkeynotfound; /* keys not found */ 79abb0f93cSkardel u_long authkeylookups; /* calls to lookup keys */ 80abb0f93cSkardel u_long authnumkeys; /* number of active keys */ 81abb0f93cSkardel u_long authkeyexpired; /* key lifetime expirations */ 82abb0f93cSkardel u_long authkeyuncached; /* cache misses */ 83abb0f93cSkardel u_long authnokey; /* calls to encrypt with no key */ 84abb0f93cSkardel u_long authencryptions; /* calls to encrypt */ 85abb0f93cSkardel u_long authdecryptions; /* calls to decrypt */ 86abb0f93cSkardel 87abb0f93cSkardel /* 882950cc38Schristos * Storage for free symkey structures. We malloc() such things but 89abb0f93cSkardel * never free them. 90abb0f93cSkardel */ 912950cc38Schristos symkey *authfreekeys; 92abb0f93cSkardel int authnumfreekeys; 93abb0f93cSkardel 942950cc38Schristos #define MEMINC 16 /* number of new free ones to get */ 95abb0f93cSkardel 96abb0f93cSkardel /* 97abb0f93cSkardel * The key cache. We cache the last key we looked at here. 9868dbbb44Schristos * Note: this should hold the last *trusted* key. Also the 9968dbbb44Schristos * cache is only loaded when the digest type / MAC algorithm 10068dbbb44Schristos * is valid. 101abb0f93cSkardel */ 102abb0f93cSkardel keyid_t cache_keyid; /* key identifier */ 1032950cc38Schristos u_char *cache_secret; /* secret */ 10468dbbb44Schristos size_t cache_secretsize; /* secret length */ 1052950cc38Schristos int cache_type; /* OpenSSL digest NID */ 106abb0f93cSkardel u_short cache_flags; /* flags that wave */ 10768dbbb44Schristos KeyAccT *cache_keyacclist; /* key access list */ 10868dbbb44Schristos 10968dbbb44Schristos /* -------------------------------------------------------------------- 11068dbbb44Schristos * manage key access lists 11168dbbb44Schristos * -------------------------------------------------------------------- 11268dbbb44Schristos */ 11368dbbb44Schristos /* allocate and populate new access node and pushes it on the list. 11468dbbb44Schristos * Returns the new head. 11568dbbb44Schristos */ 11668dbbb44Schristos KeyAccT* 11768dbbb44Schristos keyacc_new_push( 11868dbbb44Schristos KeyAccT * head, 1194eea345dSchristos const sockaddr_u * addr, 1204eea345dSchristos unsigned int subnetbits 12168dbbb44Schristos ) 12268dbbb44Schristos { 12368dbbb44Schristos KeyAccT * node = emalloc(sizeof(KeyAccT)); 12468dbbb44Schristos 12568dbbb44Schristos memcpy(&node->addr, addr, sizeof(sockaddr_u)); 1264eea345dSchristos node->subnetbits = subnetbits; 12768dbbb44Schristos node->next = head; 1284eea345dSchristos 12968dbbb44Schristos return node; 13068dbbb44Schristos } 13168dbbb44Schristos 13268dbbb44Schristos /* ----------------------------------------------------------------- */ 13368dbbb44Schristos /* pop and deallocate the first node of a list of access nodes, if 13468dbbb44Schristos * the list is not empty. Returns the tail of the list. 13568dbbb44Schristos */ 13668dbbb44Schristos KeyAccT* 13768dbbb44Schristos keyacc_pop_free( 13868dbbb44Schristos KeyAccT *head 13968dbbb44Schristos ) 14068dbbb44Schristos { 14168dbbb44Schristos KeyAccT * next = NULL; 14268dbbb44Schristos if (head) { 14368dbbb44Schristos next = head->next; 14468dbbb44Schristos free(head); 14568dbbb44Schristos } 14668dbbb44Schristos return next; 14768dbbb44Schristos } 14868dbbb44Schristos 14968dbbb44Schristos /* ----------------------------------------------------------------- */ 15068dbbb44Schristos /* deallocate the list; returns an empty list. */ 15168dbbb44Schristos KeyAccT* 15268dbbb44Schristos keyacc_all_free( 15368dbbb44Schristos KeyAccT * head 15468dbbb44Schristos ) 15568dbbb44Schristos { 15668dbbb44Schristos while (head) 15768dbbb44Schristos head = keyacc_pop_free(head); 15868dbbb44Schristos return head; 15968dbbb44Schristos } 16068dbbb44Schristos 16168dbbb44Schristos /* ----------------------------------------------------------------- */ 16268dbbb44Schristos /* scan a list to see if it contains a given address. Return the 16368dbbb44Schristos * default result value in case of an empty list. 16468dbbb44Schristos */ 16568dbbb44Schristos int /*BOOL*/ 16668dbbb44Schristos keyacc_contains( 16768dbbb44Schristos const KeyAccT *head, 16868dbbb44Schristos const sockaddr_u *addr, 16968dbbb44Schristos int defv) 17068dbbb44Schristos { 17168dbbb44Schristos if (head) { 17268dbbb44Schristos do { 1734eea345dSchristos if (keyacc_amatch(&head->addr, addr, 1744eea345dSchristos head->subnetbits)) 17568dbbb44Schristos return TRUE; 17668dbbb44Schristos } while (NULL != (head = head->next)); 17768dbbb44Schristos return FALSE; 17868dbbb44Schristos } else { 17968dbbb44Schristos return !!defv; 18068dbbb44Schristos } 18168dbbb44Schristos } 182abb0f93cSkardel 1834eea345dSchristos #if CHAR_BIT != 8 1844eea345dSchristos # error "don't know how to handle bytes with that bit size" 1854eea345dSchristos #endif 1864eea345dSchristos 1874eea345dSchristos /* ----------------------------------------------------------------- */ 1884eea345dSchristos /* check two addresses for a match, taking a prefix length into account 1894eea345dSchristos * when doing the compare. 1904eea345dSchristos * 1914eea345dSchristos * The ISC lib contains a similar function with not entirely specified 1924eea345dSchristos * semantics, so it seemed somewhat cleaner to do this from scratch. 1934eea345dSchristos * 1944eea345dSchristos * Note 1: It *is* assumed that the addresses are stored in network byte 1954eea345dSchristos * order, that is, most significant byte first! 1964eea345dSchristos * 1974eea345dSchristos * Note 2: "no address" compares unequal to all other addresses, even to 1984eea345dSchristos * itself. This has the same semantics as NaNs have for floats: *any* 1994eea345dSchristos * relational or equality operation involving a NaN returns FALSE, even 2004eea345dSchristos * equality with itself. "no address" is either a NULL pointer argument 2014eea345dSchristos * or an address of type AF_UNSPEC. 2024eea345dSchristos */ 2034eea345dSchristos int/*BOOL*/ 2044eea345dSchristos keyacc_amatch( 2054eea345dSchristos const sockaddr_u * a1, 2064eea345dSchristos const sockaddr_u * a2, 2074eea345dSchristos unsigned int mbits 2084eea345dSchristos ) 2094eea345dSchristos { 2104eea345dSchristos const uint8_t * pm1; 2114eea345dSchristos const uint8_t * pm2; 2124eea345dSchristos uint8_t msk; 2134eea345dSchristos unsigned int len; 2144eea345dSchristos 2154eea345dSchristos /* 1st check: If any address is not an address, it's inequal. */ 2164eea345dSchristos if ( !a1 || (AF_UNSPEC == AF(a1)) || 2174eea345dSchristos !a2 || (AF_UNSPEC == AF(a2)) ) 2184eea345dSchristos return FALSE; 2194eea345dSchristos 2204eea345dSchristos /* We could check pointers for equality here and shortcut the 2214eea345dSchristos * other checks if we find object identity. But that use case is 2224eea345dSchristos * too rare to care for it. 2234eea345dSchristos */ 2244eea345dSchristos 2254eea345dSchristos /* 2nd check: Address families must be the same. */ 2264eea345dSchristos if (AF(a1) != AF(a2)) 2274eea345dSchristos return FALSE; 2284eea345dSchristos 2294eea345dSchristos /* type check: address family determines buffer & size */ 2304eea345dSchristos switch (AF(a1)) { 2314eea345dSchristos case AF_INET: 2324eea345dSchristos /* IPv4 is easy: clamp size, get byte pointers */ 2334eea345dSchristos if (mbits > sizeof(NSRCADR(a1)) * 8) 2344eea345dSchristos mbits = sizeof(NSRCADR(a1)) * 8; 2354eea345dSchristos pm1 = (const void*)&NSRCADR(a1); 2364eea345dSchristos pm2 = (const void*)&NSRCADR(a2); 2374eea345dSchristos break; 2384eea345dSchristos 2394eea345dSchristos case AF_INET6: 2404eea345dSchristos /* IPv6 is slightly different: Both scopes must match, 2414eea345dSchristos * too, before we even consider doing a match! 2424eea345dSchristos */ 2434eea345dSchristos if ( ! SCOPE_EQ(a1, a2)) 2444eea345dSchristos return FALSE; 2454eea345dSchristos if (mbits > sizeof(NSRCADR6(a1)) * 8) 2464eea345dSchristos mbits = sizeof(NSRCADR6(a1)) * 8; 2474eea345dSchristos pm1 = (const void*)&NSRCADR6(a1); 2484eea345dSchristos pm2 = (const void*)&NSRCADR6(a2); 2494eea345dSchristos break; 2504eea345dSchristos 2514eea345dSchristos default: 2524eea345dSchristos /* don't know how to compare that!?! */ 2534eea345dSchristos return FALSE; 2544eea345dSchristos } 2554eea345dSchristos 2564eea345dSchristos /* Split bit length into byte length and partial byte mask. 2574eea345dSchristos * Note that the byte mask extends from the MSB of a byte down, 2584eea345dSchristos * and that zero shift (--> mbits % 8 == 0) results in an 2594eea345dSchristos * all-zero mask. 2604eea345dSchristos */ 2614eea345dSchristos msk = 0xFFu ^ (0xFFu >> (mbits & 7)); 2624eea345dSchristos len = mbits >> 3; 2634eea345dSchristos 2644eea345dSchristos /* 3rd check: Do memcmp() over full bytes, if any */ 2654eea345dSchristos if (len && memcmp(pm1, pm2, len)) 2664eea345dSchristos return FALSE; 2674eea345dSchristos 2684eea345dSchristos /* 4th check: compare last incomplete byte, if any */ 2694eea345dSchristos if (msk && ((pm1[len] ^ pm2[len]) & msk)) 2704eea345dSchristos return FALSE; 2714eea345dSchristos 2724eea345dSchristos /* If none of the above failed, we're successfully through. */ 2734eea345dSchristos return TRUE; 2744eea345dSchristos } 275abb0f93cSkardel 276abb0f93cSkardel /* 277abb0f93cSkardel * init_auth - initialize internal data 278abb0f93cSkardel */ 279abb0f93cSkardel void 280abb0f93cSkardel init_auth(void) 281abb0f93cSkardel { 2822950cc38Schristos size_t newalloc; 2832950cc38Schristos 284abb0f93cSkardel /* 285abb0f93cSkardel * Initialize hash table and free list 286abb0f93cSkardel */ 2872950cc38Schristos newalloc = authhashbuckets * sizeof(key_hash[0]); 2882950cc38Schristos 289*eabc0478Schristos key_hash = emalloc_zero(newalloc); 2902950cc38Schristos 2912950cc38Schristos INIT_DLIST(key_listhead, llink); 2922950cc38Schristos 2932950cc38Schristos #ifdef DEBUG 2942950cc38Schristos atexit(&free_auth_mem); 2952950cc38Schristos #endif 2962950cc38Schristos } 2972950cc38Schristos 2982950cc38Schristos 2992950cc38Schristos /* 3002950cc38Schristos * free_auth_mem - assist in leak detection by freeing all dynamic 3012950cc38Schristos * allocations from this module. 3022950cc38Schristos */ 3032950cc38Schristos #ifdef DEBUG 3042950cc38Schristos static void 3052950cc38Schristos free_auth_mem(void) 3062950cc38Schristos { 3072950cc38Schristos symkey * sk; 3082950cc38Schristos symkey_alloc * alloc; 3092950cc38Schristos symkey_alloc * next_alloc; 3102950cc38Schristos 3112950cc38Schristos while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) { 31268dbbb44Schristos freesymkey(sk); 3132950cc38Schristos } 3142950cc38Schristos free(key_hash); 3152950cc38Schristos key_hash = NULL; 3162950cc38Schristos cache_keyid = 0; 3172950cc38Schristos cache_flags = 0; 31868dbbb44Schristos cache_keyacclist = NULL; 3192950cc38Schristos for (alloc = authallocs; alloc != NULL; alloc = next_alloc) { 3202950cc38Schristos next_alloc = alloc->link; 3212950cc38Schristos free(alloc->mem); 3222950cc38Schristos } 3232950cc38Schristos authfreekeys = NULL; 3242950cc38Schristos authnumfreekeys = 0; 3252950cc38Schristos } 3262950cc38Schristos #endif /* DEBUG */ 3272950cc38Schristos 3282950cc38Schristos 3292950cc38Schristos /* 3302950cc38Schristos * auth_moremem - get some more free key structures 3312950cc38Schristos */ 3322950cc38Schristos void 3332950cc38Schristos auth_moremem( 3342950cc38Schristos int keycount 3352950cc38Schristos ) 3362950cc38Schristos { 3372950cc38Schristos symkey * sk; 3382950cc38Schristos int i; 3392950cc38Schristos #ifdef DEBUG 3402950cc38Schristos void * base; 3412950cc38Schristos symkey_alloc * allocrec; 3422950cc38Schristos # define MOREMEM_EXTRA_ALLOC (sizeof(*allocrec)) 3432950cc38Schristos #else 3442950cc38Schristos # define MOREMEM_EXTRA_ALLOC (0) 3452950cc38Schristos #endif 3462950cc38Schristos 3472950cc38Schristos i = (keycount > 0) 3482950cc38Schristos ? keycount 3492950cc38Schristos : MEMINC; 350ccc794f0Schristos sk = eallocarrayxz(i, sizeof(*sk), MOREMEM_EXTRA_ALLOC); 3512950cc38Schristos #ifdef DEBUG 3522950cc38Schristos base = sk; 3532950cc38Schristos #endif 3542950cc38Schristos authnumfreekeys += i; 3552950cc38Schristos 3562950cc38Schristos for (; i > 0; i--, sk++) { 3572950cc38Schristos LINK_SLIST(authfreekeys, sk, llink.f); 3582950cc38Schristos } 3592950cc38Schristos 3602950cc38Schristos #ifdef DEBUG 3612950cc38Schristos allocrec = (void *)sk; 3622950cc38Schristos allocrec->mem = base; 3632950cc38Schristos LINK_SLIST(authallocs, allocrec, link); 3642950cc38Schristos #endif 3652950cc38Schristos } 3662950cc38Schristos 3672950cc38Schristos 3682950cc38Schristos /* 3692950cc38Schristos * auth_prealloc_symkeys 3702950cc38Schristos */ 3712950cc38Schristos void 3722950cc38Schristos auth_prealloc_symkeys( 3732950cc38Schristos int keycount 3742950cc38Schristos ) 3752950cc38Schristos { 3762950cc38Schristos int allocated; 3772950cc38Schristos int additional; 3782950cc38Schristos 3792950cc38Schristos allocated = authnumkeys + authnumfreekeys; 3802950cc38Schristos additional = keycount - allocated; 3812950cc38Schristos if (additional > 0) 3822950cc38Schristos auth_moremem(additional); 3832950cc38Schristos auth_resize_hashtable(); 3842950cc38Schristos } 3852950cc38Schristos 3862950cc38Schristos 38768dbbb44Schristos static u_short 38868dbbb44Schristos auth_log2(size_t x) 3892950cc38Schristos { 39068dbbb44Schristos /* 39168dbbb44Schristos ** bithack to calculate floor(log2(x)) 39268dbbb44Schristos ** 39368dbbb44Schristos ** This assumes 39468dbbb44Schristos ** - (sizeof(size_t) is a power of two 39568dbbb44Schristos ** - CHAR_BITS is a power of two 39668dbbb44Schristos ** - returning zero for arguments <= 0 is OK. 39768dbbb44Schristos ** 39868dbbb44Schristos ** Does only shifts, masks and sums in integer arithmetic in 39968dbbb44Schristos ** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for 40068dbbb44Schristos ** 32bit/64bit size_t) 40168dbbb44Schristos */ 40268dbbb44Schristos int s; 40368dbbb44Schristos int r = 0; 40468dbbb44Schristos size_t m = ~(size_t)0; 40568dbbb44Schristos 40668dbbb44Schristos for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) { 40768dbbb44Schristos m <<= s; 40868dbbb44Schristos if (x & m) 40968dbbb44Schristos r += s; 41068dbbb44Schristos else 41168dbbb44Schristos x <<= s; 41268dbbb44Schristos } 41368dbbb44Schristos return (u_short)r; 41468dbbb44Schristos } 41568dbbb44Schristos 4164eea345dSchristos int/*BOOL*/ 4174eea345dSchristos ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *, 4184eea345dSchristos unsigned int mbits); 4194eea345dSchristos 42068dbbb44Schristos static void 42168dbbb44Schristos authcache_flush_id( 42268dbbb44Schristos keyid_t id 42368dbbb44Schristos ) 42468dbbb44Schristos { 42568dbbb44Schristos if (cache_keyid == id) { 42668dbbb44Schristos cache_keyid = 0; 42768dbbb44Schristos cache_type = 0; 42868dbbb44Schristos cache_flags = 0; 42968dbbb44Schristos cache_secret = NULL; 43068dbbb44Schristos cache_secretsize = 0; 43168dbbb44Schristos cache_keyacclist = NULL; 43268dbbb44Schristos } 4332950cc38Schristos } 4342950cc38Schristos 4352950cc38Schristos 4362950cc38Schristos /* 4372950cc38Schristos * auth_resize_hashtable 4382950cc38Schristos * 4392950cc38Schristos * Size hash table to average 4 or fewer entries per bucket initially, 4402950cc38Schristos * within the bounds of at least 4 and no more than 15 bits for the hash 4412950cc38Schristos * table index. Populate the hash table. 4422950cc38Schristos */ 4432950cc38Schristos static void 4442950cc38Schristos auth_resize_hashtable(void) 4452950cc38Schristos { 4462950cc38Schristos u_long totalkeys; 4472950cc38Schristos u_short hashbits; 4482950cc38Schristos u_short hash; 4492950cc38Schristos size_t newalloc; 4502950cc38Schristos symkey * sk; 4512950cc38Schristos 4522950cc38Schristos totalkeys = authnumkeys + authnumfreekeys; 45368dbbb44Schristos hashbits = auth_log2(totalkeys / 4) + 1; 4542950cc38Schristos hashbits = max(4, hashbits); 4552950cc38Schristos hashbits = min(15, hashbits); 4562950cc38Schristos 4572950cc38Schristos authhashbuckets = 1 << hashbits; 4582950cc38Schristos authhashmask = authhashbuckets - 1; 4592950cc38Schristos newalloc = authhashbuckets * sizeof(key_hash[0]); 4602950cc38Schristos 4612950cc38Schristos key_hash = erealloc(key_hash, newalloc); 462*eabc0478Schristos zero_mem(key_hash, newalloc); 4632950cc38Schristos 4642950cc38Schristos ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 4652950cc38Schristos hash = KEYHASH(sk->keyid); 4662950cc38Schristos LINK_SLIST(key_hash[hash], sk, hlink); 4672950cc38Schristos ITER_DLIST_END() 4682950cc38Schristos } 4692950cc38Schristos 4702950cc38Schristos 4712950cc38Schristos /* 4722950cc38Schristos * allocsymkey - common code to allocate and link in symkey 4732950cc38Schristos * 4742950cc38Schristos * secret must be allocated with a free-compatible allocator. It is 4752950cc38Schristos * owned by the referring symkey structure, and will be free()d by 4762950cc38Schristos * freesymkey(). 4772950cc38Schristos */ 4782950cc38Schristos static void 4792950cc38Schristos allocsymkey( 4802950cc38Schristos keyid_t id, 4812950cc38Schristos u_short flags, 4822950cc38Schristos u_short type, 4832950cc38Schristos u_long lifetime, 48468dbbb44Schristos size_t secretsize, 48568dbbb44Schristos u_char * secret, 48668dbbb44Schristos KeyAccT * ka 4872950cc38Schristos ) 4882950cc38Schristos { 4892950cc38Schristos symkey * sk; 49068dbbb44Schristos symkey ** bucket; 49168dbbb44Schristos 49268dbbb44Schristos bucket = &key_hash[KEYHASH(id)]; 49368dbbb44Schristos 4942950cc38Schristos 4952950cc38Schristos if (authnumfreekeys < 1) 4962950cc38Schristos auth_moremem(-1); 4972950cc38Schristos UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f); 4982950cc38Schristos DEBUG_ENSURE(sk != NULL); 4992950cc38Schristos sk->keyid = id; 5002950cc38Schristos sk->flags = flags; 5012950cc38Schristos sk->type = type; 5022950cc38Schristos sk->secretsize = secretsize; 5032950cc38Schristos sk->secret = secret; 50468dbbb44Schristos sk->keyacclist = ka; 5052950cc38Schristos sk->lifetime = lifetime; 5062950cc38Schristos LINK_SLIST(*bucket, sk, hlink); 5072950cc38Schristos LINK_TAIL_DLIST(key_listhead, sk, llink); 5082950cc38Schristos authnumfreekeys--; 5092950cc38Schristos authnumkeys++; 5102950cc38Schristos } 5112950cc38Schristos 5122950cc38Schristos 5132950cc38Schristos /* 5142950cc38Schristos * freesymkey - common code to remove a symkey and recycle its entry. 5152950cc38Schristos */ 5162950cc38Schristos static void 5172950cc38Schristos freesymkey( 51868dbbb44Schristos symkey * sk 5192950cc38Schristos ) 5202950cc38Schristos { 52168dbbb44Schristos symkey ** bucket; 5222950cc38Schristos symkey * unlinked; 5232950cc38Schristos 52468dbbb44Schristos if (NULL == sk) 52568dbbb44Schristos return; 52668dbbb44Schristos 52768dbbb44Schristos authcache_flush_id(sk->keyid); 52868dbbb44Schristos keyacc_all_free(sk->keyacclist); 52968dbbb44Schristos 53068dbbb44Schristos bucket = &key_hash[KEYHASH(sk->keyid)]; 5312950cc38Schristos if (sk->secret != NULL) { 532*eabc0478Schristos zero_mem(sk->secret, sk->secretsize); 5332950cc38Schristos free(sk->secret); 5342950cc38Schristos } 5352950cc38Schristos UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey); 5362950cc38Schristos DEBUG_ENSURE(sk == unlinked); 5372950cc38Schristos UNLINK_DLIST(sk, llink); 538*eabc0478Schristos zero_mem((char *)sk + offsetof(symkey, symkey_payload), 5392950cc38Schristos sizeof(*sk) - offsetof(symkey, symkey_payload)); 5402950cc38Schristos LINK_SLIST(authfreekeys, sk, llink.f); 5412950cc38Schristos authnumkeys--; 5422950cc38Schristos authnumfreekeys++; 543abb0f93cSkardel } 544abb0f93cSkardel 545abb0f93cSkardel 546abb0f93cSkardel /* 547abb0f93cSkardel * auth_findkey - find a key in the hash table 548abb0f93cSkardel */ 549abb0f93cSkardel struct savekey * 550abb0f93cSkardel auth_findkey( 5512950cc38Schristos keyid_t id 552abb0f93cSkardel ) 553abb0f93cSkardel { 5542950cc38Schristos symkey * sk; 555abb0f93cSkardel 55668dbbb44Schristos for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) 55768dbbb44Schristos if (id == sk->keyid) 5582950cc38Schristos return sk; 5592950cc38Schristos return NULL; 560abb0f93cSkardel } 561abb0f93cSkardel 562abb0f93cSkardel 563abb0f93cSkardel /* 56468dbbb44Schristos * auth_havekey - return TRUE if the key id is zero or known. The 56568dbbb44Schristos * key needs not to be trusted. 566abb0f93cSkardel */ 567abb0f93cSkardel int 568abb0f93cSkardel auth_havekey( 5692950cc38Schristos keyid_t id 570abb0f93cSkardel ) 571abb0f93cSkardel { 57268dbbb44Schristos return 57368dbbb44Schristos (0 == id) || 57468dbbb44Schristos (cache_keyid == id) || 57568dbbb44Schristos (NULL != auth_findkey(id)); 576abb0f93cSkardel } 577abb0f93cSkardel 578abb0f93cSkardel 579abb0f93cSkardel /* 5802950cc38Schristos * authhavekey - return TRUE and cache the key, if zero or both known 5812950cc38Schristos * and trusted. 582abb0f93cSkardel */ 583abb0f93cSkardel int 584abb0f93cSkardel authhavekey( 5852950cc38Schristos keyid_t id 586abb0f93cSkardel ) 587abb0f93cSkardel { 5882950cc38Schristos symkey * sk; 589abb0f93cSkardel 590abb0f93cSkardel authkeylookups++; 59168dbbb44Schristos if (0 == id || cache_keyid == id) 59268dbbb44Schristos return !!(KEY_TRUSTED & cache_flags); 593abb0f93cSkardel 594abb0f93cSkardel /* 59568dbbb44Schristos * Search the bin for the key. If not found, or found but the key 59668dbbb44Schristos * type is zero, somebody marked it trusted without specifying a 59768dbbb44Schristos * key or key type. In this case consider the key missing. 598abb0f93cSkardel */ 599abb0f93cSkardel authkeyuncached++; 60068dbbb44Schristos sk = auth_findkey(id); 60168dbbb44Schristos if ((sk == NULL) || (sk->type == 0)) { 602abb0f93cSkardel authkeynotfound++; 6032950cc38Schristos return FALSE; 604abb0f93cSkardel } 605abb0f93cSkardel 606abb0f93cSkardel /* 60768dbbb44Schristos * If the key is not trusted, the key is not considered found. 608abb0f93cSkardel */ 6092950cc38Schristos if ( ! (KEY_TRUSTED & sk->flags)) { 610abb0f93cSkardel authnokey++; 6112950cc38Schristos return FALSE; 612abb0f93cSkardel } 613abb0f93cSkardel 614abb0f93cSkardel /* 615abb0f93cSkardel * The key is found and trusted. Initialize the key cache. 616*eabc0478Schristos * The cache really should be a struct savekey to streamline 617*eabc0478Schristos * this code. Using a sk pointer would be even faster but more 618*eabc0478Schristos * fragile around pointing to freed memory. 619abb0f93cSkardel */ 620abb0f93cSkardel cache_keyid = sk->keyid; 621abb0f93cSkardel cache_type = sk->type; 622abb0f93cSkardel cache_flags = sk->flags; 6232950cc38Schristos cache_secret = sk->secret; 6242950cc38Schristos cache_secretsize = sk->secretsize; 62568dbbb44Schristos cache_keyacclist = sk->keyacclist; 626abb0f93cSkardel 6272950cc38Schristos return TRUE; 628abb0f93cSkardel } 629abb0f93cSkardel 630abb0f93cSkardel 631abb0f93cSkardel /* 632abb0f93cSkardel * authtrust - declare a key to be trusted/untrusted 633abb0f93cSkardel */ 634abb0f93cSkardel void 635abb0f93cSkardel authtrust( 6362950cc38Schristos keyid_t id, 637abb0f93cSkardel u_long trust 638abb0f93cSkardel ) 639abb0f93cSkardel { 6402950cc38Schristos symkey * sk; 6412950cc38Schristos u_long lifetime; 642abb0f93cSkardel 643abb0f93cSkardel /* 644abb0f93cSkardel * Search bin for key; if it does not exist and is untrusted, 645abb0f93cSkardel * forget it. 646abb0f93cSkardel */ 64768dbbb44Schristos 64868dbbb44Schristos sk = auth_findkey(id); 64968dbbb44Schristos if (!trust && sk == NULL) 650abb0f93cSkardel return; 651abb0f93cSkardel 652abb0f93cSkardel /* 653abb0f93cSkardel * There are two conditions remaining. Either it does not 654abb0f93cSkardel * exist and is to be trusted or it does exist and is or is 655abb0f93cSkardel * not to be trusted. 656abb0f93cSkardel */ 6572950cc38Schristos if (sk != NULL) { 658abb0f93cSkardel /* 65968dbbb44Schristos * Key exists. If it is to be trusted, say so and update 66068dbbb44Schristos * its lifetime. If no longer trusted, return it to the 66168dbbb44Schristos * free list. Flush the cache first to be sure there are 66268dbbb44Schristos * no discrepancies. 663abb0f93cSkardel */ 66468dbbb44Schristos authcache_flush_id(id); 665abb0f93cSkardel if (trust > 0) { 666abb0f93cSkardel sk->flags |= KEY_TRUSTED; 667abb0f93cSkardel if (trust > 1) 668abb0f93cSkardel sk->lifetime = current_time + trust; 669abb0f93cSkardel else 670abb0f93cSkardel sk->lifetime = 0; 67168dbbb44Schristos } else { 67268dbbb44Schristos freesymkey(sk); 673abb0f93cSkardel } 674abb0f93cSkardel return; 675abb0f93cSkardel } 676abb0f93cSkardel 677abb0f93cSkardel /* 6782950cc38Schristos * keyid is not present, but the is to be trusted. We allocate 6792950cc38Schristos * a new key, but do not specify a key type or secret. 680abb0f93cSkardel */ 6812950cc38Schristos if (trust > 1) { 6822950cc38Schristos lifetime = current_time + trust; 6832950cc38Schristos } else { 6842950cc38Schristos lifetime = 0; 6852950cc38Schristos } 68668dbbb44Schristos allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL); 687abb0f93cSkardel } 688abb0f93cSkardel 689abb0f93cSkardel 690abb0f93cSkardel /* 691abb0f93cSkardel * authistrusted - determine whether a key is trusted 692abb0f93cSkardel */ 693abb0f93cSkardel int 694abb0f93cSkardel authistrusted( 69568dbbb44Schristos keyid_t id 696abb0f93cSkardel ) 697abb0f93cSkardel { 6982950cc38Schristos symkey * sk; 699abb0f93cSkardel 70068dbbb44Schristos if (id == cache_keyid) 7012950cc38Schristos return !!(KEY_TRUSTED & cache_flags); 702abb0f93cSkardel 703abb0f93cSkardel authkeyuncached++; 70468dbbb44Schristos sk = auth_findkey(id); 70568dbbb44Schristos if (sk == NULL || !(KEY_TRUSTED & sk->flags)) { 706abb0f93cSkardel authkeynotfound++; 7072950cc38Schristos return FALSE; 708abb0f93cSkardel } 7092950cc38Schristos return TRUE; 710abb0f93cSkardel } 711abb0f93cSkardel 71268dbbb44Schristos 71368dbbb44Schristos /* 71468dbbb44Schristos * authistrustedip - determine if the IP is OK for the keyid 71568dbbb44Schristos */ 71668dbbb44Schristos int 71768dbbb44Schristos authistrustedip( 71868dbbb44Schristos keyid_t keyno, 71968dbbb44Schristos sockaddr_u * sau 72068dbbb44Schristos ) 72168dbbb44Schristos { 72268dbbb44Schristos symkey * sk; 72368dbbb44Schristos 72468dbbb44Schristos if (keyno == cache_keyid) { 72568dbbb44Schristos return (KEY_TRUSTED & cache_flags) && 72668dbbb44Schristos keyacc_contains(cache_keyacclist, sau, TRUE); 7274eea345dSchristos } 7284eea345dSchristos 7294eea345dSchristos if (NULL != (sk = auth_findkey(keyno))) { 73068dbbb44Schristos authkeyuncached++; 73168dbbb44Schristos return (KEY_TRUSTED & sk->flags) && 73268dbbb44Schristos keyacc_contains(sk->keyacclist, sau, TRUE); 73368dbbb44Schristos } 7344eea345dSchristos 7354eea345dSchristos authkeynotfound++; 7364eea345dSchristos return FALSE; 73768dbbb44Schristos } 73868dbbb44Schristos 7398b8da087Schristos /* Note: There are two locations below where 'strncpy()' is used. While 7408b8da087Schristos * this function is a hazard by itself, it's essential that it is used 7418b8da087Schristos * here. Bug 1243 involved that the secret was filled with NUL bytes 7428b8da087Schristos * after the first NUL encountered, and 'strlcpy()' simply does NOT have 7438b8da087Schristos * this behaviour. So disabling the fix and reverting to the buggy 7448b8da087Schristos * behaviour due to compatibility issues MUST also fill with NUL and 7458b8da087Schristos * this needs 'strncpy'. Also, the secret is managed as a byte blob of a 7468b8da087Schristos * given size, and eventually truncating it and replacing the last byte 7478b8da087Schristos * with a NUL would be a bug. 7488b8da087Schristos * perlinger@ntp.org 2015-10-10 7498b8da087Schristos */ 750abb0f93cSkardel void 751abb0f93cSkardel MD5auth_setkey( 752abb0f93cSkardel keyid_t keyno, 753abb0f93cSkardel int keytype, 754abb0f93cSkardel const u_char *key, 75568dbbb44Schristos size_t secretsize, 75668dbbb44Schristos KeyAccT *ka 757abb0f93cSkardel ) 758abb0f93cSkardel { 7592950cc38Schristos symkey * sk; 7602950cc38Schristos u_char * secret; 761abb0f93cSkardel 7622950cc38Schristos DEBUG_ENSURE(keytype <= USHRT_MAX); 76368dbbb44Schristos DEBUG_ENSURE(secretsize < 4 * 1024); 764abb0f93cSkardel /* 765abb0f93cSkardel * See if we already have the key. If so just stick in the 766abb0f93cSkardel * new value. 767abb0f93cSkardel */ 76868dbbb44Schristos sk = auth_findkey(keyno); 76968dbbb44Schristos if (sk != NULL && keyno == sk->keyid) { 770af12ab5eSchristos /* TALOS-CAN-0054: make sure we have a new buffer! */ 771af12ab5eSchristos if (NULL != sk->secret) { 772af12ab5eSchristos memset(sk->secret, 0, sk->secretsize); 773af12ab5eSchristos free(sk->secret); 774af12ab5eSchristos } 77568dbbb44Schristos sk->secret = emalloc(secretsize + 1); 7762950cc38Schristos sk->type = (u_short)keytype; 77768dbbb44Schristos sk->secretsize = secretsize; 77868dbbb44Schristos /* make sure access lists don't leak here! */ 77968dbbb44Schristos if (ka != sk->keyacclist) { 78068dbbb44Schristos keyacc_all_free(sk->keyacclist); 78168dbbb44Schristos sk->keyacclist = ka; 78268dbbb44Schristos } 783abb0f93cSkardel #ifndef DISABLE_BUG1243_FIX 7842950cc38Schristos memcpy(sk->secret, key, secretsize); 785abb0f93cSkardel #else 7868b8da087Schristos /* >MUST< use 'strncpy()' here! See above! */ 7878b8da087Schristos strncpy((char *)sk->secret, (const char *)key, 7882950cc38Schristos secretsize); 789abb0f93cSkardel #endif 79068dbbb44Schristos authcache_flush_id(keyno); 791abb0f93cSkardel return; 792abb0f93cSkardel } 793abb0f93cSkardel 794abb0f93cSkardel /* 795abb0f93cSkardel * Need to allocate new structure. Do it. 796abb0f93cSkardel */ 79768dbbb44Schristos secret = emalloc(secretsize + 1); 798abb0f93cSkardel #ifndef DISABLE_BUG1243_FIX 7992950cc38Schristos memcpy(secret, key, secretsize); 800abb0f93cSkardel #else 8018b8da087Schristos /* >MUST< use 'strncpy()' here! See above! */ 8028b8da087Schristos strncpy((char *)secret, (const char *)key, secretsize); 803abb0f93cSkardel #endif 80468dbbb44Schristos allocsymkey(keyno, 0, (u_short)keytype, 0, 80568dbbb44Schristos secretsize, secret, ka); 806abb0f93cSkardel #ifdef DEBUG 807*eabc0478Schristos if (debug >= 1) { 8082950cc38Schristos size_t j; 809abb0f93cSkardel 8102950cc38Schristos printf("auth_setkey: key %d type %d len %d ", (int)keyno, 8112950cc38Schristos keytype, (int)secretsize); 81268dbbb44Schristos for (j = 0; j < secretsize; j++) { 8132950cc38Schristos printf("%02x", secret[j]); 81468dbbb44Schristos } 815abb0f93cSkardel printf("\n"); 816abb0f93cSkardel } 817abb0f93cSkardel #endif 818abb0f93cSkardel } 819abb0f93cSkardel 820abb0f93cSkardel 821abb0f93cSkardel /* 8222950cc38Schristos * auth_delkeys - delete non-autokey untrusted keys, and clear all info 8232950cc38Schristos * except the trusted bit of non-autokey trusted keys, in 8242950cc38Schristos * preparation for rereading the keys file. 825abb0f93cSkardel */ 826abb0f93cSkardel void 827abb0f93cSkardel auth_delkeys(void) 828abb0f93cSkardel { 8292950cc38Schristos symkey * sk; 830abb0f93cSkardel 8312950cc38Schristos ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 8322950cc38Schristos if (sk->keyid > NTP_MAXKEY) { /* autokey */ 8332950cc38Schristos continue; 8342950cc38Schristos } 8352950cc38Schristos 836abb0f93cSkardel /* 837af12ab5eSchristos * Don't lose info as to which keys are trusted. Make 838af12ab5eSchristos * sure there are no dangling pointers! 839abb0f93cSkardel */ 8402950cc38Schristos if (KEY_TRUSTED & sk->flags) { 8412950cc38Schristos if (sk->secret != NULL) { 842*eabc0478Schristos zero_mem(sk->secret, sk->secretsize); 8432950cc38Schristos free(sk->secret); 844af12ab5eSchristos sk->secret = NULL; /* TALOS-CAN-0054 */ 8452950cc38Schristos } 84668dbbb44Schristos sk->keyacclist = keyacc_all_free(sk->keyacclist); 8472950cc38Schristos sk->secretsize = 0; 848abb0f93cSkardel sk->lifetime = 0; 849abb0f93cSkardel } else { 85068dbbb44Schristos freesymkey(sk); 851abb0f93cSkardel } 8522950cc38Schristos ITER_DLIST_END() 853abb0f93cSkardel } 8542950cc38Schristos 855abb0f93cSkardel 856abb0f93cSkardel /* 857abb0f93cSkardel * auth_agekeys - delete keys whose lifetimes have expired 858abb0f93cSkardel */ 859abb0f93cSkardel void 860abb0f93cSkardel auth_agekeys(void) 861abb0f93cSkardel { 8622950cc38Schristos symkey * sk; 863abb0f93cSkardel 8642950cc38Schristos ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 8652950cc38Schristos if (sk->lifetime > 0 && current_time > sk->lifetime) { 86668dbbb44Schristos freesymkey(sk); 867abb0f93cSkardel authkeyexpired++; 868abb0f93cSkardel } 8692950cc38Schristos ITER_DLIST_END() 8702950cc38Schristos DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n", 8712950cc38Schristos current_time, authnumkeys, authkeyexpired)); 872abb0f93cSkardel } 8732950cc38Schristos 874abb0f93cSkardel 875abb0f93cSkardel /* 876abb0f93cSkardel * authencrypt - generate message authenticator 877abb0f93cSkardel * 878abb0f93cSkardel * Returns length of authenticator field, zero if key not found. 879abb0f93cSkardel */ 8808b8da087Schristos size_t 881abb0f93cSkardel authencrypt( 882abb0f93cSkardel keyid_t keyno, 883abb0f93cSkardel u_int32 * pkt, 8848b8da087Schristos size_t length 885abb0f93cSkardel ) 8868b8da087Schristos { 887abb0f93cSkardel /* 888abb0f93cSkardel * A zero key identifier means the sender has not verified 889abb0f93cSkardel * the last message was correctly authenticated. The MAC 890abb0f93cSkardel * consists of a single word with value zero. 891abb0f93cSkardel */ 892abb0f93cSkardel authencryptions++; 893*eabc0478Schristos pkt[length / KEY_MAC_LEN] = htonl(keyno); 8942950cc38Schristos if (0 == keyno) { 895*eabc0478Schristos return KEY_MAC_LEN; 896abb0f93cSkardel } 8972950cc38Schristos if (!authhavekey(keyno)) { 8982950cc38Schristos return 0; 8992950cc38Schristos } 900abb0f93cSkardel 9014eea345dSchristos return MD5authencrypt(cache_type, 9024eea345dSchristos cache_secret, cache_secretsize, 9034eea345dSchristos pkt, length); 904abb0f93cSkardel } 905abb0f93cSkardel 9062950cc38Schristos 907abb0f93cSkardel /* 908abb0f93cSkardel * authdecrypt - verify message authenticator 909abb0f93cSkardel * 9102950cc38Schristos * Returns TRUE if authenticator valid, FALSE if invalid or not found. 911abb0f93cSkardel */ 912abb0f93cSkardel int 913abb0f93cSkardel authdecrypt( 914abb0f93cSkardel keyid_t keyno, 915abb0f93cSkardel u_int32 * pkt, 9168b8da087Schristos size_t length, 9178b8da087Schristos size_t size 918abb0f93cSkardel ) 919abb0f93cSkardel { 920abb0f93cSkardel /* 921abb0f93cSkardel * A zero key identifier means the sender has not verified 9222950cc38Schristos * the last message was correctly authenticated. For our 9232950cc38Schristos * purpose this is an invalid authenticator. 924abb0f93cSkardel */ 925abb0f93cSkardel authdecryptions++; 9262950cc38Schristos if (0 == keyno || !authhavekey(keyno) || size < 4) { 9272950cc38Schristos return FALSE; 9282950cc38Schristos } 929abb0f93cSkardel 9304eea345dSchristos return MD5authdecrypt(cache_type, 9314eea345dSchristos cache_secret, cache_secretsize, 932*eabc0478Schristos pkt, length, size, keyno); 933*eabc0478Schristos } 934*eabc0478Schristos 935*eabc0478Schristos 936*eabc0478Schristos /* password decoding helpers */ 937*eabc0478Schristos static size_t 938*eabc0478Schristos pwdecode_plain( 939*eabc0478Schristos u_char * dst, 940*eabc0478Schristos size_t dstlen, 941*eabc0478Schristos const char * src 942*eabc0478Schristos ) 943*eabc0478Schristos { 944*eabc0478Schristos size_t srclen = strlen(src); 945*eabc0478Schristos if (srclen > dstlen) { 946*eabc0478Schristos errno = ENOMEM; 947*eabc0478Schristos return (size_t)-1; 948*eabc0478Schristos } 949*eabc0478Schristos memcpy(dst, src, srclen); 950*eabc0478Schristos return srclen; 951*eabc0478Schristos } 952*eabc0478Schristos 953*eabc0478Schristos static size_t 954*eabc0478Schristos pwdecode_hex( 955*eabc0478Schristos u_char * dst, 956*eabc0478Schristos size_t dstlen, 957*eabc0478Schristos const char * src 958*eabc0478Schristos ) 959*eabc0478Schristos { 960*eabc0478Schristos static const char hex[] = "00112233445566778899AaBbCcDdEeFf"; 961*eabc0478Schristos 962*eabc0478Schristos size_t srclen = strlen(src); 963*eabc0478Schristos size_t reslen = (srclen >> 1) + (srclen & 1); 964*eabc0478Schristos u_char tmp; 965*eabc0478Schristos char *ptr; 966*eabc0478Schristos size_t j; 967*eabc0478Schristos 968*eabc0478Schristos if (reslen > dstlen) { 969*eabc0478Schristos errno = ENOMEM; 970*eabc0478Schristos reslen = (size_t)-1; 971*eabc0478Schristos } else { 972*eabc0478Schristos for (j = 0; j < srclen; ++j) { 973*eabc0478Schristos tmp = *(const unsigned char*)(src + j); 974*eabc0478Schristos ptr = strchr(hex, tmp); 975*eabc0478Schristos if (ptr == NULL) { 976*eabc0478Schristos errno = EINVAL; 977*eabc0478Schristos reslen = (size_t)-1; 978*eabc0478Schristos break; 979*eabc0478Schristos } 980*eabc0478Schristos tmp = (u_char)((ptr - hex) >> 1); 981*eabc0478Schristos if (j & 1) 982*eabc0478Schristos dst[j >> 1] |= tmp; 983*eabc0478Schristos else 984*eabc0478Schristos dst[j >> 1] = tmp << 4; 985*eabc0478Schristos } 986*eabc0478Schristos } 987*eabc0478Schristos return reslen; 988*eabc0478Schristos } 989*eabc0478Schristos /* 990*eabc0478Schristos * authdecodepw - decode plaintext or hex-encoded password to binary 991*eabc0478Schristos * secret. Returns size of secret in bytes or -1 on error. 992*eabc0478Schristos */ 993*eabc0478Schristos size_t 994*eabc0478Schristos authdecodepw( 995*eabc0478Schristos u_char * dst, 996*eabc0478Schristos size_t dstlen, 997*eabc0478Schristos const char * src, 998*eabc0478Schristos enum AuthPwdEnc enc 999*eabc0478Schristos ) 1000*eabc0478Schristos { 1001*eabc0478Schristos size_t reslen; 1002*eabc0478Schristos 1003*eabc0478Schristos if ( !(dst && dstlen && src)) { 1004*eabc0478Schristos errno = EINVAL; 1005*eabc0478Schristos reslen = (size_t)-1; 1006*eabc0478Schristos } else { 1007*eabc0478Schristos switch (enc) { 1008*eabc0478Schristos case AUTHPWD_UNSPEC: 1009*eabc0478Schristos if (strlen(src) <= 20) 1010*eabc0478Schristos reslen = pwdecode_plain(dst, dstlen, src); 1011*eabc0478Schristos else 1012*eabc0478Schristos reslen = pwdecode_hex(dst, dstlen, src); 1013*eabc0478Schristos break; 1014*eabc0478Schristos case AUTHPWD_PLAIN: 1015*eabc0478Schristos reslen = pwdecode_plain(dst, dstlen, src); 1016*eabc0478Schristos break; 1017*eabc0478Schristos case AUTHPWD_HEX: 1018*eabc0478Schristos reslen = pwdecode_hex(dst, dstlen, src); 1019*eabc0478Schristos break; 1020*eabc0478Schristos default: 1021*eabc0478Schristos errno = EINVAL; 1022*eabc0478Schristos reslen = (size_t)-1; 1023*eabc0478Schristos } 1024*eabc0478Schristos } 1025*eabc0478Schristos return reslen; 1026abb0f93cSkardel } 1027