LCOV - code coverage report
Current view: top level - clients/mapilib - msettings.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 283 375 75.5 %
Date: 2024-04-26 00:35:57 Functions: 32 35 91.4 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : 
      15             : #include "msettings.h"
      16             : 
      17             : #include <assert.h>
      18             : #include <ctype.h>
      19             : #include <limits.h>
      20             : #include <stdarg.h>
      21             : #include <stdio.h>
      22             : #include <stdlib.h>
      23             : #include <string.h>
      24             : #ifdef HAVE_STRINGS_H
      25             : #include <strings.h>
      26             : #endif
      27             : 
      28             : #define FATAL() do { fprintf(stderr, "\n\n abort in params.c: %s\n\n", __func__); abort(); } while (0)
      29             : 
      30         779 : int msetting_parse_bool(const char *text)
      31             : {
      32         779 :         static struct { const char *word; bool value; } variants[] = {
      33             :                 { "true", true },
      34             :                 { "false", false },
      35             :                 { "yes", true },
      36             :                 { "no", false },
      37             :                 { "on", true },
      38             :                 { "off", false },
      39             :         };
      40        3752 :         for (size_t i = 0; i < sizeof(variants) / sizeof(variants[0]); i++)
      41        3738 :                 if (strcasecmp(text, variants[i].word) == 0)
      42         765 :                         return variants[i].value;
      43             :         return -1;
      44             : }
      45             : 
      46             : char* allocprintf(const char *fmt, ...)
      47             :         __attribute__((__format__(__printf__, 1, 2)));
      48             : 
      49             : char *
      50         601 : allocprintf(const char *fmt, ...)
      51             : {
      52         601 :         size_t buflen = 80;
      53         601 :         while (1) {
      54         601 :                 char *buf = malloc(buflen);
      55         601 :                 if (buf == NULL)
      56         601 :                         return NULL;
      57         601 :                 va_list ap;
      58         601 :                 va_start(ap, fmt);
      59         601 :                 int n = vsnprintf(buf, buflen, fmt, ap);
      60         601 :                 va_end(ap);
      61         601 :                 if (n >= 0 && (size_t)n < buflen)
      62         601 :                         return buf;
      63           0 :                 free(buf);
      64           0 :                 if (n < 0)
      65             :                         return NULL;
      66           0 :                 buflen = n + 1;
      67             :         }
      68             : }
      69             : 
      70             : 
      71             : 
      72             : 
      73             : static const struct { const char *name;  mparm parm; }
      74             : by_name[] = {
      75             :         { .name="autocommit", .parm=MP_AUTOCOMMIT },
      76             :         { .name="binary", .parm=MP_BINARY },
      77             :         { .name="cert", .parm=MP_CERT },
      78             :         { .name="certhash", .parm=MP_CERTHASH },
      79             :         { .name="clientcert", .parm=MP_CLIENTCERT },
      80             :         { .name="clientkey", .parm=MP_CLIENTKEY },
      81             :         { .name="database", .parm=MP_DATABASE },
      82             :         { .name="host", .parm=MP_HOST },
      83             :         { .name="language", .parm=MP_LANGUAGE },
      84             :         { .name="password", .parm=MP_PASSWORD },
      85             :         { .name="port", .parm=MP_PORT },
      86             :         { .name="replysize", .parm=MP_REPLYSIZE },
      87             :         { .name="fetchsize", .parm=MP_REPLYSIZE },
      88             :         { .name="schema", .parm=MP_SCHEMA },
      89             :         { .name="sock", .parm=MP_SOCK },
      90             :         { .name="sockdir", .parm=MP_SOCKDIR},
      91             :         { .name="table", .parm=MP_TABLE },
      92             :         { .name="tableschema", .parm=MP_TABLESCHEMA },
      93             :         { .name="timezone", .parm=MP_TIMEZONE },
      94             :         { .name="tls", .parm=MP_TLS },
      95             :         { .name="user", .parm=MP_USER },
      96             :         //
      97             :         { .name="hash", .parm=MP_IGNORE },
      98             :         { .name="debug", .parm=MP_IGNORE },
      99             :         { .name="logfile", .parm=MP_IGNORE },
     100             : };
     101             : 
     102             : mparm
     103         515 : mparm_parse(const char *name)
     104             : {
     105         515 :         int n = sizeof(by_name) / sizeof(by_name[0]);
     106             :         // could use a binary search but this is not going to be a bottleneck
     107        5803 :         for (int i = 0; i < n; i++)
     108        5798 :                 if (strcmp(by_name[i].name, name) == 0)
     109         510 :                         return by_name[i].parm;
     110             : 
     111           5 :         return strchr(name, '_') ? MP_IGNORE : MP_UNKNOWN;
     112             : }
     113             : 
     114             : const char *
     115           0 : mparm_name(mparm parm)
     116             : {
     117           0 :         switch (parm) {
     118             :                 case MP_AUTOCOMMIT: return "autocommit";
     119           0 :                 case MP_BINARY: return "binary";
     120           0 :                 case MP_CERT: return "cert";
     121           0 :                 case MP_CERTHASH: return "certhash";
     122           0 :                 case MP_CLIENTCERT: return "clientcert";
     123           0 :                 case MP_CLIENTKEY: return "clientkey";
     124           0 :                 case MP_DATABASE: return "database";
     125           0 :                 case MP_HOST: return "host";
     126           0 :                 case MP_LANGUAGE: return "language";
     127           0 :                 case MP_PASSWORD: return "password";
     128           0 :                 case MP_PORT: return "port";
     129           0 :                 case MP_REPLYSIZE: return "replysize";
     130           0 :                 case MP_SCHEMA: return "schema";
     131           0 :                 case MP_SOCK: return "sock";
     132           0 :                 case MP_SOCKDIR: return "sockdir";
     133           0 :                 case MP_TABLE: return "table";
     134           0 :                 case MP_TABLESCHEMA: return "tableschema";
     135           0 :                 case MP_TIMEZONE: return "timezone";
     136           0 :                 case MP_TLS: return "tls";
     137           0 :                 case MP_USER: return "user";
     138           0 :                 default: FATAL();
     139             :         }
     140             : }
     141             : 
     142             : bool
     143         142 : mparm_is_core(mparm parm)
     144             : {
     145         142 :         switch (parm) {
     146             :                 case MP_TLS:
     147             :                 case MP_HOST:
     148             :                 case MP_PORT:
     149             :                 case MP_DATABASE:
     150             :                 case MP_TABLESCHEMA:
     151             :                 case MP_TABLE:
     152             :                         return true;
     153         136 :                 default:
     154         136 :                         return false;
     155             :         }
     156             : }
     157             : 
     158             : struct string {
     159             :         char *str;
     160             :         bool must_free;
     161             : };
     162             : 
     163             : struct msettings {
     164             :         // Must match EXACTLY the order of enum mparm
     165             :         bool dummy_start_bool;
     166             :         bool tls;
     167             :         bool autocommit;
     168             :         bool dummy_end_bool;
     169             : 
     170             :         // Must match EXACTLY the order of enum mparm
     171             :         long dummy_start_long;
     172             :         long port;
     173             :         long timezone;
     174             :         long replysize;
     175             :         long dummy_end_long;
     176             : 
     177             :         // Must match EXACTLY the order of enum mparm
     178             :         struct string dummy_start_string;
     179             :         struct string sock;
     180             :         struct string sockdir;
     181             :         struct string cert;
     182             :         struct string clientkey;
     183             :         struct string clientcert;
     184             :         struct string host;
     185             :         struct string database;
     186             :         struct string tableschema;
     187             :         struct string table;
     188             :         struct string certhash;
     189             :         struct string user;
     190             :         struct string password;
     191             :         struct string language;
     192             :         struct string schema;
     193             :         struct string binary;
     194             :         struct string dummy_end_string;
     195             : 
     196             :         char **unknown_parameters;
     197             :         size_t nr_unknown;
     198             : 
     199             :         bool lang_is_mal;
     200             :         bool lang_is_sql;
     201             :         long user_generation;
     202             :         long password_generation;
     203             :         char *unix_sock_name_buffer;
     204             :         char certhash_digits_buffer[64 + 2 + 1]; // fit more than required plus trailing '\0'
     205             :         bool validated;
     206             : };
     207             : 
     208             : static
     209             : const msettings msettings_default_values = {
     210             :         .tls = false,
     211             :         .autocommit = true,
     212             : 
     213             :         .port = -1 ,
     214             :         .timezone = 0,
     215             :         .replysize = 100,
     216             : 
     217             :         .sockdir = { "/tmp", false },
     218             :         .binary = { "on", false },
     219             : 
     220             :         .unknown_parameters = NULL,
     221             :         .nr_unknown = 0,
     222             : 
     223             :         .lang_is_mal = false,
     224             :         .lang_is_sql = true,
     225             :         .unix_sock_name_buffer = NULL,
     226             :         .validated = false,
     227             : };
     228             : 
     229             : const msettings *msettings_default = &msettings_default_values;
     230             : 
     231         530 : msettings *msettings_create(void)
     232             : {
     233         530 :         msettings *mp = malloc(sizeof(*mp));
     234         530 :         if (!mp) {
     235             :                 free(mp);
     236             :                 return NULL;
     237             :         }
     238         530 :         *mp = msettings_default_values;
     239         530 :         return mp;
     240             : }
     241             : 
     242           0 : msettings *msettings_clone(const msettings *orig)
     243             : {
     244           0 :         msettings *mp = malloc(sizeof(*mp));
     245           0 :         char **unknowns = calloc(2 * orig->nr_unknown, sizeof(char*));
     246           0 :         char *cloned_name_buffer = strdup(orig->unix_sock_name_buffer);
     247           0 :         if (!mp || !unknowns || !cloned_name_buffer) {
     248           0 :                 free(mp);
     249           0 :                 free(unknowns);
     250           0 :                 free(cloned_name_buffer);
     251           0 :                 return NULL;
     252             :         }
     253           0 :         *mp = *orig;
     254           0 :         mp->unknown_parameters = unknowns;
     255           0 :         mp->unix_sock_name_buffer = cloned_name_buffer;
     256             : 
     257             :         // now we have to very carefully duplicate the strings.
     258             :         // taking care to only free our own ones if that fails
     259             : 
     260           0 :         struct string *start = &mp->dummy_start_string;
     261           0 :         struct string *end = &mp->dummy_end_string;
     262           0 :         struct string *p = start;
     263           0 :         while (p < end) {
     264           0 :                 if (p->must_free) {
     265           0 :                         p->str = strdup(p->str);
     266           0 :                         if (p->str == NULL)
     267           0 :                                 goto bailout;
     268             :                 }
     269           0 :                 p++;
     270             :         }
     271             : 
     272           0 :         for (size_t i = 0; i < 2 * mp->nr_unknown; i++) {
     273           0 :                 assert(orig->unknown_parameters[i]);
     274           0 :                 char *u = strdup(orig->unknown_parameters[i]);
     275           0 :                 if (u == NULL)
     276           0 :                         goto bailout;
     277           0 :                 mp->unknown_parameters[i] = u;
     278             :         }
     279             : 
     280             :         return mp;
     281             : 
     282           0 : bailout:
     283           0 :         for (struct string *q = start; q < p; q++)
     284           0 :                 if (q->must_free)
     285           0 :                         free(q->str);
     286           0 :         for (size_t i = 0; i < 2 * mp->nr_unknown; i++)
     287           0 :                 free(mp->unknown_parameters[i]);
     288           0 :         free(mp->unix_sock_name_buffer);
     289           0 :         free(mp);
     290           0 :         return NULL;
     291             : }
     292             : 
     293             : msettings *
     294         510 : msettings_destroy(msettings *mp)
     295             : {
     296         510 :         if (mp == NULL)
     297             :                 return NULL;
     298             : 
     299        8160 :         for (struct string *p = &mp->dummy_start_string + 1; p < &mp->dummy_end_string; p++) {
     300        7650 :                 if (p->must_free)
     301        2193 :                         free(p->str);
     302             :         }
     303         518 :         for (size_t i = 0; i < mp->nr_unknown; i++) {
     304           8 :                 free(mp->unknown_parameters[2 * i]);
     305           8 :                 free(mp->unknown_parameters[2 * i + 1]);
     306             :         }
     307         510 :         free(mp->unknown_parameters);
     308         510 :         free(mp->unix_sock_name_buffer);
     309         510 :         free(mp);
     310             : 
     311         510 :         return NULL;
     312             : }
     313             : 
     314             : const char*
     315       25243 : msetting_string(const msettings *mp, mparm parm)
     316             : {
     317       25243 :         if (mparm_classify(parm) != MPCLASS_STRING)
     318           0 :                 FATAL();
     319       25243 :         int i = parm - MP__STRING_START;
     320       25243 :         struct string const *p = &mp->dummy_start_string + 1 + i;
     321       25243 :         if (p >=  &mp->dummy_end_string)
     322           0 :                 FATAL();
     323       25243 :         char *s = p->str;
     324             : 
     325       25243 :         if (s == NULL) {
     326       11635 :                 if (parm == MP_LANGUAGE)
     327             :                         return "sql";
     328       11626 :                 else if (parm == MP_BINARY)
     329             :                         return "on";
     330       11626 :                 return "";
     331             :         }
     332             :         return s;
     333             : }
     334             : 
     335             : 
     336             : msettings_error
     337        3505 : msetting_set_string(msettings *mp, mparm parm, const char* value)
     338             : {
     339        3505 :         assert(value != NULL);
     340             : 
     341        3505 :         if (mparm_classify(parm) != MPCLASS_STRING)
     342           0 :                 FATAL();
     343        3512 :         int i = parm - MP__STRING_START;
     344        3512 :         struct string *p = &mp->dummy_start_string + 1 + i;
     345        3512 :         if (p >=  &mp->dummy_end_string)
     346           0 :                 FATAL();
     347             : 
     348        3512 :         char *v = strdup(value);
     349        3512 :         if (!v)
     350             :                 return "malloc failed";
     351        3512 :         if (p->must_free)
     352        1203 :                 free(p->str);
     353        3512 :         p->str = v;
     354        3512 :         p->must_free = true;
     355             : 
     356        3512 :         switch (parm) {
     357         412 :                 case MP_USER:
     358         412 :                         mp->user_generation++;
     359         412 :                         break;
     360         610 :                 case MP_PASSWORD:
     361         610 :                         mp->password_generation++;
     362         610 :                         break;
     363         404 :                 case MP_LANGUAGE:
     364         404 :                         mp->lang_is_mal = false;
     365         404 :                         mp->lang_is_sql = false;
     366             :                         // Tricky logic, a mixture of strstr==val and strcmp
     367             :                         // strstr==val is a clever way to compute 'startswith'
     368         404 :                         if (strcmp(value, "mal") == 0 || strcmp(value, "msql") == 0)
     369         196 :                                 mp->lang_is_mal = true;
     370         208 :                         else if (strstr(value, "sql") == value)
     371         206 :                                 mp->lang_is_sql = true;
     372             :                         else if (strcmp(value, "`"))
     373             :                         break;
     374             :                 default:
     375             :                         break;
     376             :         }
     377             : 
     378        3512 :         mp->validated = false;
     379        3512 :         return NULL;
     380             : }
     381             : 
     382             : 
     383             : long
     384       38583 : msetting_long(const msettings *mp, mparm parm)
     385             : {
     386       38583 :         if (mparm_classify(parm) != MPCLASS_LONG)
     387           0 :                 FATAL();
     388       38583 :         int i = parm - MP__LONG_START;
     389       38583 :         const long * p = &mp->dummy_start_long + 1 + i;
     390       38583 :         if (p >=  &mp->dummy_end_long)
     391           0 :                 FATAL();
     392             : 
     393       38583 :         return *p;
     394             : }
     395             : 
     396             : 
     397             : msettings_error
     398        1472 : msetting_set_long(msettings *mp, mparm parm, long value)
     399             : {
     400        1472 :         if (mparm_classify(parm) != MPCLASS_LONG)
     401           0 :                 FATAL();
     402        1472 :         int i = parm - MP__LONG_START;
     403        1472 :         long *p = &mp->dummy_start_long + 1 + i;
     404        1472 :         if (p >=  &mp->dummy_end_long)
     405           0 :                 FATAL();
     406             : 
     407        1472 :         *p = value;
     408             : 
     409        1472 :         mp->validated = false;
     410        1472 :         return NULL;
     411             : }
     412             : 
     413             : 
     414             : bool
     415        6709 : msetting_bool(const msettings *mp, mparm parm)
     416             : {
     417        6709 :         if (mparm_classify(parm) != MPCLASS_BOOL)
     418           0 :                 FATAL();
     419        6709 :         int i = parm - MP__BOOL_START;
     420        6709 :         const bool *p = &mp->dummy_start_bool + 1 + i;
     421        6709 :         if (p >=  &mp->dummy_end_bool)
     422           0 :                 FATAL();
     423        6709 :         return *p;
     424             : }
     425             : 
     426             : 
     427             : msettings_error
     428        1043 : msetting_set_bool(msettings *mp, mparm parm, bool value)
     429             : {
     430        1043 :         if (mparm_classify(parm) != MPCLASS_BOOL)
     431           0 :                 FATAL();
     432        1043 :         int i = parm - MP__BOOL_START;
     433        1043 :         bool *p = &mp->dummy_start_bool + 1 + i;
     434        1043 :         if (p >=  &mp->dummy_end_bool)
     435           0 :                 FATAL();
     436        1043 :         *p = value;
     437             : 
     438        1043 :         mp->validated = false;
     439        1043 :         return NULL;
     440             : }
     441             : 
     442             : msettings_error
     443        1018 : msetting_parse(msettings *mp, mparm parm, const char *text)
     444             : {
     445        1018 :         int b; // int not bool because we need to allow for parse errors
     446        1018 :         switch (mparm_classify(parm)) {
     447             :                 case MPCLASS_BOOL:
     448          22 :                         b = msetting_parse_bool(text);
     449          22 :                         if (b < 0)
     450             :                                 return "invalid boolean value";
     451          18 :                         return msetting_set_bool(mp, parm, b);
     452             :                 case MPCLASS_LONG:
     453          38 :                         if (text[0] == '\0')
     454             :                                 return "integer parameter cannot be empty string";
     455          35 :                         char *end;
     456          35 :                         long l = strtol(text, &end, 10);
     457          35 :                         if (*end != '\0')
     458             :                                 return "invalid integer";
     459          34 :                         return msetting_set_long(mp, parm, l);
     460             :                 case MPCLASS_STRING:
     461         958 :                         return msetting_set_string(mp, parm, text);
     462             :                 default:
     463             :                         assert(0 && "unreachable");
     464             :                         return "internal error, unclassified parameter type";
     465             :         }
     466             : }
     467             : 
     468             : char *
     469           0 : msetting_as_string(msettings *mp, mparm parm)
     470             : {
     471           0 :         bool b;
     472           0 :         long l;
     473           0 :         const char *s;
     474           0 :         switch (mparm_classify(parm)) {
     475             :                 case MPCLASS_BOOL:
     476           0 :                         b = msetting_bool(mp, parm);
     477           0 :                         return strdup(b ? "true" : " false");
     478             :                 case MPCLASS_LONG:
     479           0 :                         l = msetting_long(mp, parm);
     480           0 :                         int n = 40;
     481           0 :                         char *buf = malloc(n);
     482           0 :                         if (!buf)
     483             :                                 return NULL;
     484           0 :                         snprintf(buf, n, "%ld", l);
     485           0 :                         return buf;
     486             :                 case MPCLASS_STRING:
     487           0 :                         s = msetting_string(mp, parm);
     488           0 :                         return strdup(s);
     489             :                 default:
     490             :                         assert(0 && "unreachable");
     491             :                         return NULL;
     492             :         }
     493             : }
     494             : 
     495             : msettings_error
     496           8 : msetting_set_ignored(msettings *mp, const char *key, const char *value)
     497             : {
     498           8 :         char *my_key = strdup(key);
     499           8 :         char *my_value = strdup(value);
     500             : 
     501           8 :         size_t n = mp->nr_unknown;
     502           8 :         size_t new_size = (2 * n + 2) * sizeof(char*);
     503           8 :         char **new_unknowns = realloc(mp->unknown_parameters, new_size);
     504             : 
     505           8 :         if (!my_key || !my_value || !new_unknowns) {
     506           0 :                 free(my_key);
     507           0 :                 free(my_value);
     508           0 :                 free(new_unknowns);
     509           0 :                 return "malloc failed while setting ignored parameter";
     510             :         }
     511             : 
     512           8 :         new_unknowns[2 * n] = my_key;
     513           8 :         new_unknowns[2 * n + 1] = my_value;
     514           8 :         mp->unknown_parameters = new_unknowns;
     515           8 :         mp->nr_unknown += 1;
     516             : 
     517           8 :         return NULL;
     518             : }
     519             : 
     520             : /* store named parameter */
     521             : msettings_error
     522         277 : msetting_set_named(msettings *mp, bool allow_core, const char *key, const char *value)
     523             : {
     524         277 :         mparm parm = mparm_parse(key);
     525         277 :         if (parm == MP_UNKNOWN)
     526             :                 return "unknown parameter";
     527             : 
     528         276 :         if (parm == MP_IGNORE)
     529           8 :                 return msetting_set_ignored(mp, key, value);
     530             : 
     531         268 :         if (!allow_core && mparm_is_core(parm))
     532             :                 return "parameter not allowed here";
     533             : 
     534         262 :         return msetting_parse(mp, parm, value);
     535             : }
     536             : 
     537             : 
     538             : static bool
     539        5230 : empty(const msettings *mp, mparm parm)
     540             : {
     541        5230 :         const char *value = msetting_string(mp, parm);
     542        5230 :         assert(value);
     543        5230 :         return *value == '\0';
     544             : }
     545             : 
     546             : static bool
     547        3787 : nonempty(const msettings *mp, mparm parm)
     548             : {
     549         596 :         return !empty(mp, parm);
     550             : }
     551             : 
     552             : static msettings_error
     553         600 : validate_certhash(msettings *mp)
     554             : {
     555         600 :         mp->certhash_digits_buffer[0] = '\0';
     556             : 
     557         600 :         const char *full_certhash = msetting_string(mp, MP_CERTHASH);
     558         600 :         const char *certhash = full_certhash;
     559         600 :         if (*certhash == '\0')
     560             :                 return NULL;
     561             : 
     562          28 :         if (strncmp(certhash, "sha256:", 7) == 0) {
     563          19 :                 certhash += 7;
     564             :         } else {
     565             :                 return "expected certhash to start with 'sha256:'";
     566             :         }
     567             : 
     568          19 :         size_t i = 0;
     569         367 :         for (const char *r = certhash; *r != '\0'; r++) {
     570         349 :                 if (*r == ':')
     571          21 :                         continue;
     572         328 :                 if (!isxdigit(*r))
     573             :                         return "certhash: invalid hex digit";
     574         327 :                 if (i < sizeof(mp->certhash_digits_buffer) - 1)
     575         287 :                         mp->certhash_digits_buffer[i++] = tolower(*r);
     576             :         }
     577          18 :         mp->certhash_digits_buffer[i] = '\0';
     578          18 :         if (i == 0)
     579             :                 return "certhash: need at least one digit";
     580             : 
     581             :         return NULL;
     582             : }
     583             : 
     584             : static bool
     585        1733 : validate_identifier(const char *name)
     586             : {
     587        1733 :         int first = name[0];
     588        1733 :         if (first == '\0')
     589             :                 return true;
     590         489 :         if (first != '_' && !isalpha(first))
     591             :                 return false;
     592        8954 :         for (const char *p = name; *p; p++) {
     593        8485 :                 bool ok = (isalnum(*p) || *p == '.' || *p == '-' || *p == '_');
     594        8485 :                 if (!ok)
     595             :                         return false;
     596             :         }
     597             :         return true;
     598             : }
     599             : 
     600             : bool
     601        1786 : msettings_validate(msettings *mp, char **errmsg)
     602             : {
     603        1786 :         if (mp->validated)
     604             :                 return true;
     605             : 
     606             :         // 1. The parameters have the types listed in the table in [Section
     607             :         //    Parameters](#parameters).
     608             :         // (this has already been checked)
     609             : 
     610             :         // 2. At least one of **sock** and **host** must be empty.
     611         642 :         if (nonempty(mp, MP_SOCK) && nonempty(mp, MP_HOST)) {
     612           8 :                 *errmsg = allocprintf(
     613             :                         "With sock='%s', host must be 'localhost', not '%s'",
     614             :                         msetting_string(mp, MP_SOCK),
     615             :                         msetting_string(mp, MP_HOST));
     616           8 :                 return false;
     617             :         }
     618             : 
     619             :         // 3. The string parameter **binary** must either parse as a boolean or as a
     620             :         //    non-negative integer.
     621             :         // (pretend valid so we can use msettings_connect_binary() to see if it parses)
     622         608 :         mp->validated = true;
     623         608 :         long level = msettings_connect_binary(mp);
     624         608 :         mp->validated = false;
     625         608 :         if (level < 0) {
     626           4 :                 *errmsg = allocprintf("invalid value '%s' for parameter 'binary'", msetting_string(mp, MP_BINARY));
     627           4 :                 return false;
     628             :         }
     629             : 
     630             :         // 4. If **sock** is not empty, **tls** must be 'off'.
     631         604 :         if (nonempty(mp, MP_SOCK) && msetting_bool(mp, MP_TLS)) {
     632           4 :                 *errmsg = allocprintf("TLS cannot be used with Unix domain sockets");
     633           4 :                 return false;
     634             :         }
     635             : 
     636             :         // 5. If **certhash** is not empty, it must be of the form `sha256:hexdigits`
     637             :         //    where hexdigits is a non-empty sequence of 0-9, a-f, A-F and colons.
     638         600 :         const char *certhash_msg = validate_certhash(mp);
     639         600 :         if (certhash_msg) {
     640          10 :                 *errmsg = strdup(certhash_msg);
     641          10 :                 return false;
     642             :         }
     643             :         // 6. If **tls** is 'off', **cert** and **certhash** must be 'off' as well.
     644        1160 :         if (nonempty(mp, MP_CERT) || nonempty(mp, MP_CERTHASH))
     645          32 :                 if (!msetting_bool(mp, MP_TLS)) {
     646           5 :                         *errmsg = strdup("'cert' and 'certhash' can only be used with monetdbs://");
     647           5 :                         return false;
     648             :                 }
     649             : 
     650             :         // 7. Parameters **database**, **tableschema** and **table** must consist only of
     651             :         //    upper- and lowercase letters, digits, dashes and underscores. They must not
     652             :         //    start with a dash.
     653         585 :         const char *database = msetting_string(mp, MP_DATABASE);
     654         585 :         if (!validate_identifier(database)) {
     655           8 :                 *errmsg = allocprintf("invalid database name '%s'", database);
     656           8 :                 return false;
     657             :         }
     658         577 :         const char *tableschema = msetting_string(mp, MP_TABLESCHEMA);
     659         577 :         if (!validate_identifier(tableschema)) {
     660           6 :                 *errmsg = allocprintf("invalid schema name '%s'", tableschema);
     661           6 :                 return false;
     662             :         }
     663         571 :         const char *table = msetting_string(mp, MP_TABLE);
     664         571 :         if (!validate_identifier(table)) {
     665           6 :                 *errmsg = allocprintf("invalid table name '%s'", table);
     666           6 :                 return false;
     667             :         }
     668             : 
     669             :         // 8. Parameter **port** must be -1 or in the range 1-65535.
     670         565 :         long port = msetting_long(mp, MP_PORT);
     671         565 :         bool port_ok = (port == -1 || (port >= 1 && port <= 65535));
     672         565 :         if (!port_ok) {
     673           3 :                 *errmsg = allocprintf("invalid port '%ld'", port);
     674           3 :                 return false;
     675             :         }
     676             : 
     677             :         // 9. If **clientcert** is set, **clientkey** must also be set.
     678         562 :         if (nonempty(mp, MP_CLIENTCERT) && empty(mp, MP_CLIENTKEY)) {
     679           1 :                 *errmsg = allocprintf("clientcert can only be set together with clientkey");
     680           1 :                 return false;
     681             :         }
     682             : 
     683             :         // compute this here so the getter function can take const msettings*
     684         561 :         const char *sockdir = msetting_string(mp, MP_SOCKDIR);
     685         561 :         long effective_port = msettings_connect_port(mp);
     686         561 :         free(mp->unix_sock_name_buffer);
     687         561 :         mp->unix_sock_name_buffer = allocprintf("%s/.s.monetdb.%ld", sockdir, effective_port);
     688         561 :         if (mp->unix_sock_name_buffer == NULL)
     689             :                 return false;
     690             : 
     691         561 :         mp->validated = true;
     692         561 :         return true;
     693             : }
     694             : 
     695             : bool
     696        1437 : msettings_connect_scan(const msettings *mp)
     697             : {
     698        1437 :         if (empty(mp, MP_DATABASE))
     699             :                 return false;
     700         412 :         if (nonempty(mp, MP_SOCK))
     701             :                 return false;
     702         407 :         if (nonempty(mp, MP_HOST))
     703             :                 return false;
     704          88 :         long port = msetting_long(mp, MP_PORT);
     705          88 :         if (port != -1)
     706             :                 return false;
     707           8 :         bool tls = msetting_bool(mp, MP_TLS);
     708           8 :         if (tls)
     709             :                 return false;
     710             : 
     711             :         return true;
     712             : }
     713             : 
     714             : const char *
     715        1509 : msettings_connect_unix(const msettings *mp)
     716             : {
     717        1509 :         assert(mp->validated);
     718        1509 :         const char *sock = msetting_string(mp, MP_SOCK);
     719        1509 :         const char *host = msetting_string(mp, MP_HOST);
     720        1509 :         bool tls = msetting_bool(mp, MP_TLS);
     721             : 
     722        1509 :         if (*sock)
     723             :                 return sock;
     724        1498 :         if (tls)
     725             :                 return "";
     726        1474 :         if (*host == '\0') {
     727             :                 // This was precomputed in msettings_validate(),
     728             :                 // {sockdir}/.s.monetdb.{port}
     729         144 :                 return mp->unix_sock_name_buffer;
     730             :         }
     731             :         return "";
     732             : }
     733             : 
     734             : 
     735             : const char *
     736        2776 : msettings_connect_tcp(const msettings *mp)
     737             : {
     738        2776 :         assert(mp->validated);
     739        2776 :         const char *sock = msetting_string(mp, MP_SOCK);
     740        2776 :         const char *host = msetting_string(mp, MP_HOST);
     741             :         // bool tls = msetting_bool(mp, MP_TLS);
     742             : 
     743        2776 :         if (*sock)
     744             :                 return "";
     745        2766 :         if (!*host)
     746         113 :                 return "localhost";
     747             :         return host;
     748             : }
     749             : 
     750             : long
     751        1911 : msettings_connect_port(const msettings *mp)
     752             : {
     753        1911 :         long port = msetting_long(mp, MP_PORT);
     754        1911 :         if (port == -1)
     755             :                 return 50000;
     756             :         else
     757        1764 :                 return port;
     758             : }
     759             : 
     760             : enum msetting_tls_verify
     761          36 : msettings_connect_tls_verify(const msettings *mp)
     762             : {
     763          36 :         assert(mp->validated);
     764          36 :         bool tls = msetting_bool(mp, MP_TLS);
     765          36 :         const char *cert = msetting_string(mp, MP_CERT);
     766          36 :         const char *certhash = msetting_string(mp, MP_CERTHASH);
     767             : 
     768          36 :         if (!tls)
     769             :                 return verify_none;
     770          35 :         if (*certhash) // certhash comes before cert
     771             :                 return verify_hash;
     772          24 :         if (*cert)
     773          17 :                 return verify_cert;
     774             :         return verify_system;
     775             : }
     776             : 
     777             : const char*
     778          15 : msettings_connect_clientkey(const msettings *mp)
     779             : {
     780          15 :         return msetting_string(mp, MP_CLIENTKEY);
     781             : }
     782             : 
     783             : const char*
     784          15 : msettings_connect_clientcert(const msettings *mp)
     785             : {
     786          15 :         const char *cert = msetting_string(mp, MP_CLIENTCERT);
     787          15 :         if (*cert)
     788             :                 return cert;
     789             :         else
     790          13 :                 return msetting_string(mp, MP_CLIENTKEY);
     791             : }
     792             : 
     793             : const char*
     794           4 : msettings_connect_certhash_digits(const msettings *mp)
     795             : {
     796           4 :         return mp->certhash_digits_buffer;
     797             : }
     798             : 
     799             : // also used as a validator, returns < 0 on invalid
     800             : long
     801         619 : msettings_connect_binary(const msettings *mp)
     802             : {
     803         619 :         const long sufficiently_large = 65535;
     804         619 :         const char *binary = msetting_string(mp, MP_BINARY);
     805             : 
     806             :         // may be bool
     807         619 :         int b = msetting_parse_bool(binary);
     808         619 :         if (b == 0)
     809             :                 return 0;
     810         613 :         if (b == 1)
     811             :                 return sufficiently_large;
     812          10 :         assert(b < 0);
     813             : 
     814          10 :         char *end;
     815          10 :         long level = strtol(binary, &end, 10);
     816          10 :         if (end != binary && *end == '\0')
     817           7 :                 return level;
     818             : 
     819             :         return -1;
     820             : }
     821             : 
     822             : 
     823             : /* automatically incremented each time the corresponding field is updated */
     824             : long
     825         756 : msettings_user_generation(const msettings *mp)
     826             : {
     827         756 :         return mp->user_generation;
     828             : }
     829             : 
     830             : /* automatically incremented each time the corresponding field is updated */
     831             : long
     832         758 : msettings_password_generation(const msettings *mp)
     833             : {
     834         758 :         return mp->password_generation;
     835             : }
     836             : 
     837             : 
     838             : bool
     839          12 : msettings_lang_is_mal(const msettings *mp)
     840             : {
     841          12 :         return mp->lang_is_mal;
     842             : }
     843             : 
     844             : bool
     845     1414712 : msettings_lang_is_sql(const msettings *mp)
     846             : {
     847     1414712 :         return mp->lang_is_sql;
     848             : }

Generated by: LCOV version 1.14