#include #include #include #include #include #include #include #include #include #include #include "dialout.h" #include #include "daemoni.h" #include "pppdial.h" #include "dialout.m" #include #include "../../paths.h" extern HELP_FILE help_ppp; static HELP_FILE help_ipup ("dialout","ip-up"); static HELP_FILE help_pppdev("dialout","pppdev"); static MESSAGE_DEF msg_setfw ("setfw"); static CONFIG_FILE f_ipup (ETC_PPP_IPUP ,help_ipup ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","root",0755,ppp_dialout); static CONFIG_FILE f_ipdown (ETC_PPP_IPDOWN ,help_ipup ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","root",0755,ppp_dialout); static CONFIG_FILE f_pppdev (VAR_RUN_PPPDEV ,help_pppdev ,CONFIGF_MANAGED|CONFIGF_OPTIONAL|CONFIGF_ERASED|CONFIGF_NOARCH ,"root","root",0600); // File used to store argument of pppd static CONFIG_FILE f_pppargs (VAR_RUN_PPPD_ARGS ,help_ppp ,CONFIGF_GENERATED|CONFIGF_NOARCH ,"root","root",0600); #if 0 // File used to store PAP information (+ua file) static CONFIG_FILE f_ppppap (VAR_RUN_PPPD_PAP ,help_ppp ,CONFIGF_GENERATED|CONFIGF_NOARCH ,"root","root",0600); #endif static CONFIG_FILE f_ppp0 (VAR_RUN_PPP0_PID ,help_ppp ,CONFIGF_OPTIONAL|CONFIGF_NOARCH ,"root","root",0600); static const char bin_sh[]="#!/bin/sh"; static const char bin_bash[]="#!/bin/bash"; static const char start[] = "####### start linuxconf section #####"; static const char end[] = "####### end linuxconf section #####"; static const char *script_ipup[]={ "LINUXCONF_ARG=`echo $6 | cut -f1 -d\\ `", "if [ \"$LINUXCONF_ARG\" = \"linuxconf_dialout\" -o \"$LINUXCONF_ARG\" = \"linuxconf_dialin\" ]", "then", "\t/bin/netconf %s $6 $1", "fi", NULL }; static void copy_script (FILE_CFG *fout, const char *verb, int copy_sh) { if (fout != NULL){ if (copy_sh) fprintf (fout,"%s\n",bin_sh); fprintf (fout,"%s\n",start); for (int i=0; script_ipup[i] != NULL; i++){ fprintf (fout,script_ipup[i],verb); fputc ('\n',fout); } fprintf (fout,"%s\n",end); } } /* Read/update/compare the linuxconf part of an ip-up script Return -1 if any error */ static int ipup_update( FILE_CFG *fin, FILE_CFG *fout, int replace_add, // 0: Do nothing // 1: Add the script // 2: Replace an old one const char *verb, // Variation in the script (--postconnect or --predisconnect) int &found, // The linuxconf script was there int &differ, // The linuxconf script was there, but different int &empty) { int ret = 0; int copyf = 1; int nol = 0; int first = 1; char buf[500]; found = 0; differ = 0; empty = 1; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ empty = 0; strip_end (buf); if (first){ // Strip all space in the line to make sure char *src = buf; char *dst = buf; while (*src != '\0'){ if (!isspace(*src)) *dst++ = *src; src++; } *dst = '\0'; if (strcmp(buf,bin_sh)!=0 && strcmp(buf,bin_bash)!=0){ ret = -1; break; }else{ if (fout != NULL) fprintf (fout,"%s\n",bin_sh); if (replace_add == 1) copy_script(fout,verb,0); } first = 0; }else if (strcmp(buf,start)==0){ if (replace_add == 2) copy_script (fout,verb,0); found = 1; copyf = 0; }else if (strcmp(buf,end)==0){ copyf = 1; }else if (copyf){ if (fout != NULL) fprintf (fout,"%s\n",buf); }else if (!differ){ const char *scrline = script_ipup[nol]; if (scrline == NULL){ differ = 1; }else{ char scrverb[200]; sprintf (scrverb,scrline,verb); if (strcmp(buf,scrverb)!=0){ differ = 1; }else{ nol++; } } } } return ret; } /* Compute a path for a tmp file base on a config file path */ static int format_fname (CONFIG_FILE &cf, const char *ext, char *path) { int i; const char *cfpath = cf.getpath(); for (i=0; i<100; i++){ sprintf (path,"%s.%s%d",cfpath,ext,i); if (!file_exist(path)) break; } int ret = 0; if (i==100){ xconf_error (MSG_U(E_NOIPUPTMP ,"Can't create a temporary file %s.%sxx to update %s\nNo update") ,cfpath,ext,cfpath); ret = -1; } return ret; } static void create_script ( CONFIG_FILE &cf, const char *msgbuf, const char *verb) { if (dialog_yesno (MSG_U(T_UPDSCRIPT,"Update script") ,msgbuf,help_ipup)==MENU_YES){ FILE_CFG *fout = cf.fopen ("w"); if (fout != NULL){ copy_script (fout,verb,1); fclose (fout); } } } /* Make sure /etc/ppp/ip-up has the proper hook to call back linuxconf Do the same for /etc/ppp/ip-down */ static void check_ipscript(CONFIG_FILE &cf, const char *verb) { // The message is formated here even if it may not be used char buf[2000]; const char *cfpath = cf.getpath(); sprintf (buf,MSG_U(I_UPDSCRIPT ,"The script %s is not compatible with linuxconf\n" "A special section will be added to it preserving\n" "what is already there.\n" "You may refuse to install this modification and\n" "PPP connectivity will still work, but some\n" "functionnalities won't (extra routing for one)\n" "\n" "May I install the modifications ?") ,cfpath); FILE_CFG *fin = cf.fopen ("r"); if (fin == NULL){ create_script (cf,buf,verb); }else{ int found,differ,empty; int ret = ipup_update (fin,NULL,0, verb,found,differ,empty); if (ret == -1){ xconf_error (MSG_U(E_FORMATIPUP ,"File %s is not a script\n" " (no #!/bin/sh or #!/bin/bash at the beginning)\n" "Linuxconf won't try to update it\n" "Please fix manually. Some functionnalities won't be\n" "available\n" " -disconnecting\n" " -extra routing\n" " -connection detection\n") ,cfpath); }else if (empty){ create_script (cf,buf,verb); }else{ rewind(fin); int replace_add = 0; if (!found){ replace_add = 1; }else if (differ){ replace_add = 2; } if (replace_add != 0 && dialog_yesno (MSG_R(T_UPDSCRIPT),buf,help_ipup)==MENU_YES){ char pathnew[PATH_MAX]; char pathbak[PATH_MAX]; if (format_fname (cf,"NEW",pathnew)!=-1 && format_fname (cf,"BAK",pathbak)!=-1){ FILE_CFG *fout = cf.fopen (pathnew,"w"); if (fout != NULL){ ipup_update (fin,fout,replace_add, verb ,found,differ,empty); fclose (fout); cfpath = cf.getpath(); rename (cfpath,pathbak); rename (pathnew,cfpath); } } } } fclose (fin); } } /* Make sure /etc/ppp/ip-up has the proper hook to call back linuxconf Do the same for /etc/ppp/ip-down */ void pppcon_check_ipup() { check_ipscript (f_ipup,"--postconnect"); check_ipscript (f_ipdown,"--predisconnect"); } const char linuxconf_dialout[]="linuxconf_dialout"; const char linuxconf_dialin[]="linuxconf_dialout"; /* Stuff the ipparam argument of pppd if needed */ PRIVATE void PPPONE::setipparam(char *str) { str[0] = '\0'; if (kernel_newer (2,0,0)){ pppcon_check_ipup(); sprintf (str,"ipparam '%s %s'",linuxconf_dialout,name.get()); }else if (!iproutes.empty()){ xconf_error (MSG_U(E_IPPARAM ,"To enable special routing for this PPP\n" "Linuxconf needs pppd 2.2.x which run only on linux 2.x\n" "and higher\n" "Some feature of this ppp connection won't be activated")); } } /* Stuff the ipx parameters if needed */ PRIVATE void PPPONE::setipxparam(char *str) { str[0] = '\0'; if (ipx.enable){ str = stpcpy (str,"ipx"); if (ipx.netnum != 0){ str += sprintf (str," ipx-network %x",ipx.netnum); }else{ str = stpcpy (str," ipxcp-accept-network"); } if (ipx.localnum != 0){ str += sprintf (str," ipx-node %x:%d",ipx.localnum,ipx.remotenum); }else{ str = stpcpy (str," ipxcp-accept-local ipxcp-accept-remote"); } if (ipx.routingrip){ str = stpcpy (str," ipx-routing 2"); } if (ipx.routingnlsp){ str = stpcpy (str," ipx-routing 4"); } if (!ipx.routingrip && !ipx.routingnlsp){ str = stpcpy (str," ipx-routing 0"); } str = stpcpy (str," "); strcpy (str,ipx.options.get()); } } static void strcat_b (char *chat, const SSTRING &str) { strcat (chat," "); strcat (chat,str.get()); } /* Setup the chat script and chat argument file. This scripts is called either by pppd directly or by diald */ PRIVATE int PPPONE::setpppchat (char *pathchat_sh) { int ret = -1; pathchat_sh[0] = '\0'; if (!chatscript.is_empty()){ chatscript.copy (pathchat_sh); ret = 0; }else{ DAEMON_INTERNAL *cmd_chat = daemon_find ("chat"); if (cmd_chat != NULL){ char chat[1000]; chat[0] = '\0'; if (!phone.is_empty()){ strcpy (chat,"ABORT 'NO CARRIER' ABORT BUSY '' "); strcat (chat,modeminit.get()); strcat (chat,phone.get()); strcat (chat," CONNECT "); } if (pppauth == PPP_AUTH_LOGIN){ if (!loginchat.is_empty()){ strcat (chat,loginchat.get()); }else{ strcat (chat," ''"); strcat_b (chat,loginkey); strcat_b (chat,login); strcat_b (chat,passwdkey); strcat_b (chat,"\\q"); strcat (chat,passwd.get()); if (!loginfail.is_empty()){ // If we see loginfail, this means that the login // sequence did fail, so we abort right away // instead of falling in pppd and receving all // kind of meaningless messages (pppd believes // it is talking to another pppd). strcat (chat," ABORT"); strcat_b (chat,loginfail); } if (!loginok.is_empty()){ strcat_b (chat,loginok); } if (!trigger.is_empty()){ if (loginok.is_empty()){ strcat_b (chat,"''"); } strcat_b (chat,trigger); } } } char pathchat[PATH_MAX]; sprintf (pathchat,"%s-chat.%s",f_pppargs.getpath(),name.get()); FILE_CFG *fchat = f_pppargs.fopen (pathchat,"w"); if (fchat != NULL){ sprintf (pathchat_sh,"%s.sh",pathchat); FILE_CFG *fchat_sh = f_pppargs.fopen (pathchat_sh,"w"); if (fchat_sh != NULL){ fprintf (fchat_sh ,"#!/bin/sh\n" "exec %s %s -f %s\n" ,cmd_chat->getpath() ,dbgchat ? "-v" : "" ,pathchat); fprintf (fchat,"%s\n",chat); ret = fclose (fchat_sh); chmod (pathchat_sh,0700); } if (ret == 0) ret = fclose (fchat); } } } return ret; } /* Generate the proper pppd option for PAP and CHAP */ PRIVATE void PPPONE::setpapchap(char *pppopt, PRIVILEGE *priv) { updsecrets(priv); sprintf (pppopt,"remotename lnx-%s name %s",name.get(),login.get()); #if 0 pppopt[0] = '\0'; if (pppauth == PPP_AUTH_PAP || pppauth == PPP_AUTH_LOGIN){ #if 0 /* #Specification: ppp dialout / PAP authentication PAP authentication is done through the option "+ua file". This option is specified even if we are doing PPP dialout using a normal login/password access. This is done because some terminal servers require normal login/password sequence and then later authentication with PAP. */ char uapath[PATH_MAX]; sprintf (uapath,"%s.%s",f_ppppap.getpath(),name.get()); FILE_CFG *fpap = f_ppppap.fopen (uapath,"w"); if (fpap != NULL){ fprintf (fpap,"%s\n%s\n",login.get(),passwd.get()); fclose (fpap); } sprintf (pppopt,"+ua %s",uapath); #else sprintf (pppopt,"remotename lnx-%s name %s",name.get(),login.get()); #endif }else if (pppauth == PPP_AUTH_CHAP){ sprintf (pppopt,"remotename lnx-%s name %s",name.get(),login.get()); } #endif } /* Establish the PPP connection */ PRIVATE int PPPONE::connect_ppp(bool fore, PRIVILEGE *priv) { int ret = -1; /* #Specification: ppp / pppd and chat All argument to pppd and chat are passed using file instead of command line argument. They can't be seen using ps -ax. */ char path[PATH_MAX]; sprintf (path,"%s.%s",f_pppargs.getpath(),name.get()); FILE_CFG *fargs = f_pppargs.fopen (path,"w"); if (fargs != NULL){ DAEMON_INTERNAL *cmd_pppd = daemon_find ("pppd"); if (cmd_pppd != NULL){ fprintf (fargs,"%s\n",options.get()); if (!asyncmap.is_empty()){ fprintf (fargs,"asyncmap %s\n",asyncmap.get()); } if (dbgppp){ fputs ("-d -d\n",fargs); } if (lock) fputs ("lock\n",fargs); if (modem){ fputs ("modem crtscts\n",fargs); } fprintf (fargs,"mru %d\n",mru); if (mtu != 0) fprintf (fargs,"mtu %d\n",mtu); fprintf (fargs,"%s:%s\n",ourip.get(),remoteip.get()); if (idletime != 0){ fprintf (fargs,"idle %d\n",idletime); } if (defaultroute) fputs ("defaultroute\n",fargs); if (proxyarp) fputs ("proxyarp\n",fargs); char ipparam[100]; setipparam(ipparam); strcat (ipparam,"\n"); fputs (ipparam,fargs); char ipxparam[200]; setipxparam(ipxparam); strcat (ipparam,"\n"); fputs (ipxparam,fargs); // if (fore) fputs ("-detach\n",fargs); { int d,r; if (lcpecho_parse (d,r)==1){ fprintf (fargs,"lcp-echo-interval %d lcp-echo-failure %d\n" ,d,r); } } char papopt[PATH_MAX]; setpapchap(papopt,priv); fprintf (fargs,"%s\n",papopt); char pathchat_sh[PATH_MAX]; if (setpppchat(pathchat_sh)!=-1){ fprintf (fargs,"connect %s\n",pathchat_sh); fprintf (fargs,"%s\n",device.get()); fprintf (fargs,"%d\n",baud); fclose (fargs); //dialog_end(); fflush (stdout); setuid (geteuid()); /* #Specification: netconf / --connect / --fore When connecting a PPP link with the --fore option, linuxconf sleep for 5 seconds before calling pppd. Generally this option is used to establish a permanent link by calling netconf from inittab. The sleep give some chance to the getty/mgetty process to initialise the modem properly before launching another pppd. When using the --fore option, netconf just pass control to pppd with the -detach option. netconf does not stay in memory. */ const char *pppdpath = cmd_pppd->getpath(); if (fore){ sleep(5); execl (pppdpath,pppdpath,"file",path,NULL); }else if (getusetype() == PPP_USE_24on24){ DAEMON_INTERNAL *cmd_watch = daemon_find ("pppwatch"); char buf[PATH_MAX]; sprintf (buf,"%s %s.%s %s file %s",cmd_watch->getpath() ,VAR_RUN_PPPRESTART,name.get() ,pppdpath,path); ret = pppwait_cmd(buf); }else{ char buf[PATH_MAX]; sprintf (buf,"%s file %s",pppdpath,path); ret = pppwait_cmd(buf); } }else{ fclose (fargs); } } } return ret; } /* Establish a PPP link using ssh */ PRIVATE int PPPONE::connect_pppssh(int ) { int ret = -1; DAEMON_INTERNAL *cmd_ssh = daemon_find ("ssh"); if (!cmd_ssh->is_managed()){ xconf_error (MSG_U(E_NODAEMON ,"%s is not available on this system\n" "or linuxconf is not allowed to use it. Sorry!\n"),"ssh"); }else{ DAEMON_INTERNAL *cmd_pppd = daemon_find ("pppd"); if (!cmd_pppd->is_managed()){ xconf_error (MSG_R(E_NODAEMON),"pppd"); }else{ DAEMON_INTERNAL *cmd_redir = daemon_find ("pty-redir"); if (!ssh.use_patch && !cmd_redir->is_managed()) { xconf_error (MSG_R(E_NODAEMON), "pty-redir"); return ret; } char buf1[300]; char encstr[30]; encstr[0] = '\0'; if (!ssh.encrypt.is_empty()){ sprintf (encstr,"-c %s",ssh.encrypt.get()); } if (!ssh.use_patch) sprintf (buf1,"%s `%s %s -x %s -l %s -e none %s -t " ,cmd_pppd->getpath() ,cmd_redir->getpath() ,cmd_ssh->getpath() ,ssh.compress ? "-C" : "" ,ssh.user.get() ,encstr); else sprintf (buf1,"%s -x %s -l %s -e none %s -t -r" ,cmd_ssh->getpath() ,ssh.compress ? "-C" : "" ,ssh.user.get() ,encstr); char buf2[300]; char idlestr[30]; idlestr[0] = '\0'; if (idletime > 0) sprintf (idlestr,"idle %d",idletime); char lcpstr[100]; lcpstr[0] = '\0'; { int d,r; if (lcpecho_parse (d,r)==1){ sprintf (lcpstr,"lcp-echo-interval %d lcp-echo-failure %d" ,d,r); } } char ipparam[100]; setipparam(ipparam); char ipxparam[200]; setipxparam(ipxparam); if (!ssh.use_patch) sprintf (buf2,"%s %s %s %s %s %s 300 asyncmap %s passive modem %s:%s %s %s 2>~/.pppd-ssh.err" ,dbgppp ? "debug" : "" ,proxyarp ? "proxyarp" : "" ,defaultroute ? "defaultroute" : "" ,idlestr ,lcpstr ,options.get() ,asyncmap.get() ,ourip.get() ,remoteip.get() ,ipparam ,ipxparam); else sprintf (buf2,"-E \"%s %s %s %s %s %s %s 300 asyncmap %s passive modem %s:%s %s %s 2>~/.pppd-ssh.err\"" ,cmd_pppd->getpath() ,dbgppp ? "debug" : "" ,proxyarp ? "proxyarp" : "" ,defaultroute ? "defaultroute" : "" ,idlestr ,lcpstr ,options.get() ,asyncmap.get() ,ourip.get() ,remoteip.get() ,ipparam ,ipxparam); char buf3[300]; if (ssh.via_shell){ char mtustr[15]; mtustr[0] = '\0'; if (mtu != 0) sprintf (mtustr,"mtu %d",mtu); sprintf (buf3,"%s %s %s 300 %s asyncmap %s modem %s mru %d 2\\>~/.pppd-ssh.err" ,ssh.host.get() ,ssh.pppd_path.get() ,dbgppp ? "debug" : "" ,proxyarp ? "proxyarp" : "" ,asyncmap.get() ,mtustr,mru); }else{ ssh.host.copy(buf3); } setuid (geteuid()); char buf[2000]; if (!ssh.use_patch) sprintf (buf,"%s %s; sleep 10` %s",buf1,buf3,buf2); else sprintf (buf,"%s %s %s",buf1,buf2,buf3); dialog_end(); fprintf (stderr,"Executing :%s:\n",buf); ret = system (buf); } } return ret; } /* Read a PID in an ascii file. Return -1 if it can't be read. */ static int pppcon_readpid(const char *path) { int ret = -1; FILE_CFG *fin = f_ppp0.fopen (path,"r"); if (fin != NULL){ int pid; if (fscanf (fin,"%d",&pid)==1) ret = pid; fclose (fin); } return ret; } /* Return the PID and the PPP device of the pppd process for the ppp connection Return -1 if the connection is not active. */ PUBLIC int PPPONE::getpppd_info(char pppdev[8]) { pppdev[0] = '\0'; int ret = -1; char pathdev[PATH_MAX]; sprintf (pathdev,"%s.%s",f_pppdev.getpath(),name.get()); if (file_exist(pathdev)){ FILE_CFG *fin = f_pppdev.fopen (pathdev,"r"); if (fin != NULL){ char dev[100]; if (fscanf (fin,"%s\n",dev)==1){ char pathpid[PATH_MAX]; sprintf (pathpid,"/var/run/%s.pid",dev); strcpy (pppdev,dev); ret = pppcon_readpid (pathpid); } fclose (fin); } }else if (!kernel_newer (2,0,0)){ ret = pppcon_readpid (f_ppp0.getpath()); } if (ret != -1 && kill(ret,0)==-1) ret = -1; return ret; } /* Return the PID of the pppd process for the ppp connection Return -1 if the connection is not active. */ PUBLIC int PPPONE::getpppd_pid() { char dev[8]; return getpppd_info(dev); } /* Terminate the PPP connection */ PRIVATE int PPPONE::disconnect_ppp() { /* #Specification: ppp / disconnecting When IPPARAM is available, linuxconf can write in /var/run/pppddev the PPP device associated with a link. This way, linuxconf can find the PID of the associated pppd process and disconnect the link for a specific config easily. When ipparam is not available, well... The support for disconnection is weak, as it kills the first ppp connexion (ppp0) without checking. Although this is fine for simple setup, it is not acceptable. We must find a way to get the pid of the pppd process and stores it in our own pid file. The problem is that pppd fork at one point so we don't know the final pid. Maybe an option is needed (or already available) in pppd to set the pid file name. This would solve the problem. */ int ret = -1; int pid = getpppd_pid(); if (pid == -1){ xconf_error (MSG_U(E_PPPNOTACTIVE,"PPP %s not active"),name.get()); }else{ /* #Specification: pppwatch / strategy pppwatch restart the PPP connection whenever it ends (for whatever reason). It will try to start the connection over and over if the file /var/run/ppprestart.config exist (config is the ppp dialout configuraion name). When we stop a PPP session with linuxconf, we simply kill the pppd process and remove (blindly) this control file, so pppwatch won't restart the ppp session. */ char pathwatch[PATH_MAX]; sprintf (pathwatch,"%s.%s",VAR_RUN_PPPRESTART,name.get()); unlink (pathwatch); ret = kill (pid,SIGTERM); } return ret; } /* Initialise a PLIP link */ PRIVATE int PPPONE::connect_plip() { int ret = -1; char buf[100]; const char *plipdev = type == TYPE_PLIP1 ? "plip1" : "plip2"; sprintf (buf,"%s %s pointopoint %s",plipdev ,ourip.get(),remoteip.get()); if (netconf_system_if ("ifconfig",buf) != -1){ sprintf (buf,"add %s %s",remoteip.get(),plipdev); if (netconf_system_if ("route",buf) != -1){ if (!defaultroute){ ret = 0; }else{ sprintf (buf,"add default %s",plipdev); if (netconf_system_if ("route",buf) != -1){ ret = 0; } } } } return ret; } /* Terminate a PLIP link */ PRIVATE int PPPONE::disconnect_plip() { char buf[100]; const char *plipdev = type == TYPE_PLIP1 ? "plip1" : "plip2"; sprintf (buf,"%s down",plipdev); return netconf_system_if ("ifconfig",buf); } PRIVATE int PPPONE::connect_slip(int) { xconf_error (MSG_U(E_ONLYPPP,"Only normal PPP is supported yet!")); return -1; } PRIVATE int PPPONE::disconnect_slip() { xconf_error (MSG_R(E_ONLYPPP)); return -1; } /* Establish the PPP/SLIP/PLIP connection Return 0 if ok, -1 if connection fail. Return 0 if already connected */ PUBLIC int PPPONE::connect( bool fore) // Don't go in background { int ret=0; if (ppphook_control != NULL){ ret = (*ppphook_control) (name.get(),true); }else if (getpppd_pid()==-1){ PRIVILEGE *priv = ppp_lookuppriv(name.get()); PRIVILEGE *old = perm_setdefprivi (priv); if (!preconcmd.is_empty()){ if (perm_access (priv,MSG_U(P_RUNCMD ,"Running pre-connect and pre-disconnect commands"))){ netconf_system (30,preconcmd.get()); } } if (getusetype() == PPP_USE_DEMAND){ ret = connect_diald(); }else if (type == TYPE_PLIP1 || type == TYPE_PLIP2){ ret = connect_plip(); }else if (type == TYPE_SLIP){ ret = connect_slip(fore); }else if (type == TYPE_PPP_SSH){ ret = connect_pppssh(fore); }else{ ret = connect_ppp(fore,priv); } perm_setdefprivi (old); } return ret; } /* Disconnect the PPP/SLIP/PLIP connection */ PUBLIC int PPPONE::disconnect() { int ret = 0; if (ppphook_control != NULL){ ret = (*ppphook_control) (name.get(),false); }else{ PRIVILEGE *priv = ppp_lookuppriv(name.get()); PRIVILEGE *old = perm_setdefprivi (priv); if (getusetype() == PPP_USE_DEMAND){ ret = disconnect_diald(); }else{ if (!prediscmd.is_empty()){ if (perm_access (priv,MSG_R(P_RUNCMD))){ netconf_system (30,prediscmd.get()); } } if (type == TYPE_PLIP1 || type == TYPE_PLIP2){ ret = disconnect_plip(); }else if (type == TYPE_SLIP){ ret = disconnect_slip(); }else{ ret = disconnect_ppp(); } } perm_setdefprivi (old); } return ret; } /* Install the route for the PPP connection This function is called by postconnect() or by setupdiald() */ PUBLIC int PPPONE::setroutes (const char *cmd_suffix) { int ret = 0; for (int r=0; rdest.get(); if (dest[0] != '\0'){ char ip[100],msk[100]; if (netconf_convert(dest,ip,msk)!=-1){ char buf[300]; if (ir->mask.is_empty()){ if (strcmp(msk,"255.255.255.255")==0){ sprintf (buf,"add -host %s %s",dest,cmd_suffix); }else{ sprintf (buf,"add -net %s netmask %s %s",dest,msk ,cmd_suffix); } }else{ sprintf (buf,"add -net %s netmask %s %s",dest ,ir->mask.get(),cmd_suffix); } ret |= netconf_system_if ("route",buf); }else{ net_prtlog (NETLOG_ERR ,MSG_U(E_IVLRT,"Invalid routing destination %s\n") ,dest); } } } return ret; } /* Execute a command in background */ static void pppcon_execbg(SSTRING &cmd) { if (fork()==0){ // We know we are run by root here. No need to do any cleanup system (cmd.get()); _exit(0); } } /* Activate the route associate with a PPP setup */ PUBLIC int PPPONE::postconnect(const char *dev) { int ret = 0; net_introlog (NETINTRO_PPPPOST); net_prtlog (NETLOG_SECTION ,MSG_U(M_SETRT,"Setting routes for PPP dialout %s\n") ,name.get()); if (getusetype() != PPP_USE_DEMAND){ ret = setroutes (dev); } char pathid[PATH_MAX]; sprintf (pathid,"%s.%s",f_pppdev.getpath(),name.get()); FILE_CFG *fout = f_pppdev.fopen (pathid,"w"); if (fout != NULL){ fprintf (fout,"%s\n",dev); fclose (fout); } char fifo[PATH_MAX]; setfifowait(fifo); if (file_exist(fifo)){ int fd = open (fifo,O_WRONLY|O_NDELAY,0); write (fd,"success\n",8); close (fd); } if (firewall) module_sendmessage (msg_setfw); if (!postconcmd.is_empty()) pppcon_execbg (postconcmd); return ret; } /* Do some processing on a PPP account AFTER it is disconnected. (It is an old typo, this is really after). */ PUBLIC int PPPONE::predisconnect(const char *) { if (!postdiscmd.is_empty()) pppcon_execbg (postdiscmd); delpidfile(); if (firewall) module_sendmessage (msg_setfw); return 0; } PUBLIC void PPPONE::delpidfile() { char pathid[PATH_MAX]; sprintf (pathid,"%s.%s",f_pppdev.getpath(),name.get()); if (file_exist(pathid)){ unlink (pathid); net_prtlog (NETLOG_CMD,"rm %s\n",pathid); } }