]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/ntp/ntpq/libntpq.c
Fix multiple vulnerabilities of ntp. [SA-17:03]
[FreeBSD/releng/10.3.git] / contrib / ntp / ntpq / libntpq.c
1 /*****************************************************************************
2  *
3  *  libntpq.c
4  *
5  *  This is the wrapper library for ntpq, the NTP query utility. 
6  *  This library reuses the sourcecode from ntpq and exports a number
7  *  of useful functions in a library that can be linked against applications
8  *  that need to query the status of a running ntpd. The whole 
9  *  communcation is based on mode 6 packets.
10  *
11  ****************************************************************************/
12 #define LIBNTPQ_C
13 #define NO_MAIN_ALLOWED 1
14 /* #define BUILD_AS_LIB         Already provided by the Makefile */
15
16 #include "ntpq.c"
17 #include "libntpq.h"
18
19 /* Function Prototypes */
20  
21
22 const char *Version = "libntpq 0.3beta";
23
24 /* global variables used for holding snapshots of data */
25 char peervars[NTPQ_BUFLEN];
26 int peervarlen = 0;
27 associd_t peervar_assoc = 0;
28 char clockvars[NTPQ_BUFLEN];
29 int clockvarlen = 0;
30 int clockvar_assoc = 0;
31 char sysvars[NTPQ_BUFLEN];
32 int sysvarlen = 0;
33 char *ntpq_resultbuffer[NTPQ_BUFLEN];
34 unsigned short ntpq_associations[MAXASSOC];
35 struct ntpq_varlist ntpq_varlist[MAXLIST];
36
37 /*****************************************************************************
38  *
39  *  ntpq_stripquotes
40  *
41  *  Parses a given character buffer srcbuf and removes all quoted
42  *  characters. The resulting string is copied to the specified 
43  *  resultbuf character buffer.  E.g. \" will be translated into "
44  * 
45  ****************************************************************************
46  * Parameters:
47  *      resultbuf       char*   The resulting string without quoted
48  *                              characters
49  *      srcbuf          char*   The buffer holding the original string
50  *      datalen         int     The number of bytes stored in srcbuf
51  *      maxlen          int     Max. number of bytes for resultbuf
52  *
53  * Returns:
54  *      int             number of chars that have been copied to 
55  *                      resultbuf 
56  ****************************************************************************/
57
58 int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen )
59 {
60         char* dst = resultbuf;
61         char* dep = resultbuf + maxlen - 1;
62         char* src = srcbuf;
63         char* sep = srcbuf + (datalen >= 0 ? datalen : 0); 
64         int   esc = 0;
65         int   ch;
66         
67         if (maxlen <= 0)
68                 return 0;
69         
70         while ((dst != dep) && (src != sep) && (ch = (u_char)*src++) != 0) {
71                 if (esc) {
72                         esc = 0;
73                         switch (ch) {
74                                 /* skip and do not copy */
75                                 /* case '"':*/ /* quotes */
76                         case 'n': /*newline*/
77                         case 'r': /*carriage return*/
78                         case 'g': /*bell*/
79                         case 't': /*tab*/
80                                 continue;
81                         default:
82                                 break;
83                         }
84                 } else {
85                         switch (ch) {
86                         case '\\':
87                                 esc = 1;
88                         case '"':
89                                 continue;
90                         default:
91                                 break;
92                         }
93                 }
94                 *dst++ = (char)ch;
95         }
96         *dst = '\0';
97         return (int)(dst - resultbuf);
98 }                       
99
100
101 /*****************************************************************************
102  *
103  *  ntpq_getvar
104  *
105  *  This function parses a given buffer for a variable/value pair and
106  *  copies the value of the requested variable into the specified
107  *  varvalue buffer.
108  *
109  *  It returns the number of bytes copied or zero for an empty result
110  *  (=no matching variable found or empty value)
111  *
112  ****************************************************************************
113  * Parameters:
114  *      resultbuf       char*   The resulting string without quoted
115  *                              characters
116  *      datalen         size_t  The number of bytes stored in 
117  *                                                      resultbuf
118  *      varname         char*   Name of the required variable 
119  *      varvalue        char*   Where the value of the variable should
120  *                                                      be stored
121  *      maxlen          size_t  Max. number of bytes for varvalue
122  *
123  * Returns:
124  *      size_t          number of chars that have been copied to 
125  *                      varvalue
126  ****************************************************************************/
127
128 size_t
129 ntpq_getvar(
130         const char *    resultbuf,
131         size_t          datalen,
132         const char *    varname,
133         char *          varvalue,
134         size_t          maxlen)
135 {
136         char *  name;
137         char *  value;
138         size_t  idatalen;
139
140         value = NULL;
141         idatalen = (int)datalen;
142
143         while (nextvar(&idatalen, &resultbuf, &name, &value)) {
144                 if (strcmp(varname, name) == 0) {
145                         ntpq_stripquotes(varvalue, value, strlen(value), maxlen);
146
147                         return strlen(varvalue);
148                 }
149         }
150
151         return 0;
152 }
153
154
155 /*****************************************************************************
156  *
157  *  ntpq_queryhost
158  *
159  *  Sends a mode 6 query packet to the current open host (see 
160  *  ntpq_openhost) and stores the requested variable set in the specified
161  *  character buffer. 
162  *  It returns the number of bytes read or zero for an empty result
163  *  (=no answer or empty value)
164  *
165  ****************************************************************************
166  * Parameters:
167  *      VARSET          u_short Which variable set should be
168  *                              read (PEERVARS or CLOCKVARS)
169  *      association     int     The association ID that should be read
170  *                              0 represents the ntpd instance itself
171  *      resultbuf       char*   The resulting string without quoted
172  *                              characters
173  *      maxlen          int     Max. number of bytes for varvalue
174  *
175  * Returns:
176  *      int             number of bytes that have been copied to 
177  *                      resultbuf
178  *                      - OR -
179  *                      0 (zero) if no reply has been received or
180  *                      another failure occured
181  ****************************************************************************/
182
183 int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen)
184 {
185         const char *datap;
186         int res;
187         size_t  dsize;
188         u_short rstatus;
189         
190         if ( numhosts > 0 )
191                 res = doquery(VARSET,association,0,0, (char *)0, &rstatus, &dsize, &datap);
192         else
193                 return 0;
194         
195         if ( ( res != 0) || ( dsize == 0 ) ) /* no data */
196                 return 0;
197         
198         if ( dsize > maxlen) 
199                 dsize = maxlen;
200         
201         
202         /* fill result resultbuf */
203         memcpy(resultbuf, datap, dsize);
204         
205         return dsize;
206 }
207
208
209
210 /*****************************************************************************
211  *
212  *  ntpq_openhost
213  *
214  *  Sets up a connection to the ntpd instance of a specified host. Note:
215  *  There is no real "connection" established because NTP solely works
216  *  based on UDP.
217  *
218  ****************************************************************************
219  * Parameters:
220  *      hostname        char*   Hostname/IP of the host running ntpd
221  *      fam             int     Address Family (AF_INET, AF_INET6, or 0)
222  *
223  * Returns:
224  *      int             1 if the host connection could be set up, i.e. 
225  *                      name resolution was succesful and/or IP address
226  *                      has been validated
227  *                      - OR -
228  *                      0 (zero) if a failure occured
229  ****************************************************************************/
230
231 int
232 ntpq_openhost(
233         char *hostname,
234         int fam
235         )
236 {
237         if ( openhost(hostname, fam) )
238         {
239                 numhosts = 1;
240         } else {
241                 numhosts = 0;
242         }
243         
244         return numhosts;
245         
246 }
247
248
249 /*****************************************************************************
250  *
251  *  ntpq_closehost
252  *
253  *  Cleans up a connection by closing the used socket. Should be called
254  *  when no further queries are required for the currently used host.
255  *
256  ****************************************************************************
257  * Parameters:
258  *      - none -
259  *
260  * Returns:
261  *      int             0 (zero) if no host has been opened before
262  *                      - OR -
263  *                      the resultcode from the closesocket function call
264  ****************************************************************************/
265
266 int ntpq_closehost(void)
267 {
268         if ( numhosts )
269          return closesocket(sockfd);
270         
271         return 0;
272 }
273
274
275 /*****************************************************************************
276  *
277  *  ntpq_read_associations
278  *
279  *  This function queries the ntp host for its associations and returns the 
280  *  number of associations found.
281  *
282  *  It takes an u_short array as its first parameter, this array holds the 
283  *  IDs of the associations, 
284  *  the function will not write more entries than specified with the 
285  *  max_entries parameter.
286  *
287  *  However, if more than max_entries associations were found, the return 
288  *  value of this function will reflect the real number, even if not all 
289  *  associations have been stored in the array.
290  *
291  ****************************************************************************
292  * Parameters:
293  *      resultbuf       u_short*Array that should hold the list of
294  *                              association IDs
295  *      maxentries      int     maximum number of association IDs that can
296  *                              be stored in resultbuf
297  *
298  * Returns:
299  *      int             number of association IDs stored in resultbuf
300  *                      - OR -
301  *                      0 (zero) if a failure occured or no association has
302  *                      been returned.
303  ****************************************************************************/
304  
305  int  ntpq_read_associations ( u_short resultbuf[], int max_entries )
306 {
307     int i = 0;
308
309     if (ntpq_dogetassoc()) {       
310         
311         if(numassoc < max_entries)
312           max_entries = numassoc;
313
314         for (i=0;i<max_entries;i++)
315             resultbuf[i] = assoc_cache[i].assid;
316
317         return numassoc;
318     }
319
320     return 0;
321 }
322
323
324
325
326 /*****************************************************************************
327  *
328  *  ntpq_get_assocs
329  *
330  *  This function reads the associations of a previously selected (with 
331  *  ntpq_openhost) NTP host into its own (global) array and returns the 
332  *  number of associations found. 
333  *
334  *  The obtained association IDs can be read by using the ntpq_get_assoc_id 
335  *  function.
336  *
337  ****************************************************************************
338  * Parameters:
339  *      - none -
340  *
341  * Returns:
342  *      int             number of association IDs stored in resultbuf
343  *                      - OR -
344  *                      0 (zero) if a failure occured or no association has
345  *                      been returned.
346  ****************************************************************************/
347  
348  int  ntpq_get_assocs ( void )
349 {
350     return ntpq_read_associations( ntpq_associations, MAXASSOC );
351 }
352
353
354 /*****************************************************************************
355  *  
356  *  ntpq_get_assoc_number
357  *
358  *  This function returns for a given Association ID the association number 
359  *  in the internal association array, which is filled by the ntpq_get_assocs 
360  *  function.
361  * 
362  ****************************************************************************
363  * Parameters:
364  *      associd         int     requested associaton ID 
365  *
366  * Returns:
367  *      int             the number of the association array element that is
368  *                      representing the given association ID
369  *                      - OR -
370  *                      -1 if a failure occured or no matching association 
371  *                      ID has been found
372  ****************************************************************************/
373  
374 int ntpq_get_assoc_number ( associd_t associd )
375 {
376         int i;
377
378         for (i=0;i<numassoc;i++) {
379                 if (assoc_cache[i].assid == associd)
380                         return i;
381         }
382
383         return -1;
384
385 }
386
387
388 /*****************************************************************************
389  *  
390  *  ntpq_read_assoc_peervars
391  *
392  *  This function reads the peervars variable-set of a specified association 
393  *  from a NTP host and writes it to the result buffer specified, honoring 
394  *  the maxsize limit.
395  *
396  *  It returns the number of bytes written or 0 when the variable-set is 
397  *  empty or failed to read.
398  *  
399  ****************************************************************************
400  * Parameters:
401  *      associd         int     requested associaton ID 
402  *      resultbuf       char*   character buffer where the variable set
403  *                              should be stored
404  *      maxsize         int     the maximum number of bytes that can be
405  *                              written to resultbuf
406  *
407  * Returns:
408  *      int             number of chars that have been copied to 
409  *                      resultbuf
410  *                      - OR - 
411  *                      0 (zero) if an error occured
412  ****************************************************************************/
413
414 int
415 ntpq_read_assoc_peervars(
416         associd_t       associd,
417         char *          resultbuf,
418         int             maxsize
419         )
420 {
421         const char *    datap;
422         int             res;
423         size_t          dsize;
424         u_short         rstatus;
425
426         res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
427                       &dsize, &datap);
428         if (res != 0)
429                 return 0;
430         if (dsize <= 0) {
431                 if (numhosts > 1)
432                         fprintf(stderr, "server=%s ", currenthost);
433                 fprintf(stderr,
434                         "***No information returned for association %d\n",
435                         associd);
436
437                 return 0;
438         }
439         if (dsize > maxsize) 
440                 dsize = maxsize;
441         memcpy(resultbuf, datap, dsize);
442
443         return dsize;
444 }
445
446
447
448
449 /*****************************************************************************
450  *  
451  *  ntpq_read_sysvars
452  *
453  *  This function reads the sysvars variable-set from a NTP host and writes it
454  *  to the result buffer specified, honoring the maxsize limit.
455  *
456  *  It returns the number of bytes written or 0 when the variable-set is empty
457  *  or could not be read.
458  *  
459  ****************************************************************************
460  * Parameters:
461  *      resultbuf       char*   character buffer where the variable set
462  *                              should be stored
463  *      maxsize         int     the maximum number of bytes that can be
464  *                              written to resultbuf
465  *
466  * Returns:
467  *      int             number of chars that have been copied to 
468  *                      resultbuf
469  *                      - OR - 
470  *                      0 (zero) if an error occured
471  ****************************************************************************/
472 size_t
473 ntpq_read_sysvars(
474         char *  resultbuf,
475         size_t  maxsize
476         )
477 {
478         const char *    datap;
479         int             res;
480         size_t          dsize;
481         u_short         rstatus;
482
483         res = doquery(CTL_OP_READVAR, 0, 0, 0, NULL, &rstatus,
484                       &dsize, &datap);
485
486         if (res != 0)
487                 return 0;
488
489         if (dsize == 0) {
490                 if (numhosts > 1)
491                         fprintf(stderr, "server=%s ", currenthost);
492                 fprintf(stderr, "***No sysvar information returned\n");
493
494                 return 0;
495         } else {
496                 dsize = min(dsize, maxsize);
497                 memcpy(resultbuf, datap, dsize);
498         }
499
500         return dsize;
501 }
502
503
504 /*****************************************************************************
505  *  ntpq_get_assoc_allvars
506  *
507  *  With this function all association variables for the specified association
508  *  ID can be requested from a NTP host. They are stored internally and can be
509  *  read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
510  *
511  *  Basically this is only a combination of the ntpq_get_assoc_peervars and 
512  *  ntpq_get_assoc_clockvars functions.
513  *
514  *  It returns 1 if both variable-sets (peervars and clockvars) were 
515  *  received successfully. If one variable-set or both of them weren't 
516  *  received,
517  *
518  ****************************************************************************
519  * Parameters:
520  *      associd         int     requested associaton ID 
521  *
522  * Returns:
523  *      int             nonzero if at least one variable set could be read
524  *                      - OR - 
525  *                      0 (zero) if an error occured and both variable sets
526  *                      could not be read
527  ****************************************************************************/
528  int  ntpq_get_assoc_allvars( associd_t associd  )
529 {
530         return ntpq_get_assoc_peervars ( associd ) &
531                ntpq_get_assoc_clockvars( associd );
532 }
533
534
535
536
537 /*****************************************************************************
538  *
539  *  ntpq_get_sysvars
540  *
541  *  The system variables of a NTP host can be requested by using this function
542  *  and afterwards using ntpq_get_sysvar to read the single variable values.
543  *
544  ****************************************************************************
545  * Parameters:
546  *      - none -
547  *
548  * Returns:
549  *      int             nonzero if the variable set could be read
550  *                      - OR - 
551  *                      0 (zero) if an error occured and the sysvars
552  *                      could not be read
553  ****************************************************************************/
554 int
555 ntpq_get_sysvars(void)
556 {
557         sysvarlen = ntpq_read_sysvars(sysvars, sizeof(sysvars));
558         if (sysvarlen <= 0)
559                 return 0;
560         else
561                 return 1;
562 }
563
564
565 /*****************************************************************************
566  *  
567  *  ntp_get_peervar
568  *
569  *  This function uses the variable-set which was read by using 
570  *  ntp_get_peervars and searches for a variable specified with varname. If 
571  *  such a variable exists, it writes its value into
572  *  varvalue (maxlen specifies the size of this target buffer).
573  *  
574  ****************************************************************************
575  * Parameters:
576  *      varname         char*   requested variable name
577  *      varvalue        char*   the buffer where the value should go into
578  *      maxlen          int     maximum number of bytes that can be copied to
579  *                              varvalue
580  *
581  * Returns:
582  *      int             number of bytes copied to varvalue
583  *                      - OR - 
584  *                      0 (zero) if an error occured or the variable could 
585  *                      not be found
586  ****************************************************************************/
587 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
588 {
589     return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
590 }
591
592
593
594 /*****************************************************************************
595  *  
596  *  ntpq_get_assoc_peervars
597  *
598  *  This function requests the peer variables of the specified association 
599  *  from a NTP host. In order to access the variable values, the function 
600  *  ntpq_get_peervar must be used.
601  *
602  ****************************************************************************
603  * Parameters:
604  *      associd         int     requested associaton ID 
605  *
606  * Returns:
607  *      int             1 (one) if the peervars have been read
608  *                      - OR - 
609  *                      0 (zero) if an error occured and the variable set
610  *                      could not be read
611  ****************************************************************************/
612 int
613 ntpq_get_assoc_peervars(
614         associd_t associd
615         )
616 {
617         peervarlen = ntpq_read_assoc_peervars(associd, peervars, 
618                                               sizeof(peervars));
619         if (peervarlen <= 0) {
620                 peervar_assoc = 0;
621
622                 return 0;
623         }
624         peervar_assoc = associd;
625
626         return 1;
627 }
628
629
630 /*****************************************************************************
631  *  
632  *  ntp_read_assoc_clockvars
633  *
634  *  This function reads the clockvars variable-set of a specified association
635  *  from a NTP host and writes it to the result buffer specified, honoring 
636  *  the maxsize limit.
637  *
638  *  It returns the number of bytes written or 0 when the variable-set is 
639  *  empty or failed to read.
640  *  
641  ****************************************************************************
642  * Parameters:
643  *      associd         int     requested associaton ID 
644  *      resultbuf       char*   character buffer where the variable set
645  *                              should be stored
646  *      maxsize         int     the maximum number of bytes that can be
647  *                              written to resultbuf
648  *
649  * Returns:
650  *      int             number of chars that have been copied to 
651  *                      resultbuf
652  *                      - OR - 
653  *                      0 (zero) if an error occured
654  ****************************************************************************/
655
656 int
657 ntpq_read_assoc_clockvars(
658         associd_t       associd,
659         char *          resultbuf,
660         int             maxsize
661         )
662 {
663         const char *datap;
664         int res;
665         size_t dsize;
666         u_short rstatus;
667
668         res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd,
669                                0, &rstatus, &dsize, &datap);
670         if (res != 0)
671                 return 0;
672
673         if (dsize == 0) {
674                 if (numhosts > 1) /* no information returned from server */
675                         return 0;
676         } else {
677                 if (dsize > maxsize) 
678                         dsize = maxsize;
679                 memcpy(resultbuf, datap, dsize);
680         }
681
682         return dsize;
683 }
684
685
686
687 /*****************************************************************************
688  *  
689  *  ntpq_get_assoc_clocktype
690  *
691  *  This function returns a clocktype value for a given association number 
692  *  (not ID!):
693  *
694  *  NTP_CLOCKTYPE_UNKNOWN   Unknown clock type
695  *  NTP_CLOCKTYPE_BROADCAST Broadcast server
696  *  NTP_CLOCKTYPE_LOCAL     Local clock
697  *  NTP_CLOCKTYPE_UNICAST   Unicast server
698  *  NTP_CLOCKTYPE_MULTICAST Multicast server
699  * 
700  ****************************************************************************/
701 int
702 ntpq_get_assoc_clocktype(
703         int assoc_index
704         )
705 {
706         associd_t       associd;
707         int             i;
708         int             rc;
709         sockaddr_u      dum_store;
710         char            dstadr[LENHOSTNAME];
711         char            resultbuf[NTPQ_BUFLEN];
712
713         if (assoc_index < 0 || assoc_index >= numassoc)
714                 return -1;
715
716         associd = assoc_cache[assoc_index].assid;
717         if (associd == peervar_assoc) {
718                 rc = ntpq_get_peervar("dstadr", dstadr, sizeof(dstadr));
719         } else {
720                 i = ntpq_read_assoc_peervars(associd, resultbuf,
721                                              sizeof(resultbuf));
722                 if (i <= 0)
723                         return -1;
724                 rc = ntpq_getvar(resultbuf, i, "dstadr", dstadr,
725                                  sizeof(dstadr));
726         }
727
728         if (0 != rc && decodenetnum(dstadr, &dum_store))
729                 return ntpq_decodeaddrtype(&dum_store);
730
731         return -1;
732 }
733
734
735
736 /*****************************************************************************
737  *  
738  *  ntpq_get_assoc_clockvars
739  *
740  *  With this function the clock variables of the specified association are 
741  *  requested from a NTP host. This makes only sense for associations with 
742  *  the type 'l' (Local Clock) and you should check this with 
743  *  ntpq_get_assoc_clocktype for each association, before you use this function
744  *  on it.
745  *
746  ****************************************************************************
747  * Parameters:
748  *      associd         int     requested associaton ID 
749  *
750  * Returns:
751  *      int             1 (one) if the clockvars have been read
752  *                      - OR - 
753  *                      0 (zero) if an error occured and the variable set
754  *                      could not be read
755  ****************************************************************************/
756 int  ntpq_get_assoc_clockvars( associd_t associd )
757 {
758         if (NTP_CLOCKTYPE_LOCAL != ntpq_get_assoc_clocktype(
759             ntpq_get_assoc_number(associd)))
760                 return 0;
761         clockvarlen = ntpq_read_assoc_clockvars( associd, clockvars,
762                                                  sizeof(clockvars) );
763         if ( clockvarlen <= 0 ) {
764                 clockvar_assoc = 0;
765                 return 0;
766         } else {
767                 clockvar_assoc = associd;
768                 return 1;
769         }
770 }
771
772