static struct SH_UTMP_S * sh_utmp_getutline(struct SH_UTMP_S * ut) { struct SH_UTMP_S * out; while (1) { if ((out = sh_utmp_getutent()) == NULL) { return NULL; } #ifdef HAVE_UTTYPE if (out->ut_type == USER_PROCESS || out->ut_type == LOGIN_PROCESS) if (sl_strcmp(ut->ut_line, out->ut_line) == 0) return out; #else if ( 0 != sl_strncmp (out->ut_name, "reboot", 6) && 0 != sl_strncmp (out->ut_name, "shutdown", 8) && 0 != sl_strncmp (out->ut_name, "date", 4) ) return out; #endif } return NULL; }
static int sh_utmp_is_virtual (char * in_utline, char * in_uthost) { if (in_uthost != NULL && in_utline != NULL && in_uthost[0] == ':' && in_uthost[1] == '0' && 0 == sl_strncmp(in_utline, _("pts/"), 4)) { return 1; } return 0; }
dso *load_elf(dso *loader, const char *name, const char *path, long fd, unsigned char rt_load, unsigned int rtld_mode, Elf32_auxv_t *auxv) { #ifdef D_LOAD sl_printf("\nLoading elf file: %s (%s)\n", path, name); #endif #ifdef SL_STATISTIC /* Some statistics */ loaded_dsos++; curr_loaded_dsos++; max_loaded_dsos = MAX(max_loaded_dsos, curr_loaded_dsos); #endif /* Get file information */ struct kernel_stat file_info; if(sl_fstat(fd, &file_info) == -1) { /* Close file */ sl_close(fd); /* Signal error (longjmp) if we load at runtime */ if(rt_load) signal_error(0, name, 0, "fstat failed"); /* Not at runtime -> fail */ sl_printf("Error load_elf: fstat failed while loading %s.\n", name); sl_exit(1); } /* Map entire file in memory */ void *file_map = sl_mmap(0, file_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if ((long)file_map == -1) { /* Close file */ sl_close(fd); /* Signal error (longjmp) if we load at runtime */ if(rt_load) signal_error(0, name, 0, "mmap failed"); /* Not at runtime -> fail */ sl_printf("Error load_elf: mmap of file %s failed.\n", name); sl_exit(1); } /* Get ELF header and check file */ Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) file_map; long valid = check_elf(elf_hdr); if (valid != 0) { /* Invalid elf file */ sl_close(fd); /* Signal error (longjmp) if we load at runtime */ if(rt_load) signal_error(0, name, 0, "invalid ELF file"); /* Not at runtime -> fail */ sl_printf("Error load_elf: %s is not a valid ELF file (error: %d).\n", name, valid); sl_exit(1); } /* Get program and section header */ Elf32_Phdr *program_hdr = (Elf32_Phdr *) (file_map + elf_hdr->e_phoff); Elf32_Shdr *shdr = (Elf32_Shdr *) (file_map + elf_hdr->e_shoff); /* Segments (text and data) which we have to map in memory */ Elf32_Phdr *load_segments[2]; long num_load = 0; /* Create new shared object */ dso *so = sl_calloc(sizeof(dso), 1); /* Iterate over program headers */ unsigned long i = 0; for(i = 0; i < elf_hdr->e_phnum; ++i) { switch (program_hdr[i].p_type) { case PT_DYNAMIC: /* Dynamic Header */ so->dynamic_section = (Elf32_Dyn *)(program_hdr[i].p_vaddr); break; case PT_LOAD: /* Section must be mapped in memory */ if (num_load >= 2) { sl_printf("Error load_elf: more than two PT_LOAD segments!"); sl_exit(1); } load_segments[num_load++] = program_hdr+i; break; case PT_TLS: /* Thread Local Storage information*/ if (program_hdr[i].p_memsz == 0) break; /* Initialize TLS information */ so->tls_blocksize = program_hdr[i].p_memsz; so->tls_align = program_hdr[i].p_align; so->tls_initimage_size = program_hdr[i].p_filesz; /* TLS image (addr later adjusted) */ so->tls_initimage = (void *) program_hdr[i].p_vaddr; /* Assign next module ID */ so->tls_modid = ++GL(_dl_tls_max_dtv_idx); break; /* case PT_GNU_STACK: if (program_hdr[i].p_flags & PF_X) { sl_printf("Warning: executable stack\n"); sl_exit(1); } break; */ case PT_GNU_RELRO: /* Sections to set readonly after relocation */ /* Address is later adjusted */ so->relro = program_hdr[i].p_vaddr; so->relro_size = program_hdr[i].p_memsz; break; } } /* Map segments into memory and intitialize dso struct */ if(rtld_mode == 1 && auxv != NULL) { Elf32_Phdr *program_hdr_auxv; Elf32_Phdr *load_segments_auxv[2]; program_hdr_auxv = (Elf32_Phdr *)get_aux_value(auxv, AT_PHDR); uint32_t auxv_e_phnum = (uint32_t)get_aux_value(auxv, AT_PHNUM); unsigned long j = 0; unsigned int nr_load = 0; for(j = 0; j < auxv_e_phnum; j++) { switch (program_hdr_auxv[j].p_type) { case PT_LOAD: /* Section must be mapped in memory */ if (nr_load >= 2) { sl_exit(1); } load_segments_auxv[nr_load++] = program_hdr_auxv+j; break; } } map_segments_RTLD(fd, load_segments, elf_hdr->e_type, so, load_segments_auxv); } else { map_segments(fd, load_segments, elf_hdr->e_type, so); } so->ref_count = 1; so->deps_count = 0; so->name = name; so->path = path; so->type = elf_hdr->e_type; so->entry = (void*) elf_hdr->e_entry; so->loader = loader; so->dynamic_section = (Elf32_Dyn *) BYTE_STEP(so->dynamic_section, so->base_addr); so->program_header = (Elf32_Phdr *) BYTE_STEP(elf_hdr->e_phoff, so->text_addr); so->program_header_num = elf_hdr->e_phnum; so->l_real = so; /* Adjust address of TLS init image and relro address */ if (so->tls_initimage) { so->tls_initimage = (char *)so->tls_initimage + (long)so->base_addr; } if (so->relro) { so->relro = (Elf32_Addr) BYTE_STEP(so->relro, so->base_addr); } /* Iterate over section headers */ char *strtab = (char *)file_map + shdr[elf_hdr->e_shstrndx].sh_offset; char *sname=0; for (i=0; i<elf_hdr->e_shnum; ++i) { sname = strtab + shdr[i].sh_name; /* Save important sections */ if (sl_strncmp(sname, ".got", 5) == 0) { so->got = (char *) (so->base_addr + shdr[i].sh_addr); so->got_size = shdr[i].sh_size; } if (sl_strncmp(sname, ".plt", 5) == 0) { so->plt = (char *) (so->base_addr + shdr[i].sh_addr); so->plt_size = shdr[i].sh_size; } if (sl_strncmp(sname, ".got.plt", 9) == 0) { so->gotplt = (char *) (so->base_addr + shdr[i].sh_addr); so->gotplt_size = shdr[i].sh_size; } } /* Resolve */ Elf32_Dyn *dyn; long rpath=-1; for (dyn = so->dynamic_section; dyn->d_tag != DT_NULL; ++dyn) { switch (dyn->d_tag) { case DT_INIT: /* Initialization function */ so->init = (void (*)(int, char**, char**)) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_INIT_ARRAY: /* Array of initialization functions */ so->init_array = (Elf32_Addr *)BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_INIT_ARRAYSZ: /* Size of init array */ so->init_array_sz = (long)dyn->d_un.d_val / sizeof(Elf32_Addr); break; case DT_FINI: /* Finalization function */ so->fini = (void (*)()) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_FINI_ARRAY: /* Array of finalization functions */ so->fini_array = (Elf32_Addr *)BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_FINI_ARRAYSZ: /* Size of fini array */ so->fini_array_sz = (long)dyn->d_un.d_val / sizeof(Elf32_Addr); break; case DT_RUNPATH: /* String with library search paths */ rpath = dyn->d_un.d_val; break; case DT_RPATH: /* String with library search paths */ if (rpath == -1) rpath = dyn->d_un.d_val; break; case DT_PLTGOT: /* Plt part of the global offset table */ so->gotplt = (char *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_REL: /* Relocation table */ so->rel = (Elf32_Rel *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_RELSZ: /* Size of the relocation table */ so->relsz = (long)dyn->d_un.d_val / sizeof(Elf32_Rel); break; case DT_JMPREL: /* Plt relocations part of relocation table */ so->pltrel = (Elf32_Rel *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_PLTRELSZ: /* Size of plt relocations part of relocation table */ so->pltrelsz = (long)dyn->d_un.d_val / sizeof(Elf32_Rel); break; case DT_HASH: /* ELF hash table */ so->hash_table = (Elf32_Word *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_GNU_HASH: /* GNU hash table */ so->gnu_hash_table = (Elf32_Word *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_SYMTAB: /* Dynamic symbol table */ so->symbol_table = (Elf32_Sym *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_VERDEF: /* Versions defined in this DSO */ so->verdef = (Elf32_Verdef *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_VERDEFNUM: /* Number of versions defined in this DSO */ so->verdef_num = (unsigned long) dyn->d_un.d_val; break; case DT_VERNEED: /* Versions needed by this DSO */ so->verneed = (Elf32_Verneed *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_VERNEEDNUM: /* Number of versions needed by this DSO */ so->verneed_num = (unsigned long) dyn->d_un.d_val; break; case DT_VERSYM: /* Version symbol table */ so->versym = (Elf32_Half *) BYTE_STEP(dyn->d_un.d_ptr, so->base_addr); break; case DT_STRTAB: /* Dynamic string table */ so->string_table = (char *) so->base_addr + dyn->d_un.d_ptr; break; case DT_NEEDED: /* Dependencies on other DSOs */ /* Count the number of direct dependencies */ so->deps_count++; break; case DT_FLAGS: /* Flags */ so->flags = dyn->d_un.d_val; if ((so->flags & DF_SYMBOLIC) || (so->flags & DF_TEXTREL)) { sl_printf("Error load_elf: not supported flag 0x%x in %s.\n", so->flags, so->name); sl_exit(1); } break; case DT_FLAGS_1: /* Flags */ so->flags_1 = dyn->d_un.d_val; if ((so->flags_1 & DF_1_GROUP) || (so->flags_1 & DF_1_LOADFLTR) || (so->flags_1 & DF_1_DIRECT) || (so->flags_1 & DF_1_INTERPOSE) || (so->flags_1 & DF_1_NODEFLIB) // || (so->flags_1 & DF_1_NODUMP) || (so->flags_1 & DF_1_CONFALT) || (so->flags_1 & DF_1_ENDFILTEE) || (so->flags_1 & DF_1_DISPRELDNE) || (so->flags_1 & DF_1_DISPRELPND)) { sl_printf("Error load_elf: not supported flag_1 0x%x in %s.\n", so->flags_1, so->name); sl_exit(1); } break; } } /* Initialize the versioning data */ init_versions(so); /* Set library search paths */ if (rpath != -1) so->search_path = decompose_path(so->string_table+rpath,so->name, "RPATH"); /* Allocate memory for deps */ if (so->deps_count != 0) so->deps = sl_malloc(so->deps_count * sizeof(dso *)); /* Add shared object to chain */ chain_add(so); /* Now that we have the stringtable, iterate a second time over dynamic section to get the names of the needed libraries. */ char *lib_name = 0; long num = 0; for (dyn = so->dynamic_section; dyn->d_tag != DT_NULL; dyn++) { switch (dyn->d_tag) { case DT_NEEDED: /* Get name of needed lib */ lib_name = (char *)so->string_table + dyn->d_un.d_val; #ifdef D_LOAD sl_printf("Found dependency in %s: %s\n", so->name, lib_name); #endif /* Do not load the linux dynamic loader, because we replace it */ if (sl_strncmp(lib_name, LINUX_LOADER, sl_strnlen(LINUX_LOADER, MAX_LIB_NAME))==0) { so->deps_count--; continue; } /* Check if we already loaded it */ dso *so_search = chain_search(lib_name); if (so_search == 0) { /* Not already loaded, search for it */ char *lib_path; long fd = search_lib(so, lib_name, &lib_path); if (fd == -1) { /* Not found, signal error (longjmp) if we load at runtime */ if(rt_load) signal_error(0, lib_name, 0, "cannot open shared object file"); /* Not at runtime -> fail */ sl_printf("Error load_elf: lib %s not found.\n", lib_name); sl_exit(1); } /* Copy name */ char *lname = sl_malloc(MAX_LIB_NAME); sl_strncpy(lname, lib_name, MAX_LIB_NAME); PROT_DATA(lname, MAX_LIB_NAME); /* Load it */ dso *so_loaded = load_elf(so, lname, lib_path, fd, rt_load, 0, NULL); /* Increment local scope counter and add to direct deps */ so->lscope_num += so_loaded->lscope_num; so->deps[num] = so_loaded; } else { /* Increment reference counter */ UNPROT(so_search); so_search->ref_count++; PROT(so_search); /* Increment local scope counter and add to direct deps */ so->lscope_num += so_search->lscope_num; so->deps[num] = so_search; } num++; so->lscope_num++; break; } } so->lscope_num++; /* Create local scope list. This has to be done in breadth-first order! */ so->lscope = sl_malloc(so->lscope_num * sizeof(dso *)); long j,k,l; i = 0; /* Add object itself */ so->lscope[i++] = so; /* First add direct dependencies */ for (l=0; l<so->deps_count; ++l) { so->lscope[i] = so->deps[l]; ++i; } /* Now add deps recursively */ for (l=0; l<so->deps_count; ++l) { for (k=0; k<so->deps[l]->lscope_num; ++k) { dso *dep = so->deps[l]->lscope[k]; /* Check if already added */ long found = 0; for (j=0; j<i; ++j) { if (so->lscope[j] == dep) found = 1; } if (found || !dep) continue; so->lscope[i] = dep; ++i; } } /* Initialize Global Offset Table */ init_got(so); #if defined(VERIFY_CFTX) /* Add object to dso chain if libdetox wants to check the control flow transfers */ add_dso(so, (char *)file_map); #if defined(CALLBACK_MAIN_DETECTION) || defined(CALLBACK_DATA_SECTION_SEARCH) /* Right after loading the dso we need to detect the libc callbacks to main/__libc_csu_init */ if(so->loader == NULL && dso_chain->next != 0) { /* This is the main executable. Get the immediate values pushed on the stack right before __libc_start_main is called. */ #if defined(CALLBACK_MAIN_DETECTION) /* This is the main function callback detection hack! * - it tries to find the callback pointers passed to libc * - and it adds them to the callback table so CFTX checks will pass */ long count = 0; unsigned char *iptr; unsigned long ptr; if(so->type == ET_EXEC) iptr = (unsigned char *)so->entry; else /* PIE executable */ iptr = (unsigned char *)((unsigned long)so->base_addr + (unsigned long)so->entry); /* TODO: 48? Remove hardcoded value. */ while(count<48) { /* is it a push instruction with a 32bit immediate value? */ if(*iptr == 0x68) { /* add the immediate value pushed to the stack */ ptr = *((unsigned long*)(++iptr)); fbt_add_callback(dso_chain->next, (void*)ptr); iptr+=4; count+=5; } else { iptr++; count++; } /* in case we reached NOPs we can just stop looking for the pushes */ if(*iptr == 0x90) break; } #endif /* CALLBACK_MAIN_DETECTION */ #if defined(CALLBACK_DATA_SECTION_SEARCH) /* Some x* applications have global function pointers in their .data section. * This are probably widget class objects and their members. It seems that there is no other * way to detect these potential callbacks than scanning through the .data section. This has * only to be done for prelinked executables as we will detect the other callbacks during relocation. */ unsigned long *dptr = so->data_addr; if(dptr) { while((unsigned long)dptr < ((unsigned long)so->data_addr+(unsigned long)so->data_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through GOT */ dptr = (unsigned long*)(so->got); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->got+(unsigned long)so->got_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through GOT.PLT */ dptr = (unsigned long*)(so->gotplt); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->gotplt+(unsigned long)so->gotplt_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through rodata */ dptr = (unsigned long*)(so->dso->rodata); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->dso->rodata+(unsigned long)so->dso->rodata_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through reldyn */ dptr = (unsigned long*)(so->dso->reldyn); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->dso->reldyn+(unsigned long)so->dso->reldyn_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through relplt */ dptr = (unsigned long*)(so->dso->relplt); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->dso->relplt+(unsigned long)so->dso->relplt_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } #endif /* CALLBACK_DATA_SECTION_SEARCH */ } #endif /* defined(CALLBACK_MAIN_DETECTION) || defined(CALLBACK_DATA_SECTION_SEARCH) */ #if defined(CALLBACK_LIBRARIES_DATA_SECTION_SEARCH) if(so->loader != NULL) { /* it's a library! */ unsigned long *dptr = so->data_addr; if(dptr) { while((unsigned long)dptr < ((unsigned long)so->data_addr+(unsigned long)so->data_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through GOT */ dptr = (unsigned long*)(so->got); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->got+(unsigned long)so->got_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through GOT.PLT */ dptr = (unsigned long*)(so->gotplt); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->gotplt+(unsigned long)so->gotplt_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through rodata */ dptr = (unsigned long*)(so->dso->rodata); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->dso->rodata+(unsigned long)so->dso->rodata_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through reldyn */ dptr = (unsigned long*)(so->dso->reldyn); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->dso->reldyn+(unsigned long)so->dso->reldyn_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } /* go through relplt */ dptr = (unsigned long*)(so->dso->relplt); if(dptr) { while((unsigned long)dptr < ((unsigned long)so->dso->relplt+(unsigned long)so->dso->relplt_size)) { /* check if the obtained address points to executable memory (potential callback target) */ if (PTR_IN_REGION(*dptr, so->text_addr, so->text_size) || PTR_IN_REGION(*dptr, so->dso->init, so->dso->init_size) || PTR_IN_REGION(*dptr, so->dso->fini, so->dso->fini_size)) { fbt_add_callback(so->dso, (void*)*dptr); } dptr++; /* increase by sizeof(unsigned long) = bytes */ } } } #endif /* CALLBACK_LIBRARIES_DATA_SECTION_SEARCH */ #endif /* VERIFY_CFTX */ /* All necessary information in memory -> unmap file */ sl_munmap(file_map, file_info.st_size); sl_close(fd); /* Protect dependencies and local search scope */ PROT_DATA(so->deps, so->deps_count*sizeof(dso *)); PROT_DATA(so->lscope, so->lscope_num*sizeof(dso *)); return so; }
static void sh_utmp_addlogin (struct SH_UTMP_S * ut) { struct log_user * user = userlist; struct log_user * userold = userlist; #ifdef HAVE_UTTYPE struct log_user * username = userlist; #endif char ttt[TIM_MAX]; #ifdef HAVE_UTTYPE volatile int status; #endif SL_ENTER(_("sh_utmp_addlogin")); if (ut->ut_line[0] == '\0') SL_RET0(_("sh_utmp_addlogin")); /* for some stupid reason, AIX repeats the wtmp entry for logouts * with ssh */ if (memcmp (&save_utmp, ut, sizeof(struct SH_UTMP_S)) == 0) { memset(&save_utmp, (int) '\0', sizeof(struct SH_UTMP_S)); SL_RET0(_("sh_utmp_addlogin")); } memcpy (&save_utmp, ut, sizeof(struct SH_UTMP_S)); /* Take the address to keep gcc from putting them into registers. * Avoids the 'clobbered by longjmp' warning. */ sh_dummy_userold = (void*) &userold; sh_dummy_user = (void*) &user; /* ------- find user -------- */ while (user != NULL) { if (0 == sl_strncmp((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE) ) break; userold = user; user = user->next; } #ifdef HAVE_UTTYPE while (username != NULL) { if (0 == sl_strncmp(username->name, ut->ut_name, UT_NAMESIZE) ) break; username = username->next; } #endif #ifdef HAVE_UTTYPE /* ---------- LOGIN -------------- */ if (ut->ut_type == USER_PROCESS) { if (user == NULL) { user = SH_ALLOC(sizeof(struct log_user)); user->next = userlist; userlist = (struct log_user *) user; } (void) sl_strlcpy((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE+1); (void) sl_strlcpy((char*)(user->name), ut->ut_name, UT_NAMESIZE+1); #ifdef HAVE_UTHOST (void) sl_strlcpy((char*)(user->ut_host), ut->ut_host, UT_HOSTSIZE+1); #else user->ut_host[0] = '\0'; #endif #ifdef HAVE_UTADDR #ifdef HAVE_UTADDR_V6 my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF); #else my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF); #endif #endif user->time = ut->ut_time; if (username == NULL /* not yet logged in */ || 0 == sl_strncmp(ut->ut_line, _("ttyp"), 4) /* in virt. console */ || 0 == sl_strncmp(ut->ut_line, _("ttyq"), 4) /* in virt. console */ ) { status = sh_utmp_login_a((char*)user->name); SH_MUTEX_LOCK(mutex_thread_nolog); (void) sh_unix_time (user->time, ttt, TIM_MAX); sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) MSG_UT_LG1X, #elif defined(HAVE_UTHOST) MSG_UT_LG1A, #else MSG_UT_LG1B, #endif user->name, user->ut_tty, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) user->ut_host, user->ut_ship, #elif defined(HAVE_UTHOST) user->ut_host, #endif ttt, status ); SH_MUTEX_UNLOCK(mutex_thread_nolog); } else if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host)) { status = sh_utmp_login_a((char*)user->name); SH_MUTEX_LOCK(mutex_thread_nolog); (void) sh_unix_time (user->time, ttt, TIM_MAX); sh_error_handle( ShUtmpLoginMulti, FIL__, __LINE__, 0, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) MSG_UT_LG2X, #elif defined(HAVE_UTHOST) MSG_UT_LG2A, #else MSG_UT_LG2B, #endif user->name, user->ut_tty, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) user->ut_host, user->ut_ship, #elif defined(HAVE_UTHOST) user->ut_host, #endif ttt, status ); SH_MUTEX_UNLOCK(mutex_thread_nolog); } sh_utmp_login_morechecks(ut); goto out; } /* --------- LOGOUT ---------------- */ else if (ut->ut_name[0] == '\0' || ut->ut_type == DEAD_PROCESS /* solaris does not clear ut_name */ ) { if (user != NULL) { #if defined(__linux__) if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host)) { #endif status = sh_utmp_login_r((char*)user->name); SH_MUTEX_LOCK(mutex_thread_nolog); (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX); sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) MSG_UT_LG3X, #elif defined(HAVE_UTHOST) MSG_UT_LG3A, #else MSG_UT_LG3B, #endif user->name, user->ut_tty, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) user->ut_host, user->ut_ship, #elif defined(HAVE_UTHOST) user->ut_host, #endif ttt, status ); SH_MUTEX_UNLOCK(mutex_thread_nolog); userold->next = user->next; if (user == userlist) userlist = user->next; sh_utmp_logout_morechecks((struct log_user *)user); SH_FREE((struct log_user *)user); user = NULL; #if defined(__linux__) } #endif } else { (void) sl_strlcpy(terminated_line, ut->ut_line, UT_HOSTSIZE); SH_MUTEX_LOCK(mutex_thread_nolog); (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX); sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0, MSG_UT_LG3C, terminated_line, ttt, 0 ); SH_MUTEX_UNLOCK(mutex_thread_nolog); } goto out; } /* default */ goto out; /* #ifdef HAVE_UTTYPE */ #else if (user == NULL) /* probably a login */ { user = SH_ALLOC(sizeof(struct log_user)); sl_strlcpy(user->ut_tty, ut->ut_line, UT_LINESIZE+1); sl_strlcpy(user->name, ut->ut_name, UT_NAMESIZE+1); #ifdef HAVE_UTHOST sl_strlcpy(user->ut_host, ut->ut_host, UT_HOSTSIZE+1); #endif #ifdef HAVE_UTADDR #ifdef HAVE_UTADDR_V6 my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF); #else my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF); #endif #endif user->time = ut->ut_time; user->next = userlist; userlist = user; SH_MUTEX_LOCK(mutex_thread_nolog); (void) sh_unix_time (user->time, ttt, TIM_MAX); sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) MSG_UT_LG1X, #elif defined(HAVE_UTHOST) MSG_UT_LG1A, #else MSG_UT_LG1B, #endif user->name, user->ut_tty, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) user->ut_host, user->ut_ship, #elif defined(HAVE_UTHOST) user->ut_host, #endif ttt, 1 ); SH_MUTEX_UNLOCK(mutex_thread_nolog); sh_utmp_login_morechecks(ut); } else /* probably a logout */ { SH_MUTEX_LOCK(mutex_thread_nolog); (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX); sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) MSG_UT_LG2X, #elif defined(HAVE_UTHOST) MSG_UT_LG2A, #else MSG_UT_LG2B, #endif user->name, user->ut_tty, #if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) user->ut_host, user->ut_ship, #elif defined(HAVE_UTHOST) user->ut_host, #endif ttt, 1 ); SH_MUTEX_UNLOCK(mutex_thread_nolog); sh_utmp_logout_morechecks(user); userold->next = user->next; if (user == userlist) /* inserted Apr 4, 2004 */ userlist = user->next; SH_FREE(user); user = NULL; } #endif out: sh_dummy_user = NULL; sh_dummy_userold = NULL; SL_RET0(_("sh_utmp_addlogin")); }
/* --- Read the configuration file. --- */ int sh_readconf_read (void) { #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) /* This is for modules. */ int modnum; #endif int i; SL_TICKET fd = -1; #if defined(SH_STEALTH) && !defined(SH_STEALTH_MICRO) SL_TICKET fdTmp = -1; #endif #if defined(WITH_GPG) || defined(WITH_PGP) SL_TICKET fdGpg = -1; #endif char * tmp; #define SH_LINE_IN 16384 char * line_in; char * line; /* This is for nested conditionals. */ int cond_depth = 0; int cond_excl = 0; int local_file = 1; char local_flag = 'R'; #if defined(WITH_GPG) || defined(WITH_PGP) int signed_content = S_FALSE; int true_content = S_FALSE; #endif #if defined(SH_STEALTH) && !defined(SH_STEALTH_MICRO) int hidden_count = 0; #endif uid_t euid; char hashbuf[KEYBUF_SIZE]; SL_ENTER(_("sh_readconf_read")); /* --- Open config file, exit on failure. --- */ #if defined(SH_WITH_CLIENT) if (0 == sl_strcmp(file_path('C', 'R'), _("REQ_FROM_SERVER"))) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_START); fd = sh_forward_req_file(_("CONF")); if (!SL_ISERROR(fd)) { local_file = 0; } else if (sh.flag.checkSum != SH_CHECK_INIT) { aud_exit (FIL__, __LINE__, EXIT_FAILURE); } else { sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_D_FAIL); local_file = 1; local_flag = 'I'; } } #endif /* Use a local configuration file. */ if (local_file == 1) { if (0 != tf_trust_check (file_path('C', local_flag), SL_YESPRIV)) { sl_get_euid(&euid); dlog(1, FIL__, __LINE__, _("The configuration file: %s is untrusted, i.e. an\nuntrusted user owns or can write to some directory in the path.\n"), ( (NULL == file_path('C', local_flag)) ? _("(null)") : file_path('C', local_flag) )); sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_TRUST, (long) euid, ( (NULL == file_path('C', local_flag)) ? _("(null)") : file_path('C', local_flag) ) ); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } if (SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, file_path('C',local_flag),SL_YESPRIV))) { sl_get_euid(&euid); dlog(1, FIL__, __LINE__, _("Could not open the local configuration file for reading because\nof the following error: %s (errnum = %ld)\nIf this is a permission problem, you need to change file permissions\nto make the file readable for the effective UID: %d\n"), sl_get_errmsg(), fd, (int) euid); sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_NOACCESS, (long) euid, ( (NULL == file_path('C', local_flag)) ? _("(null)") : file_path('C', local_flag) ) ); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } } /* Compute the checksum of the open file. */ sl_strlcpy(sh.conf.hash, sh_tiger_hash(file_path('C',local_flag), fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf)), KEY_LEN+1); sl_rewind (fd); line_in = SH_ALLOC(SH_LINE_IN); #if defined(SH_STEALTH) && !defined(SH_STEALTH_MICRO) /* extract the data and copy to temporary file */ fdTmp = open_tmp(); sh_unix_getline_stealth (0, NULL, 0); /* initialize */ while ( sh_unix_getline_stealth (fd, line_in, SH_LINE_IN-2) > 0) { hidden_count++; if (line_in[0] == '\n') { sl_write(fdTmp, line_in, 1); } else { sl_write_line(fdTmp, line_in, sl_strlen(line_in)); } #if defined(WITH_GPG) || defined(WITH_PGP) if (0 == sl_strncmp(line_in, _("-----END PGP SIGNATURE-----"), 25)) break; #else if (0 == sl_strncmp(line_in, _("[EOF]"), 5)) break; #endif if (hidden_count > 1048576) /* arbitrary safeguard, 1024*1024 */ break; } sl_close(fd); fd = fdTmp; sl_rewind (fd); #endif #if defined(WITH_GPG) || defined(WITH_PGP) /* extract the data and copy to temporary file */ fdGpg = sh_gpg_extract_signed(fd); sl_close(fd); fd = fdGpg; /* Validate signature of open file. */ if (0 != sh_gpg_check_sign (fd, 0, 1)) { SH_FREE(line_in); aud_exit (FIL__, __LINE__, EXIT_FAILURE); } sl_rewind (fd); #endif /* --- Start reading lines. --- */ conf_line = 0; while ( sh_unix_getline (fd, line_in, SH_LINE_IN-2) > 0) { ++conf_line; line = &(line_in[0]); /* fprintf(stderr, "<%s>\n", line); */ /* Sun May 27 18:40:05 CEST 2001 */ #if defined(WITH_GPG) || defined(WITH_PGP) if (signed_content == S_FALSE) { if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNED MESSAGE-----"))) signed_content = S_TRUE; else continue; } else if (true_content == S_FALSE) { if (line[0] == '\n') true_content = S_TRUE; else continue; } else if (signed_content == S_TRUE) { if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNATURE-----"))) break; else if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNED MESSAGE-----"))) { sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, _("second signed message in file"), _("sh_readconf_read")); dlog(1, FIL__, __LINE__, _("There seems to be more than one signed message in the configuration\nfile. Please make sure there is only one signed message.\n")); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name); SH_FREE(line_in); aud_exit (FIL__, __LINE__,EXIT_FAILURE); } } #endif /* Skip leading white space. */ while (isspace((int)*line)) ++line; /* Skip header etc. */ if (line[0] == '#' || line[0] == '\0' || line[0] == ';' || (line[0] == '/' && line[1] == '/')) continue; /* Clip off trailing white space. */ tmp = line + sl_strlen( line ); --tmp; while( isspace((int) *tmp ) && tmp >= line ) *tmp-- = '\0'; /* --- an @host/@if/$system directive -------------- */ if (line[0] == '@' || (line[0] == '!' && line[1] == '@') || line[0] == '$' || (line[0] == '!' && line[1] == '$')) { if (sh_readconf_is_end(line)) { if (0 == cond_depth) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALD, _("config file"), (long) conf_line); } else { if (cond_excl == cond_depth) cond_excl = 0; --cond_depth; } } else if (sh_readconf_is_else(line)) { if (0 == cond_depth) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALD, _("config file"), (long) conf_line); } else if (cond_excl == cond_depth) { cond_excl = 0; } else if (cond_excl == 0) { cond_excl = cond_depth; } } else { if (sh_readconf_cond_match(line, conf_line)) { ++cond_depth; } else { ++cond_depth; if (cond_excl == 0) cond_excl = cond_depth; } } continue; } /**************************************************** * * Only carry on if this section is intended for us * ****************************************************/ if (cond_excl != 0) { continue; } /* ------- starts a section ------------ */ else if (line[0] == '[') { read_mode = SH_SECTION_NONE; if (0 == sl_strncasecmp (line, _("[EOF]"), 5)) { goto nopel; } i = 0; while (tab_ListSections[i].name != 0) { if (sl_strncasecmp (line, _(tab_ListSections[i].name), sl_strlen(tab_ListSections[i].name)) == 0) { read_mode = tab_ListSections[i].type; break; } ++i; } #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) if (read_mode == SH_SECTION_NONE) { for (modnum = 0; modList[modnum].name != NULL; ++modnum) { if (0 == sl_strncasecmp (line, _(modList[modnum].conf_section), sl_strlen(modList[modnum].conf_section)) ) read_mode = SH_SECTION_OTHER; } } #endif if (read_mode == SH_SECTION_NONE) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALHEAD, (long) conf_line); } } /* --- an %schedule directive ------------ */ else if (line[0] == '%' || (line[0] == '!' && line[1] == '%')) { #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) if (line[0] == '!' && 0 == sl_strcasecmp(&(line[2]), _("SCHEDULE_TWO"))) set_dirList(1); else if (0 == sl_strcasecmp(&(line[1]), _("SCHEDULE_TWO"))) set_dirList(2); #else ; #endif } /* ------ no new section -------------- */ else if (read_mode != SH_SECTION_NONE) { if (0 != sh_readconfig_line (line)) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALCONF, (long) conf_line); } } } /* while getline() */ nopel: if (0 != cond_depth) sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALDD, _("config file"), (long) conf_line); sl_close (fd); sh_error_fixup(); read_mode = SH_SECTION_NONE; /* reset b/o sighup reload */ SH_FREE(line_in); SL_RETURN( 0, _("sh_readconf_read")); }
static int sh_readconf_cond_match(char * str, int line) { int match = 0; int negate = 1; int cond_type = SH_RC_ANY; char myident[3*SH_MINIBUF+3]; struct stat buf; char * p = str; if (*p == '!') { negate = 0; ++p; } if (*p == '$') { cond_type = SH_RC_SYSTEM; ++p; /* [!]$system */ } else { /* *p == '@' */ ++p; while (isspace((int)*p)) ++p; if (0 != strncasecmp(p, _("if "), 3)) { cond_type = SH_RC_HOST; /* [!]$host */ } else { p += 3; while (isspace((int)*p)) ++p; /* skip the 'if\s+' */ if (0 == strncasecmp(p, _("not "), 4)) { p += 4; while (isspace((int)*p)) ++p; negate = 0; } else if (0 == strncmp(p, _("!"), 1)) { ++p; while (isspace((int)*p)) ++p; negate = 0; } if (0 == strncasecmp(p, _("file_exists "), 12)) { p += 12; cond_type = SH_RC_FILE; } else if (0 == strncasecmp(p, _("interface_exists "), 17)) { p += 17; cond_type = SH_RC_IFACE; } else if (0 == strncasecmp(p, _("hostname_matches "), 17)) { p += 17; cond_type = SH_RC_HOST; } else if (0 == strncasecmp(p, _("system_matches "), 15)) { p += 15; cond_type = SH_RC_SYSTEM; } #ifdef SH_EVAL_SHELL else if (0 == strncasecmp(p, _("command_succeeds "), 17)) { p += 17; cond_type = SH_RC_CMD; } #endif else { char errbuf[SH_ERRBUF_SIZE]; sl_snprintf(errbuf, sizeof(errbuf), _("Unsupported test at line %d of configuration file"), line); sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, errbuf, _("sh_readconf_cond_match")); return 0; } } } while (isspace((int)*p)) ++p; switch (cond_type) { case SH_RC_HOST: if (sl_strncmp (p, sh.host.name, strlen(sh.host.name)) == 0 #ifdef HAVE_REGEX_H || sh_util_regcmp (p, sh.host.name) == 0 #endif ) match = negate; break; case SH_RC_SYSTEM: /* * The system type, release, and machine. */ sl_snprintf(myident, sizeof(myident), _("%s:%s:%s"), sh.host.system, /* flawfinder: ignore */ sh.host.release, sh.host.machine); if (sl_strncmp (p, myident, strlen(myident)) == 0 #ifdef HAVE_REGEX_H || sh_util_regcmp (p, myident) == 0 #endif ) match = negate; break; case SH_RC_FILE: if (0 == retry_lstat(FIL__, __LINE__, p, &buf)) match = negate; break; case SH_RC_IFACE: if (sh_tools_iface_is_present(p)) match = negate; break; #ifdef SH_EVAL_SHELL case SH_RC_CMD: if (0 == sh_unix_run_command(p)) match = negate; break; #endif default: match = 0; } return match; }
static int sh_readconfig_line (char * line) { char * key; const char * value; char * tmp; int i; int good_opt = -1; #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) int modnum, modkey; #endif static const char *dummy = N_("dummy"); static const char *closing[] = { N_("closecommand"), N_("closeaddress"), N_("logmonendgroup"), N_("logmonendhost"), NULL }; static const char *ident[] = { N_("severityreadonly"), N_("severitylogfiles"), N_("severitygrowinglogs"), N_("severityignorenone"), N_("severityignoreall"), N_("severityattributes"), N_("severitydirs"), N_("severityfiles"), N_("severitynames"), N_("severityuser0"), N_("severityuser1"), N_("severityuser2"), N_("severityuser3"), N_("severityuser4"), N_("severityprelink"), NULL }; static int identnum[] = { SH_ERR_T_RO, SH_ERR_T_LOGS, SH_ERR_T_GLOG, SH_ERR_T_NOIG, SH_ERR_T_ALLIG, SH_ERR_T_ATTR, SH_ERR_T_DIR, SH_ERR_T_FILE, SH_ERR_T_NAME, SH_ERR_T_USER0, SH_ERR_T_USER1, SH_ERR_T_USER2, SH_ERR_T_USER3, SH_ERR_T_USER4, SH_ERR_T_PRELINK, }; SL_ENTER(_("sh_readconf_line")); /* convert to lowercase */ tmp = line; while (*tmp != '=' && *tmp != '\0') { *tmp = tolower( (int) *tmp); ++tmp; } key = line; /* interpret line */ value = strchr(line, '='); if (value == NULL || (*value) == '\0') { if (key != NULL) { i = 0; while (closing[i] != NULL) { if (sl_strncmp(key,_(closing[i]),sl_strlen(closing[i])-1) == 0) { value = dummy; goto ok_novalue; } ++i; } TPT(( 0, FIL__, __LINE__, _("msg=<ConfigFile: not key=value: %s>\n"), line)); } SL_RETURN(good_opt, _("sh_readconf_line")); } else ++value; /* skip leading whitespace */ while ((*value) == ' ' || (*value) == '\t') ++value; if ((*value) == '\0') /* no value */ { if (key != NULL) { TPT(( 0, FIL__, __LINE__, _("msg=<ConfigFile: not key=value: %s>\n"), line)); } SL_RETURN(good_opt, _("sh_readconf_line")); } ok_novalue: if (!sl_is_suid()) { TPT(( 0, FIL__, __LINE__, _("msg=<ConfigFile: %s>\n"), line)); } /* Expand shell expressions. This return allocated memory which we must free. * If !defined(SH_EVAL_SHELL), this will reduce to a strdup. */ value = sh_readconf_expand_value(value); if (!value || (*value) == '\0') { TPT(( 0, FIL__, __LINE__, _("msg=<ConfigFile: empty after shell expansion: %s>\n"), line)); SL_RETURN(good_opt, _("sh_readconf_line")); } #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) if (read_mode == SH_SECTION_OTHER) { for (modnum = 0; modList[modnum].name != NULL; ++modnum) { for (modkey = 0; modList[modnum].conf_table[modkey].the_opt != NULL; ++modkey) { if (sl_strncmp (key, _(modList[modnum].conf_table[modkey].the_opt), sl_strlen(modList[modnum].conf_table[modkey].the_opt) ) == 0) { good_opt = 0; if (0 != modList[modnum].conf_table[modkey].func(value)) sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALS, _(modList[modnum].conf_table[modkey].the_opt), value); if (!sl_is_suid()) { TPT(( 0, FIL__, __LINE__, _("msg=<line = %s, option = %s>\n"), line, _(modList[modnum].conf_table[modkey].the_opt))); } goto outburst; } } } } outburst: #endif if (read_mode == SH_SECTION_THRESHOLD) { i = 0; while (ident[i] != NULL) { if (sl_strncmp (key, _(ident[i]), sl_strlen(ident[i])) == 0) { good_opt = 0; sh_error_set_iv (identnum[i], value); break; } ++i; } } else { i = 0; while (ext_table[i].optname != NULL) { if ((ext_table[i].section == read_mode || ext_table[i].alt_section == read_mode) && sl_strncmp (key, _(ext_table[i].optname), sl_strlen(ext_table[i].optname)) == 0) { good_opt = 0; if (0 != ext_table[i].func (value)) sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALS, _(ext_table[i].optname), value); break; } ++i; } } SH_FREE((char*)value); SL_RETURN(good_opt, _("sh_readconf_line")); }