17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*a87701e9SGary Mills * Copyright 2015 Gary Mills 247c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * DESCRIPTION: Contains utilities relating to TTL calculation. 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate #include <unistd.h> 327c478bd9Sstevel@tonic-gate #include <syslog.h> 337c478bd9Sstevel@tonic-gate #include <errno.h> 347c478bd9Sstevel@tonic-gate #include <strings.h> 357c478bd9Sstevel@tonic-gate #include <ndbm.h> 367c478bd9Sstevel@tonic-gate #include "ypsym.h" 377c478bd9Sstevel@tonic-gate #include "ypdefs.h" 387c478bd9Sstevel@tonic-gate #include "shim.h" 397c478bd9Sstevel@tonic-gate #include "yptol.h" 407c478bd9Sstevel@tonic-gate #include "../ldap_util.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * Constants used in time calculations 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate #define MILLION 1000000 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* 487c478bd9Sstevel@tonic-gate * Decs 497c478bd9Sstevel@tonic-gate */ 507c478bd9Sstevel@tonic-gate suc_code is_greater_timeval(struct timeval *, struct timeval *); 517c478bd9Sstevel@tonic-gate suc_code add_to_timeval(struct timeval *, int); 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 547c478bd9Sstevel@tonic-gate * FUNCTION: has_entry_expired() 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * DESCRIPTION: Determines if an individual entry has expired. 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * INPUTS: Map control structure for an open map 597c478bd9Sstevel@tonic-gate * Entry key 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * OUTPUTS: TRUE = Entry has expired or cannot be found this will cause 627c478bd9Sstevel@tonic-gate * missing entries to be pulled out of the DIT. 637c478bd9Sstevel@tonic-gate * FALSE = Entry has not expired 647c478bd9Sstevel@tonic-gate * 657c478bd9Sstevel@tonic-gate */ 667c478bd9Sstevel@tonic-gate bool_t 677c478bd9Sstevel@tonic-gate has_entry_expired(map_ctrl *map, datum *key) 687c478bd9Sstevel@tonic-gate { 697c478bd9Sstevel@tonic-gate datum ttl; 707c478bd9Sstevel@tonic-gate struct timeval now; 717c478bd9Sstevel@tonic-gate struct timeval old_time; 727c478bd9Sstevel@tonic-gate char *key_name; 737c478bd9Sstevel@tonic-gate char *myself = "has_entry_expired"; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate if ((map == NULL) || (map->ttl == NULL)) 767c478bd9Sstevel@tonic-gate return (FALSE); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* Get expiry time entry for key */ 797c478bd9Sstevel@tonic-gate ttl = dbm_fetch(map->ttl, *key); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate if (NULL == ttl.dptr) { 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * If we failed to get a map expiry key, which must always be 847c478bd9Sstevel@tonic-gate * present, then something is seriously wrong. Try to recreate 857c478bd9Sstevel@tonic-gate * the map. 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate if ((key->dsize == strlen(MAP_EXPIRY_KEY)) && 887c478bd9Sstevel@tonic-gate (0 == strncmp(key->dptr, MAP_EXPIRY_KEY, key->dsize))) { 897c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, "Cannot find %s TTL " 907c478bd9Sstevel@tonic-gate "for map %s. Will attempt to recreate map", 917c478bd9Sstevel@tonic-gate MAP_EXPIRY_KEY, map->map_name); 927c478bd9Sstevel@tonic-gate return (TRUE); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * Not a problem just no TTL entry for this entry. Maybe it has 977c478bd9Sstevel@tonic-gate * not yet been downloaded. Maybe it will be handled by a 987c478bd9Sstevel@tonic-gate * service other than NIS. Check if the entire map has expired. 997c478bd9Sstevel@tonic-gate * This prevents repeated LDAP reads when requests are made for 1007c478bd9Sstevel@tonic-gate * nonexistant entries. 1017c478bd9Sstevel@tonic-gate */ 1027c478bd9Sstevel@tonic-gate if (has_map_expired(map)) { 1037c478bd9Sstevel@tonic-gate /* Kick of a map update */ 1047c478bd9Sstevel@tonic-gate update_map_if_required(map, FALSE); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* Don't update the entry */ 1087c478bd9Sstevel@tonic-gate return (FALSE); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate if (ttl.dsize != sizeof (struct timeval)) { 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Need to malloc some memory before can syslog the key name 1147c478bd9Sstevel@tonic-gate * but this may fail. Solution log a simple message first THEn 1157c478bd9Sstevel@tonic-gate * a more detailed one if it works. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 1187c478bd9Sstevel@tonic-gate "Invalid TTL key in map %s. error %d", 1197c478bd9Sstevel@tonic-gate map->map_name, dbm_error(map->ttl)); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* Log the key name */ 1227c478bd9Sstevel@tonic-gate key_name = (char *)am(myself, key->dsize + 1); 1237c478bd9Sstevel@tonic-gate if (NULL == key_name) { 1247c478bd9Sstevel@tonic-gate logmsg(MSG_NOMEM, LOG_ERR, 1257c478bd9Sstevel@tonic-gate "Could not alloc memory for keyname"); 1267c478bd9Sstevel@tonic-gate } else { 1277c478bd9Sstevel@tonic-gate strncpy(key_name, key->dptr, key->dsize); 1287c478bd9Sstevel@tonic-gate key_name[key->dsize] = '\0'; 1297c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 1307c478bd9Sstevel@tonic-gate "Key name was %s", key_name); 1317c478bd9Sstevel@tonic-gate sfree(key_name); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate /* Update it Anyway */ 1347c478bd9Sstevel@tonic-gate return (TRUE); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* Get current time */ 1387c478bd9Sstevel@tonic-gate gettimeofday(&now, NULL); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * Because dptr may not be int aligned need to build an int 1427c478bd9Sstevel@tonic-gate * out of what it points to or will get a bus error 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate bcopy(ttl.dptr, &old_time, sizeof (struct timeval)); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate return (is_greater_timeval(&now, &old_time)); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * FUNCTION: has_map_expired() 1517c478bd9Sstevel@tonic-gate * 1527c478bd9Sstevel@tonic-gate * DESCRIPTION: Determines if an entire map has expire 1537c478bd9Sstevel@tonic-gate * 1547c478bd9Sstevel@tonic-gate * INPUTS: Map control structure for an open map 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * OUTPUTS: TRUE = Map has expired 1577c478bd9Sstevel@tonic-gate * FALSE Map has not expired 1587c478bd9Sstevel@tonic-gate * 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate bool_t 1617c478bd9Sstevel@tonic-gate has_map_expired(map_ctrl *map) 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate datum key; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* Set up datum with magic expiry key */ 1667c478bd9Sstevel@tonic-gate key.dsize = strlen(MAP_EXPIRY_KEY); 1677c478bd9Sstevel@tonic-gate key.dptr = MAP_EXPIRY_KEY; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* Call has_entry_expired() with magic map expiry key */ 1707c478bd9Sstevel@tonic-gate return (has_entry_expired(map, &key)); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * FUNCTION: update_entry_ttl() 1757c478bd9Sstevel@tonic-gate * 1767c478bd9Sstevel@tonic-gate * DESCRIPTION: Updates the TTL for one map entry 1777c478bd9Sstevel@tonic-gate * 1787c478bd9Sstevel@tonic-gate * INPUTS: Map control structure for an open map 1797c478bd9Sstevel@tonic-gate * Entry key 1807c478bd9Sstevel@tonic-gate * Flag indication if TTL should be max, min or random 1817c478bd9Sstevel@tonic-gate * 1827c478bd9Sstevel@tonic-gate * OUTPUTS: SUCCESS = TTL updated 1837c478bd9Sstevel@tonic-gate * FAILURE = TTL not updated 1847c478bd9Sstevel@tonic-gate * 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate suc_code 1887c478bd9Sstevel@tonic-gate update_entry_ttl(map_ctrl *map, datum *key, TTL_TYPE type) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate datum expire; 1917c478bd9Sstevel@tonic-gate struct timeval now; 1927c478bd9Sstevel@tonic-gate int ttl; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* Get current time */ 1957c478bd9Sstevel@tonic-gate gettimeofday(&now, NULL); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* Get TTL from mapping file */ 1987c478bd9Sstevel@tonic-gate ttl = get_ttl_value(map, type); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate if (FAILURE == add_to_timeval(&now, ttl)) 2017c478bd9Sstevel@tonic-gate return (FAILURE); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* Convert time into a datum */ 2047c478bd9Sstevel@tonic-gate expire.dsize = sizeof (struct timeval); 2057c478bd9Sstevel@tonic-gate expire.dptr = (char *)&now; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* Set expiry time entry for key */ 2087c478bd9Sstevel@tonic-gate errno = 0; 2097c478bd9Sstevel@tonic-gate if (0 > dbm_store(map->ttl, *key, expire, DBM_REPLACE)) { 2107c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not write TTL entry " 2117c478bd9Sstevel@tonic-gate "(errno=%d)", errno); 2127c478bd9Sstevel@tonic-gate return (FAILURE); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate return (SUCCESS); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * FUNCTION: update_map_ttl() 2207c478bd9Sstevel@tonic-gate * 2217c478bd9Sstevel@tonic-gate * DESCRIPTION: Updates the TTL for entire map. This can be called either with 2227c478bd9Sstevel@tonic-gate * the map open (map_ctrl DBM pointer set up) or the map closed 2237c478bd9Sstevel@tonic-gate * (map_ctrl DBM pointers not set). The latter case will occur 2247c478bd9Sstevel@tonic-gate * when we have just created a new map. 2257c478bd9Sstevel@tonic-gate * 2267c478bd9Sstevel@tonic-gate * This function must open the TTL map but, in either case, must 2277c478bd9Sstevel@tonic-gate * return with the map_ctrl in it's original state. 2287c478bd9Sstevel@tonic-gate * 2297c478bd9Sstevel@tonic-gate * INPUTS: Map control structure for an open map 2307c478bd9Sstevel@tonic-gate * 2317c478bd9Sstevel@tonic-gate * OUTPUTS: SUCCESS = TTL updated 2327c478bd9Sstevel@tonic-gate * FAILURE = TTL not updated 2337c478bd9Sstevel@tonic-gate * 2347c478bd9Sstevel@tonic-gate */ 2357c478bd9Sstevel@tonic-gate suc_code 2367c478bd9Sstevel@tonic-gate update_map_ttl(map_ctrl *map) 2377c478bd9Sstevel@tonic-gate { 2387c478bd9Sstevel@tonic-gate datum key; 2397c478bd9Sstevel@tonic-gate bool_t map_was_open = TRUE; 2407c478bd9Sstevel@tonic-gate suc_code ret; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* Set up datum with magic expiry key */ 2437c478bd9Sstevel@tonic-gate key.dsize = strlen(MAP_EXPIRY_KEY); 2447c478bd9Sstevel@tonic-gate key.dptr = MAP_EXPIRY_KEY; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* If TTL not open open it */ 2477c478bd9Sstevel@tonic-gate if (NULL == map->ttl) { 2487c478bd9Sstevel@tonic-gate map->ttl = dbm_open(map->ttl_path, O_RDWR, 0644); 2497c478bd9Sstevel@tonic-gate if (NULL == map->ttl) 2507c478bd9Sstevel@tonic-gate return (FAILURE); 2517c478bd9Sstevel@tonic-gate map_was_open = FALSE; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* Call update_entry_ttl() with magic map expiry key */ 2557c478bd9Sstevel@tonic-gate ret = update_entry_ttl(map, &key, TTL_MIN); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* If we had to open TTL file close it */ 2587c478bd9Sstevel@tonic-gate if (!map_was_open) { 2597c478bd9Sstevel@tonic-gate dbm_close(map->ttl); 2607c478bd9Sstevel@tonic-gate map->ttl_path = NULL; 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate return (ret); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * FUNCTION: add_to_timeval() 2687c478bd9Sstevel@tonic-gate * 2697c478bd9Sstevel@tonic-gate * DESCRIPTION: Adds an int to a timeval 2707c478bd9Sstevel@tonic-gate * 2717c478bd9Sstevel@tonic-gate * NOTE : Seems strange that there is not a library function to do this 2727c478bd9Sstevel@tonic-gate * if one exists then this function can be removed. 2737c478bd9Sstevel@tonic-gate * 2747c478bd9Sstevel@tonic-gate * NOTE : Does not handle UNIX clock wrap round but this is a much bigger 2757c478bd9Sstevel@tonic-gate * problem. 2767c478bd9Sstevel@tonic-gate * 2777c478bd9Sstevel@tonic-gate * INPUTS: Time value to add to 2787c478bd9Sstevel@tonic-gate * Time value to add in seconds 2797c478bd9Sstevel@tonic-gate * 2807c478bd9Sstevel@tonic-gate * OUTPUTS: SUCCESS = Addition successful 2817c478bd9Sstevel@tonic-gate * FAILURE = Addition failed (probably wrapped) 2827c478bd9Sstevel@tonic-gate * 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate suc_code 2857c478bd9Sstevel@tonic-gate add_to_timeval(struct timeval *t1, int t2) 2867c478bd9Sstevel@tonic-gate { 2877c478bd9Sstevel@tonic-gate struct timeval oldval; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate oldval.tv_sec = t1->tv_sec; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* Add seconds part */ 2927c478bd9Sstevel@tonic-gate t1->tv_sec += t2; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* Check for clock wrap */ 2957c478bd9Sstevel@tonic-gate if (!(t1->tv_sec >= oldval.tv_sec)) { 2967c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 2977c478bd9Sstevel@tonic-gate "Wrap when adding %d to %d", t2, oldval.tv_sec); 2987c478bd9Sstevel@tonic-gate return (FAILURE); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate return (SUCCESS); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * FUNCTION: is_greater_timeval() 3067c478bd9Sstevel@tonic-gate * 3077c478bd9Sstevel@tonic-gate * DESCRIPTION: Compares two timevals 3087c478bd9Sstevel@tonic-gate * 3097c478bd9Sstevel@tonic-gate * NOTE : Seems strange that there is not a library function to do this 3107c478bd9Sstevel@tonic-gate * if one exists then this function can be removed. 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * INPUTS: First time value 3137c478bd9Sstevel@tonic-gate * Time value to compare it with 3147c478bd9Sstevel@tonic-gate * 3157c478bd9Sstevel@tonic-gate * OUTPUTS: TRUE t1 > t2 3167c478bd9Sstevel@tonic-gate * FALSE t1 <= t2 3177c478bd9Sstevel@tonic-gate * 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate suc_code 3207c478bd9Sstevel@tonic-gate is_greater_timeval(struct timeval *t1, struct timeval *t2) 3217c478bd9Sstevel@tonic-gate { 3227c478bd9Sstevel@tonic-gate if (t1->tv_sec > t2->tv_sec) 3237c478bd9Sstevel@tonic-gate return (TRUE); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (t1->tv_sec == t2->tv_sec) { 3267c478bd9Sstevel@tonic-gate if (t1->tv_usec > t2->tv_usec) 3277c478bd9Sstevel@tonic-gate return (TRUE); 3287c478bd9Sstevel@tonic-gate else 3297c478bd9Sstevel@tonic-gate return (FALSE); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate return (FALSE); 3337c478bd9Sstevel@tonic-gate } 334