1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2015 Gary Mills
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* DESCRIPTION: Contains utilities relating to TTL calculation.
*/
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <strings.h>
#include <ndbm.h>
#include "ypsym.h"
#include "ypdefs.h"
#include "shim.h"
#include "yptol.h"
#include "../ldap_util.h"
/*
* Constants used in time calculations
*/
#define MILLION 1000000
/*
* Decs
*/
suc_code is_greater_timeval(struct timeval *, struct timeval *);
suc_code add_to_timeval(struct timeval *, int);
/*
* FUNCTION: has_entry_expired()
*
* DESCRIPTION: Determines if an individual entry has expired.
*
* INPUTS: Map control structure for an open map
* Entry key
*
* OUTPUTS: TRUE = Entry has expired or cannot be found this will cause
* missing entries to be pulled out of the DIT.
* FALSE = Entry has not expired
*
*/
bool_t
has_entry_expired(map_ctrl *map, datum *key)
{
datum ttl;
struct timeval now;
struct timeval old_time;
char *key_name;
char *myself = "has_entry_expired";
if ((map == NULL) || (map->ttl == NULL))
return (FALSE);
/* Get expiry time entry for key */
ttl = dbm_fetch(map->ttl, *key);
if (NULL == ttl.dptr) {
/*
* If we failed to get a map expiry key, which must always be
* present, then something is seriously wrong. Try to recreate
* the map.
*/
if ((key->dsize == strlen(MAP_EXPIRY_KEY)) &&
(0 == strncmp(key->dptr, MAP_EXPIRY_KEY, key->dsize))) {
logmsg(MSG_NOTIMECHECK, LOG_ERR, "Cannot find %s TTL "
"for map %s. Will attempt to recreate map",
MAP_EXPIRY_KEY, map->map_name);
return (TRUE);
}
/*
* Not a problem just no TTL entry for this entry. Maybe it has
* not yet been downloaded. Maybe it will be handled by a
* service other than NIS. Check if the entire map has expired.
* This prevents repeated LDAP reads when requests are made for
* nonexistant entries.
*/
if (has_map_expired(map)) {
/* Kick of a map update */
update_map_if_required(map, FALSE);
}
/* Don't update the entry */
return (FALSE);
}
if (ttl.dsize != sizeof (struct timeval)) {
/*
* Need to malloc some memory before can syslog the key name
* but this may fail. Solution log a simple message first THEn
* a more detailed one if it works.
*/
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Invalid TTL key in map %s. error %d",
map->map_name, dbm_error(map->ttl));
/* Log the key name */
key_name = (char *)am(myself, key->dsize + 1);
if (NULL == key_name) {
logmsg(MSG_NOMEM, LOG_ERR,
"Could not alloc memory for keyname");
} else {
strncpy(key_name, key->dptr, key->dsize);
key_name[key->dsize] = '\0';
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Key name was %s", key_name);
sfree(key_name);
}
/* Update it Anyway */
return (TRUE);
}
/* Get current time */
gettimeofday(&now, NULL);
/*
* Because dptr may not be int aligned need to build an int
* out of what it points to or will get a bus error
*/
bcopy(ttl.dptr, &old_time, sizeof (struct timeval));
return (is_greater_timeval(&now, &old_time));
}
/*
* FUNCTION: has_map_expired()
*
* DESCRIPTION: Determines if an entire map has expire
*
* INPUTS: Map control structure for an open map
*
* OUTPUTS: TRUE = Map has expired
* FALSE Map has not expired
*
*/
bool_t
has_map_expired(map_ctrl *map)
{
datum key;
/* Set up datum with magic expiry key */
key.dsize = strlen(MAP_EXPIRY_KEY);
key.dptr = MAP_EXPIRY_KEY;
/* Call has_entry_expired() with magic map expiry key */
return (has_entry_expired(map, &key));
}
/*
* FUNCTION: update_entry_ttl()
*
* DESCRIPTION: Updates the TTL for one map entry
*
* INPUTS: Map control structure for an open map
* Entry key
* Flag indication if TTL should be max, min or random
*
* OUTPUTS: SUCCESS = TTL updated
* FAILURE = TTL not updated
*
*/
suc_code
update_entry_ttl(map_ctrl *map, datum *key, TTL_TYPE type)
{
datum expire;
struct timeval now;
int ttl;
/* Get current time */
gettimeofday(&now, NULL);
/* Get TTL from mapping file */
ttl = get_ttl_value(map, type);
if (FAILURE == add_to_timeval(&now, ttl))
return (FAILURE);
/* Convert time into a datum */
expire.dsize = sizeof (struct timeval);
expire.dptr = (char *)&now;
/* Set expiry time entry for key */
errno = 0;
if (0 > dbm_store(map->ttl, *key, expire, DBM_REPLACE)) {
logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not write TTL entry "
"(errno=%d)", errno);
return (FAILURE);
}
return (SUCCESS);
}
/*
* FUNCTION: update_map_ttl()
*
* DESCRIPTION: Updates the TTL for entire map. This can be called either with
* the map open (map_ctrl DBM pointer set up) or the map closed
* (map_ctrl DBM pointers not set). The latter case will occur
* when we have just created a new map.
*
* This function must open the TTL map but, in either case, must
* return with the map_ctrl in it's original state.
*
* INPUTS: Map control structure for an open map
*
* OUTPUTS: SUCCESS = TTL updated
* FAILURE = TTL not updated
*
*/
suc_code
update_map_ttl(map_ctrl *map)
{
datum key;
bool_t map_was_open = TRUE;
suc_code ret;
/* Set up datum with magic expiry key */
key.dsize = strlen(MAP_EXPIRY_KEY);
key.dptr = MAP_EXPIRY_KEY;
/* If TTL not open open it */
if (NULL == map->ttl) {
map->ttl = dbm_open(map->ttl_path, O_RDWR, 0644);
if (NULL == map->ttl)
return (FAILURE);
map_was_open = FALSE;
}
/* Call update_entry_ttl() with magic map expiry key */
ret = update_entry_ttl(map, &key, TTL_MIN);
/* If we had to open TTL file close it */
if (!map_was_open) {
dbm_close(map->ttl);
map->ttl_path = NULL;
}
return (ret);
}
/*
* FUNCTION: add_to_timeval()
*
* DESCRIPTION: Adds an int to a timeval
*
* NOTE : Seems strange that there is not a library function to do this
* if one exists then this function can be removed.
*
* NOTE : Does not handle UNIX clock wrap round but this is a much bigger
* problem.
*
* INPUTS: Time value to add to
* Time value to add in seconds
*
* OUTPUTS: SUCCESS = Addition successful
* FAILURE = Addition failed (probably wrapped)
*
*/
suc_code
add_to_timeval(struct timeval *t1, int t2)
{
struct timeval oldval;
oldval.tv_sec = t1->tv_sec;
/* Add seconds part */
t1->tv_sec += t2;
/* Check for clock wrap */
if (!(t1->tv_sec >= oldval.tv_sec)) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Wrap when adding %d to %d", t2, oldval.tv_sec);
return (FAILURE);
}
return (SUCCESS);
}
/*
* FUNCTION: is_greater_timeval()
*
* DESCRIPTION: Compares two timevals
*
* NOTE : Seems strange that there is not a library function to do this
* if one exists then this function can be removed.
*
* INPUTS: First time value
* Time value to compare it with
*
* OUTPUTS: TRUE t1 > t2
* FALSE t1 <= t2
*
*/
suc_code
is_greater_timeval(struct timeval *t1, struct timeval *t2)
{
if (t1->tv_sec > t2->tv_sec)
return (TRUE);
if (t1->tv_sec == t2->tv_sec) {
if (t1->tv_usec > t2->tv_usec)
return (TRUE);
else
return (FALSE);
}
return (FALSE);
}
|