1 /* $OpenBSD: parser.c,v 1.22 2011/10/23 17:12:41 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/queue.h> 24 #include <sys/tree.h> 25 #include <sys/param.h> 26 27 #include <event.h> 28 #include <imsg.h> 29 30 #include <openssl/ssl.h> 31 32 #include "smtpd.h" 33 34 #include "parser.h" 35 36 enum token_type { 37 NOTOKEN, 38 ENDTOKEN, 39 KEYWORD, 40 VARIABLE 41 }; 42 43 struct token { 44 enum token_type type; 45 const char *keyword; 46 int value; 47 const struct token *next; 48 }; 49 50 static const struct token t_main[]; 51 static const struct token t_schedule_id[]; 52 static const struct token t_show[]; 53 static const struct token t_pause[]; 54 static const struct token t_remove[]; 55 static const struct token t_resume[]; 56 static const struct token t_log[]; 57 58 static const struct token t_main[] = { 59 {KEYWORD, "schedule-id", NONE, t_schedule_id}, 60 {KEYWORD, "schedule-all", SCHEDULE_ALL, NULL}, 61 {KEYWORD, "show", NONE, t_show}, 62 {KEYWORD, "monitor", MONITOR, NULL}, 63 {KEYWORD, "pause", NONE, t_pause}, 64 /* {KEYWORD, "reload", RELOAD, NULL},*/ 65 {KEYWORD, "remove", NONE, t_remove}, 66 {KEYWORD, "resume", NONE, t_resume}, 67 {KEYWORD, "stop", SHUTDOWN, NULL}, 68 {KEYWORD, "log", NONE, t_log}, 69 {ENDTOKEN, "", NONE, NULL} 70 }; 71 72 static const struct token t_remove[] = { 73 {VARIABLE, "evpid", REMOVE, NULL}, 74 {ENDTOKEN, "", NONE, NULL} 75 }; 76 77 static const struct token t_schedule_id[] = { 78 {VARIABLE, "msgid/evpid", SCHEDULE, NULL}, 79 {ENDTOKEN, "", NONE, NULL} 80 }; 81 82 static const struct token t_show[] = { 83 {KEYWORD, "queue", SHOW_QUEUE, NULL}, 84 {KEYWORD, "runqueue", SHOW_RUNQUEUE, NULL}, 85 {KEYWORD, "stats", SHOW_STATS, NULL}, 86 {KEYWORD, "sizes", SHOW_SIZES, NULL}, 87 {ENDTOKEN, "", NONE, NULL} 88 }; 89 90 static const struct token t_pause[] = { 91 {KEYWORD, "local", PAUSE_MDA, NULL}, 92 {KEYWORD, "outgoing", PAUSE_MTA, NULL}, 93 {KEYWORD, "incoming", PAUSE_SMTP, NULL}, 94 {ENDTOKEN, "", NONE, NULL} 95 }; 96 97 static const struct token t_resume[] = { 98 {KEYWORD, "local", RESUME_MDA, NULL}, 99 {KEYWORD, "outgoing", RESUME_MTA, NULL}, 100 {KEYWORD, "incoming", RESUME_SMTP, NULL}, 101 {ENDTOKEN, "", NONE, NULL} 102 }; 103 104 static const struct token t_log[] = { 105 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 106 {KEYWORD, "brief", LOG_BRIEF, NULL}, 107 {ENDTOKEN, "", NONE, NULL} 108 }; 109 110 static const struct token *match_token(const char *, const struct token [], 111 struct parse_result *); 112 static void show_valid_args(const struct token []); 113 114 struct parse_result * 115 parse(int argc, char *argv[]) 116 { 117 static struct parse_result res; 118 const struct token *table = t_main; 119 const struct token *match; 120 121 bzero(&res, sizeof(res)); 122 123 while (argc >= 0) { 124 if ((match = match_token(argv[0], table, &res)) == NULL) { 125 fprintf(stderr, "valid commands/args:\n"); 126 show_valid_args(table); 127 return (NULL); 128 } 129 130 argc--; 131 argv++; 132 133 if (match->type == NOTOKEN || match->next == NULL) 134 break; 135 136 table = match->next; 137 } 138 139 if (argc > 0) { 140 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 141 return (NULL); 142 } 143 144 return (&res); 145 } 146 147 const struct token * 148 match_token(const char *word, const struct token table[], 149 struct parse_result *res) 150 { 151 u_int i, match; 152 const struct token *t = NULL; 153 154 match = 0; 155 156 for (i = 0; table[i].type != ENDTOKEN; i++) { 157 switch (table[i].type) { 158 case NOTOKEN: 159 if (word == NULL || strlen(word) == 0) { 160 match++; 161 t = &table[i]; 162 } 163 break; 164 case KEYWORD: 165 if (word != NULL && strncmp(word, table[i].keyword, 166 strlen(word)) == 0) { 167 match++; 168 t = &table[i]; 169 if (t->value) 170 res->action = t->value; 171 } 172 break; 173 case VARIABLE: 174 if (word != NULL && strlen(word) != 0) { 175 match++; 176 t = &table[i]; 177 if (t->value) { 178 res->action = t->value; 179 res->data = word; 180 } 181 } 182 break; 183 case ENDTOKEN: 184 break; 185 } 186 } 187 188 if (match != 1) { 189 if (word == NULL) 190 fprintf(stderr, "missing argument:\n"); 191 else if (match > 1) 192 fprintf(stderr, "ambiguous argument: %s\n", word); 193 else if (match < 1) 194 fprintf(stderr, "unknown argument: %s\n", word); 195 return (NULL); 196 } 197 198 return (t); 199 } 200 201 static void 202 show_valid_args(const struct token table[]) 203 { 204 int i; 205 206 for (i = 0; table[i].type != ENDTOKEN; i++) { 207 switch (table[i].type) { 208 case NOTOKEN: 209 fprintf(stderr, " <cr>\n"); 210 break; 211 case KEYWORD: 212 fprintf(stderr, " %s\n", table[i].keyword); 213 break; 214 case VARIABLE: 215 fprintf(stderr, " %s\n", table[i].keyword); 216 break; 217 case ENDTOKEN: 218 break; 219 } 220 } 221 } 222