1 /*
2   chronyd/chronyc - Programs for keeping computer clocks accurate.
3 
4  **********************************************************************
5  * Copyright (C) Richard P. Curnow  1997-2002
6  * Copyright (C) Miroslav Lichvar  2014-2016
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of version 2 of the GNU General Public License as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  *
21  **********************************************************************
22 
23   =======================================================================
24 
25   Routines to compute the expected length of a command or reply packet.
26   These operate on the RAW NETWORK packets, from the point of view of
27   integer endianness within the structures.
28 
29   */
30 #include "config.h"
31 
32 #include "sysincl.h"
33 
34 #include "util.h"
35 #include "pktlength.h"
36 
37 #define PADDING_LENGTH_(request_length, reply_length) \
38   (uint16_t)((request_length) < (reply_length) ? (reply_length) - (request_length) : 0)
39 
40 #define PADDING_LENGTH(request_data, reply_data) \
41   PADDING_LENGTH_(offsetof(CMD_Request, request_data), offsetof(CMD_Reply, reply_data))
42 
43 #define REQ_LENGTH_ENTRY(request_data_field, reply_data_field) \
44   { offsetof(CMD_Request, data.request_data_field.EOR), \
45     PADDING_LENGTH(data.request_data_field.EOR, data.reply_data_field.EOR) }
46 
47 #define RPY_LENGTH_ENTRY(reply_data_field) \
48   offsetof(CMD_Reply, data.reply_data_field.EOR)
49 
50 /* ================================================== */
51 
52 struct request_length {
53   uint16_t command;
54   uint16_t padding;
55 };
56 
57 static const struct request_length request_lengths[] = {
58   REQ_LENGTH_ENTRY(null, null),                 /* NULL */
59   REQ_LENGTH_ENTRY(online, null),               /* ONLINE */
60   REQ_LENGTH_ENTRY(offline, null),              /* OFFLINE */
61   REQ_LENGTH_ENTRY(burst, null),                /* BURST */
62   REQ_LENGTH_ENTRY(modify_minpoll, null),       /* MODIFY_MINPOLL */
63   REQ_LENGTH_ENTRY(modify_maxpoll, null),       /* MODIFY_MAXPOLL */
64   REQ_LENGTH_ENTRY(dump, null),                 /* DUMP */
65   REQ_LENGTH_ENTRY(modify_maxdelay, null),      /* MODIFY_MAXDELAY */
66   REQ_LENGTH_ENTRY(modify_maxdelayratio, null), /* MODIFY_MAXDELAYRATIO */
67   REQ_LENGTH_ENTRY(modify_maxupdateskew, null), /* MODIFY_MAXUPDATESKEW */
68   REQ_LENGTH_ENTRY(logon, null),                /* LOGON */
69   REQ_LENGTH_ENTRY(settime, manual_timestamp),  /* SETTIME */
70   { 0, 0 },                                     /* LOCAL */
71   REQ_LENGTH_ENTRY(manual, null),               /* MANUAL */
72   REQ_LENGTH_ENTRY(null, n_sources),            /* N_SOURCES */
73   REQ_LENGTH_ENTRY(source_data, source_data),   /* SOURCE_DATA */
74   REQ_LENGTH_ENTRY(null, null),                 /* REKEY */
75   REQ_LENGTH_ENTRY(allow_deny, null),           /* ALLOW */
76   REQ_LENGTH_ENTRY(allow_deny, null),           /* ALLOWALL */
77   REQ_LENGTH_ENTRY(allow_deny, null),           /* DENY */
78   REQ_LENGTH_ENTRY(allow_deny, null),           /* DENYALL */
79   REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDALLOW */
80   REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDALLOWALL */
81   REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDDENY */
82   REQ_LENGTH_ENTRY(allow_deny, null),           /* CMDDENYALL */
83   REQ_LENGTH_ENTRY(ac_check, null),             /* ACCHECK */
84   REQ_LENGTH_ENTRY(ac_check, null),             /* CMDACCHECK */
85   { 0, 0 },                                     /* ADD_SERVER */
86   { 0, 0 },                                     /* ADD_PEER */
87   REQ_LENGTH_ENTRY(del_source, null),           /* DEL_SOURCE */
88   REQ_LENGTH_ENTRY(null, null),                 /* WRITERTC */
89   REQ_LENGTH_ENTRY(dfreq, null),                /* DFREQ */
90   { 0, 0 },                                     /* DOFFSET - not supported */
91   REQ_LENGTH_ENTRY(null, tracking),             /* TRACKING */
92   REQ_LENGTH_ENTRY(sourcestats, sourcestats),   /* SOURCESTATS */
93   REQ_LENGTH_ENTRY(null, rtc),                  /* RTCREPORT */
94   REQ_LENGTH_ENTRY(null, null),                 /* TRIMRTC */
95   REQ_LENGTH_ENTRY(null, null),                 /* CYCLELOGS */
96   { 0, 0 },                                     /* SUBNETS_ACCESSED - not supported */
97   { 0, 0 },                                     /* CLIENT_ACCESSES - not supported */
98   { 0, 0 },                                     /* CLIENT_ACCESSES_BY_INDEX - not supported */
99   REQ_LENGTH_ENTRY(null, manual_list),          /* MANUAL_LIST */
100   REQ_LENGTH_ENTRY(manual_delete, null),        /* MANUAL_DELETE */
101   REQ_LENGTH_ENTRY(null, null),                 /* MAKESTEP */
102   REQ_LENGTH_ENTRY(null, activity),             /* ACTIVITY */
103   REQ_LENGTH_ENTRY(modify_minstratum, null),    /* MODIFY_MINSTRATUM */
104   REQ_LENGTH_ENTRY(modify_polltarget, null),    /* MODIFY_POLLTARGET */
105   REQ_LENGTH_ENTRY(modify_maxdelaydevratio, null), /* MODIFY_MAXDELAYDEVRATIO */
106   REQ_LENGTH_ENTRY(null, null),                 /* RESELECT */
107   REQ_LENGTH_ENTRY(reselect_distance, null),    /* RESELECTDISTANCE */
108   REQ_LENGTH_ENTRY(modify_makestep, null),      /* MODIFY_MAKESTEP */
109   REQ_LENGTH_ENTRY(null, smoothing),            /* SMOOTHING */
110   REQ_LENGTH_ENTRY(smoothtime, null),           /* SMOOTHTIME */
111   REQ_LENGTH_ENTRY(null, null),                 /* REFRESH */
112   REQ_LENGTH_ENTRY(null, server_stats),         /* SERVER_STATS */
113   { 0, 0 },                                     /* CLIENT_ACCESSES_BY_INDEX2 - not supported */
114   REQ_LENGTH_ENTRY(local, null),                /* LOCAL2 */
115   REQ_LENGTH_ENTRY(ntp_data, ntp_data),         /* NTP_DATA */
116   { 0, 0 },                                     /* ADD_SERVER2 */
117   { 0, 0 },                                     /* ADD_PEER2 */
118   { 0, 0 },                                     /* ADD_SERVER3 */
119   { 0, 0 },                                     /* ADD_PEER3 */
120   REQ_LENGTH_ENTRY(null, null),                 /* SHUTDOWN */
121   REQ_LENGTH_ENTRY(null, null),                 /* ONOFFLINE */
122   REQ_LENGTH_ENTRY(ntp_source, null),           /* ADD_SOURCE */
123   REQ_LENGTH_ENTRY(ntp_source_name,
124                    ntp_source_name),            /* NTP_SOURCE_NAME */
125   REQ_LENGTH_ENTRY(null, null),                 /* RESET_SOURCES */
126   REQ_LENGTH_ENTRY(auth_data, auth_data),       /* AUTH_DATA */
127   REQ_LENGTH_ENTRY(client_accesses_by_index,
128                    client_accesses_by_index),   /* CLIENT_ACCESSES_BY_INDEX3 */
129   REQ_LENGTH_ENTRY(select_data, select_data),   /* SELECT_DATA */
130   REQ_LENGTH_ENTRY(null, null),                 /* RELOAD_SOURCES */
131   REQ_LENGTH_ENTRY(doffset, null),              /* DOFFSET2 */
132 };
133 
134 static const uint16_t reply_lengths[] = {
135   0,                                            /* empty slot */
136   RPY_LENGTH_ENTRY(null),                       /* NULL */
137   RPY_LENGTH_ENTRY(n_sources),                  /* N_SOURCES */
138   RPY_LENGTH_ENTRY(source_data),                /* SOURCE_DATA */
139   0,                                            /* MANUAL_TIMESTAMP */
140   RPY_LENGTH_ENTRY(tracking),                   /* TRACKING */
141   RPY_LENGTH_ENTRY(sourcestats),                /* SOURCESTATS */
142   RPY_LENGTH_ENTRY(rtc),                        /* RTC */
143   0,                                            /* SUBNETS_ACCESSED - not supported */
144   0,                                            /* CLIENT_ACCESSES - not supported */
145   0,                                            /* CLIENT_ACCESSES_BY_INDEX - not supported */
146   0,                                            /* MANUAL_LIST - not supported */
147   RPY_LENGTH_ENTRY(activity),                   /* ACTIVITY */
148   RPY_LENGTH_ENTRY(smoothing),                  /* SMOOTHING */
149   0,                                            /* SERVER_STATS - not supported */
150   0,                                            /* CLIENT_ACCESSES_BY_INDEX2 - not supported */
151   RPY_LENGTH_ENTRY(ntp_data),                   /* NTP_DATA */
152   RPY_LENGTH_ENTRY(manual_timestamp),           /* MANUAL_TIMESTAMP2 */
153   RPY_LENGTH_ENTRY(manual_list),                /* MANUAL_LIST2 */
154   RPY_LENGTH_ENTRY(ntp_source_name),            /* NTP_SOURCE_NAME */
155   RPY_LENGTH_ENTRY(auth_data),                  /* AUTH_DATA */
156   RPY_LENGTH_ENTRY(client_accesses_by_index),   /* CLIENT_ACCESSES_BY_INDEX3 */
157   0,                                            /* SERVER_STATS2 - not supported */
158   RPY_LENGTH_ENTRY(select_data),                /* SELECT_DATA */
159   RPY_LENGTH_ENTRY(server_stats),               /* SERVER_STATS3 */
160 };
161 
162 /* ================================================== */
163 
164 int
PKL_CommandLength(CMD_Request * r)165 PKL_CommandLength(CMD_Request *r)
166 {
167   uint32_t type;
168   int command_length;
169 
170   assert(sizeof (request_lengths) / sizeof (request_lengths[0]) == N_REQUEST_TYPES);
171 
172   type = ntohs(r->command);
173   if (type >= N_REQUEST_TYPES)
174     return 0;
175 
176   command_length = request_lengths[type].command;
177   if (!command_length)
178     return 0;
179 
180   return command_length + PKL_CommandPaddingLength(r);
181 }
182 
183 /* ================================================== */
184 
185 int
PKL_CommandPaddingLength(CMD_Request * r)186 PKL_CommandPaddingLength(CMD_Request *r)
187 {
188   uint32_t type;
189 
190   if (r->version < PROTO_VERSION_PADDING)
191     return 0;
192 
193   type = ntohs(r->command);
194 
195   if (type >= N_REQUEST_TYPES)
196     return 0;
197 
198   return request_lengths[ntohs(r->command)].padding;
199 }
200 
201 /* ================================================== */
202 
203 int
PKL_ReplyLength(CMD_Reply * r)204 PKL_ReplyLength(CMD_Reply *r)
205 {
206   uint32_t type;
207 
208   assert(sizeof (reply_lengths) / sizeof (reply_lengths[0]) == N_REPLY_TYPES);
209 
210   type = ntohs(r->reply);
211 
212   /* Note that reply type codes start from 1, not 0 */
213   if (type < 1 || type >= N_REPLY_TYPES)
214     return 0;
215 
216   return reply_lengths[type];
217 }
218 
219 /* ================================================== */
220 
221