OpenDNSSEC-signer 1.2.1
|
00001 /* 00002 * $Id: ods-signer.c 4524 2011-03-03 14:01:47Z matthijs $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "config.h" 00035 #include "util/file.h" 00036 #include "util/log.h" 00037 #include "util/se_malloc.h" 00038 00039 #include <errno.h> 00040 #include <fcntl.h> /* fcntl() */ 00041 #include <stdio.h> /* fprintf() */ 00042 #include <string.h> /* strerror(), strncmp(), strlen(), strcpy(), strncat() */ 00043 #include <strings.h> /* bzero() */ 00044 #include <sys/select.h> /* select(), FD_ZERO(), FD_SET(), FD_ISSET(), FD_CLR() */ 00045 #include <sys/socket.h> /* socket(), connect(), shutdown() */ 00046 #include <sys/un.h> 00047 #include <unistd.h> /* exit(), read(), write() */ 00048 00049 /* According to earlier standards, we need sys/time.h, sys/types.h, unistd.h for select() */ 00050 #include <sys/types.h> 00051 #include <sys/time.h> 00052 00053 #define SE_CLI_CMDLEN 6 00054 00059 static void 00060 usage(FILE* out) 00061 { 00062 fprintf(out, "Usage: %s [<cmd>]\n", "ods-signer"); 00063 fprintf(out, "Simple command line interface to control the signer " 00064 "engine daemon.\nIf no cmd is given, the tool is going " 00065 "to interactive mode.\n"); 00066 fprintf(out, "\nBSD licensed, see LICENSE in source package for " 00067 "details.\n"); 00068 fprintf(out, "Version %s. Report bugs to <%s>.\n", 00069 PACKAGE_VERSION, PACKAGE_BUGREPORT); 00070 } 00071 00072 00077 static int 00078 max(int a, int b) 00079 { 00080 return a<b ? b : a; 00081 } 00082 00083 00088 static void 00089 interface_run(FILE* fp, int sockfd, char* cmd) 00090 { 00091 int maxfdp1 = 0; 00092 int stdineof = 0; 00093 int i = 0; 00094 int n = 0; 00095 int ret = 0; 00096 int cmd_written = 0; 00097 int cmd_response = 0; 00098 fd_set rset; 00099 char buf[ODS_SE_MAXLINE]; 00100 00101 stdineof = 0; 00102 FD_ZERO(&rset); 00103 for(;;) { 00104 /* prepare */ 00105 if (stdineof == 0) { 00106 FD_SET(fileno(fp), &rset); 00107 } 00108 FD_SET(sockfd, &rset); 00109 maxfdp1 = max(fileno(fp), sockfd) + 1; 00110 00111 if (!cmd || cmd_written) { 00112 /* interactive mode */ 00113 ret = select(maxfdp1, &rset, NULL, NULL, NULL); 00114 if (ret < 0) { 00115 if (errno != EINTR && errno != EWOULDBLOCK) { 00116 se_log_warning("interface select error: %s", 00117 strerror(errno)); 00118 } 00119 continue; 00120 } 00121 } else if (cmd) { 00122 /* passive mode */ 00123 se_writen(sockfd, cmd, strlen(cmd)); 00124 cmd_written = 1; 00125 stdineof = 1; 00126 continue; 00127 } 00128 00129 if (cmd && cmd_written && cmd_response) { 00130 /* normal termination */ 00131 return; 00132 } 00133 00134 if (FD_ISSET(sockfd, &rset)) { 00135 /* clear buffer */ 00136 for (i=0; i < ODS_SE_MAXLINE; i++) { 00137 buf[i] = 0; 00138 } 00139 buf[ODS_SE_MAXLINE-1] = '\0'; 00140 00141 /* socket is readable */ 00142 if ((n = read(sockfd, buf, ODS_SE_MAXLINE)) <= 0) { 00143 if (n < 0) { 00144 /* error occurred */ 00145 fprintf(stderr, "error: %s\n", strerror(errno)); 00146 if (cmd) { 00147 se_free((void*)cmd); 00148 } 00149 exit(1); 00150 } else if (stdineof == 1) { 00151 /* normal termination */ 00152 return; 00153 } else { 00154 /* weird termination */ 00155 fprintf(stderr, "signer engine terminated " 00156 "prematurely\n"); 00157 exit(1); 00158 } 00159 } 00160 00161 if (cmd && strncmp(buf+n-SE_CLI_CMDLEN, "\ncmd> ", SE_CLI_CMDLEN) == 0) { 00162 /* we have the full response */ 00163 if (n > SE_CLI_CMDLEN) { 00164 ret = (int) write(fileno(stdout), buf, n-SE_CLI_CMDLEN); 00165 } 00166 buf[(n-SE_CLI_CMDLEN)] = '\0'; 00167 cmd_response = 1; 00168 ret = 1; 00169 } else { 00170 /* we can expect more */ 00171 ret = (int) write(fileno(stdout), buf, n); 00172 } 00173 00174 /* error and shutdown handling */ 00175 if (ret == 0) { 00176 fprintf(stderr, "no write\n"); 00177 } else if (ret < 0) { 00178 fprintf(stderr, "write error: %s\n", strerror(errno)); 00179 } 00180 if (se_strcmp(buf, ODS_SE_STOP_RESPONSE) == 0 || cmd_response) { 00181 fprintf(stderr, "\n"); 00182 return; 00183 } 00184 } 00185 00186 if (FD_ISSET(fileno(fp), &rset)) { 00187 /* input is readable */ 00188 00189 if (cmd && cmd_written) { 00190 /* passive mode */ 00191 stdineof = 1; 00192 ret = shutdown(sockfd, SHUT_WR); 00193 if (ret != 0) { 00194 fprintf(stderr, "shutdown failed: %s\n", 00195 strerror(errno)); 00196 if (cmd) { 00197 se_free((void*)cmd); 00198 } 00199 exit(1); 00200 } 00201 FD_CLR(fileno(fp), &rset); 00202 continue; 00203 } 00204 00205 /* clear buffer */ 00206 for (i=0; i< ODS_SE_MAXLINE; i++) { 00207 buf[i] = 0; 00208 } 00209 00210 /* interactive mode */ 00211 if ((n = read(fileno(fp), buf, ODS_SE_MAXLINE)) == 0) { 00212 stdineof = 1; 00213 ret = shutdown(sockfd, SHUT_WR); 00214 if (ret != 0) { 00215 fprintf(stderr, "shutdown failed: %s\n", 00216 strerror(errno)); 00217 exit(1); 00218 } 00219 FD_CLR(fileno(fp), &rset); 00220 continue; 00221 } 00222 if (strncmp(buf, "exit", 4) == 0 || 00223 strncmp(buf, "quit", 4) == 0) { 00224 return; 00225 } 00226 se_str_trim(buf); 00227 n = strlen(buf); 00228 se_writen(sockfd, buf, n); 00229 } 00230 } 00231 } 00232 00233 00238 static void 00239 interface_start(char* cmd) 00240 { 00241 int sockfd, ret, flags; 00242 struct sockaddr_un servaddr; 00243 const char* servsock_filename = ODS_SE_SOCKFILE; 00244 00245 /* new socket */ 00246 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 00247 if (sockfd <= 0) { 00248 fprintf(stderr, "Unable to connect to engine. " 00249 "socket() failed: %s\n", strerror(errno)); 00250 if (cmd) { 00251 se_free((void*)cmd); 00252 } 00253 exit(1); 00254 } 00255 00256 /* no suprises */ 00257 bzero(&servaddr, sizeof(servaddr)); 00258 servaddr.sun_family = AF_UNIX; 00259 strncpy(servaddr.sun_path, servsock_filename, 00260 sizeof(servaddr.sun_path) - 1); 00261 00262 /* connect */ 00263 ret = connect(sockfd, (const struct sockaddr*) &servaddr, 00264 sizeof(servaddr)); 00265 if (ret != 0) { 00266 if (cmd && se_strcmp(cmd, "start\n") == 0) { 00267 ret = system(ODS_SE_ENGINE); 00268 return; 00269 } 00270 00271 if (cmd && se_strcmp(cmd, "running\n") == 0) { 00272 fprintf(stderr, "Engine not running.\n"); 00273 } else { 00274 fprintf(stderr, "Unable to connect to engine: " 00275 "connect() failed: %s\n", strerror(errno)); 00276 } 00277 00278 close(sockfd); 00279 if (cmd) { 00280 se_free((void*)cmd); 00281 } 00282 exit(1); 00283 } 00284 00285 /* set socket to non-blocking */ 00286 flags = fcntl(sockfd, F_GETFL, 0); 00287 if (flags < 0) { 00288 se_log_error("unable to start interface, fcntl(F_GETFL) " 00289 "failed: %s", strerror(errno)); 00290 close(sockfd); 00291 return; 00292 } 00293 flags |= O_NONBLOCK; 00294 if (fcntl(sockfd, F_SETFL, flags) < 0) { 00295 se_log_error("Unable to start interface, fcntl(F_SETFL) " 00296 "failed: %s", strerror(errno)); 00297 close(sockfd); 00298 return; 00299 } 00300 00301 /* set stdin to non-blocking */ 00302 flags = fcntl(fileno(stdin), F_GETFL, 0); 00303 if (flags < 0) { 00304 se_log_error("Unable to start interface, fcntl(F_GETFL) " 00305 "failed: %s", strerror(errno)); 00306 close(sockfd); 00307 return; 00308 } 00309 flags |= O_NONBLOCK; 00310 if (fcntl(fileno(stdin), F_SETFL, flags) < 0) { 00311 se_log_error("Unable to start interface, fcntl(F_SETFL) " 00312 "failed: %s", strerror(errno)); 00313 close(sockfd); 00314 return; 00315 } 00316 00317 /* some sort of interface */ 00318 if (!cmd) { 00319 fprintf(stderr, "cmd> "); 00320 } 00321 00322 /* run */ 00323 se_log_init(NULL, 0, 0); 00324 interface_run(stdin, sockfd, cmd); 00325 close(sockfd); 00326 return; 00327 } 00328 00329 00334 int 00335 main(int argc, char* argv[]) 00336 { 00337 int c; 00338 int options_size = 0; 00339 const char* options[4]; 00340 char* cmd = NULL; 00341 00342 if (argc > 3) { 00343 fprintf(stderr,"error, too many arguments\n"); 00344 exit(1); 00345 } 00346 00347 /* command line options */ 00348 for (c = 0; c < argc; c++) { 00349 options[c] = argv[c]; 00350 if (c > 0) { 00351 options_size += strlen(argv[c]) + 1; 00352 } 00353 } 00354 if (argc > 1) { 00355 cmd = (char*) se_calloc(options_size+2,sizeof(char)); 00356 (void)strncpy(cmd, "", 1); 00357 for (c = 1; c < argc; c++) { 00358 (void)strncat(cmd, options[c], strlen(options[c])); 00359 (void)strncat(cmd, " ", 1); 00360 } 00361 cmd[options_size-1] = '\n'; 00362 } 00363 00364 /* main stuff */ 00365 if (cmd && se_strcmp(cmd, "-h\n") == 0) { 00366 usage(stdout); 00367 return 0; 00368 } else if (cmd && se_strcmp(cmd, "--help\n") == 0) { 00369 usage(stdout); 00370 return 0; 00371 } 00372 00373 interface_start(cmd); 00374 00375 /* done */ 00376 if (cmd) { 00377 se_free((void*)cmd); 00378 } 00379 return 0; 00380 }