Don't fail with an error if an attribute that is to be deleted does not exist
[strongswan.git] / src / libhydra / plugins / attr_sql / pool_attributes.c
index 7ee2075..0ef1b4a 100644 (file)
@@ -32,7 +32,7 @@ extern database_t *db;
 ENUM(value_type_names, VALUE_HEX, VALUE_SUBNET,
        "hex",
        "string",
-       "server",
+       "addr",
        "subnet"
 );
 
@@ -46,31 +46,36 @@ struct attr_info_t {
 };
 
 static const attr_info_t attr_info[] = {
-       { "internal_ip4_dns",    VALUE_ADDR,   INTERNAL_IP4_DNS,    0 },
-       { "internal_ip6_dns",    VALUE_ADDR,   INTERNAL_IP6_DNS,    0 },
-       { "dns",                 VALUE_ADDR,   INTERNAL_IP4_DNS,
-                                                                                  INTERNAL_IP6_DNS       },
-       { "internal_ip4_nbns",   VALUE_ADDR,   INTERNAL_IP4_NBNS,   0 },
-       { "internal_ip6_nbns",   VALUE_ADDR,   INTERNAL_IP6_NBNS,   0 },
-       { "nbns",                VALUE_ADDR,   INTERNAL_IP4_NBNS,
-                                                                                  INTERNAL_IP6_NBNS      },
-       { "wins",                VALUE_ADDR,   INTERNAL_IP4_NBNS,
-                                                                                  INTERNAL_IP6_NBNS      },
-       { "internal_ip4_dhcp",   VALUE_ADDR,   INTERNAL_IP4_DHCP,   0 },
-       { "internal_ip6_dhcp",   VALUE_ADDR,   INTERNAL_IP6_DHCP,   0 },
-       { "dhcp",                VALUE_ADDR,   INTERNAL_IP4_DHCP,
-                                                                                  INTERNAL_IP6_DHCP      },
-       { "internal_ip4_server", VALUE_ADDR,   INTERNAL_IP4_SERVER, 0 },
-       { "internal_ip6_server", VALUE_ADDR,   INTERNAL_IP6_SERVER, 0 },
-       { "server",              VALUE_ADDR,   INTERNAL_IP4_SERVER,
-                                                                                  INTERNAL_IP6_SERVER    },
-       { "application_version", VALUE_STRING, APPLICATION_VERSION, 0 },
-       { "version",             VALUE_STRING, APPLICATION_VERSION, 0 },
-       { "unity_banner",        VALUE_STRING, UNITY_BANNER,        0 },
-       { "banner",              VALUE_STRING, UNITY_BANNER,        0 },
-       { "unity_splitdns_name", VALUE_STRING, UNITY_SPLITDNS_NAME, 0 },
-       { "unity_split_include", VALUE_SUBNET, UNITY_SPLIT_INCLUDE, 0 },
-       { "unity_local_lan",     VALUE_SUBNET, UNITY_LOCAL_LAN,     0 },
+       { "internal_ip4_netmask", VALUE_ADDR,   INTERNAL_IP4_NETMASK, 0 },
+       { "internal_ip6_netmask", VALUE_ADDR,   INTERNAL_IP6_NETMASK, 0 },
+       { "netmask",              VALUE_ADDR,   INTERNAL_IP4_NETMASK,
+                                                                                       INTERNAL_IP6_NETMASK    },
+       { "internal_ip4_dns",     VALUE_ADDR,   INTERNAL_IP4_DNS,     0 },
+       { "internal_ip6_dns",     VALUE_ADDR,   INTERNAL_IP6_DNS,     0 },
+       { "dns",                  VALUE_ADDR,   INTERNAL_IP4_DNS,
+                                                                                       INTERNAL_IP6_DNS        },
+       { "internal_ip4_nbns",    VALUE_ADDR,   INTERNAL_IP4_NBNS,    0 },
+       { "internal_ip6_nbns",    VALUE_ADDR,   INTERNAL_IP6_NBNS,    0 },
+       { "nbns",                 VALUE_ADDR,   INTERNAL_IP4_NBNS,
+                                                                                       INTERNAL_IP6_NBNS       },
+       { "wins",                 VALUE_ADDR,   INTERNAL_IP4_NBNS,
+                                                                                       INTERNAL_IP6_NBNS       },
+       { "internal_ip4_dhcp",    VALUE_ADDR,   INTERNAL_IP4_DHCP,    0 },
+       { "internal_ip6_dhcp",    VALUE_ADDR,   INTERNAL_IP6_DHCP,    0 },
+       { "dhcp",                 VALUE_ADDR,   INTERNAL_IP4_DHCP,
+                                                                                       INTERNAL_IP6_DHCP       },
+       { "internal_ip4_server",  VALUE_ADDR,   INTERNAL_IP4_SERVER,  0 },
+       { "internal_ip6_server",  VALUE_ADDR,   INTERNAL_IP6_SERVER,  0 },
+       { "server",               VALUE_ADDR,   INTERNAL_IP4_SERVER,
+                                                                                       INTERNAL_IP6_SERVER     },
+       { "application_version",  VALUE_STRING, APPLICATION_VERSION,  0 },
+       { "version",              VALUE_STRING, APPLICATION_VERSION,  0 },
+       { "unity_banner",         VALUE_STRING, UNITY_BANNER,         0 },
+       { "banner",               VALUE_STRING, UNITY_BANNER,         0 },
+       { "unity_def_domain",     VALUE_STRING, UNITY_DEF_DOMAIN,     0 },
+       { "unity_splitdns_name",  VALUE_STRING, UNITY_SPLITDNS_NAME,  0 },
+       { "unity_split_include",  VALUE_SUBNET, UNITY_SPLIT_INCLUDE,  0 },
+       { "unity_local_lan",      VALUE_SUBNET, UNITY_LOCAL_LAN,      0 },
 };
 
 /**
@@ -82,8 +87,8 @@ static bool parse_attributes(char *name, char *value, value_type_t *value_type,
                                                         chunk_t *blob)
 {
        host_t *addr = NULL, *mask = NULL;
-       chunk_t addr_chunk, mask_chunk;
-       char *text = "", *pos, *endptr;
+       chunk_t addr_chunk, mask_chunk, blob_next;
+       char *text = "", *pos_addr, *pos_mask, *pos_next, *endptr;
        int i;
 
        switch (*value_type)
@@ -106,31 +111,53 @@ static bool parse_attributes(char *name, char *value, value_type_t *value_type,
                        *blob = chunk_clone(addr_chunk);
                        break;
                case VALUE_SUBNET:
-                       pos = strchr(value, '/');
-                       if (pos == NULL || (value - pos) == strlen(value))
-                       {
-                               fprintf(stderr, "invalid IPv4 subnet: '%s'.\n", value);
-                               return FALSE;
-                       }
-                       *pos = '\0';
-                       addr = host_create_from_string(value, 0);
-                       mask = host_create_from_string(pos+1, 0);
-                       if (addr == NULL || addr->get_family(addr) != AF_INET ||
-                               mask == NULL || mask->get_family(addr) != AF_INET)
+                       *blob = chunk_empty;
+                       pos_next = value;
+
+                       do
                        {
-                               fprintf(stderr, "invalid IPv4 subnet: '%s'.\n", value);
-                               DESTROY_IF(addr);
-                               DESTROY_IF(mask);
-                               return FALSE;
+                               pos_addr = pos_next;
+                               pos_next = strchr(pos_next, ',');
+                               if (pos_next)
+                               {
+                                       *pos_next = '\0';
+                                       pos_next += 1;
+                               }
+                               pos_mask = strchr(pos_addr, '/');
+                               if (pos_mask == NULL)
+                               {
+                                       fprintf(stderr, "invalid IPv4 subnet: '%s'.\n", pos_addr);
+                                       free(blob->ptr);
+                                       return FALSE;
+                               }
+                               *pos_mask = '\0';
+                               pos_mask += 1;
+                               addr = host_create_from_string(pos_addr, 0);
+                               mask = host_create_from_string(pos_mask, 0);
+                               if (addr == NULL || addr->get_family(addr) != AF_INET ||
+                                       mask == NULL || mask->get_family(addr) != AF_INET)
+                               {
+                                       fprintf(stderr, "invalid IPv4 subnet: '%s/%s'.\n",
+                                                                       pos_addr, pos_mask);
+                                       DESTROY_IF(addr);
+                                       DESTROY_IF(mask);
+                                       free(blob->ptr);
+                                       return FALSE;
+                               }
+                               addr_chunk = addr->get_address(addr);
+                               mask_chunk = mask->get_address(mask);
+                               blob_next = chunk_alloc(blob->len + UNITY_NETWORK_LEN);
+                               memcpy(blob_next.ptr, blob->ptr, blob->len);
+                               pos_addr = blob_next.ptr + blob->len;
+                               memset(pos_addr, 0x00, UNITY_NETWORK_LEN);
+                               memcpy(pos_addr,     addr_chunk.ptr, 4);
+                               memcpy(pos_addr + 4, mask_chunk.ptr, 4);
+                               addr->destroy(addr);
+                               mask->destroy(mask);
+                               chunk_free(blob);
+                               *blob = blob_next;
                        }
-                       addr_chunk = addr->get_address(addr);
-                       mask_chunk = mask->get_address(mask);
-                       *blob = chunk_alloc(UNITY_NETWORK_LEN);
-                       memset(blob->ptr, 0x00, UNITY_NETWORK_LEN);
-                       memcpy(blob->ptr,     addr_chunk.ptr, 4);
-                       memcpy(blob->ptr + 4, mask_chunk.ptr, 4);
-                       addr->destroy(addr);
-                       mask->destroy(mask);
+                       while (pos_next);
                        break;
                case VALUE_NONE:
                        *blob = chunk_empty;
@@ -145,13 +172,15 @@ static bool parse_attributes(char *name, char *value, value_type_t *value_type,
        {
                if (strcaseeq(name, attr_info[i].keyword))
                {
+                       *type      = attr_info[i].type;
+                       *type_ip6  = attr_info[i].type_ip6;
+
                        if (*value_type == VALUE_NONE)
                        {
                                *value_type = attr_info[i].value_type;
-                               *type       = attr_info[i].type;
-                               *type_ip6   = attr_info[i].type_ip6;
                                return TRUE;
                        }
+
                        if (*value_type != attr_info[i].value_type &&
                                *value_type != VALUE_HEX)
                        {
@@ -179,27 +208,24 @@ static bool parse_attributes(char *name, char *value, value_type_t *value_type,
                                free(blob->ptr);
                                return FALSE;
                        }
+
                        if (*value_type == VALUE_ADDR)
                        {
                                *type = (addr->get_family(addr) == AF_INET) ?
                                                        attr_info[i].type : attr_info[i].type_ip6;
                                addr->destroy(addr);
                        }
-                       if (*value_type == VALUE_HEX)
+                       else if (*value_type == VALUE_HEX)
                        {
                                *value_type = attr_info[i].value_type;
 
                                if (*value_type == VALUE_ADDR)
                                {
-                                       if (blob->len == 4)
-                                       {
-                                               *type = attr_info[i].type;
-                                       }
-                                       else if (blob->len == 16)
+                                       if (blob->len == 16)
                                        {
                                                *type = attr_info[i].type_ip6;
                                        }
-                                       else
+                                       else if (blob->len != 4)
                                        {
                                                fprintf(stderr, "the %s attribute requires "
                                                                                "a valid IP address.\n", name);
@@ -207,14 +233,6 @@ static bool parse_attributes(char *name, char *value, value_type_t *value_type,
                                                return FALSE;
                                        }
                                }
-                               else
-                               {
-                                       *type = attr_info[i].type;
-                               }                       
-                       }
-                       else
-                       {
-                               *type = attr_info[i].type;
                        }
                        return TRUE;
                }
@@ -236,7 +254,7 @@ static bool parse_attributes(char *name, char *value, value_type_t *value_type,
        {
                fprintf(stderr, "the attribute type must lie in the range 1..32767.\n");
                free(blob->ptr);
-               return FALSE);
+               return FALSE;
        }
        if (*value_type == VALUE_NONE)
        {
@@ -264,6 +282,7 @@ void add_attr(char *name, char *value, value_type_t value_type)
        {
                exit(EXIT_FAILURE);
        }
+
        success = db->execute(db, NULL,
                                "INSERT INTO attributes (type, value) VALUES (?, ?)",
                                DB_INT, type, DB_BLOB, blob) == 1;
@@ -297,6 +316,7 @@ void del_attr(char *name, char *value, value_type_t value_type)
        {
                exit(EXIT_FAILURE);
        }
+
        if (blob.len > 0)
        {
                query = db->query(db,
@@ -415,14 +435,12 @@ void del_attr(char *name, char *value, value_type_t value_type)
                        }
                        else
                        {
-                               fprintf(stderr, "the %s attribute (%N) with value '%*.s' "
+                               fprintf(stderr, "the %s attribute (%N) with value '%.*s' "
                                                                "was not found.\n", name,
                                                                 configuration_attribute_type_names, type,
                                                                 blob.len, blob.ptr);
                        }
                }
-               free(blob.ptr);
-               exit(EXIT_FAILURE);
        }
        free(blob.ptr);
 }
@@ -430,13 +448,16 @@ void del_attr(char *name, char *value, value_type_t value_type)
 /**
  * ipsec pool --statusattr - show all attribute entries
  */
-void status_attr(void)
+void status_attr(bool hexout)
 {
        configuration_attribute_type_t type;
-       chunk_t value;
+       value_type_t value_type;
+       chunk_t value, addr_chunk, mask_chunk;
        enumerator_t *enumerator;
+       host_t *addr, *mask;
        char type_name[30];
        bool first = TRUE;
+       int i;
 
        /* enumerate over all attributes */
        enumerator = db->query(db, "SELECT type, value FROM attributes ORDER BY type",
@@ -447,7 +468,7 @@ void status_attr(void)
                {
                        if (first)
                        {
-                               printf(" type  description          value\n");
+                               printf(" type  description           value\n");
                                first = FALSE;
                        }
                        snprintf(type_name, sizeof(type_name), "%N",
@@ -456,7 +477,63 @@ void status_attr(void)
                        {
                                type_name[0] = '\0';
                        }
-                       printf("%5d  %-20s %#B\n",type, type_name, &value);
+                       printf("%5d  %-20s ",type, type_name);
+
+                       value_type = VALUE_HEX;
+                       if (!hexout)
+                       {
+                               for (i = 0; i < countof(attr_info); i++)
+                               {
+                                       if (type == attr_info[i].type)
+                                       {
+                                               value_type = attr_info[i].value_type;
+                                               break; 
+                                       }
+                               }
+                       }
+                       switch (value_type)
+                       {
+                               case VALUE_ADDR:
+                                       addr = host_create_from_chunk(AF_UNSPEC, value, 0);
+                                       if (addr)
+                                       {
+                                               printf(" %H\n", addr);
+                                               addr->destroy(addr);
+                                       }
+                                       else
+                                       {
+                                               /* value cannot be represented as an IP address */
+                                               printf(" %#B\n", &value);
+                                       }
+                                       break;
+                               case VALUE_SUBNET:
+                                       if (value.len % UNITY_NETWORK_LEN == 0)
+                                       {
+                                               for (i = 0; i < value.len / UNITY_NETWORK_LEN; i++)
+                                               {
+                                                       addr_chunk = chunk_create(value.ptr + i*UNITY_NETWORK_LEN, 4);
+                                                       addr = host_create_from_chunk(AF_INET, addr_chunk, 0);
+                                                       mask_chunk = chunk_create(addr_chunk.ptr + 4, 4);
+                                                       mask = host_create_from_chunk(AF_INET, mask_chunk, 0);
+                                                       printf("%s%H/%H", (i > 0) ? "," : " ", addr, mask);
+                                                       addr->destroy(addr);
+                                                       mask->destroy(mask);
+                                               }
+                                               printf("\n");
+                                       }
+                                       else
+                                       {
+                                               /* value cannot be represented as a list of subnets */
+                                               printf(" %#B\n", &value);
+                                       }
+                                       break;
+                               case VALUE_STRING:
+                                       printf("\"%.*s\"\n", value.len, value.ptr);
+                                       break;                                  
+                               case VALUE_HEX:
+                               default:
+                                       printf(" %#B\n", &value);
+                       }
                }
                enumerator->destroy(enumerator);
        }
@@ -477,7 +554,7 @@ void show_attr(void)
                snprintf(value_name, sizeof(value_name), "%N",
                        value_type_names, attr_info[i].value_type);
        
-               printf("%-19s  --%-6s  (%N", 
+               printf("%-20s  --%-6s  (%N", 
                                attr_info[i].keyword, value_name, 
                                configuration_attribute_type_names, attr_info[i].type);