/*
Copyright (c) 2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/


/** @file uaconf.c	Useraud configuration reading. */


/** In the uaconf module. */
#define UACONF_C	1


#include "useraudi.h"




#line 50 "uaconf.ctr"



/** Data for one backend.
*/
typedef struct {
  char		*name;	/**< Backend type name. */
  int		type;	/**< Backend type numeric. */
  ua_be_fct_t	*f;	/**< Backend function. */
} USERAUD_BACKEND_DESCRIPTION;



/**	Backends available.
*/
static USERAUD_BACKEND_DESCRIPTION backends[] = {
  { "system", USERAUD_BE_SYS, uabesys }
/* +++++ Insert further backends here. +++++ */
};
/** Number of backends in the \a backends array. */
static size_t n_backends = sizeof(backends)/sizeof(USERAUD_BACKEND_DESCRIPTION);

/** @defgroup cmd	Commands for configuration file. */
/*@{*/

/** Log file. */
static char *cmd_log_file[] = {
"log", "file", NULL
};

/** Log file level. */
static char *cmd_log_file_level[] = {
"log", "file", "level", NULL
};

/** Socket. */
static char *cmd_socket[] = {
"socket", NULL
};

/** Socket timeout. */
static char *cmd_socket_timeout[] = {
"socket", "timeout", NULL
};

/** Database. */
static char *cmd_database[] = {
"database", NULL
};

/** Cleanup interval. */
static char *cmd_cleanup_interval[] = {
"cleanup", "interval", NULL
};

/** Hash types. */
static char *cmd_hash_types[] = {
"hash", "types", NULL
};

/** Cookie time to live. */
static char *cmd_cookie_ttl[] = {
"cookie", "ttl", NULL
};

/** Maximum cookie length. */
static char *cmd_lgt_cookie[] = {
"max", "cookie", "length", NULL
};

/** Challenge time to live. */
static char *cmd_challenge_ttl[] = {
"challenge", "ttl", NULL
};

/** Faked user salt time to live. */
static char *cmd_faked_user_salt_ttl[] = {
"faked", "user", "salt", "ttl", NULL
};

/** Random seed file. */
static char *cmd_random_seed_file[] = {
"random", "seed", "file", NULL
};

/** Run as user. */
static char *cmd_run_as_user[] = {
"run", "as", "user", NULL
};

/** Run as group. */
static char *cmd_run_as_group[] = {
"run", "as", "group", NULL
};

/** Syslog level. */
static char *cmd_syslog_level[] = {
"syslog", "level", NULL
};

/** Report "no such user". */
static char *cmd_report_no_such_user[] = {
"report", "no", "such", "user", NULL
};

/** Password hash type. */
static char *cmd_password_hash_type[] = {
"password", "hash", "type", NULL
};

/** Exclude user. */
static char *cmd_exclude_user[] = {
"exclude", "user", NULL
};

/** Allow. */
static char *cmd_allow[] = {
"allow", NULL
};

/** Add attribute. */
static char *cmd_add_attribute[] = {
"add", "attribute", NULL
};

/** Map attribute. */
static char *cmd_map_attribute[] = {
"map", "attribute", NULL
};

/** Local user name test. */
static char *cmd_local_user_name_test[] = {
"local", "user", "name", "test", NULL
};

/** Net user name test. */
static char *cmd_net_user_name_test[] = {
"net", "user", "name", "test", NULL
};

/** Commands for options section. */
static char **cmds_options[] = {
  /*  0 */	cmd_log_file,
  /*  1 */	cmd_log_file_level,
  /*  2 */	cmd_socket,
  /*  3 */	cmd_socket_timeout,
  /*  4 */	cmd_database,
  /*  5 */	cmd_cleanup_interval,
  /*  6 */	cmd_hash_types,
  /*  7 */	cmd_cookie_ttl,
  /*  8 */	cmd_challenge_ttl,
  /*  9 */	cmd_faked_user_salt_ttl,
  /* 10 */	cmd_random_seed_file,
  /* 11 */	cmd_run_as_user,
  /* 12 */	cmd_run_as_group,
  /* 13 */	cmd_syslog_level,
  /* 14 */	cmd_report_no_such_user,
  /* 15 */	cmd_allow,
  /* 16 */	cmd_lgt_cookie,
  /* 17 */	cmd_local_user_name_test,
  /* 18 */	cmd_net_user_name_test,
  NULL
};

/** Commands for backends section. */
static char **cmds_backend[] = {
  /*  0 */	cmd_password_hash_type,
  /*  1 */	cmd_exclude_user,
  /*  2 */	cmd_add_attribute,
  /*  3 */	cmd_map_attribute,
  NULL
};

/** Section titles. */
static char *section_titles[] = {
"options",
"backend",
NULL
};

/*@}*/


/**	Log levels.
*/
static char *log_levels[] = {
"none",
"panic",
"fatal",
"error",
"warning",
"info",
"progress",
"debug",
NULL
};


/**	Hash types.
*/
static char *hash_types[] = {
"sha-512",
"sha-384",
"sha-256",
"sha-224",
"ripemd-160",
"sha-1",
"md5",
"crypt",
NULL
};


/**	Subtypes for crypt hash.
*/
static char *crypt_hash_sub_types[] = {
  /*  0 */ "des",
  /*  1 */ "big",
  /*  2 */ "bigcrypt",
  /*  3 */ "md5",
  /*  4 */ "$1$",
  /*  5 */ "blowfish",
  /*  6 */ "$2a$",
  /*  7 */ "sha-256",
  /*  8 */ "$5$",
  /*  9 */ "sha-512",
  /* 10 */ "$6$",
  NULL
};



void
uac_close DK_P1(UAC *,u) {
  UAB *b;
  UAPEER *p;
  
  if(u) {
    if(u->s_allow) {
      if(u->i_allow) {
        dksto_it_reset(u->i_allow);
	while((p = (UAPEER *)dksto_it_next(u->i_allow)) != NULL) {
	  
	  dk_delete(p);
	}
        dksto_it_close(u->i_allow);
      } 
      dksto_close(u->s_allow);
    } u->s_allow = NULL; u->i_allow = NULL;
    if(u->s_be) {
      if(u->i_be) {
        dksto_it_reset(u->i_be);
	while((b = dksto_it_next(u->i_be)) != NULL) {
	  
	  uab_delete(u, b);
	}
        dksto_it_close(u->i_be);
      }
      dksto_close(u->s_be);
    } u->s_be = NULL; u->i_be = NULL;
    if(u->sockname) { dk_delete(u->sockname); }
    u->sockname = NULL;
    if(u->logname) { dk_delete(u->logname); }
    u->logname = NULL;
    if(u->dbname) { dk_delete(u->dbname); }
    u->dbname = NULL;
    if(u->seedname) { dk_delete(u->seedname); }
    u->seedname = NULL;
    if(u->run_as_user) { dk_delete(u->run_as_user); }
    u->run_as_user = NULL;
    if(u->run_as_group) { dk_delete(u->run_as_group); }
    u->run_as_group = NULL;
    dk_delete(u);
  } 
}



/**	Initialize UAC structure.
	@param	u	Structure to initialize.
*/
static
void
uac__init DK_P1(UAC *,u) {
  
  u->sockname = NULL;
  u->logname = NULL;
  u->dbname = NULL;
  u->seedname = NULL;
  u->run_as_user = NULL;
  u->run_as_group = NULL;
  u->s_be = NULL;
  u->i_be = NULL;
  u->s_allow = NULL;
  u->i_allow = NULL;
  u->ttl_challenge = 300UL;
  u->ttl_cookie = 300UL;
  u->ttl_salt = 31536000UL;
  u->sec_cleanup = 86400UL;
  u->to_socket = 5UL;
  u->last_cleanup = (time_t)0UL;
  u->ll_file = DK_LOG_LEVEL_INFO;
  u->ll_syslog = DK_LOG_LEVEL_ERROR;
  u->username_test = 0;
  u->hash_types = 0
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA512
                  | USERAUD_HASH_SHA512
#endif
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA384
		  | USERAUD_HASH_SHA384
#endif
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA256
		  | USERAUD_HASH_SHA256
#endif
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA224
		  | USERAUD_HASH_SHA224
#endif
#if DK_HAVE_OPENSSL_RIPEMD_H
		  | USERAUD_HASH_RIPEMD160
#endif
#if DK_HAVE_OPENSSL_SHA_H
		  | USERAUD_HASH_SHA1
#endif
#if DK_HAVE_OPENSSL_MD5_H
		  | USERAUD_HASH_MD5
#endif
#if DK_HAVE_CRYPT_H
		  | USERAUD_HASH_CRYPT
#endif
  ;
  u->f_no_such = 0x00;
}



UAC *
uac_open DK_P2(char *,fn, int,tp) {
  UAC	*back = NULL;	/* Function result. */
  UAB	*uab = NULL;	/* Current backend to modify. */
  FILE	*fipo = NULL;	/* Configuration file. */
  int	st = 0;		/* Current section type. */
  int	so = 0;		/* Flag: Syntax ok. */
  int	have_error = 0;	/* Flag: Error occured. */
  int	ac = 0;		/* Action to take. */
  unsigned long lineno;	/* Line number in file. */
  char	*p1;		/* Start of string. */
  char	*p2;		/* Start of value. */
  char	*p3;		/* Next part of value. */
  char	*p4;		/* Copy of user name to exclude. */
  char	*parts[16];	/* Parts of the key. */
  size_t	n_p;	/* Number of parts in parts. */
  int	have_sll = 0;	/* Flag: Have syslog level. */
  int	have_rns = 0;	/* Flag: Have report no such user. */
  int	have_ll_f = 0;	/* Flag: Have file log level. */
  int	have_fus = 0;	/* Flag: Have faked user salt ttl. */
  int	have_cli = 0;	/* Flag: Have cleanup interval. */
  int	have_cttl = 0;	/* Flag: Have cookie ttl. */
  int	have_mcl = 0;	/* Flag: Have max cookie length. */
  int	have_cht = 0;	/* Flag: Have challenge ttl. */
  int	have_sot = 0;	/* Flag: Have socket timeout. */
  int	ll = 0;		/* Log level. */
  unsigned	nb = 0;	/* Number of backends. */
  unsigned long ul;	/* Processing of configuration entries. */
  UAB_API	uabapi;	/* Communication with backends. */
  int	backend_found;	/* Number of backends found. */
  UAP		*uap;	/* User authentication property. */
  char	buffer[USERAUD_LINESIZE];
  
  if(fn) {				
    lineno = 0UL;
    back = dk_new(UAC,1);
    if(back) {				
      uac__init(back);
      fipo = fopen(fn, "r");
      if(fipo) {			
        lineno = 0UL;
        while((!(have_error)) && fgets(buffer, sizeof(buffer), fipo)) {
	  lineno++;
	  p1 = dkstr_start(buffer, NULL);
	  if(p1) {
	    dkstr_chomp(p1, NULL);	
	    if(*p1 != '#') {
	      so = 0;
	      if(*p1 == '[') {		
	        st = 0; uab = NULL;
	        p2 = dkstr_chr(p1, ']');
		if(p2) {		
		  *p2 = '\0';
		  p1++;
		  p1 = dkstr_start(p1, NULL);
		  if(p1) {		
		    p2 = dkstr_next(p1, NULL);
		    if(p2) {		
		      if(strcmp(p1, section_titles[1]) == 0) {
		        so = 1; st = 1;	
		        if(tp == 1) {
			  size_t i;
			  ua_be_fct_t *fptr;
		          USERAUD_BACKEND_DESCRIPTION *beptr;
			  
			  beptr = backends; fptr = NULL; tp = -1;
			  for(i = 0; ((i < n_backends) && (fptr == NULL)); i++)
			  {
			    if(strcmp(beptr->name, p2) == 0) {
			      fptr = beptr->f; tp = beptr->type; i = n_backends;
			    }
			    beptr++;
			  }
			  if((fptr != NULL) && (tp > -1)) {
			    if(!(back->s_be)) {
			      back->s_be = dksto_open(0);
			      if(back->s_be) {
			        back->i_be = dksto_it_open(back->s_be);
				if(!(back->i_be)) {
				  have_error = 1;	
				  dksto_close(back->s_be);
				  back->s_be = NULL;
                                  ualog_file_lineno_1(
	                            back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                  );
				}
			      } else {	
			        have_error = 1;
                                ualog_file_lineno_1(
	                          back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                );
			      }
			    }
			    if((back->s_be) && (back->i_be)) {
			      uab = uab_new(back, nb, tp, fptr, fn, lineno);
			      if(uab) {
			        if(!dksto_add(back->s_be, (void *)uab)) {
			          uab_delete(back, uab); uab = NULL;
			          have_error = 1;
                                  ualog_file_lineno_1(
	                            back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                  );
				}
			      } else {
			        have_error = 1;
                                ualog_file_lineno_1(
	                          back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                );
			      }
			    } else {	
			      have_error = 1;
                              ualog_file_lineno_1(
	                        back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                              );
			    }
			  } else {	
			    so = 0;
			  }
			}
		      } else {		
		      }
		    } else {		
		      if(strcmp(p1, section_titles[0]) == 0) {
		        so = 1; st = 0;	
		      } else {		
		      }
		    }
		  } else {		
		    have_error = 1;
                    ualog_file_lineno_1(
	              back, DK_LOG_LEVEL_ERROR, fn, lineno, 12
                    );
		  }
		} else {		
		  have_error = 1;
                  ualog_file_lineno_1(
	            back, DK_LOG_LEVEL_ERROR, fn, lineno, 12
                  );
		}
	      } else {			
	        p2 = dkstr_chr(p1, '=');
		if(p2) {		
		  *(p2++) = '\0';
		  p2 = dkstr_start(p2, NULL);
		  if(p2) {		
		    dkstr_chomp(p1, NULL);
		    dkstr_chomp(p2, NULL);
		    for(n_p = 0; n_p < 16; n_p++) { parts[n_p] = NULL; }
		    n_p = dkstr_explode(parts, 15, p1, NULL);
		    if(n_p > 0) {	
		      switch(st) {
		        case 1: {	
			  if(tp == 1) {
			    if(uab) {
			      ac =
			      dkstr_find_multi_part_cmd(parts,cmds_backend,0);
			      if(ac >= 0) {	
			        so = 1;
			        switch(ac) {
			          case 0: {	
				    p3 = dkstr_next(p2, NULL);
				    switch(dkstr_array_index(hash_types, p2, 0))
				    {
				      case 0: {
				        uab->ht = USERAUD_HASH_SHA512;
				      } break;
				      case 1: {
				        uab->ht = USERAUD_HASH_SHA384;
				      } break;
				      case 2: {
				        uab->ht = USERAUD_HASH_SHA256;
				      } break;
				      case 3: {
				        uab->ht = USERAUD_HASH_SHA224;
				      } break;
				      case 4: {
				        uab->ht = USERAUD_HASH_RIPEMD160;
				      } break;
				      case 5: {
				        uab->ht = USERAUD_HASH_SHA1;
				      } break;
				      case 6: {
				        uab->ht = USERAUD_HASH_MD5;
				      } break;
				      case 7: {
				        uab->ht = USERAUD_HASH_CRYPT;
				        uab->st = 0;
				        if(p3) {
				          int action;
					  action = dkstr_array_index(
					    crypt_hash_sub_types, p3, 0
					  );
					  switch(action) {
					    case 0: {
					      uab->st =
					      USERAUD_HASHSUB_CRYPT_DES;
					    } break;
					    case 1: case 2: {
					      uab->st =
					      USERAUD_HASHSUB_CRYPT_BIG;
					    } break;
					    case 3: case 4: {
					      uab->st =
					      USERAUD_HASHSUB_CRYPT_MD5;
					    } break;
					    case 5: case 6: {
					      uab->st =
					      USERAUD_HASHSUB_CRYPT_BLOWFISH;
					    } break;
					    case 7: case 8: {
					      uab->st =
					      USERAUD_HASHSUB_CRYPT_SHA256;
					    } break;
					    case 9: case 10: {
					      uab->st =
					      USERAUD_HASHSUB_CRYPT_SHA512;
					    } break;
					    default: {
					      so = 0;
					    } break;
					  }
				        }
				      } break;
				      default: {	
				        so = 0;
				      } break;
				    }
				  } break;
				  case 1: {	
				    while(p2) {
				      p3 = dkstr_next(p2, NULL);
				      p4 = dkstr_dup(p2);
				      if(p4) {
				        if(!dksto_add(uab->s_ex, (void *)p4)) {
				          dk_delete(p4);
					  have_error = 1;
                                          ualog_file_lineno_1(
	                                    back, DK_LOG_LEVEL_ERROR, fn,
					    lineno, 14
                                          );
				        }
				      } else {
				        have_error = 1;
                                        ualog_file_lineno_1(
	                                  back, DK_LOG_LEVEL_ERROR, fn,
					  lineno, 14
                                        );
				      }
				      p2 = p3;
				    }
				  } break;
			          case 2: {
				    int maj, min;
				    if(!(uab->s_a)) {
				      uab->s_a = dksto_open(0);
				      if(uab->s_a) {
				        uab->i_a = dksto_it_open(uab->s_a);
				      }
				    }
				    if((uab->s_a) && (uab->i_a)) {
				      p3 = dkstr_next(p2, NULL);
				      if(p3) {
				        p4 = dkstr_next(p3, NULL);
					if(p4) {
					  if(sscanf(p2, "%d", &maj) == 1) {
					    if(sscanf(p3, "%d", &min) == 1) {
					      uap =
					      uau_property_new(maj, min, p4);
					      if(uap) {
					        if(!dksto_add(uab->s_a,(void *)uap))
						{
						  uau_property_delete(uap);
						  have_error = 1;
				                  ualog_file_lineno_1(
				                    back, DK_LOG_LEVEL_ERROR,
						    fn, lineno, 14
				                  );
						}
					      } else {
					        have_error = 1;
				                ualog_file_lineno_1(
				                  back, DK_LOG_LEVEL_ERROR, fn,
						  lineno, 14
				                );
					      }
					    } else { have_error = 1; so = 0; }
					  } else { have_error = 1; so = 0; }
					} else { have_error = 1; so = 0; }
				      } else { have_error = 1; so = 0;
				      }
				    } else {
				      have_error = 1;
				      ualog_file_lineno_1(
				        back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
				      );
				    }
			          } break;
			          case 3: {
				    int maj, min;
				    if(!(uab->s_m)) {
				      uab->s_m = dksto_open(0);
				      if(uab->s_m) {
				        uab->i_m = dksto_it_open(uab->s_m);
				      }
				    }
				    if((uab->s_m) && (uab->i_m)) {
				      p3 = dkstr_next(p2, NULL);
				      if(p3) {
				        p4 = dkstr_next(p3, NULL);
					if(p4) {
					  if(sscanf(p2, "%d", &maj) == 1) {
					    if(sscanf(p3, "%d", &min) == 1) {
					      uap =
					      uau_property_new(maj, min, p4);
					      if(uap) {
					        if(!dksto_add(uab->s_m, (void *)uap))
						{
						  have_error = 1;
						  ualog_file_lineno_1(
						    back, DK_LOG_LEVEL_ERROR,
						    fn, lineno, 14
						  );
						}
					      } else {
					        have_error = 1;
						ualog_file_lineno_1(
						  back, DK_LOG_LEVEL_ERROR, fn,
						  lineno, 14
						);
					      }
					    } else { so = 0; have_error = 1; }
					  } else { so = 0; have_error = 1; }
					} else { so = 0; have_error = 1; }
				      } else { so = 0; have_error = 1; }
				    } else {
				      have_error = 1;
				      ualog_file_lineno_1(
				        back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
				      );
				    }
			          } break;
			        }
			      } else {	
			        if(uab->f) {
			          uabapi.a.c = UA_API_CONFLINE;
			          uabapi.a.t = parts;
			          uabapi.a.v = p2;
				  (*(uab->f))(back, (void *)uab, &uabapi);
				  if(uabapi.r.s) {
				    so = 1;
				  } else {
				    have_error = 1;
				    ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 22
				    );
				  }
			        }
			      }
			    }
			  } else {	
			    so = 1;
			  }
			} break;
			default: {	
		          ac = dkstr_find_multi_part_cmd(parts,cmds_options,0);
		          if(ac >= 0) {	
		            so = 1;
			    switch(ac) {
			      case  0: {	/* log file */
			        if(tp == 1) {
			          if(back->logname) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    back->logname = dkstr_dup(p2);
				    if(!(back->logname)) {
				      have_error = 1;	
                                      ualog_file_lineno_1(
	                                back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                      );
				    }
				  }
				}
			      } break;
			      case  1: {	/* log file level */
			        int ll;
				if(tp == 1) {
				  if(have_ll_f) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    ll = dkstr_array_index(log_levels, p2, 0);
				    if(ll > -1) {
				      back->ll_file = ll;
				    } else {
				      so = 0;
				    }
				    have_ll_f = 1;
				  }
				}
			      } break;
			      case  2: {	/* socket */
			        if(back->sockname) {
				  have_error = 1;	
	                          ualog_file_lineno_1(
				    back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				  );
				} else {
				  back->sockname = dkstr_dup(p2);
				  if(!(back->sockname)) {
				    have_error = 1;	
                                    ualog_file_lineno_1(
	                              back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                    );
				  }
				}
			      } break;
			      case  3: {	/* socket timeout */
			        if(tp == 1) {
			          if(have_sot) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    have_sot = 1;
				    if(sscanf(p2, "%lu", &ul) == 1) {
				      back->to_socket = ul;
				    } else {
				      so = 0;	
				    }
				  }
				}
			      } break;
			      case  4: {	/* database */
			        if(tp == 1) {
			          if(back->dbname) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    back->dbname = dkstr_dup(p2);
				    if(!(back->dbname)) {
				      have_error = 1;	
                                      ualog_file_lineno_1(
	                                back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                      );
				    }
				  }
				}
			      } break;
			      case  5: {	/* cleanup interval */
			        if(tp == 1) {
			          if(have_cli) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    have_cli = 1;
				    if(sscanf(p2, "%lu", &ul) == 1) {
				      back->sec_cleanup = ul;
				    } else {
				      so = 0;	
				    }
				  }
				}
			      } break;
			      case  6: {	/* hash types */
				back->hash_types = 0;
				while(p2) {
				  p3 = dkstr_next(p2, NULL);
				  switch(dkstr_array_index(hash_types, p2, 0)) {
				    case 0: {
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA512
				      back->hash_types |= USERAUD_HASH_SHA512;
#endif
				    } break;
				    case 1: {
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA384
				      back->hash_types |= USERAUD_HASH_SHA384;
#endif
				    } break;
				    case 2: {
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA256
				      back->hash_types |= USERAUD_HASH_SHA256;
#endif
				    } break;
				    case 3: {
#if DK_HAVE_OPENSSL_SHA_H && DK_HAVE_SHA224
				      back->hash_types |= USERAUD_HASH_SHA224;
#endif
				    } break;
				    case 4: {
#if DK_HAVE_OPENSSL_RIPEMD_H
				      back->hash_types |= USERAUD_HASH_RIPEMD160;
#endif
				    } break;
				    case 5: {
#if DK_HAVE_OPENSSL_SHA_H
				      back->hash_types |= USERAUD_HASH_SHA1;
#endif
				    } break;
				    case 6: {
#if DK_HAVE_OPENSSL_MD5_H
				      back->hash_types |= USERAUD_HASH_MD5;
#endif
				    } break;
				    case 7: {
#if DK_HAVE_CRYPT_H
				      back->hash_types |= USERAUD_HASH_CRYPT;
#endif
				    } break;
				  }
				  p2 = p3;
				}
			      } break;
			      case  7: {	/* cookie ttl */
			        if(tp == 1) {
			          if(have_cttl) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    if(sscanf(p2, "%lu", &ul) == 1) {
				      back->ttl_cookie = ul;
				    } else {
				      so = 0;	
				    }
				    have_cttl = 1;
				  }
				}
			      } break;
			      case  8: {	/* challenge ttl */
			        if(tp == 1) {
			          if(have_cht) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    have_cht = 1;
				    if(sscanf(p2, "%lu", &ul) == 1) {
				      back->ttl_challenge = ul;
				    } else {
				      so = 0;	
				    }
				  }
				}
			      } break;
			      case  9: {	/* faked user salt ttl */
			        if(tp == 1) {
			          if(have_fus) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    if(sscanf(p2, "%lu", &ul) == 1) {
				      back->ttl_salt = ul;
				    } else {
				      so = 0;	
				    }
				    have_fus = 1;
				  }
				}
			      } break;
			      case 10: {	/* random seed file */
			        if(tp == 1) {
			          if(back->seedname) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    back->seedname = dkstr_dup(p2);
				    if(!(back->seedname)) {
				      have_error = 1;	
                                      ualog_file_lineno_1(
	                                back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                      );
				    }
				  }
				}
			      } break;
			      case 11: {	/* run as user */
			        if(tp == 1) {
			          if(back->run_as_user) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    back->run_as_user = dkstr_dup(p2);
				    if(!(back->run_as_user)) {
				      have_error = 1;	
                                      ualog_file_lineno_1(
	                                back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                      );
				    }
				  }
				}
			      } break;
			      case 12: {	/* run as group */
			        if(tp == 1) {
			          if(back->run_as_group) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    back->run_as_group = dkstr_dup(p2);
				    if(!(back->run_as_group)) {
				      have_error = 1;	
                                      ualog_file_lineno_1(
	                                back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                      );
				    }
				  }
				}
			      } break;
			      case 13: {	/* syslog level */
			        if(have_sll) {
				  have_error = 1;	
	                          ualog_file_lineno_1(
				    back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				  );
				} else {
				  ll = dkstr_array_index(log_levels, p2, 0);
				  if(ll > -1) {
				    back->ll_syslog = ll;
				  } else {
				    so = 0;	
				  }
				  have_sll = 1;
				}
			      } break;	
			      case 14: {	/* report no such user */
			        if(tp == 1) {
			          if(have_rns) {
				    have_error = 1;	
	                            ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    have_rns = 1;
				    if(dkstr_is_on(p2)) {
				      back->f_no_such = 0x01;
				    } else {
				      back->f_no_such = 0x00;
				    }
				    if(!dkstr_is_bool(p2)) {
				      so = 0;	
				    }
				  }
				}
			      } break;
			      case 15: {	/* allow */
			        if(tp == 0) {
			          unsigned long i, m, n;
				  int j;
				  m = 0xFFFFFFFFUL;
			          p3 = dkstr_chr(p2, '/');
				  if(p3) {
				    *(p3++) = '\0';
				    i = uatcs_dotted_string_to_ip(p2);
				    p3 = dkstr_start(p3, NULL);
				    if(p3) {
				      if(dkstr_chr(p3, '.')) {
				        m = uatcs_dotted_string_to_ip(p3);
				      } else {
				        if(sscanf(p3, "%d", &j) == 1) {
				          if(j >= 0) {
					    if(j <= 32) {
					      m = 0UL;
					      n = 0x80000000UL;
					      while(j-- > 0) {
					        m |= n; n = n / 2UL;
					      }
					    } else { so = 0; }
					  } else { so = 0; }
				        } else { so = 0; }
				      }
				    } else { so = 0; }
				  }
				  if(so) {
				    i = uatcs_dotted_string_to_ip(p2);
				    UAPEER *p;
				    if(!(back->s_allow)) {
				      back->s_allow = dksto_open(0);
				      if(back->s_allow) {
				        back->i_allow = dksto_it_open(
				          back->s_allow
				        );
				        if(!(back->i_allow)) {
				          have_error = 1;	
					  dksto_close(back->s_allow);
					  back->s_allow = NULL;
                                          ualog_file_lineno_1(
	                                    back, DK_LOG_LEVEL_ERROR, fn, lineno,
					    14
                                          );
				        }
				      } else {
				        have_error = 1;		
                                        ualog_file_lineno_1(
	                                  back, DK_LOG_LEVEL_ERROR, fn,
					  lineno, 14
                                        );
				      }
				    }
				    if((back->s_allow) && (back->i_allow)) {
				      p = dk_new(UAPEER,1);
				      if(p) {
				        i = htonl(i); m = htonl(m);
				        p->ip = i; p->mask = m;
				        if(!dksto_add(back->s_allow, (void *)p))
					{
				          have_error = 1;	
				          dk_delete(p);
                                          ualog_file_lineno_1(
	                                    back, DK_LOG_LEVEL_ERROR, fn,
					    lineno, 14
                                          );
				        }
				      } else {			
				        have_error = 1;
                                        ualog_file_lineno_1(
	                                back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
                                        );
				      }
				    }
				  }
				}
			      } break;
			      case 16: {
			        if(tp == 1) {
				  if(have_mcl) {
				    have_error = 1;
				    ualog_file_lineno_1(
				      back, DK_LOG_LEVEL_ERROR, fn, lineno, 13
				    );
				  } else {
				    if(sscanf(p2, "%lu", &ul) == 1) {
				      back->lgt_cookie = ul;
				    } else {
				      so = 0;	
				    }
				    have_mcl = 1;
				  }
				}
			      } break;
			      case 17: {
			        if(tp == 1) {
				  if(dkstr_is_on(p2)) {
				    back->username_test = 1;
				  } else {
				    back->username_test = 0;
				    if(!dkstr_is_bool(p2)) {
				      so = 1;
				    }
				  }
				}
			      } break;
			      case 18: {	/* Nothing to do */
			      } break;
			    }
		          } else {	
			    ualog_file_lineno_1(
			      back, DK_LOG_LEVEL_ERROR, fn, lineno, 53
			    );
			  }
			} break;
		      }
		    } else {		
		      ualog_file_lineno_1(
		        back, DK_LOG_LEVEL_ERROR, fn, lineno, 54
		      );
		    }
		  } else {		
		    ualog_file_lineno_1(
		      back, DK_LOG_LEVEL_ERROR, fn, lineno, 55
		    );
		  }
		} else {		
		  ualog_file_lineno_1(back, DK_LOG_LEVEL_ERROR, fn, lineno, 55);
		}
	      }
	      if(!so) {			
	        have_error = 1;
	        ualog_file_lineno_1(back, DK_LOG_LEVEL_ERROR, fn, lineno, 12);
	      }
	    }
	  }
	}
        fclose(fipo);
	switch(tp) {
	  case 1: {	/* useraud */
	    if(!(back->logname)) {
	      ualog_1(back, DK_LOG_LEVEL_WARNING, 17);
	      back->logname = dkstr_dup(
	        uatcs_get_default_log_file_name()
	      );
	      if(!(back->logname)) {
	        ualog_1(back, DK_LOG_LEVEL_WARNING, 14);
	      }
	    }
	    if(!(back->sockname)) {
	      ualog_1(back, DK_LOG_LEVEL_WARNING, 16);
	      back->sockname = dkstr_dup(
	        uatcs_get_default_socket_name()
	      );
	      if(!(back->sockname)) {
	        ualog_1(back, DK_LOG_LEVEL_ERROR, 14);
		have_error = 1;
	      }
	    }
	    if(!(back->dbname)) {
	      ualog_1(back, DK_LOG_LEVEL_WARNING, 18);
	      back->dbname = dkstr_dup(
	        uatcs_get_default_database_name()
	      );
	      if(!(back->dbname)) {
	        ualog_1(back, DK_LOG_LEVEL_ERROR, 14);
		have_error = 1;
	      }
	    }
	    if(!(back->seedname)) {
	      ualog_1(back, DK_LOG_LEVEL_WARNING, 19);
	      back->seedname = dkstr_dup(
	        uatcs_get_default_random_seed()
	      );
	      if(!(back->seedname)) {
	        ualog_1(back, DK_LOG_LEVEL_WARNING, 14);
	      }
	    }
	    backend_found = 0;
	    if((back->s_be) && (back->i_be)) {
	      dksto_it_reset(back->i_be);
	      while((uab = (UAB *)dksto_it_next(back->i_be)) != NULL) {
	        if(uab->f) {
	          uabapi.a.c = UA_API_CHECK_CONFIG;
		  uabapi.a.f = 0;
		  uabapi.a.t = NULL;
		  uabapi.a.v = NULL;
		  uabapi.a.i = NULL;
		  (*(uab->f))(back, (void *)uab, &uabapi);
		  if(uabapi.r.s) {
		    backend_found++;
		  } else {
		    have_error = 1;
		    ualog_1(back, DK_LOG_LEVEL_ERROR, 23);
		  }
		} else {
		  have_error = 1;
		  ualog_1(back, DK_LOG_LEVEL_ERROR, 24);
		}
	      }
	    }
	    if(!backend_found) {
	      have_error = 1;
	      ualog_1(back, DK_LOG_LEVEL_ERROR, 25);
	    }
	  } break;
	  default: {	/* useraudi */
	    if(!(back->sockname)) {
	      ualog_1(back, DK_LOG_LEVEL_WARNING, 16);
	      back->sockname = dkstr_dup(
	        uatcs_get_default_socket_name()
	      );
	      if(!(back->sockname)) {
	        ualog_1(back, DK_LOG_LEVEL_ERROR, 14);
		have_error = 1;
	      }
	    }
	  } break;
	}
      } else {				
      }
      if(have_error) {
        ualog_3(back, DK_LOG_LEVEL_ERROR, 10, 11, fn);
        uac_close(back); back = NULL;
      }
    } else {				
      ualog_file_lineno_1(
	back, DK_LOG_LEVEL_ERROR, fn, lineno, 14
      );
    }
  } else {				
  }
  if(back) {
    ualog_3(back, DK_LOG_LEVEL_INFO, 8, 9, fn);
  } 
  return back;
}



