The problem was reported back on July 28, 1998 by Martin Lacasse mdlacas to RedHat or more specificlly msf and ewt for lpr-0.31-1 and yet lpr-0.33-1 was released with the same problem. THE CAUSE When a remote user prints to a queue that is _not_ restricted (no rs capability in printcap) on a print server they don't have an account on, lpd will try to fork the filter as that user. By this time lpd has already established a connection to the printer, not being able to fork because user is not found the connection presist tying up the printer so that other TCP connection are refused hence the first denial of service. Also the job remains at the top of the queue jaming the queue so other request are accepted but not printed hence the second denial of service. Also in looking at the code to hack a fix I noticed that althought lpd attempts not to run the filters as root if the remote or local user is root the filters are run as root. This leaves the filters open to race condition and the like on poorly writen filters. THE FIX Attached is a patch to printjob.c where the problem was found. The fix was if user did not exist or is root effectively become lp to fork the filters other wise fork the filter as the user. THE PROOF First let me appologize for the log prompts, but I like to know when, what, whence, who and where at a glance. Also the hostnames and IPs have been xxxed out to hide their IDs, security you know. #testprint user _does_not_ exist on server #kksocha user does exist on the server #both printer job are remote request #the printcap _does_not_ have a 'rs' for this queue #as you can see a small 124 byte print request has be made by testprint user #and the lpd has a connection hence the sending to reported by lpq Mon Dec 14 16:33:05 </dev/ttyp0> /usr/src/redhat/BUILD/lpr-0.33/lpd [root@xxprint1]$ lpq -Pxxx01-cc103 xxprint1.erenj.com: sending to xxx01-cc103 Rank Owner Job Files Total Size 1st testprint 11 .bashrc 124 bytes 2nd kksocha 12 .bashrc 682 bytes 0 bytes connection to xxx01-cc103 is down #any attempted to connet to the printer port of the printer is refused as long as lpd is sending #however lpd can't fork the filter to actually send the data because the user _does_not_ exist #oh port 9100 is also refused but I don't show that here Mon Dec 14 16:33:53 </dev/ttyp0> /usr/src/redhat/BUILD/lpr-0.33/lpd [root@xxprint1]$ telnet xxx01-cc103 printer Trying xxx.xxx.1.167... telnet: Unable to connect to remote host: Connection refused #over 2 minutes later lpd is still trying to send 124 bytes to printer which is more then enough #time as will be proven later with the second larger job in the queue Mon Dec 14 16:35:36 </dev/ttyp0> /usr/src/redhat/BUILD/lpr-0.33/lpd [root@xxprint1]$ lpq -Pxxx01-cc103 xxprint1.erenj.com: sending to xxx01-cc103 Rank Owner Job Files Total Size 1st testprint 11 .bashrc 124 bytes 2nd kksocha 12 .bashrc 682 bytes 0 bytes connection to xxx01-cc103 is down #remove the job that is jamming the queue and tying up the connection to the printer Mon Dec 14 16:36:12 </dev/ttyp0> /usr/src/redhat/BUILD/lpr-0.33/lpd [root@xxrint1]$ lprm -Pxxx01-cc103 11 dfA011Aa07949 dequeued cfA011dXXXXXXenj.com dequeued dfA011Aa14026 dequeued cfA011xxnk.erenj.com dequeued #lpd is now sending the second job to the printer (and their are already no entries) Mon Dec 14 16:36:40 </dev/ttyp0> /usr/src/redhat/BUILD/lpr-0.33/lpd [root@xxprint1]$ lpq -Pxxx01-cc103 xxprint1.erenj.com: sending to xxx01-cc103 Rank Owner Job Files Total Size 1st kksocha 12 .bashrc 682 bytes 0 bytes JetDirect lpd: no entries #only 7 seconds to send 682 bytes to the printer Mon Dec 14 16:36:47 </dev/ttyp0> /usr/src/redhat/BUILD/lpr-0.33/lpd [root@xxprint1]$ lpq -Pxxx01-cc103 JetDirect lpd: no entries #oh look we can now connet to the printer port of the printer Mon Dec 14 16:36:56 </dev/ttyp0> /usr/src/redhat/BUILD/lpr-0.33/lpd [root@xxprint1]$ telnet xxx01-cc103 printer Trying xxx.xxx.1.167... Connected to xxx01-cc103.erenj.com. Escape character is '^]'. ^] telnet> close Connection closed. #after my hack every thing worked fine including not fork filters as root Thanks for your attention.......... 81a82 > static char euser[32]; /* effective user */ 368a370,383 > } else { /* not restricted */ > struct passwd *dude; > dude = getpwnam(logname); > if (dude == NULL || dude->pw_uid == 0) { > /* if user doesn't exist will cause a DoS so set */ > /* effective user to lp, also we don't want to be */ > /* root either to prevent race condition and buffer */ > /* overrun and the like in poorly designed filters */ > /* don't change logname so mail & banner are right */ > strncpy(euser, "lp", 3); > } else { > /* since the user does exist run filter as user */ > strncpy(euser, logname, sizeof(logname)); > } 526c541 < if (getpwnam(logname) == (struct passwd *)0 || !*logname) --- > if (getpwnam(euser) == (struct passwd *)0 || !*euser) 553c568 < if ((prchild=doforkuser(DORETURN,logname)) == 0) { /* child */ --- > if ((prchild=doforkuser(DORETURN,euser)) == 0) { /* child */ 671c686 < if ((child = doforkuser(DORETURN,logname)) == 0) { /* child */ --- > if ((child = doforkuser(DORETURN,euser)) == 0) { /* child */ 810a826 > logname[sizeof(logname) - 1] = '\0'; 815a832,845 > } else { /* not restricted */ > struct passwd *dude; > dude = getpwnam(logname); > if (dude == NULL || dude->pw_uid == 0) { > /* if user doesn't exist will cause a DoS so set */ > /* effective user to lp, also we don't want to be */ > /* root either to prevent race condition and buffer */ > /* overrun and the like in poorly designed filters */ > /* don't change logname so mail & banner are right */ > strncpy(euser, "lp", 3); > } else { > /* since the user does exist run filter as user */ > strncpy(euser, logname, sizeof(logname)); > } 851c881 < if ((ifchild = doforkuser(DORETURN,logname)) == 0) { /*child*/ --- > if ((ifchild = doforkuser(DORETURN,euser)) == 0) { /*child*/
This has been verified to be a problem. I am assigning it to a developer for further review.
fixed in lpr-0.34-1 ------- Email Received From "Kevin K. Sochacki" <kksocha> 02/26/99 10:18 -------