Add interface to select client security objects
[openafs.git] / src / bucoord / expire.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <afs/stds.h>
15 #include <sys/types.h>
16 #include <afs/ktime.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <afs/cmd.h>
20 #include <ctype.h>
21 #include "bc.h"
22
23
24 #define MAX_YEAR_VALUE  0
25 #define MAX_MONTH_VALUE 11
26 #define MAX_DAY_VALUE   30
27
28 /* for parsing relative expiration dates */
29 static struct parseseqS {
30     afs_int32 ps_field;
31     char ps_keychar;
32     afs_int32 ps_maxValue;
33 } parseseq[] = {
34     KTIMEDATE_YEAR, 'y', MAX_YEAR_VALUE,        /* no max. value */
35         KTIMEDATE_MONTH, 'm', MAX_MONTH_VALUE,  /* months max. 12 */
36         KTIMEDATE_DAY, 'd', MAX_DAY_VALUE,      /* days max. 31 */
37 0, 0, 0,};
38
39 /* Encodings to and from relative dates. The caller is responsible for
40  * enforcing appropriate use of these routines
41  */
42 afs_int32
43 ktimeRelDate_ToLong(kdptr)
44      struct ktime_date *kdptr;
45 {
46     afs_int32 retval;
47
48     retval =
49         (((kdptr->year * (MAX_MONTH_VALUE + 1)) +
50           kdptr->month) * (MAX_DAY_VALUE + 1)) + kdptr->day;
51     return (retval);
52 }
53
54 /* LongTo_ktimeRelDate
55  *      Convert a relative date encoded in a long - back into a ktime_date
56  *      structure
57  */
58
59 LongTo_ktimeRelDate(longDate, kdptr)
60      afs_int32 longDate;
61      struct ktime_date *kdptr;
62 {
63     memset(kdptr, 0, sizeof(*kdptr));
64
65     kdptr->day = longDate % (MAX_DAY_VALUE + 1);
66     if (kdptr->day != 0)
67         kdptr->mask |= KTIMEDATE_DAY;
68
69     longDate = longDate / (MAX_DAY_VALUE + 1);
70
71     kdptr->month = longDate % (MAX_MONTH_VALUE + 1);
72     if (kdptr->month != 0)
73         kdptr->mask |= KTIMEDATE_MONTH;
74
75     longDate = longDate / (MAX_MONTH_VALUE + 1);
76
77     kdptr->year = longDate;
78     if (kdptr->year != 0)
79         kdptr->mask |= KTIMEDATE_YEAR;
80
81     return (0);
82 }
83
84
85 #ifdef notdef
86 /* First some date storage and retrieval routines.
87  * These routines are for convert ktime date structures into text, and back.
88  * the format is compact and suitable for relative dates. These are used
89  * to store dates into the backup database.
90  */
91
92 /* ktimeDate_ToCompactString
93  *      convert the ktime into a compact text form.
94  * exit:
95  *      pointer to a static string containing the text form of the ktime.
96  * notes:
97  *      it assumes that non-valid portions of the date are set to 0 and that
98  *      all date fields are non-negative.
99  */
100
101 char *
102 ktimeDate_ToCompactString(kdptr)
103      struct ktime_date *kdptr;
104 {
105     char buffer[1024];
106
107     sprintf(buffer, "%-d:%-d:%-d:%-d:%-d:%-d", kdptr->year, kdptr->month,
108             kdptr->day, kdptr->hour, kdptr->min, kdptr->sec);
109
110     return (&buffer[0]);
111 }
112
113 /* CompactStringTo_ktimeDate
114  *      parses the string and places it in the ktime structure
115  * exit:
116  *      0 - success
117  *      -1 - failed, string format error
118  */
119 afs_int32
120 CompactStringTo_ktimeDate(stptr, kdptr)
121      char *stptr;
122      struct ktime_date *kdptr;
123 {
124     afs_int32 code;
125
126     code =
127         sscanf(stptr, "%d:%d:%d:%d:%d:%d", &kdptr->year, &kdptr->month,
128                &kdptr->day, &kdptr->hour, &kdptr->min, &kdptr->sec);
129
130     if (code != 6)
131         return (-1);
132
133     kdptr->mask = 0;
134
135     if (kdptr->year)
136         kdptr->mask |= KTIMEDATE_YEAR;
137
138     if (kdptr->month)
139         kdptr->mask |= KTIMEDATE_MONTH;
140
141     if (kdptr->day)
142         kdptr->mask |= KTIMEDATE_DAY;
143
144     if (kdptr->hour)
145         kdptr->mask |= KTIMEDATE_HOUR;
146
147     if (kdptr->min)
148         kdptr->mask |= KTIMEDATE_MIN;
149
150     if (kdptr->sec)
151         kdptr->mask |= KTIMEDATE_SEC;
152
153     return (0);
154 }
155
156 /* ktimeDate_FromLong
157  *      Converts a time in seconds, to a time (in ktime_date format). Result is
158  *      placed in the supplied structure
159  * entry:
160  *      timeSecs - time in seconds
161  *      ktimePtr - ptr to struct for the return value
162  */
163
164 ktimeDate_FromLong(timeSecs, ktimePtr)
165      afs_int32 timeSecs;
166      struct ktime_date *ktimePtr;
167 {
168     struct tm timePtr;
169
170     timePtr = localtime(&timeSecs);
171
172     /* copy the relevant fields */
173     ktimePtr->sec = timePtr->sec;
174     ktimePtr->min = timePtr->min;
175     ktimePtr->hour = timePtr->hour;
176     ktimePtr->day = timePtr->mday;
177     ktimePtr->month = timePtr->mon;
178     ktimePtr->year = timePtr->year;
179
180     ktimePtr->mask =
181         KTIMEDATE_YEAR | KTIMEDATE_MONTH | KTIMEDATE_DAY | KTIMEDATE_HOUR |
182         KTIMEDATE_MIN | KTIMEDATE_SEC;
183
184     return (0);
185 }
186
187
188 /* AddKtimeToNow
189  *      Returns current time with a relative time added. Note that the 
190  *      computation adds in most significant fields first, i.e. year, month
191  *      day etc. Addition of least significant fields would produce different
192  *      results (depending on the data).
193  * entry:
194  *      relDatePtr - a ktime_date containing a relative time specification
195  * exit:
196  *      returns current time with relative time added.
197  */
198
199 afs_int32
200 AddKtimeToNow(relDatePtr)
201      struct ktime_date *relDatePtr;
202 {
203     struct parseseqS typePtr;
204     afs_int32 curTime;
205     afs_int32 moreYears;
206     static struct ktime_date absDate;
207
208     curTime = time(0);          /* get current time */
209     ktimeDate_FromLong(curTime, &absDate);      /* convert to ktime */
210
211     /* add in years */
212     absDate.year += relDatePtr->year;
213
214     /* add in months */
215     absDate.month += relDatePtr->month;
216     if (absDate.month > 12) {
217         moreYears = absDate.month / 12;
218         absDate.month = absDate.month % 12;
219         absDate.year += moreYears;
220     }
221
222     /* day computations depend upon month size, so do these in seconds */
223     curTime = ktime_InterpretDate(&absDate);
224
225     curTime =
226         curTime + relDatePtr->sec + relDatePtr->min * 60 +
227         relDatePtr->hour * 60 * 60 + relDatePtr->day * 24 * 60 * 60;
228
229     return (curTime);
230 }
231 #endif /* notdef */
232
233 #define RD_DIGIT_LIMIT  4       /* max. no. digits permitted */
234
235
236 /* ParseRelDate
237  *      Parses a relative date of the form  <n>y<n>m<n>d representing years
238  *      months and days. <n> is limited to RD_DIGIT_LIMIT digits in length.
239  * entry:
240  *      dateStr - ptr to string to parse. Leading white space ingnored.
241  * exit:
242  *      returns a ptr to a static ktime_date structure containing
243  *              appropriately set fields. The mask field is unused.
244  *      0 - error in date specification
245  */
246
247 afs_int32
248 ParseRelDate(dateStr, relDatePtr)
249      char *dateStr;
250      struct ktime_date *relDatePtr;
251 {
252     struct parseseqS *psPtr;
253     afs_int32 value, digit_limit;
254     afs_int32 type_index;
255
256     memset(relDatePtr, 0, sizeof(*relDatePtr));
257     type_index = 0;
258
259     while (1) {                 /*w */
260
261         while (isspace(*dateStr))       /* skip leading whitespace */
262             dateStr++;
263
264         if (isdigit(*dateStr) == 0)
265             goto error;
266
267         digit_limit = RD_DIGIT_LIMIT;
268         value = 0;
269         while (isdigit(*dateStr)) {
270             value = value * 10 + *dateStr - '0';
271             dateStr++;
272             if (digit_limit-- == 0)
273                 goto error;
274         }
275
276         psPtr = &parseseq[type_index];
277         /* determine the units. Search for a matching type character */
278         while ((psPtr->ps_keychar != *dateStr)
279                && (psPtr->ps_keychar != 0)
280             ) {
281             type_index++;
282             psPtr = &parseseq[type_index];
283         }
284
285         /* no matching type found */
286         if (psPtr->ps_keychar == 0)
287             goto error;
288
289         /* check the bounds on the maximum value. Can't be negative
290          * and if a maximum value is specified, check against it
291          */
292         if ((value < 0)
293             || ((psPtr->ps_maxValue > 0) && (value > psPtr->ps_maxValue))
294             )
295             goto error;
296
297         /* save computed value in the relevant type field */
298         switch (psPtr->ps_field) {
299         case KTIMEDATE_YEAR:
300             relDatePtr->year = value;
301             relDatePtr->mask |= KTIMEDATE_YEAR;
302             break;
303
304         case KTIMEDATE_MONTH:
305             relDatePtr->month = value;
306             relDatePtr->mask |= KTIMEDATE_MONTH;
307             break;
308
309         case KTIMEDATE_DAY:
310             relDatePtr->mask |= KTIMEDATE_DAY;
311             relDatePtr->day = value;
312             break;
313
314         default:
315             goto error;
316         }
317         dateStr++;              /* next digit */
318
319         if (*dateStr == 0) {
320             /* no more chars to process, return the result */
321             return (0);
322         }
323     }                           /*w */
324
325   error:
326     return (1);
327 }
328
329 /* RelDatetoString
330  *      returns a static string representing the relative date. This is in
331  *      a format acceptable to the relative date parser.
332  * entry:
333  *      datePtr - relative date to be converted.
334  * exit:
335  *      ptr to static string
336  */
337
338 char *
339 RelDatetoString(datePtr)
340      struct ktime_date *datePtr;
341 {
342     static char dateString[64];
343     char tempstring[64], *sptr;
344
345     dateString[0] = 0;
346     sptr = &dateString[0];
347
348     if (datePtr->mask & KTIMEDATE_YEAR) {
349         sprintf(tempstring, "%-dy", datePtr->year);
350         strcat(sptr, tempstring);
351     }
352
353     if (datePtr->mask & KTIMEDATE_MONTH) {
354         strcat(sptr, " ");
355         sprintf(tempstring, "%-dm", datePtr->month);
356         strcat(sptr, tempstring);
357     }
358
359     if (datePtr->mask & KTIMEDATE_DAY) {
360         strcat(sptr, " ");
361         sprintf(tempstring, "%-dd", datePtr->day);
362         strcat(sptr, tempstring);
363     }
364     return (sptr);
365 }
366
367 #define FAIL(n)                                         \
368 {                                                       \
369      code = n;                                          \
370      goto error;                                        \
371 }
372
373 /* bc_ParseExpiration
374  *
375  * Notes:
376  *      dates are specified as absolute or relative, the syntax is:
377  *      absolute:       at %d/%d/%d [%d:%d]     where [..] is optional
378  *      relative:       in [%dy][%dm][%dd]      where at least one component
379  *                                              must be specified
380  */
381
382 afs_int32
383 bc_ParseExpiration(struct cmd_parmdesc *paramPtr, afs_int32 *expType, 
384                    afs_int32 *expDate)
385 {
386     struct cmd_item *itemPtr, *tempPtr;
387     struct ktime_date kt;
388     char *dateString;
389     afs_int32 length = 0;
390     afs_int32 code = 0;
391
392     if (paramPtr->items == 0) {
393         /* no expiration specified */
394         *expType = BC_NO_EXPDATE;
395         *expDate = 0;
396         return (0);
397     }
398
399     /* some form of expiration date specified. First validate the prefix */
400     itemPtr = paramPtr->items;
401
402     if (strcmp(itemPtr->data, "at") == 0) {
403         *expType = BC_ABS_EXPDATE;
404     } else if (strcmp(itemPtr->data, "in") == 0) {
405         *expType = BC_REL_EXPDATE;
406     } else
407         FAIL(1);
408
409     /* before parsing the date string - concatenate all the pieces */
410     itemPtr = itemPtr->next;
411     tempPtr = itemPtr;
412
413     /* compute the length of string required */
414     while (tempPtr != 0) {
415         length += strlen(tempPtr->data);
416         tempPtr = tempPtr->next;
417         length++;               /* space or null terminator */
418     }
419     if (length == 0)            /* no actual date string */
420         FAIL(1);
421
422     dateString = (char *)malloc(length);
423     if (dateString == 0)
424         FAIL(2);
425
426     /* now assemble the date string */
427     dateString[0] = 0;
428     while (itemPtr != 0) {
429         strcat(dateString, itemPtr->data);
430         itemPtr = itemPtr->next;
431         if (itemPtr != 0)
432             strcat(dateString, " ");
433     }
434
435     switch (*expType) {
436     case BC_ABS_EXPDATE:
437         code = ktime_DateToLong(dateString, expDate);
438         if (code)
439             FAIL(1);
440         break;
441
442     case BC_REL_EXPDATE:
443         code = ParseRelDate(dateString, &kt);
444         if (code)
445             FAIL(1);
446         *expDate = ktimeRelDate_ToLong(&kt);
447         break;
448
449     default:
450         FAIL(1);
451     }
452
453     /* code will be 0 */
454   exit:
455     /* normal exit */
456     if (dateString)
457         free(dateString);
458     return (code);
459
460   error:
461     /* assign default values */
462     *expType = BC_NO_EXPDATE;
463     *expDate = 0;
464     goto exit;
465 }