#include #include #include #include #include #include #include #include #include "../askrunlevel/askrunlevel.h" #include #include #include "main.h" #include "main.m" #include #include #include #include char *revision = LINUXCONF_REVISION; /* #Specification: configuration programs / strategy The configuration program askrunlevel, netconf, xconf and lpdconf share a lot of code. They are seldom used (at startup only) generally. so they have been melted in one program. By using proper symlinks this program can behave differently ln -s /bin/linuxconf /bin/netconf ln -s /bin/linuxconf /bin/lpdconf ln -s /bin/linuxconf /bin/userconf ln -s /bin/linuxconf /bin/fsconf ln -s /bin/linuxconf /bin/xconf ln -s /bin/linuxconf /sbin/askrunlevel ln -s /bin/linuxconf /sbin/fixperm ln -s /bin/linuxconf /sbin/dnsconf ln -s /bin/linuxconf /sbin/mailconf ln -s /bin/linuxconf /sbin/uucpconf This is done mostly to save disk space and also make sure all those utility are updated in sync (a single program :-) ) */ static HELP_FILE introweb ("main","introweb"); /* Load the proper messages dictionnary */ static void main_loaddict () { /* #Specification: messages dictionnary / location The messages dictionnary is normally located in /usr/lib/linuxconf/linuxconf-msg-x.y.lang. This can't be overriden by the user. There is a way to override this during development, allowing to linuxconf to coexist. The environnement variable "LINUXCONF_DICT" contain the path of the directory containing the directories. This variable is not checked and when the program is run setuid */ /* #Specification: messages & help / langage selection The environnement variable LINUXCONF_LANG select the extension use to load the messages dictionnay and the help files. help file will be located in /usr/lib/linuxconf/help.LANG This mecanism is specific to Linuxconf. This will remain as an ultimate override. In the future, linuxconf should be able to probe the system to find out which langage to support. */ linuxconf_loadmsg ("linuxconf",PACKAGE_REV); translat_checkmissing(); help_setlang (linuxconf_getlang(),"LINUXCONF_LANG"); } void linuxconf_usage() { SSTRINGS tb; tb.add (new SSTRING (MSG_U(I_USAGE, "linuxconf main command line options\n" "\n" " --archive absolute_file_path [ ... ]\n" " --archive sub-system [ ... ]\n" " --demo\n" " --debug\n" " --debugfile\n" " --debugpath path\n" " --debugsyms\n" " --diff absolute_file_path [ ... ]\n" " --diff sub-systems [ ... ]\n" " --extract [ --to dest-dir ] absolute_file_path [ ... ]\n" " --extract [ --to dest-dir ] sub-system [ ... ]\n" " --gui\n" " --guiproto\n" " --help\n" " --helpfile\n" " --hint service key\n" " --history absolute_file_path [ ... ]\n" " --history sub-systems [ ... ]\n" " --http\n" " --listapi\n" " --listconfig\n" " --md5sum [ sub-systems ... ]\n" " --modulemain modulename [ args ... ]\n" " --services\n" " --setkeymap keymapfile\n" " --setmod modulename_or_path\n" " --showmsgs\n" " --shutdown\n" " --silent\n" " --status\n" " --selectprofile profile\n" " --text [--mono]\n" " --unsetmod modulename_or_path\n" " --update\n" " --vdb ...\n" " --version\n" "\n" ))); tb.add (new SSTRING(netconf_getusage())); tb.add (new SSTRING(userconf_getusage())); tb.add (new SSTRING(fsconf_getusage())); module_usage(tb); SSTRINGS lines; for (int i=0; iget(); char line[200]; char *dst = line; while (*pt != '\0' && dst < (line+sizeof(line)-1)){ if (*pt == '\n'){ *dst = '\0'; lines.add (new SSTRING (line)); dst = line; }else{ *dst++ = *pt; } pt++; } *dst = '\0'; lines.add (new SSTRING (line)); } dialog_textbox (MSG_U(I_CMDLINE,"Command line usage"),lines); } static void usage() { diagui_setmode (DIAGUI_NOGUI); linuxconf_usage(); exit(-1); } static void main_error (const char *s) { xconf_error ("%s",s); } /* Make sure we are root or else, exit */ static void main_needroot(const char *opt) { SSTRING tmp; tmp.setfromf (MSG_U(E_DEBUGOPT ,"Debugging options %s may only be used by root\n"),opt); if (!netconf_rootaccess(tmp.get())){ exit (-1); } } /* Parse the various debugging options. Only root is allowed to play with those options. argv[] may be modified. It returns the new argc. */ static int main_parsedebug (int argc, char *argv[]) { while (argc > 1){ const char *arg1 = argv[1]; int skip = 1; if (strcmp(arg1,"--debug")==0){ main_needroot(arg1); debug_seton(); }else if (strcmp(arg1,"--debugkeys")==0){ main_needroot(arg1); debug_keys(); }else if (strcmp(arg1,"--debugfile")==0){ main_needroot(arg1); if (argc == 1){ fprintf (stderr,MSG_U(E_OPTNEEDARG,"Option %s need one argument\n"),arg1); exit (-1); }else{ skip=2; debug_setfdebug(argv[2]); } }else if (strcmp(arg1,"--debugpath")==0){ main_needroot(arg1); if (argc == 1){ fprintf (stderr,MSG_R(E_OPTNEEDARG),arg1); exit (-1); }else{ skip = 2; debug_setpath (argv[2]); } }else{ break; } argc -= skip; // Copy argv to the left, including the ending NULL for (int i=1; i<=argc; i++){ argv[i] = argv[i+skip]; } } return argc; } int main (int argc, char *argv[]) { setlocale(LC_ALL,""); dialog_mayuselynx(false); LINUXCONF_CONTEXT main_context ("/"); ui_context.set(main_context); int ret = -1; char argv0[PATH_MAX]; char *pta = argv0; char *pt = argv[0]; // Make sure no error may stop linuxconf normal startup // so we put a 15 seconds timeout // This was created because sometime, after updating linuxconf // a module becomes incompatible and an error pops up at load time. // If linuxconf is called at boot time, then things go wrong... // The timeout prevent this. dialog_settimeout (15,MENU_ESCAPE,true); main_loaddict(); module_loaddistmod(); configf_readlookup (); // Extract the name of the program from its path while (*pt != '\0'){ if (*pt == '/'){ pt++; pta = argv0; }else{ *pta++ = *pt++; } } *pta = '\0'; /* #Specification: linuxconf / aliases linuxconf manipulate of lot of stuff for configuring properly a Linux station. Because of this, it include code to perform many task normally done by utilities seldom used. It was decide that in order to save some disk space, linuxconf could act as clone for those different programs. Here is the list of the different aliases. # /bin/fsconf /bin/linuxconf /bin/netconf /bin/userconf /bin/xconf /bin/hostname /bin/passwd /bin/dnsdomainname /sbin/askrunlevel /sbin/dnsconf /sbin/fixperm /sbin/mailconf # */ if(argc > 1 && strcmp(argv[1],"--demo")==0){ simul_setdemoflag (1); if (chroot("/demo_linuxconf")==-1 || chdir ("/") == -1){ syslog (LOG_ERR,MSG_U(E_DEMOINIT,"can't chroot(\"/demo_linuxconf\" (%m)")); exit (-1); } linuxconf_forget(); // Make sure we use the conf.linuxconf file // in the /demo_linuxconf/etc directory // not the main one. } // Registering and unregistering modules has to be done before they // are loaded if (argc == 3 && strcmp(argv[1],"--setmod")==0){ if (netconf_rootaccess(MSG_U(E_SETMOD ,"--setmod and --unsetmod may only be done by root\n"))){ module_setone (argv[2]); ret = 0; } exit (ret); }else if (argc == 3 && strcmp(argv[1],"--unsetmod")==0){ if (netconf_rootaccess(MSG_R(E_SETMOD))){ module_unsetone (argv[2]); ret = 0; } exit (ret); } argc = main_parsedebug(argc,argv); argc = dialog_parseuioptions(argc,argv); tlmp_seterrorfct (main_error); module_load(); dropin_module_load(); dialog_settimeout (-1,MENU_ESCAPE,false); dialog_mayuselynx(true); if (strcmp(argv0,"askrunlevel")==0){ if (getuid()!=0){ xconf_error (MSG_U(ERR_BOOT,"Askrunlevel is only used\n" "at boot time\n")); }else{ ret = askrunlevel_main (argc, argv); } }else if (strcmp(argv0,"dnsdomainname")==0){ ret = netconf_dnsdomainname (argc,argv); }else if (strcmp(argv0,"hostname")==0){ ret = netconf_hostname (argc,argv); }else if (strcmp(argv0,"fixperm")==0){ ret = fstab_fixperm (argc,argv); }else if (strcmp(argv0,"linuxconf")==0){ ret = 0; if (argc == 2 && strcmp(argv[1],"--helpfile")==0){ helpf_checkall(); }else if (argc == 2 && strcmp(argv[1],"--listconfig")==0){ if (perm_rootaccess(MSG_U(P_LISTCONFIG,"list configuration files"))){ configf_list(); } }else if (argc == 2 && strcmp(argv[1],"--listapi")==0){ if (perm_rootaccess(MSG_U(P_LISTAPI,"list inter-module APIs"))){ module_listapi(); } }else if (argc > 2 && strcmp(argv[1],"--modulemain")==0){ ret = module_execmain (argc-2,argv+2,false); if (ret<-1) usage(); }else if (argc == 2 && strcmp(argv[1],"--help")==0){ usage(); }else if (argc == 2 && strcmp(argv[1],"--version")==0){ char version[80]; linuxconf_formatversion(version); printf ("%s\n%s\n",version ,MSG_U(MOREINFO,"For more information, please use linuxconf --help")); }else if (argc >= 2 && strcmp(argv[1],"--archive")==0){ if (perm_rootaccess(MSG_U(P_ARCHIVE,"archive config files"))){ error_setmode (true); ret = subsys_archive(argc-2,(const char **)(argv+2)); } }else if (argc >= 2 && strcmp(argv[1],"--diff")==0){ if (perm_rootaccess(MSG_U(P_DIFF,"view config changes"))){ error_setmode (true); ret = subsys_diff(argc-2,(const char **)(argv+2)); } }else if (argc >= 2 && strcmp(argv[1],"--history")==0){ if (perm_rootaccess(MSG_U(P_HISTORY,"view config history"))){ error_setmode (true); ret = subsys_history(argc-2,(const char **)(argv+2)); } }else if (argc >= 3 && strcmp(argv[1],"--hint")==0){ if (perm_rootaccess(MSG_U(P_HINT,"obtain configuration hints"))){ error_setmode (true); ret = netconf_hint (argc-2,argv+2); } }else if (argc >= 2 && strcmp(argv[1],"--extract")==0){ if (perm_rootaccess(MSG_U(P_EXTRACT,"extract config files"))){ error_setmode (true); ret = subsys_extract(argc-2,(const char **)(argv+2)); } }else if (argc == 3 && strcmp(argv[1],"--selectprofile")==0){ if (perm_rootaccess(MSG_U(P_SELPROFILE,"select a profile"))){ error_setmode (true); ret = confver_selectprofile(argv[2]); } }else if (argc >= 2 && strcmp(argv[1],"--md5sum")==0){ if (perm_rootaccess(MSG_U(P_SUMCONF,"sum config files"))){ error_setmode (true); ret = subsys_md5sum(argc-2,(const char **)(argv+2)); } }else if (argc == 3 && strcmp(argv[1],"--setkeymap")==0){ if (netconf_rootaccess(MSG_U(E_SETKEYMAP ,"--setkeymap may only be used by root\n"))){ linuxconf_recordkeymap(argv[2]); } }else if (argc == 2 && strcmp(argv[1],"--services")==0){ if (netconf_rootaccess(MSG_U(E_SERVICES ,"--services may only be used by root\n"))){ service_control (); } }else if (argc == 2 && strcmp(argv[1],"--update")==0){ netconf_update(); }else if (argc == 2 && strcmp(argv[1],"--status")==0){ netconf_status(); }else if (argc == 2 && strcmp(argv[1],"--shutdown")==0){ shutdown_control(); }else if (argc == 2 && strcmp(argv[1],"--showmsgs")==0){ module_showmsgs(); }else if (argc >= 2 && strcmp(argv[1],"--vdb")==0){ if (netconf_rootaccess(MSG_U(E_VDB ,"--vdb may only be used by root\n"))){ ret = virtdb_main (argc-2,argv+2); } }else if (argc >= 2 && (strcmp(argv[1],"--http")==0 || strcmp(argv[1],"--demo")==0)){ /* #Specification: linuxconf / command line / --http The --http option of linuxconf tells it to behave like an httpd server. It will all of a sudden start talking ... html. This option is normally used when starting linuxconf from /etc/inetd.conf Suboptions are available (--http --options ...) # --port port_number: Use this portnumber to format URLs. Default to LINUXCONF_HTTP_PORT --name name: Use this name to format URLs. Default to the fully qualified hostname. --debug 0|1: Assume standalone startup (Not from inetd) and use a different port (LINUXCONF_HTTP_PORT_DEBUG). This way, gdb can be used on linuxconf without problem. # The --debug option is maybe useless. If linuxconf detect that the handle 0 is a tty, it assumes it is starting from a command line (not inetd) so assume the same context as debug mode and use the same port. */ /* #Specification: Linuxconf / startting from inetd Here is the proper configuration line which must be added to /etc/inetd.conf linuxconf stream tcp wait root /bin/linuxconf --http */ openlog ("linuxconf",LOG_PID,LOG_DAEMON); /* #Specification: linuxconf / command line / --demo The --demo option of linuxconf is like the --http except linuxconf will do a chroot("/demo_linuxconf") and will not do anything except probing the system. The mode "simul" on all the time */ if (getuid()!=0){ xconf_error(MSG_U(E_HTTP ,"--http and --demo may only be used by root")); exit (-1); } if (strcmp(argv[1],"--demo")==0){ /* #Specification: demo mode / PAM PAM authentication is disabled in demo mode to avoid setting up too many things for PAM in the demo chroot environment, */ users_sethook (NULL,NULL,NULL); passwd_sethook (NULL,NULL,NULL); } dialog_setmode (DIALOG_HTML); int port = -1; THISHOST host; const char *name = host.getname1(); int debug = 0; for (int i=2; i