%% options copyright owner = Dirk Krause copyright year = 2012-2014 license = bsd %% module #include "dk3all.h" #include "itadmin.h" $!trace-include /** Key names in configuration file. */ static dkChar const * const itadmin_config_keys[] = { $!string-table macro=dkT # # 0: Database host # database-host # # 1: Database name # database-name # # 2: my.cnf file containing credential for database connection # database-credentials-file # # 3: VLAN for which we have to write a dhcpd.conf file # dhcpd.conf-vlan # # 4: Organization name # organization # # 5: Organizational unit name # organizational-unit # # 6: Administrator name # administrator-name # # 7: Flag: Create dhcpd.conf file # create-dhcpd.conf # # 8: Database type # database-type # # 9: LDAP base # ldap-base # # 10: use koma-script # use-koma-script $!end }; /** Names of SQL database types. */ static dkChar const * const itadmin_config_database_types[] = { $!string-table macro=dkT # # 0: MySQL # MySQL $!end }; /** Keywords to watch out for when processing a credential file. Typically this is a .my.cnf file. */ static dkChar const * const itadmin_config_credential_keys[] = { $!string-table macro=dkT # # 0: Section title "client" # client # # 1: Key name "user" # user # # 2: Key name "password" # password $!end }; /** Set one string entry in job structure. @param job Job structure to modify. @param resptr Pointer to result pointer. @param srcptr Source string. @return 1 on success, 0 on error. */ static int itadmin_config_set_string( itadmin_job *job, dkChar const **resptr, dkChar const *srcptr ) { dkChar const *np; /* New string duplicate. */ int back = 0; $? "+ itadmin_config_set_string \"%s\"", TR_STR(srcptr) np = dk3str_dup_app(srcptr,job->app); if(np) { dk3_release(*resptr); *resptr = np; back = 1; } else { /* ERROR: Memory allocation failed! */ } $? "- itadmin_config_set_string %d", back return back; } /** Configure a boolean value setting. @param job Job structure. @param bp Pointer to result variable. @param defv Default value, used for empty or non-boolean strings. @param txt Configuration text. @return 1 on success, 0 on error. */ static int itadmin_config_set_bool(itadmin_job *job, int *bp, int defv, dkChar const *txt) { dkChar lb[ITADMIN_CONFIG_LINE_SIZE]; /* Copy of value. */ dkChar *p1; /* Start of text in copy. */ int back = 1; $? "+ itadmin_config_set_bool \"%s\"", TR_STR(txt) if(txt) { p1 = dk3str_start(txt, NULL); if(p1) { if(dk3str_len(p1) < DK3_SIZEOF(lb,dkChar)) { dk3str_cpy_not_overlapped(lb, p1); dk3str_normalize(lb,NULL,dkT(' ')); if(dk3str_is_bool(lb)) { *bp = ((dk3str_is_on(lb)) ? 1 : 0); } else { $? "! not a boolean" back = 0; *bp = defv; /* ERROR: Not a boolean! */ dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 106, 107, lb); } } else { $? "! text too long" back = 0; *bp = defv; /* ERROR: Text too long! */ dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 108, 109, p1); } } else { $? ". empty text" *bp = defv; } } else { $? ". no text" *bp = defv; } $? "- itadmin_config_set_bool %d", back return back; } /** Set database type. @param job Job structure. @param txt Text for database type (at this time only "MySQL" can be used). @return 1 on success, 0 on error. */ static int itadmin_config_set_dbtype(itadmin_job *job, dkChar const *txt) { int back = 0; int i; /* Index of type in array of known types. */ if(txt) { i = dk3str_array_index(itadmin_config_database_types, txt, 0); if(i >= 0) { job->dbt = i; back = 1; } else { /* ERROR: No such database type! */ dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 110, 111, txt); } } else { /* ERROR: Empty text. */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 112); } return back; } /** Handler function for one configuration file line. @param obj Reader object. @param il Input line to process (constant text). @return 1 for OK, 0 for recoverable error, -1 for abort. */ static int itadmin_config_const_line_handler(void *obj, dkChar const *il) { dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Private copy of line.*/ itadmin_job *job; dkChar *p1; /* Start of line. */ dkChar *p2; /* Start of value in line. */ int back = 0; $? "+ itadmin_config_const_line_handler \"%s\"", TR_STR(il) if((obj) && (il)) { job = (itadmin_job *)obj; if(dk3str_len(il) < DK3_SIZEOF(line,dkChar)) { dk3str_cpy_not_overlapped(line, il); dk3str_delnl(line); p1 = dk3str_start(line, NULL); if(p1) { if(*p1 == dkT('#')) { back = 1; /* Comment line. */ } else { p2 = dk3str_chr(p1, dkT('=')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); if(p2) { dk3str_normalize(p1, NULL, dkT('-')); switch(dk3str_array_index(itadmin_config_keys, p1, 0)) { case 0: { /* database host */ back = itadmin_config_set_string(job, &(job->dbhn), p2); } break; case 1: { /* database name */ back = itadmin_config_set_string(job, &(job->dbn), p2); } break; case 2: { /* credentials file */ back = itadmin_config_set_string(job, &(job->dbcf), p2); } break; case 3: { /* VLAN name */ back = itadmin_config_set_string(job, &(job->vlan), p2); if(back) { job->f_dh = 1; } } break; case 4: { /* organization */ back = itadmin_config_set_string(job, &(job->org), p2); } break; case 5: { /* organizational unit */ back = itadmin_config_set_string(job, &(job->ou), p2); } break; case 6: { /* administrator name */ back = itadmin_config_set_string(job, &(job->admn), p2); } break; case 7: { back = itadmin_config_set_bool(job, &(job->f_dh), 1, p2); } break; case 8: { back = itadmin_config_set_dbtype(job, p2); } break; case 9: { dk3str_normalize(p2, NULL, ' '); back = itadmin_config_set_string(job, &(job->ldapb), p2); } break; case 10: { if(dk3str_is_bool(p2)) { back = 1; job->ukoma = ((dk3str_is_on(p2)) ? 1 : 0); } else { /* ERROR: Boolean expected! */ dk3app_log_3(job->app,DK3_LL_ERROR,job->msg,106,107,p2); } } break; default: { /* ERROR: Unknown option ... */ dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 113, 114, p1); } break; } } else { /* ERROR: No value! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 115); } } else { /* ERROR: Missing '=' */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 115); } } } else { back = 1; /* Empty line. */ } } else { /* ERROR: Input line too long! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 116); } } $? "- itadmin_config_const_line_handler %d", back return back; } /** Handler function for one configuration file line. @param obj Reader object. @param il Input line to process. @return 1 for OK, 0 for recoverable error, -1 for abort. */ static int itadmin_cred_file_const_line_handler(void *obj, dkChar const *il) { dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Copy of line. */ dkChar *p1; /* Start of key. */ dkChar *p2; /* Start of value. */ itadmin_cred_reader *reader; /* Help structure to read creds. */ int back = 0; $? "+ itadmin_cred_file_const_line_handler \"%s\"", il if((obj) && (il)) { $? ". objects ok" reader = (itadmin_cred_reader *)obj; if(dk3str_len(il) < DK3_SIZEOF(line,dkChar)) { $? ". length ok" dk3str_cpy_not_overlapped(line, il); dk3str_delnl(line); p1 = dk3str_start(line, NULL); if(p1) { $? ". p1" if(*p1 == dkT('#')) { $? ". comment" back = 1; /* Ignore comment. */ } else { $? ". no comment" if(*p1 == dkT('[')) { $? ". section" reader->f_clnt = 0; p1++; p2 = dk3str_chr(p1, dkT(']')); if(p2) { $? ". section end ok" back = 1; *p2 = dkT('\0'); if(dk3str_cmp(p1, itadmin_config_credential_keys[0]) == 0) { reader->f_clnt = 1; } } else { $? "! no section end" /* ERROR: Syntax! */ dk3app_log_1( (reader->job)->app, DK3_LL_ERROR, (reader->job)->msg, 117 ); } } else { $? ". not a section" back = 1; p2 = dk3str_chr(p1, dkT('=')); if(p2) { $? ". value found" *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); if(p2) { $? ". value found" dk3str_normalize(p1,NULL,dkT(' ')); switch(dk3str_array_index(itadmin_config_credential_keys,p1,0)) { case 1: { /* user */ $? ". user" back = itadmin_config_set_string( reader->job, &((reader->job)->dbus), p2 ); } break; case 2: { /* password */ $? ". password" back = itadmin_config_set_string( reader->job, &((reader->job)->dbpw), p2 ); } break; } } else { $? "! no value" /* Empty key. */ } } else { $? "! no value" /* Not a key=value line. */ } } } } else { $? ". empty line" back = 1; /* Ignore empty line. */ } } else { $? "! length" /* ERROR: Line too long! */ dk3app_log_1( (reader->job)->app, DK3_LL_ERROR, (reader->job)->msg, 116 ); } } else { $? "! args" } $? "- itadmin_cred_file_const_line_handler %d", back return back; } /** Handler function for one configuration file line. @param obj Reader object. @param il Input line to process. @return 1 for OK, 0 for recoverable error, -1 for abort. */ static int itadmin_cred_file_line_handler(void *obj, dkChar *il) { int back; back = itadmin_cred_file_const_line_handler(obj, il); return back; } /** Handler function for one configuration file line. @param obj Reader object. @param il Input line to process. @return 1 for OK, 0 for recoverable error, -1 for abort. */ static int itadmin_config_line_handler(void *obj, dkChar *il) { int back; back = itadmin_config_const_line_handler(obj, il); return back; } /** Process one configuration file. @param job Job structure. @param fn File name to process. @return 1 on success, 0 on error. */ static int itadmin_config_process_one_file(itadmin_job *job, dkChar const *fn) { dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Copy of line. */ int back = 0; $? "+ itadmin_config_process_one_file %s", TR_STR(fn) back = dk3stream_process_filename_lines_app( (void *)job, itadmin_config_line_handler, fn, line, DK3_SIZEOF(line,dkChar), dk3app_get_encoding(job->app), dk3app_get_input_file_encoding(job->app), job->app ); if(back < 1) { back = 0; } $? "- itadmin_config_process_one_file %d", back return back; } /** Read credentials file to obtain database user name and password. @param job Job structure. @return 1 on success, 0 on error. */ static int itadmin_config_read_credentials(itadmin_job *job) { dkChar fnb[DK3_MAX_PATH]; /* File name buffer. */ dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Input line buffer. */ itadmin_cred_reader reader; /* Helper structure to read creds. */ int back = 0; $? "+ itadmin_config_read_credentials" if(dk3str_len(job->dbcf) < DK3_SIZEOF(fnb,dkChar)) { dk3str_cpy_not_overlapped(fnb, job->dbcf); dk3str_correct_filename(fnb); if(dk3sf_must_expand(fnb)) { /* ERROR: File name must not contain wildcards! */ dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 118, 119, fnb); } else { if(!dk3str_is_abs_path(fnb)) { /* WARNING: File name should be specified as absolute path! */ dk3app_log_3(job->app, DK3_LL_WARNING, job->msg, 120, 121, fnb); } reader.job = job; reader.f_clnt = 1; $? ". really read credentials" back = dk3stream_process_filename_lines_app( (void *)(&reader), itadmin_cred_file_line_handler, fnb, line, DK3_SIZEOF(line,dkChar), dk3app_get_encoding(job->app), dk3app_get_input_file_encoding(job->app), job->app ); } } else { /* ERROR: File name too long! */ dk3app_log_i3(job->app, DK3_LL_ERROR, 65, 66, job->dbcf); } if(job->ec) { $? "! any error during run" back = 0; } $? "- itadmin_config_read_credentials %d", back return back; } int itadmin_config_read(itadmin_job *job) { dkChar fnb[DK3_MAX_PATH]; /* Copy of file name. */ dk3_search_t *res; /* Search result, config. */ dk3_dir_t *fne; /* File name expander. */ dk3_stat_t const *es; /* Expandend file status. */ dkChar const *fn; /* File name. */ dkChar const *en; /* Expanded file name. */ dkChar const *fnorig; /* Original file name. */ int back = 0; int have_file = 0; /* Flag: File found. */ int have_error = 0; /* Flag: Error occured. */ int argc; /* Number of file names. */ int i; /* Current file name index. */ $? "+ itadmin_config_read" /* Process default configuration files. */ res = dk3app_find_config_file(job->app, (job->noloc)[4], 0); if(res) { dk3search_reset(res); while((fn = dk3search_next(res)) != NULL) { have_file = 1; if(!itadmin_config_process_one_file(job, fn)) { have_error = 1; } } dk3search_close(res); } /* Process configuration file(s) specified on command line. */ argc = dk3opt_get_num_args(job->opt); for(i = 0; i < argc; i++) { fnorig = dk3opt_get_arg(job->opt, i); if(fnorig) { if(dk3str_len(fnorig) < DK3_SIZEOF(fnb,dkChar)) { dk3str_cpy_not_overlapped(fnb, fnorig); dk3str_correct_filename(fnb); if(dk3sf_must_expand(fnb)) { fne = dk3dir_fne_open_app(fnb, job->app); if(fne) { while(dk3dir_get_next_file(fne)) { en = dk3dir_get_fullname(fne); es = dk3dir_get_stat(fne); if((en) && (es)) { switch((es->ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_REGULAR: { have_file = 1; if(!itadmin_config_process_one_file(job, fnb)) { have_error = 1; } } break; default: { have_error = 1; /* ERROR: Wrong file type! */ dk3app_log_i3(job->app, DK3_LL_ERROR, 255, 256, en); } break; } } else { /* BUG: No complete information available! */ } } dk3dir_close(fne); } else { /* ERROR: Failed to expand file name! */ } } else { have_file = 1; if(!itadmin_config_process_one_file(job, fnb)) { have_error = 1; } } } else { /* ERROR: File name fnorig too long! */ dk3app_log_i3(job->app, DK3_LL_ERROR, 65, 66, fnorig); } } else { /* BUG: No pointer returned! */ } } /* Final tests and error messages. */ if(have_file) { $? ". files found" if(!(have_error)) { $? ". no errors" back = 1; if(!(job->dbhn)) { $? "! db host" /* ERROR: Missing database host name! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 122); back = 0; } if(!(job->dbn)) { $? "! db name" /* ERROR: Missing database name! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 123); back = 0; } if(!(job->vlan)) { $? "! vlan" /* Warning: Missing VLAN name! */ dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 124); } if(!(job->org)) { $? "! org" /* ERROR: Missing organization name! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 125); back = 0; } if(!(job->ou)) { $? "! ou" /* ERROR: Missing organizational unit name! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 126); back = 0; } if(!(job->admn)) { $? "! admn" /* ERROR: Missing administrator name! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 127); back = 0; } if(!(job->dbcf)) { $? "! dbcf" /* ERROR: Missing database credentials file name! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 128); back = 0; } else { $? ". dbcf" if(back) { $? ". back" back = itadmin_config_read_credentials(job); if(back) { if(!(job->dbus)) { $? "! dbus" /* ERROR: Missing database user name! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 129); back = 0; } if(!(job->dbpw)) { $? "! dbpw" /* ERROR: Missing database user password! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 130); back = 0; } } } } if(back) { if(!(job->ukoma)) { if(dk3str_casecmp(dkT("de"), dk3app_get_language(job->app)) == 0) { dk3app_log_1(job->app, DK3_LL_INFO, job->msg, 302); } } } if(!(back)) { dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 132); } } else { $? "! errors found" } } else { $? "! no files" /* ERROR: No configuration file found for processing! */ dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 131); } $? "- itadmin_config_read %d", back return back; }