/*++
/* NAME
/* config_known_tcp_ports 3
/* SUMMARY
/* parse and store known TCP port configuration
/* SYNOPSIS
/* #include <config_known_tcp_ports.h>
/*
/* void config_known_tcp_ports(
/* const char *source,
/* const char *settings);
/* DESCRIPTION
/* config_known_tcp_ports() parses the known TCP port information
/* in the settings argument, and reports any warnings to the standard
/* error stream. The source argument is used to provide warning
/* context. It typically is a configuration parameter name.
/* EXPECTED SYNTAX (ABNF)
/* configuration = empty | name-to-port *("," name-to-port)
/* name-to-port = 1*(name "=") port
/* EXAMPLES
/* In the example below, the whitespace is optional.
/* smtp = 25, smtps = submissions = 465, submission = 587
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/
/*
* System library .
*/
#include <sys_defs.h>
/*
* Utility library .
*/
#include <argv.h>
#include <known_tcp_ports.h>
#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
/*
* Application - specific .
*/
#include <config_known_tcp_ports.h>
/* config_known_tcp_ports - parse configuration and store associations */
void config_known_tcp_ports(const char *source, const char *settings)
{
ARGV *associations;
ARGV *association;
char **cpp;
clear_known_tcp_ports();
/*
* The settings is in the form of associations separated by comma . Split
* it into separate associations .
*/
associations = argv_split(settings, "," );
if (associations->argc == 0 ) {
argv_free(associations);
return ;
}
/*
* Each association is in the form of " 1 * ( name = ) port " . We use
* argv_split ( ) to carve this up , then we use mystrtok ( ) to validate the
* individual fragments . But first we prepend and append space so that we
* get sensible results when an association starts or ends in " = " .
*/
for (cpp = associations->argv; *cpp != 0 ; cpp++) {
char *temp = concatenate(" " , *cpp, " " , (char *) 0 );
association = argv_split_at(temp, '=' );
myfree(temp);
if (association->argc == 0 ) {
/* empty, ignore */ ;
} else if (association->argc == 1 ) {
msg_warn("%s: in \" %s\" is not in \" name = value\" form" ,
source, *cpp);
} else {
char *bp;
char *lhs;
char *rhs;
const char *err = 0 ;
int n;
bp = association->argv[association->argc - 1 ];
if ((rhs = mystrtok(&bp, CHARS_SPACE)) == 0 ) {
err = "missing port value after \" =\"" ;
} else if (mystrtok(&bp, CHARS_SPACE) != 0 ) {
err = "whitespace in port number" ;
} else {
for (n = 0 ; n < association->argc - 1 ; n++) {
const char *new_err;
bp = association->argv[n];
if ((lhs = mystrtok(&bp, CHARS_SPACE)) == 0 ) {
new_err = "missing service name before \" =\"" ;
} else if (mystrtok(&bp, CHARS_SPACE) != 0 ) {
new_err = "whitespace in service name" ;
} else {
new_err = add_known_tcp_port(lhs, rhs);
}
if (new_err != 0 && err == 0 )
err = new_err;
}
}
if (err != 0 ) {
msg_warn("%s: in \" %s\": %s" , source, *cpp, err);
}
}
argv_free(association);
}
argv_free(associations);
}
#ifdef TEST
#include <stdlib.h>
#include <string.h>
#include <msg_vstream.h>
#define STR(x) vstring_str(x)
/* TODO(wietse) make this a proper VSTREAM interface */
/* vstream_swap - kludge to capture output for testing */
static void vstream_swap(VSTREAM *one, VSTREAM *two)
{
VSTREAM save;
save = *one;
*one = *two;
*two = save;
}
struct test_case {
const char *label; /* identifies test case */
const char *config; /* configuration under test */
const char *exp_warning; /* expected warning or null */
const char *exp_export; /* expected export or null */
};
static struct test_case test_cases[] = {
{"good" ,
/* config */ "smtp = 25, smtps = submissions = 465, lmtp = 24",
/* warning */ "",
/* export */ "lmtp=24 smtp=25 smtps=465 submissions=465"
},
{"equal-equal" ,
/* config */ "smtp = 25, smtps == submissions = 465, lmtp = 24",
/* warning */ "config_known_tcp_ports: warning: equal-equal: "
"in \" smtps == submissions = 465 \": missing service name before "
"\" =\"\n" ,
/* export */ "lmtp=24 smtp=25 smtps=465 submissions=465"
},
{"port test 1" ,
/* config */ "smtps = submission =",
/* warning */ "config_known_tcp_ports: warning: port test 1: "
"in \" smtps = submission =\": missing port value after \" =\"\n" ,
/* export */ ""
},
{"port test 2" ,
/* config */ "smtps = submission = 4 65",
/* warning */ "config_known_tcp_ports: warning: port test 2: "
"in \" smtps = submission = 4 65 \": whitespace in port number\n" ,
/* export */ ""
},
{"port test 3" ,
/* config */ "lmtp = 24, smtps = submission = foo",
/* warning */ "config_known_tcp_ports: warning: port test 3: "
"in \" smtps = submission = foo\": non-numerical service port\n" ,
/* export */ "lmtp=24"
},
{"service name test 1" ,
/* config */ "smtps = sub mission = 465",
/* warning */ "config_known_tcp_ports: warning: service name test 1: "
"in \" smtps = sub mission = 465 \": whitespace in service name\n" ,
/* export */ "smtps=465"
},
{"service name test 2" ,
/* config */ "lmtp = 24, smtps = 1234 = submissions = 465",
/* warning */ "config_known_tcp_ports: warning: service name test 2: "
"in \" smtps = 1234 = submissions = 465 \": numerical service name\n" ,
/* export */ "lmtp=24 smtps=465 submissions=465"
},
0 ,
};
int main(int argc, char **argv)
{
VSTRING *export_buf;
struct test_case *tp;
int pass = 0 ;
int fail = 0 ;
int test_failed;
const char *export;
VSTRING *msg_buf;
VSTREAM *memory_stream;
#define STRING_OR_NULL(s) ((s) ? (s) : "(null)" )
msg_vstream_init("config_known_tcp_ports" , VSTREAM_ERR);
export_buf = vstring_alloc(100 );
msg_buf = vstring_alloc(100 );
for (tp = test_cases; tp->label != 0 ; tp++) {
test_failed = 0 ;
if ((memory_stream = vstream_memopen(msg_buf, O_WRONLY)) == 0 )
msg_fatal("open memory stream: %m" );
vstream_swap(VSTREAM_ERR, memory_stream);
config_known_tcp_ports(tp->label, tp->config);
vstream_swap(memory_stream, VSTREAM_ERR);
if (vstream_fclose(memory_stream))
msg_fatal("close memory stream: %m" );
if (strcmp(STR(msg_buf), tp->exp_warning) != 0 ) {
msg_warn("test case %s: got error: \" %s\", want: \" %s\"" ,
tp->label, STR(msg_buf),
STRING_OR_NULL(tp->exp_warning));
test_failed = 1 ;
} else {
export = export_known_tcp_ports(export_buf);
if (strcmp(export, tp->exp_export) != 0 ) {
msg_warn("test case %s: got export: \" %s\", want: \" %s\"" ,
tp->label, export, tp->exp_export);
test_failed = 1 ;
}
clear_known_tcp_ports();
VSTRING_RESET(msg_buf);
VSTRING_TERMINATE(msg_buf);
}
if (test_failed) {
msg_info("%s: FAIL" , tp->label);
fail++;
} else {
msg_info("%s: PASS" , tp->label);
pass++;
}
}
msg_info("PASS=%d FAIL=%d" , pass, fail);
vstring_free(msg_buf);
vstring_free(export_buf);
exit (fail != 0 );
}
#endif
Messung V0.5 in Prozent C=90 H=99 G=94
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland