LCOV - code coverage report
Current view: top level - cmail-smtpd - config.c (source / functions) Hit Total Coverage
Test: smtpd.info Lines: 134 173 77.5 %
Date: 2015-11-25 19:06:20 Functions: 7 7 100.0 %

          Line data    Source code
       1           6 : int config_bind(CONFIGURATION* config, char* directive, char* params){
       2           6 :         char* tokenize_line = NULL;
       3           6 :         char* tokenize_argument = NULL;
       4           6 :         char* token = NULL;
       5             : 
       6           6 :         char* bindhost = NULL;
       7           6 :         char* port = NULL;
       8             : 
       9             :         #ifndef CMAIL_NO_TLS
      10           6 :         TLSMODE tls_mode=TLS_NONE;
      11           6 :         char* tls_keyfile = NULL;
      12           6 :         char* tls_certfile = NULL;
      13           6 :         char* tls_priorities = NULL;
      14           6 :         char* tls_dh_paramfile = NULL;
      15             :         #endif
      16             : 
      17           6 :         int listen_fd = -1;
      18           6 :         int listener_slot = -1;
      19           6 :         LISTENER settings = {
      20             :                 .fixed_user = NULL,
      21             :                 .max_size = 0,
      22             :                 .announce_domain = "cmail-smtpd",
      23             :                 .auth_offer = AUTH_NONE,
      24             :                 .auth_require = false,
      25             :                 .suppress_submitter = false
      26             :         };
      27           6 :         LISTENER* listener_data = NULL;
      28             : 
      29             :         //tokenize line
      30           6 :         bindhost = strtok_r(params, " ", &tokenize_line);
      31             :         do{
      32          52 :                 token = strtok_r(NULL, " ", &tokenize_line);
      33          52 :                 if(token){
      34          46 :                         if(!port){
      35           6 :                                 port = token;
      36             :                         }
      37             :                         #ifndef CMAIL_NO_TLS
      38          40 :                         else if(!strncmp(token, "cert=", 5)){
      39           6 :                                 tls_certfile = token + 5;
      40             :                         }
      41          34 :                         else if(!strncmp(token, "key=", 4)){
      42           6 :                                 tls_keyfile = token + 4;
      43             :                         }
      44          28 :                         else if(!strcmp(token, "tlsonly")){
      45           2 :                                 tls_mode = TLS_ONLY;
      46             :                         }
      47          26 :                         else if(!strncmp(token, "ciphers=", 8)){
      48           6 :                                 tls_priorities = token + 8;
      49             :                         }
      50          20 :                         else if(!strncmp(token, "dhparams=", 9)){
      51           6 :                                 tls_dh_paramfile = token + 9;
      52             :                         }
      53             :                         #endif
      54          14 :                         else if(!strncmp(token, "auth", 4)){
      55           2 :                                 settings.auth_offer = AUTH_ANY;
      56           2 :                                 if(token[4] == '='){
      57           2 :                                         token = strtok_r(token + 5, ",", &tokenize_argument);
      58           8 :                                         while(token){
      59           4 :                                                 if(!strcmp(token, "tlsonly")){
      60           2 :                                                         settings.auth_offer = AUTH_TLSONLY;
      61             :                                                 }
      62           2 :                                                 else if(!strcmp(token, "strict")){
      63           2 :                                                         settings.auth_require = true;
      64             :                                                 }
      65           0 :                                                 else if(!strcmp(token, "private")){
      66           0 :                                                         settings.suppress_submitter = true;
      67             :                                                 }
      68           0 :                                                 else if(!strncmp(token, "fixed@", 6)){
      69           0 :                                                         settings.auth_require = true;
      70           0 :                                                         settings.fixed_user = token + 6;
      71             :                                                 }
      72             :                                                 else{
      73           0 :                                                         logprintf(config->log, LOG_WARNING, "Unknown auth parameter %s\n", token);
      74             :                                                 }
      75           4 :                                                 token = strtok_r(NULL, ",", &tokenize_argument);
      76             :                                         }
      77             : 
      78           2 :                                         token = ""; //reset to anything but NULL to meet condition
      79             :                                 }
      80             :                         }
      81          12 :                         else if(!strncmp(token, "announce=", 9)){
      82           6 :                                 settings.announce_domain = token + 9;
      83             :                         }
      84           6 :                         else if(!strncmp(token, "size=", 5)){
      85           6 :                                 settings.max_size = strtoul(token + 5, NULL, 10);
      86             :                         }
      87             :                         else{
      88           0 :                                 logprintf(config->log, LOG_INFO, "Ignored additional bind parameter %s\n", token);
      89             :                         }
      90             :                 }
      91          52 :         }while(token);
      92             : 
      93             :         #ifndef CMAIL_NO_TLS
      94           6 :         if(tls_keyfile && tls_certfile){
      95           6 :                 if(tls_mode == TLS_NONE){
      96           4 :                         tls_mode = TLS_NEGOTIATE;
      97             :                 }
      98             : 
      99          12 :                 if(tls_init_listener(config->log, &settings, tls_certfile, tls_keyfile, tls_dh_paramfile, tls_priorities) < 0){
     100           0 :                         return -1;
     101             :                 }
     102             :         }
     103           0 :         else if(tls_keyfile || tls_certfile || tls_mode != TLS_NONE){
     104           0 :                 logprintf(config->log, LOG_ERROR, "Need both certificate and key for TLS\n");
     105           0 :                 return -1;
     106             :         }
     107             :         #endif
     108             : 
     109             :         //try to open a listening socket
     110           6 :         listen_fd = network_listener(config->log, bindhost, port);
     111             : 
     112           6 :         if(listen_fd < 0){
     113           0 :                 return -1;
     114             :         }
     115             : 
     116             :         //add the new listener to the pool
     117           6 :         listener_slot = connpool_add(&(config->listeners), listen_fd);
     118           6 :         if(listener_slot >= 0){
     119           6 :                 logprintf(config->log, LOG_INFO, "Bound to %s port %s (slot %d)\n", bindhost, port, listener_slot);
     120             : 
     121             :                 //create listener auxdata
     122           6 :                 config->listeners.conns[listener_slot].aux_data = calloc(1, sizeof(LISTENER));
     123           6 :                 if(!config->listeners.conns[listener_slot].aux_data){
     124           0 :                         logprintf(config->log, LOG_ERROR, "Failed to allocate auxiliary data for listener\n");
     125           0 :                         return -1;
     126             :                 }
     127             : 
     128           6 :                 listener_data = (LISTENER*)config->listeners.conns[listener_slot].aux_data;
     129           6 :                 *listener_data = settings;
     130             : 
     131             :                 //copy data to heap
     132             :                 #ifndef CMAIL_NO_TLS
     133           6 :                 config->listeners.conns[listener_slot].tls_mode = tls_mode;
     134             :                 #endif
     135             : 
     136           6 :                 listener_data->announce_domain = common_strdup(settings.announce_domain);
     137           6 :                 if(!listener_data->announce_domain){
     138           0 :                         logprintf(config->log, LOG_ERROR, "Failed to allocate auxiliary data for listener announce\n");
     139           0 :                         return -1;
     140             :                 }
     141             : 
     142           6 :                 if(settings.fixed_user){
     143           0 :                         listener_data->fixed_user = common_strdup(settings.fixed_user);
     144           0 :                         if(!listener_data->fixed_user){
     145           0 :                                 logprintf(config->log, LOG_ERROR, "Failed to allocate memory for fixed user storage\n");
     146           0 :                                 return -1;
     147             :                         }
     148             :                 }
     149           6 :                 return 0;
     150             :         }
     151             : 
     152           0 :         logprintf(config->log, LOG_ERROR, "Failed to store listen socket\n");
     153           0 :         return -1;
     154             : }
     155             : 
     156           2 : int config_privileges(CONFIGURATION* config, char* directive, char* params){
     157             :         struct passwd* user_info;
     158             :         struct group* group_info;
     159             : 
     160           2 :         errno = 0;
     161           2 :         if(!strcmp(directive, "user")){
     162           1 :                 user_info = getpwnam(params);
     163           1 :                 if(!user_info){
     164           0 :                         logprintf(config->log, LOG_ERROR, "Failed to get user info for %s\n", params);
     165           0 :                         return -1;
     166             :                 }
     167           1 :                 config->privileges.uid = user_info->pw_uid;
     168           1 :                 config->privileges.gid = user_info->pw_gid;
     169           1 :                 logprintf(config->log, LOG_DEBUG, "Configured dropped privileges to uid %d gid %d\n", config->privileges.uid, config->privileges.gid);
     170           1 :                 return 0;
     171             :         }
     172           1 :         else if(!strcmp(directive, "group")){
     173           1 :                 group_info = getgrnam(params);
     174           1 :                 if(!group_info){
     175           0 :                         logprintf(config->log, LOG_ERROR, "Failed to get group info for %s\n", params);
     176           0 :                         return -1;
     177             :                 }
     178           1 :                 config->privileges.gid = group_info->gr_gid;
     179           1 :                 logprintf(config->log, LOG_DEBUG, "Configured dropped privileges to gid %d\n", config->privileges.gid);
     180           1 :                 return 0;
     181             :         }
     182           0 :         return -1;
     183             : }
     184             : 
     185           1 : int config_database(CONFIGURATION* config, char* directive, char* params){
     186           1 :         if(config->database.conn){
     187           0 :                 logprintf(config->log, LOG_ERROR, "Can not use %s as master database, another one is already attached\n", params);
     188           0 :                 return -1;
     189             :         }
     190             : 
     191           1 :         config->database.conn = database_open(config->log, params, SQLITE_OPEN_READWRITE);
     192             : 
     193           1 :         return (config->database.conn) ? 0:-1;
     194             : }
     195             : 
     196           2 : int config_logger(CONFIGURATION* config, char* directive, char* params){
     197             :         FILE* log_file;
     198             : 
     199           2 :         if(!strcmp(directive, "verbosity")){
     200           1 :                 config->log.verbosity = strtoul(params, NULL, 10);
     201           1 :                 return 0;
     202             :         }
     203           1 :         else if(!strcmp(directive, "logfile")){
     204           1 :                 log_file = fopen(params, "a");
     205           1 :                 if(!log_file){
     206           0 :                         logprintf(config->log, LOG_ERROR, "Failed to open logfile %s for appending\n", params);
     207           0 :                         return -1;
     208             :                 }
     209           1 :                 config->log.stream = log_file;
     210           1 :                 config->log.log_secondary = true;
     211           1 :                 return 0;
     212             :         }
     213           0 :         return -1;
     214             : }
     215             : 
     216           1 : int config_pidfile(CONFIGURATION* config, char* directive, char* params){
     217           1 :         if(config->pid_file){
     218           0 :                 logprintf(config->log, LOG_ERROR, "Multiple pidfile stanzas read, aborting\n");
     219           0 :                 return -1;
     220             :         }
     221             : 
     222           1 :         config->pid_file = common_strdup(params);
     223             : 
     224           1 :         if(!config->pid_file){
     225           0 :                 logprintf(config->log, LOG_ERROR, "Failed to allocate memory for pidfile path\n");
     226           0 :                 return -1;
     227             :         }
     228           1 :         return 0;
     229             : }
     230             : 
     231          12 : int config_line(void* config_data, char* line){
     232             :         unsigned parameter;
     233          12 :         CONFIGURATION* config = (CONFIGURATION*)config_data;
     234             : 
     235             :         //scan over directive
     236          12 :         for(parameter = 0; (!isspace(line[parameter])) && line[parameter] != 0; parameter++){
     237             :         }
     238             : 
     239          12 :         if(line[parameter] != 0){
     240          12 :                 line[parameter] = 0;
     241          12 :                 parameter++;
     242             :         }
     243             : 
     244             :         //scan for parameter begin
     245          12 :         for(; isspace(line[parameter]); parameter++){
     246             :         }
     247             : 
     248             :         //route directives
     249          12 :         if(!strncmp(line, "bind", 4)){
     250           6 :                 return config_bind(config, line, line + parameter);
     251             :         }
     252             : 
     253           6 :         else if(!strncmp(line, "user", 4) || !strncmp(line, "group", 5)){
     254           2 :                 return config_privileges(config, line, line + parameter);
     255             :         }
     256             : 
     257           4 :         else if(!strncmp(line, "database", 8)){
     258           1 :                 return config_database(config, line, line + parameter);
     259             :         }
     260             : 
     261           3 :         else if(!strncmp(line, "verbosity", 9) || !strncmp(line, "logfile", 7)){
     262           2 :                 return config_logger(config, line, line + parameter);
     263             :         }
     264             : 
     265           1 :         else if(!strncmp(line, "pidfile", 7)){
     266           1 :                 return config_pidfile(config, line, line + parameter);
     267             :         }
     268             : 
     269           0 :         logprintf(config->log, LOG_ERROR, "Unknown configuration directive %s\n", line);
     270           0 :         return -1;
     271             : }
     272             : 
     273           2 : void config_free(CONFIGURATION* config){
     274             :         unsigned i;
     275             :         LISTENER* listener_data;
     276             : 
     277          14 :         for(i = 0; i < config->listeners.count; i++){
     278          12 :                 listener_data = (LISTENER*)config->listeners.conns[i].aux_data;
     279             : 
     280          12 :                 close(config->listeners.conns[i].fd);
     281             : 
     282          12 :                 free(listener_data->announce_domain);
     283             : 
     284          12 :                 if(listener_data->fixed_user){
     285           0 :                         free(listener_data->fixed_user);
     286             :                 }
     287             : 
     288             :                 #ifndef CMAIL_NO_TLS
     289          12 :                 if(config->listeners.conns[i].tls_mode != TLS_NONE){
     290          12 :                         gnutls_certificate_free_credentials(listener_data->tls_cert);
     291          12 :                         gnutls_priority_deinit(listener_data->tls_priorities);
     292          12 :                         gnutls_dh_params_deinit(listener_data->tls_dhparams);
     293             :                 }
     294             :                 #endif
     295             :         }
     296             : 
     297           2 :         connpool_free(&(config->listeners));
     298           2 :         database_free(config->log, &(config->database));
     299             : 
     300           2 :         if(config->pid_file){
     301           2 :                 free(config->pid_file);
     302             :         }
     303             : 
     304           2 :         if(config->log.stream != stderr){
     305           2 :                 fflush(config->log.stream);
     306           2 :                 fclose(config->log.stream);
     307           2 :                 config->log.stream = stderr;
     308             :         }
     309           2 : }

Generated by: LCOV version 1.11