1 /* $OpenBSD: parser.c,v 1.32 2013/01/28 11:09:53 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_log[]; 51 static const struct token t_main[]; 52 static const struct token t_pause[]; 53 static const struct token t_remove[]; 54 static const struct token t_resume[]; 55 static const struct token t_schedule[]; 56 static const struct token t_show[]; 57 static const struct token t_show_envelope[]; 58 static const struct token t_show_message[]; 59 static const struct token t_update[]; 60 static const struct token t_update_table[]; 61 static const struct token t_trace[]; 62 static const struct token t_untrace[]; 63 static const struct token t_profile[]; 64 static const struct token t_unprofile[]; 65 66 static const struct token t_main[] = { 67 {KEYWORD, "schedule", NONE, t_schedule}, 68 {KEYWORD, "show", NONE, t_show}, 69 {KEYWORD, "monitor", MONITOR, NULL}, 70 {KEYWORD, "pause", NONE, t_pause}, 71 {KEYWORD, "remove", NONE, t_remove}, 72 {KEYWORD, "resume", NONE, t_resume}, 73 {KEYWORD, "stop", SHUTDOWN, NULL}, 74 {KEYWORD, "log", NONE, t_log}, 75 {KEYWORD, "profile", NONE, t_profile}, 76 {KEYWORD, "trace", NONE, t_trace}, 77 {KEYWORD, "unprofile", NONE, t_unprofile}, 78 {KEYWORD, "untrace", NONE, t_untrace}, 79 {KEYWORD, "update", NONE, t_update}, 80 {ENDTOKEN, "", NONE, NULL} 81 }; 82 83 static const struct token t_remove[] = { 84 {VARIABLE, "evpid", REMOVE, NULL}, 85 {ENDTOKEN, "", NONE, NULL} 86 }; 87 88 static const struct token t_schedule[] = { 89 {VARIABLE, "msgid/evpid/all", SCHEDULE, NULL}, 90 {ENDTOKEN, "", NONE, NULL} 91 }; 92 93 static const struct token t_show[] = { 94 {KEYWORD, "queue", SHOW_QUEUE, NULL}, 95 {KEYWORD, "stats", SHOW_STATS, NULL}, 96 {KEYWORD, "envelope", NONE, t_show_envelope}, 97 {KEYWORD, "message", SHOW_MESSAGE, t_show_message}, 98 {ENDTOKEN, "", NONE, NULL} 99 }; 100 101 static const struct token t_show_envelope[] = { 102 {VARIABLE, "evpid", SHOW_ENVELOPE, NULL}, 103 {ENDTOKEN, "", NONE, NULL} 104 }; 105 106 static const struct token t_show_message[] = { 107 {VARIABLE, "evpid", SHOW_MESSAGE, NULL}, 108 {ENDTOKEN, "", NONE, NULL} 109 }; 110 111 static const struct token t_pause[] = { 112 {KEYWORD, "mda", PAUSE_MDA, NULL}, 113 {KEYWORD, "mta", PAUSE_MTA, NULL}, 114 {KEYWORD, "smtp", PAUSE_SMTP, NULL}, 115 {ENDTOKEN, "", NONE, NULL} 116 }; 117 118 static const struct token t_resume[] = { 119 {KEYWORD, "mda", RESUME_MDA, NULL}, 120 {KEYWORD, "mta", RESUME_MTA, NULL}, 121 {KEYWORD, "smtp", RESUME_SMTP, NULL}, 122 {ENDTOKEN, "", NONE, NULL} 123 }; 124 125 static const struct token t_log[] = { 126 {KEYWORD, "verbose", LOG_VERBOSE, NULL}, 127 {KEYWORD, "brief", LOG_BRIEF, NULL}, 128 {ENDTOKEN, "", NONE, NULL} 129 }; 130 131 static const struct token t_update[] = { 132 {KEYWORD, "table", NONE, t_update_table}, 133 {ENDTOKEN, "", NONE, NULL} 134 }; 135 136 static const struct token t_update_table[] = { 137 {VARIABLE, "name", UPDATE_TABLE, NULL}, 138 {ENDTOKEN, "", NONE, NULL} 139 }; 140 141 static const struct token t_trace[] = { 142 {KEYWORD, "imsg", LOG_TRACE_IMSG, NULL}, 143 {KEYWORD, "io", LOG_TRACE_IO, NULL}, 144 {KEYWORD, "smtp", LOG_TRACE_SMTP, NULL}, 145 {KEYWORD, "filter", LOG_TRACE_MFA, NULL}, 146 {KEYWORD, "transfer", LOG_TRACE_MTA, NULL}, 147 {KEYWORD, "bounce", LOG_TRACE_BOUNCE, NULL}, 148 {KEYWORD, "scheduler", LOG_TRACE_SCHEDULER, NULL}, 149 {KEYWORD, "lookup", LOG_TRACE_LOOKUP, NULL}, 150 {KEYWORD, "stat", LOG_TRACE_STAT, NULL}, 151 {KEYWORD, "rules", LOG_TRACE_RULES, NULL}, 152 {KEYWORD, "msg-size", LOG_TRACE_IMSG_SIZE, NULL}, 153 {KEYWORD, "all", LOG_TRACE_ALL, NULL}, 154 {ENDTOKEN, "", NONE, NULL} 155 }; 156 157 static const struct token t_untrace[] = { 158 {KEYWORD, "imsg", LOG_UNTRACE_IMSG, NULL}, 159 {KEYWORD, "io", LOG_UNTRACE_IO, NULL}, 160 {KEYWORD, "smtp", LOG_UNTRACE_SMTP, NULL}, 161 {KEYWORD, "filter", LOG_UNTRACE_MFA, NULL}, 162 {KEYWORD, "transfer", LOG_UNTRACE_MTA, NULL}, 163 {KEYWORD, "bounce", LOG_UNTRACE_BOUNCE, NULL}, 164 {KEYWORD, "scheduler", LOG_UNTRACE_SCHEDULER, NULL}, 165 {KEYWORD, "lookup", LOG_UNTRACE_LOOKUP, NULL}, 166 {KEYWORD, "stat", LOG_UNTRACE_STAT, NULL}, 167 {KEYWORD, "rules", LOG_UNTRACE_RULES, NULL}, 168 {KEYWORD, "msg-size", LOG_UNTRACE_IMSG_SIZE, NULL}, 169 {KEYWORD, "all", LOG_UNTRACE_ALL, NULL}, 170 {ENDTOKEN, "", NONE, NULL} 171 }; 172 173 static const struct token t_profile[] = { 174 {KEYWORD, "imsg", LOG_PROFILE_IMSG, NULL}, 175 {KEYWORD, "queue", LOG_PROFILE_QUEUE, NULL}, 176 {ENDTOKEN, "", NONE, NULL} 177 }; 178 179 static const struct token t_unprofile[] = { 180 {KEYWORD, "imsg", LOG_UNPROFILE_IMSG, NULL}, 181 {KEYWORD, "queue", LOG_UNPROFILE_QUEUE, NULL}, 182 {ENDTOKEN, "", NONE, NULL} 183 }; 184 185 186 static const struct token *match_token(const char *, const struct token [], 187 struct parse_result *); 188 static void show_valid_args(const struct token []); 189 190 struct parse_result * 191 parse(int argc, char *argv[]) 192 { 193 static struct parse_result res; 194 const struct token *table = t_main; 195 const struct token *match; 196 197 bzero(&res, sizeof(res)); 198 199 while (argc >= 0) { 200 if ((match = match_token(argv[0], table, &res)) == NULL) { 201 fprintf(stderr, "valid commands/args:\n"); 202 show_valid_args(table); 203 return (NULL); 204 } 205 206 argc--; 207 argv++; 208 209 if (match->type == NOTOKEN || match->next == NULL) 210 break; 211 212 table = match->next; 213 } 214 215 if (argc > 0) { 216 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 217 return (NULL); 218 } 219 220 return (&res); 221 } 222 223 const struct token * 224 match_token(const char *word, const struct token table[], 225 struct parse_result *res) 226 { 227 uint i, match; 228 const struct token *t = NULL; 229 230 match = 0; 231 232 for (i = 0; table[i].type != ENDTOKEN; i++) { 233 switch (table[i].type) { 234 case NOTOKEN: 235 if (word == NULL || strlen(word) == 0) { 236 match++; 237 t = &table[i]; 238 } 239 break; 240 case KEYWORD: 241 if (word != NULL && strncmp(word, table[i].keyword, 242 strlen(word)) == 0) { 243 match++; 244 t = &table[i]; 245 if (t->value) 246 res->action = t->value; 247 } 248 break; 249 case VARIABLE: 250 if (word != NULL && strlen(word) != 0) { 251 match++; 252 t = &table[i]; 253 if (t->value) { 254 res->action = t->value; 255 res->data = word; 256 } 257 } 258 break; 259 case ENDTOKEN: 260 break; 261 } 262 } 263 264 if (match != 1) { 265 if (word == NULL) 266 fprintf(stderr, "missing argument:\n"); 267 else if (match > 1) 268 fprintf(stderr, "ambiguous argument: %s\n", word); 269 else if (match < 1) 270 fprintf(stderr, "unknown argument: %s\n", word); 271 return (NULL); 272 } 273 274 return (t); 275 } 276 277 static void 278 show_valid_args(const struct token table[]) 279 { 280 int i; 281 282 for (i = 0; table[i].type != ENDTOKEN; i++) { 283 switch (table[i].type) { 284 case NOTOKEN: 285 fprintf(stderr, " <cr>\n"); 286 break; 287 case KEYWORD: 288 fprintf(stderr, " %s\n", table[i].keyword); 289 break; 290 case VARIABLE: 291 fprintf(stderr, " %s\n", table[i].keyword); 292 break; 293 case ENDTOKEN: 294 break; 295 } 296 } 297 } 298