]> granicus.if.org Git - sudo/blob - plugins/sudoers/timeout.c
3b621e355055c2827c884919a65baf074dd997b7
[sudo] / plugins / sudoers / timeout.c
1 /*
2  * Copyright (c) 2017 Todd C. Miller <Todd.Miller@sudo.ws>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 /*
18  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
19  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
20  */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stddef.h>
28 #ifdef HAVE_STRING_H
29 # include <string.h>
30 #endif /* HAVE_STRING_H */
31 #ifdef HAVE_STRINGS_H
32 # include <strings.h>
33 #endif /* HAVE_STRINGS_H */
34 #include <ctype.h>
35 #include <errno.h>
36 #include <limits.h>
37
38 #include "sudo_compat.h"
39 #include "sudoers_debug.h"
40 #include "parse.h"
41
42 /*
43  * Parse a command timeout in sudoers in the format 1d2h3m4s
44  * (days, hours, minutes, seconds) or a number of seconds with no suffix.
45  * Returns the number of seconds or -1 on error.
46  */
47 int
48 parse_timeout(const char *timestr)
49 {
50     debug_decl(parse_timeout, SUDOERS_DEBUG_PARSER)
51     const char suffixes[] = "dhms";
52     const char *cp = timestr;
53     int timeout = 0;
54     int idx = 0;
55
56     do {
57         char *ep;
58         char ch;
59         long l;
60
61         /* Parse number, must be present and positive. */
62         errno = 0;
63         l = strtol(cp, &ep, 10);
64         if (ep == cp) {
65             /* missing timeout */
66             errno = EINVAL;
67             debug_return_int(-1);
68         }
69         if (errno == ERANGE || l < 0 || l > INT_MAX)
70             goto overflow;
71
72         /* Find a matching suffix or return an error. */
73         if (*ep != '\0') {
74             ch = tolower((unsigned char)*ep++);
75             while (suffixes[idx] != ch) {
76                 if (suffixes[idx] == '\0') {
77                     /* parse error */
78                     errno = EINVAL;
79                     debug_return_int(-1);
80                 }
81                 idx++;
82             }
83
84             /* Apply suffix. */
85             switch (ch) {
86             case 'd':
87                 if (l > INT_MAX / (24 * 60 * 60))
88                     goto overflow;
89                 l *= 24 * 60 * 60;
90                 break;
91             case 'h':
92                 if (l > INT_MAX / (60 * 60))
93                     goto overflow;
94                 l *= 60 * 60;
95                 break;
96             case 'm':
97                 if (l > INT_MAX / 60)
98                     goto overflow;
99                 l *= 60;
100                 break;
101             }
102             if (l > INT_MAX - timeout)
103                 goto overflow;
104         }
105         cp = ep;
106
107         timeout += l;
108     } while (*cp != '\0');
109
110     debug_return_int(timeout);
111 overflow:
112     errno = ERANGE;
113     debug_return_int(-1);
114 }