fix source so that '-Wformat -Werror=format-security' doesn't stop us from compiling
[citadel.git] / citadel / utillib / citadel_ipc.c
index bfef117d5582d6a6ab3ff1912a37eafdcd968939..52da9167e10a1d34860421f3fc05247e0b5a9b14 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id$ 
- *
+/*
  * Copyright (c) 1987-2009 by the citadel.org team
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -364,8 +363,6 @@ int CtdlIPCGetConfig(CtdlIPC *ipc, struct ctdluser **uret, char *cret)
 
        ret = CtdlIPCGenericCommand(ipc, "GETU", NULL, 0, NULL, NULL, cret);
        if (ret / 100 == 2) {
-               uret[0]->USscreenwidth = extract_int(cret, 0);
-               uret[0]->USscreenheight = extract_int(cret, 1);
                uret[0]->flags = extract_int(cret, 2);
        }
        return ret;
@@ -380,9 +377,10 @@ int CtdlIPCSetConfig(CtdlIPC *ipc, struct ctdluser *uret, char *cret)
        if (!uret) return -2;
        if (!cret) return -2;
 
-       sprintf(aaa, "SETU %d|%d|%d",
-                       uret->USscreenwidth, uret->USscreenheight,
-                       uret->flags);
+       sprintf(aaa,
+               "SETU 80|24|%d",
+               uret->flags
+       );
        return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
 }
 
@@ -756,6 +754,8 @@ int CtdlIPCServerInfo(CtdlIPC *ipc, char *cret)
                                        break;
                        case 22:        strcpy(ipc->ServInfo.svn_revision, buf);
                                        break;
+                       case 24:        ipc->ServInfo.guest_logins = atoi(buf);
+                                       break;
                        }
                }
 
@@ -2184,7 +2184,7 @@ int CtdlIPCMessageBaseCheck(CtdlIPC *ipc, char **mret, char *cret)
 
 
 /* ************************************************************************** */
-/*             Stuff below this line is not for public consumption            */
+/*          Stuff below this line is not for public consumption            */
 /* ************************************************************************** */
 
 
@@ -2613,55 +2613,79 @@ int CtdlIPCGenericCommand(CtdlIPC *ipc,
 }
 
 
-static int connectsock(char *host, char *service, char *protocol, int defaultPort)
+/*
+ * Connect to a Citadel on a remote host using a TCP/IP socket
+ */
+static int tcp_connectsock(char *host, char *service)
 {
-       struct hostent *phe;
-       struct servent *pse;
-       struct protoent *ppe;
-       struct sockaddr_in sin;
-       int s, type;
+       struct in6_addr serveraddr;
+       struct addrinfo hints;
+       struct addrinfo *res = NULL;
+       struct addrinfo *ai = NULL;
+       int rc = (-1);
+       int sock = (-1);
 
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
-
-       pse = getservbyname(service, protocol);
-       if (pse != NULL) {
-               sin.sin_port = pse->s_port;
-       }
-       else if (atoi(service) > 0) {
-               sin.sin_port = htons(atoi(service));
+       if ((host == NULL) || IsEmptyStr(host)) {
+               service = DEFAULT_HOST ;
        }
-       else {
-               sin.sin_port = htons(defaultPort);
-       }
-       phe = gethostbyname(host);
-       if (phe) {
-               memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
-       } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
-               return -1;
+       if ((service == NULL) || IsEmptyStr(service)) {
+               service = DEFAULT_PORT ;
        }
-       if ((ppe = getprotobyname(protocol)) == 0) {
-               return -1;
+
+       memset(&hints, 0x00, sizeof(hints));
+       hints.ai_flags = AI_NUMERICSERV;
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+
+       /*
+        * Handle numeric IPv4 and IPv6 addresses
+        */
+       rc = inet_pton(AF_INET, host, &serveraddr);
+       if (rc == 1) {                                          /* dotted quad */
+               hints.ai_family = AF_INET;
+               hints.ai_flags |= AI_NUMERICHOST;
        }
-       if (!strcmp(protocol, "udp")) {
-               type = SOCK_DGRAM;
-       } else {
-               type = SOCK_STREAM;
+       else {
+               rc = inet_pton(AF_INET6, host, &serveraddr);
+               if (rc == 1) {                                  /* IPv6 address */
+                       hints.ai_family = AF_INET6;
+                       hints.ai_flags |= AI_NUMERICHOST;
+               }
        }
 
-       s = socket(PF_INET, type, ppe->p_proto);
-       if (s < 0) {
-               return -1;
+       /* Begin the connection process */
+
+       rc = getaddrinfo(host, service, &hints, &res);
+       if (rc != 0) {
+               return(-1);
        }
 
-       if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-               close(s);
-               return -1;
+       /*
+        * Try all available addresses until we connect to one or until we run out.
+        */
+       for (ai = res; ai != NULL; ai = ai->ai_next) {
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0) return(-1);
+
+               rc = connect(sock, ai->ai_addr, ai->ai_addrlen);
+               if (rc >= 0) {
+                       return(sock);           /* Connected! */
+               }
+               else {
+                       close(sock);            /* Failed.  Close the socket to avoid fd leak! */
+               }
        }
 
-       return (s);
+       return(-1);
 }
 
+
+
+
+
+/*
+ * Connect to a Citadel on the local host using a unix domain socket
+ */
 static int uds_connectsock(int *isLocal, char *sockpath)
 {
        struct sockaddr_un addr;
@@ -3227,7 +3251,7 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf)
        /* If we're using a unix domain socket we can do a bunch of stuff */
        if (!strcmp(cithost, UDS)) {
                if (!strcasecmp(citport, DEFAULT_PORT)) {
-                       snprintf(sockpath, sizeof sockpath, file_citadel_socket);
+                       snprintf(sockpath, sizeof sockpath, "%s", file_citadel_socket);
                }
                else {
                        snprintf(sockpath, sizeof sockpath, "%s/%s", citport, "citadel.socket");
@@ -3239,14 +3263,36 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf)
                }
                if (hostbuf != NULL) strcpy(hostbuf, cithost);
                if (portbuf != NULL) strcpy(portbuf, sockpath);
+               strcpy(ipc->ip_hostname, "");
+               strcpy(ipc->ip_address, "");
                return ipc;
        }
 
-       ipc->sock = connectsock(cithost, citport, "tcp", 504);
+       ipc->sock = tcp_connectsock(cithost, citport);
        if (ipc->sock == -1) {
                ifree(ipc);
                return 0;
        }
+
+
+       /* Learn the actual network identity of the host to which we are connected */
+
+       struct sockaddr_in6 clientaddr;
+       unsigned int addrlen = sizeof(clientaddr);
+
+       ipc->ip_hostname[0] = 0;
+       ipc->ip_address[0] = 0;
+
+       getpeername(ipc->sock, (struct sockaddr *)&clientaddr, &addrlen);
+       getnameinfo((struct sockaddr *)&clientaddr, addrlen,
+               ipc->ip_hostname, sizeof ipc->ip_hostname, NULL, 0, 0
+       );
+       getnameinfo((struct sockaddr *)&clientaddr, addrlen,
+               ipc->ip_address, sizeof ipc->ip_address, NULL, 0, NI_NUMERICHOST
+       );
+
+       /* stuff other things elsewhere */
+
        if (hostbuf != NULL) strcpy(hostbuf, cithost);
        if (portbuf != NULL) strcpy(portbuf, citport);
        return ipc;