3 /*****************************************************************
5 ** @(#) soaserial.c -- helper function for the dnssec zone key tools
7 ** Copyright (c) Jan 2005, Holger Zuleger HZnet. All rights reserved.
9 ** This software is open source.
11 ** Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions
15 ** Redistributions of source code must retain the above copyright notice,
16 ** this list of conditions and the following disclaimer.
18 ** Redistributions in binary form must reproduce the above copyright notice,
19 ** this list of conditions and the following disclaimer in the documentation
20 ** and/or other materials provided with the distribution.
22 ** Neither the name of Holger Zuleger HZnet nor the names of its contributors may
23 ** be used to endorse or promote products derived from this software without
24 ** specific prior written permission.
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
30 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 ** POSSIBILITY OF SUCH DAMAGE.
38 *****************************************************************/
43 # include <sys/types.h>
44 # include <sys/stat.h>
51 # include "config_zkt.h"
56 # include "soaserial.h"
59 static int inc_soa_serial (FILE *fp
, int use_unixtime
);
60 static int is_soa_rr (const char *line
);
61 static const char *strfindstr (const char *str
, const char *search
);
64 /****************************************************************
66 ** int inc_serial (filename, use_unixtime)
68 ** This function depends on a special syntax formating the
69 ** SOA record in the zone file!!
71 ** To match the SOA record, the SOA RR must be formatted
73 ** @ [ttl] IN SOA <master.fq.dn.> <hostmaster.fq.dn.> (
74 ** <SPACEes or TABs> 1234567890; serial number
75 ** <SPACEes or TABs> 86400 ; other values
77 ** The space from the first digit of the serial number to
78 ** the first none white space char or to the end of the line
79 ** must be at least 10 characters!
80 ** So you have to left justify the serial number in a field
81 ** of at least 10 characters like this:
82 ** <SPACEes or TABs> 1 ; Serial
84 ****************************************************************/
85 int inc_serial (const char *fname
, int use_unixtime
)
92 since BIND 9.4, there is a dnssec-signzone option available for
93 serial number increment.
94 If the user requests "unixtime"; then use this mechanism.
96 #if defined(BIND_VERSION) && BIND_VERSION >= 940
100 if ( (fp
= fopen (fname
, "r+")) == NULL
)
103 /* read until the line matches the beginning of a soa record ... */
104 while ( fgets (buf
, sizeof buf
, fp
) && !is_soa_rr (buf
) )
113 error
= inc_soa_serial (fp
, use_unixtime
); /* .. inc soa serial no ... */
115 if ( fclose (fp
) != 0 )
120 /*****************************************************************
121 ** check if line is the beginning of a SOA RR record, thus
122 ** containing the string "IN .* SOA" and ends with a '('
124 *****************************************************************/
125 static int is_soa_rr (const char *line
)
129 assert ( line
!= NULL
);
131 if ( (p
= strfindstr (line
, "IN")) && strfindstr (p
+2, "SOA") ) /* line contains "IN" and "SOA" */
133 p
= line
+ strlen (line
) - 1;
134 while ( p
> line
&& isspace (*p
) )
136 if ( *p
== '(' ) /* last character have to be a '(' to start a multi line record */
143 /*****************************************************************
144 ** Find string 'search' in 'str' and ignore case in comparison.
145 ** returns the position of 'search' in 'str' or NULL if not found.
146 *****************************************************************/
147 static const char *strfindstr (const char *str
, const char *search
)
152 assert ( str
!= NULL
);
153 assert ( search
!= NULL
);
155 c
= tolower (*search
);
158 while ( *p
&& tolower (*p
) != c
)
160 if ( strncasecmp (p
, search
, strlen (search
)) == 0 )
168 /*****************************************************************
169 ** return the serial number of the given time in the form
170 ** of YYYYmmdd00 as ulong value
171 *****************************************************************/
172 static ulong
serialtime (time_t sec
)
178 serialtime
= (t
->tm_year
+ 1900) * 10000;
179 serialtime
+= (t
->tm_mon
+1) * 100;
180 serialtime
+= t
->tm_mday
;
186 /*****************************************************************
187 ** inc_soa_serial (fp, use_unixtime)
188 ** increment the soa serial number of the file 'fp'
189 ** 'fp' must be opened "r+"
190 *****************************************************************/
191 static int inc_soa_serial (FILE *fp
, int use_unixtime
)
199 /* move forward until any non ws reached */
200 while ( (c
= getc (fp
)) != EOF
&& isspace (c
) )
202 ungetc (c
, fp
); /* push back the last char */
204 pos
= ftell (fp
); /* mark position */
206 serial
= 0L; /* read in the current serial number */
207 /* be aware of the trailing space in the format string !! */
208 if ( fscanf (fp
, "%lu ", &serial
) != 1 ) /* try to get serial no */
210 eos
= ftell (fp
); /* mark first non digit/ws character pos */
213 if ( digits
< 10 ) /* not enough space for serial no ? */
219 today
= serialtime (today
); /* YYYYmmdd00 */
220 if ( serial
> 1970010100L && serial
< today
)
221 serial
= today
; /* set to current time */
222 serial
++; /* increment anyway */
225 fseek (fp
, pos
, SEEK_SET
); /* go back to the beginning */
226 fprintf (fp
, "%-*lu", digits
, serial
); /* write as many chars as before */
231 /*****************************************************************
232 ** return the error text of the inc_serial return coode
233 *****************************************************************/
234 const char *inc_errstr (int err
)
238 case -1: return "couldn't open zone file for modifying";
239 case -2: return "unexpected end of file";
240 case -3: return "no serial number found in zone file";
241 case -4: return "not enough space left for serialno";
242 case -5: return "error on closing zone file";
248 const char *progname
;
249 main (int argc
, char *argv
[])
258 now
= serialtime (now
);
259 printf ("now = %lu\n", now
);
261 if ( (err
= inc_serial (argv
[1], 0)) <= 0 )
263 error ("can't change serial errno=%d\n", err
);
267 snprintf (cmd
, sizeof(cmd
), "head -15 %s", argv
[1]);