1 /* $OpenBSD: parser.c,v 1.7 2009/02/24 12:07:47 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 26 #include <net/if.h> 27 #include <netinet/in.h> 28 #include <arpa/inet.h> 29 30 #include <err.h> 31 #include <errno.h> 32 #include <limits.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <event.h> 37 38 #include <openssl/ssl.h> 39 40 #include "smtpd.h" 41 42 #include "parser.h" 43 44 enum token_type { 45 NOTOKEN, 46 ENDTOKEN, 47 KEYWORD, 48 VARIABLE 49 }; 50 51 struct token { 52 enum token_type type; 53 const char *keyword; 54 int value; 55 const struct token *next; 56 }; 57 58 static const struct token t_main[]; 59 static const struct token t_show[]; 60 static const struct token t_pause[]; 61 static const struct token t_resume[]; 62 static const struct token t_schedule[]; 63 64 static const struct token t_main[] = { 65 {KEYWORD, "show", NONE, t_show}, 66 {KEYWORD, "monitor", MONITOR, NULL}, 67 {KEYWORD, "pause", NONE, t_pause}, 68 {KEYWORD, "reload", RELOAD, NULL}, 69 {KEYWORD, "resume", NONE, t_resume}, 70 {KEYWORD, "stop", SHUTDOWN, NULL}, 71 {KEYWORD, "schedule", SCHEDULE, t_schedule}, 72 {ENDTOKEN, "", NONE, NULL} 73 }; 74 75 static const struct token t_show[] = { 76 {KEYWORD, "queue", SHOW_QUEUE, NULL}, 77 {KEYWORD, "runqueue", SHOW_RUNQUEUE, NULL}, 78 {KEYWORD, "stats", SHOW_STATS, NULL}, 79 {ENDTOKEN, "", NONE, NULL} 80 }; 81 82 static const struct token t_pause[] = { 83 {KEYWORD, "local", PAUSE_MDA, NULL}, 84 {KEYWORD, "outgoing", PAUSE_MTA, NULL}, 85 {KEYWORD, "incoming", PAUSE_SMTP, NULL}, 86 {ENDTOKEN, "", NONE, NULL} 87 }; 88 89 static const struct token t_resume[] = { 90 {KEYWORD, "local", RESUME_MDA, NULL}, 91 {KEYWORD, "outgoing", RESUME_MTA, NULL}, 92 {KEYWORD, "incoming", RESUME_SMTP, NULL}, 93 {ENDTOKEN, "", NONE, NULL} 94 }; 95 96 static const struct token t_schedule[] = { 97 {VARIABLE, "message id/uid", SCHEDULE, NULL}, 98 {ENDTOKEN, "", NONE, NULL} 99 }; 100 101 static struct parse_result res; 102 103 struct parse_result * 104 parse(int argc, char *argv[]) 105 { 106 const struct token *table = t_main; 107 const struct token *match; 108 109 bzero(&res, sizeof(res)); 110 111 while (argc >= 0) { 112 if ((match = match_token(argv[0], table)) == NULL) { 113 fprintf(stderr, "valid commands/args:\n"); 114 show_valid_args(table); 115 return (NULL); 116 } 117 118 argc--; 119 argv++; 120 121 if (match->type == NOTOKEN || match->next == NULL) 122 break; 123 124 table = match->next; 125 } 126 127 if (argc > 0) { 128 fprintf(stderr, "superfluous argument: %s\n", argv[0]); 129 return (NULL); 130 } 131 132 return (&res); 133 } 134 135 const struct token * 136 match_token(const char *word, const struct token table[]) 137 { 138 u_int i, match; 139 const struct token *t = NULL; 140 141 match = 0; 142 143 for (i = 0; table[i].type != ENDTOKEN; i++) { 144 switch (table[i].type) { 145 case NOTOKEN: 146 if (word == NULL || strlen(word) == 0) { 147 match++; 148 t = &table[i]; 149 } 150 break; 151 case KEYWORD: 152 if (word != NULL && strncmp(word, table[i].keyword, 153 strlen(word)) == 0) { 154 match++; 155 t = &table[i]; 156 if (t->value) 157 res.action = t->value; 158 } 159 break; 160 case VARIABLE: 161 if (word != NULL && strlen(word) != 0) { 162 match++; 163 t = &table[i]; 164 if (t->value) { 165 res.action = t->value; 166 res.data = word; 167 } 168 } 169 break; 170 case ENDTOKEN: 171 break; 172 } 173 } 174 175 if (match != 1) { 176 if (word == NULL) 177 fprintf(stderr, "missing argument:\n"); 178 else if (match > 1) 179 fprintf(stderr, "ambiguous argument: %s\n", word); 180 else if (match < 1) 181 fprintf(stderr, "unknown argument: %s\n", word); 182 return (NULL); 183 } 184 185 return (t); 186 } 187 188 void 189 show_valid_args(const struct token table[]) 190 { 191 int i; 192 193 for (i = 0; table[i].type != ENDTOKEN; i++) { 194 switch (table[i].type) { 195 case NOTOKEN: 196 fprintf(stderr, " <cr>\n"); 197 break; 198 case KEYWORD: 199 fprintf(stderr, " %s\n", table[i].keyword); 200 break; 201 case VARIABLE: 202 fprintf(stderr, " %s\n", table[i].keyword); 203 break; 204 case ENDTOKEN: 205 break; 206 } 207 } 208 } 209