OpenDNSSEC-signer 1.2.1

/build/buildd-opendnssec_1.2.1.dfsg-1-mips-p9AT07/opendnssec-1.2.1.dfsg/signer/src/ods-signer.c

Go to the documentation of this file.
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 }