/* * Copyright (c) 1998-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ /* * lp-gw.c, a line printer protocol gateway for TIS fwtk with lprNG support * (strict RFC 1179 conformance) * * (C) Copyright 1998-2001 by ArkanoiD * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "firewall.h" #include "firewall2.h" #include "fwfunc.h" static char* moduleId ATTR_UNUSED = "$Id: lp-gw.c,v 1.13 2007/09/10 02:49:13 arkenoi Exp $"; typedef struct { char *name; void (*handler)(char,char*,char*); int flg; } lp_action; #define LP_PORT 515 static char server_queue[512] = "none"; /* name of the server queue */ static time_t offtime; /* time when proxy is off */ static int lprng_client = 0; static int anyport = 0; static int transparent = 0; static int extendperm = 0; static int force = 0; static int server_fd = -1; static int maxrequest = 1024; static int cdscp = 0; static int sdscp = 0; static Cfg *cfp; /* pointer to configuration*/ static char **validqueues = (char **)0; static char **validests = (char **)0; static char **validusers = (char **)0; static char **denyops = (char **)0; static char **logops = (char **)0; static char lp_cmd = 0; static void do_restart(char,char*,char*); static void do_print(char,char*,char*); static void do_status(char,char*,char*); static void do_remove(char,char*,char*); static lp_action lp_actions[] = { { "null", 0, 0 }, { "restart", do_restart, 0 }, { "print", do_print, 0 }, { "qstate_s", do_status, 0 }, { "qstate_l", do_status, 0 }, { "remove", do_remove, 0 }, { 0, 0, 0 } }; static void job_abort(char,char*,char*); static void job_control(char,char*,char*); static void job_data(char,char*,char*); static lp_action job_actions[] = { { "null", 0, 0 }, { "abort", job_abort, 0 }, { "control", job_control, 0 }, { "data ", job_data, 0 }, { 0, 0, 0 } }; static fwparm options[] = { { FWPARM_BOOL, "-lprng", (char*) &lprng_client }, { FWPARM_BOOL, "-anyport", (char*) &anyport }, { FWPARM_BOOL, "-force-user", (char*) &force }, { FWPARM_BOOL, "-transparent", (char*) &transparent }, { FWPARM_BOOL, "-extnd", (char*) &extendperm }, { FWPARM_STRING, "-plug-to", proxy_stats.dst }, { FWPARM_STRING, "-authuser", proxy_stats.authuser }, { FWPARM_LIST, "-dest", (char*) &validests }, { FWPARM_LIST, "-user", (char*) &validusers }, { FWPARM_LIST, "-queue", (char*) &validqueues }, { FWPARM_LIST, "-deny", (char*) &denyops }, { FWPARM_LIST, "-log", (char*) &logops }, { FWPARM_DSCP, "-client-dscp", (char*) &cdscp }, { FWPARM_DSCP, "-server-dscp", (char*) &sdscp }, { 0, 0, 0 } }; extern int lp_conn_server(char*,int,int,char*); void lp_proxy_exit() { time(&offtime); syslog(LLEV,"exit host=%.512s/%.20s cmd=%.9s queue=%.20s in=%u out=%u duration=%u", proxy_stats.rladdr,proxy_stats.riaddr, lp_actions[(int)lp_cmd].name,server_queue, proxy_stats.inbytes,proxy_stats.outbytes, (u_int)offtime - (u_int)proxy_stats.start_time); exit(1); } void server_puts(line) char *line; { int x; x = strlen(line); if (write(server_fd,line,x) != x) { syslog(LLEV,"error writing server data"); write(0,"\001", 1); lp_proxy_exit(); } proxy_stats.outbytes += x+1; proxy_update_status(); } int get_server_ack() { int x; x = 0; if (soread(server_fd,(char*)&x,1)!=1) { syslog(LLEV,"error reading server data"); write(0,"\001", 1); lp_proxy_exit(); } proxy_stats.inbytes += 1; if (write(0,&x,1)!=1) { syslog(LLEV,"error writing client data"); lp_proxy_exit(); } proxy_update_status(); return(x); } void client_puts(line,cmd,queue) char *line; int cmd; char *queue; { int x; x = strlen(line); if (write(0,line,x) != x) { syslog(LLEV,"error writing client data"); lp_proxy_exit(); } proxy_stats.inbytes += x; proxy_update_status(); } int check_string(s) char *s; { char *c; for (c = s; *c; c++) { if ( ((*c < 'a') || (*c > 'z')) && ((*c < 'A') || (*c > 'Z')) && ((*c < '0') || (*c > '9')) && (*c!= '.') && (*c!= '-') ) return(1); } return(0); } /* * First level protocol command handling functions */ static void do_restart(char cmd,char *queue,char *args) { char lp_cmd_buf[104]; if (*args) { syslog(LLEV,"lp protocol error in RESTART command"); write(0,"\001", 1); lp_proxy_exit(); } snprintf(lp_cmd_buf,sizeof(lp_cmd_buf),"%c%.32s\n", 001, queue); server_puts(lp_cmd_buf); } static void do_print(char cmd,char *queue,char *args) { static char buf[1024]; int x; if (*args) { syslog(LLEV,"lp protocol error in PRINT command"); write(0,"\001", 1); lp_proxy_exit(); } snprintf(buf,sizeof(buf),"%c%.32s\n", 002, queue); server_puts(buf); #ifdef DEBUG syslog(LLEV,"waiting to acknowledge PRINT command"); #endif if (get_server_ack()) syslog(LLEV,"PRINT command failed"); #ifdef DEBUG syslog(LLEV,"got ack"); #endif while ((x=sogets(0,buf,sizeof(buf)-1)) > 0) { if ((buf[0] < 1) || (buf[0] > 3)) { syslog(LLEV,"lp protocol error in PRINT command"); write(0,"\001", 1); lp_proxy_exit(); } if (buf[x-1] != 0x0a) { syslog(LLEV,"error reading line printer protocol"); lp_proxy_exit(); } else buf[x-1] = 0; proxy_update_status(); job_actions[(int)buf[0]].handler(buf[0],queue,buf); } } static void do_status(char cmd,char* queue,char* args) { char buf[1024]; char tokbuf[1024]; char *tokav[56]; int tokac; char **user; int x; /* The way we handle allowed user lists: * If no user list is supplied within status query we do build new * one from our list of allowed users. * If one does exist we permit entries that match the list to pass * through. Non-matching ones are discarded and deny message is * recorded. */ if (!*args) { if (force) { snprintf(buf,sizeof(buf),"%c%.32s %.32s\n", cmd, queue, proxy_stats.authuser); server_puts(buf); } else if (validusers) { snprintf(buf,sizeof(buf),"%c%.32s", cmd, queue); x = strlen(buf); server_puts(buf); for (user = validusers; *user; user++) { if ((x += strlen(*user) + 1) >= maxrequest) { syslog(LLEV,"fwtkcfgerr: user list exceeds request size limit"); lp_proxy_exit(); } server_puts(" "); server_puts(*user); } server_puts("\n"); } else { snprintf(buf,sizeof(buf),"%c%.32s\n", cmd, queue); server_puts(buf); } } else { snprintf(buf,sizeof(buf),"%c%.32s", cmd, queue); server_puts(buf); tokac = enargv(args,tokav,56,tokbuf,sizeof(tokbuf)); /* * XXX * Note that we don't know if a job with given numeric id is permitted. * (belongs to allowed user). Do we need a workaround? * Hope not. We just do not care, it is not a major security risk. */ for (x = 0; x < tokac ; x++) { if (searchlist(tokav[x],validusers) && !isalldigits(tokav[x])) { syslog(LLEV,"deny host=%.512s/%.20s status request for user %.64s",proxy_stats.rladdr,proxy_stats.riaddr,tokav[x]); } else { server_puts(" "); server_puts(tokav[x]); } } server_puts("\n"); } while (sogets(server_fd,buf,sizeof(buf)-1) > 0) client_puts(buf,cmd,queue); } static void do_remove(char cmd,char *queue,char *args) { char buf[1024]; char *agent; if (!*args) { syslog(LLEV,"lp protocol error in REMOVE command"); write(0,"\001", 1); lp_proxy_exit(); } agent = args; if ((args = index(args,' '))) *args++ = '\0'; if (force) agent = proxy_stats.authuser; if (searchlist(agent,validusers)) { syslog(LLEV,"deny host=%.512s/%.20s remove request for user %.64s",proxy_stats.rladdr,proxy_stats.riaddr,agent); write(0,"\001", 1); lp_proxy_exit(); } if (args) snprintf(buf,sizeof(buf),"%c%.32s %.64s %.512s\n", 005, queue, agent, args); else snprintf(buf,sizeof(buf),"%c%.32s %.64s\n", 005, queue, agent); server_puts(buf); } /* * Job control (PRINT command, 0x02) subcommands */ static void job_abort(char cmd,char *queue,char *buf) { /* * From rfc1179: * Abort job * * +----+----+ * | 01 | LF | * +----+----+ * * No operands should be supplied. This subcommand will remove any * files which have been created during this "Receive job" command. * * NOTE: we do not process this locally, though we can, but just have * no reason to. */ if (buf[1]) { syslog(LLEV,"lp protocol error in PRINT command"); write(0,"\001", 1); lp_proxy_exit(); } server_puts("\001\n"); if (get_server_ack()) syslog(LLEV,"PRINT ABORT failed"); } static void job_control(char cmd,char *queue,char *buf) { unsigned int cfAsize; char* cfAname; char* cfAhname; unsigned short jobnum; char jobnumb[3]; int x; unsigned int icount, ocount ; char cfAline[1024]; char buf1[1024]; char** cfAdata = NULL; char* Hname = NULL; char* Pname = NULL; char* Nname = "stdin"; int num; char** cfAp; char r; /* * From rfc1179: * Receive control file * * +----+-------+----+------+----+ * | 02 | Count | SP | Name | LF | * +----+-------+----+------+----+ * Command code - 2 * Operand 1 - Number of bytes in control file * Operand 2 - Name of control file * * The control file must be an ASCII stream with the ends of lines * indicated by ASCII LF. The total number of bytes in the stream is * sent as the first operand. The name of the control file is sent as * the second. */ if ((!(cfAname = index(buf,' '))) || (!(*(++cfAname)))) { syslog(LLEV,"lp protocol error in PRINT command"); write(0,"\001", 1); lp_proxy_exit(); } *(cfAname - 1) = '\0'; if (!(cfAsize = atoi(buf+1))) { syslog(LLEV,"lp protocol error in PRINT command: invalid control file size %s",buf+1); write(0,"\001", 1); lp_proxy_exit(); } /* * Check if control file name is correct. * According to rfc1179, it should have cfAxxxhostname syntax, * where xxx is 3-digit job number (decimal) and hostname * should not be longer than 31 octet. * Some implementations use other than cfA... names but "cf" should * always be there. */ if ((strncmp(cfAname,"cf",2)) || ((x = strlen(cfAname)) < 7) || (x > 38) || check_string(cfAname)) { syslog(LLEV,"lp protocol error in PRINT command: invalid control file name %s",cfAname); write(0,"\001", 1); lp_proxy_exit(); } /* * We already performed length checks, right? */ strncpy(jobnumb,cfAname+3,3); jobnum = atoi(jobnumb); cfAhname = cfAname + 6; /* * Spoof acknowledgement */ write(0,"\0",1); /* * Receive and process control file itself */ icount = ocount = 0; while (icount < cfAsize) { if ((x = sogets(0,cfAline,sizeof(cfAline))) < 1) { syslog(LLEV,"error reading client data"); lp_proxy_exit(); } if (cfAline[x-1] != 0x0a) { syslog(LLEV,"error receiving control file"); lp_proxy_exit(); } else cfAline[x-1] = 0; if (!cfAline[1] || (x >128)) { syslog(LLEV,"bad line in control file %.40s",cfAname); write(0,"\001", 1); lp_proxy_exit(); } switch (cfAline[0]) { case 'C': if (x > 33) { syslog(LLEV,"securityalert: too long Class line in control file"); write(0,"\001", 1); lp_proxy_exit(); } break; case 'H': if (x > 33) { syslog(LLEV,"securityalert: too long Host line in control file"); write(0,"\001", 1); lp_proxy_exit(); } if (check_string(cfAline+1)) { syslog(LLEV,"lp protocol error in PRINT command: invalid Host line in control file, %s",cfAline+1); write(0,"\001", 1); lp_proxy_exit(); } Hname = strdup(cfAline+1); break; case 'I': case 'W': if ((num = atoi(cfAline+1)) <= 0) { syslog(LLEV,"bad line in control file"); write(0,"\001", 1); lp_proxy_exit(); } snprintf(cfAline,sizeof(cfAline),"%c%d",cfAline[1],num); break; case 'J': if (x > 101) { syslog(LLEV,"securityalert: too long Job line in control file"); write(0,"\001", 1); lp_proxy_exit(); } break; case 'N': if (x > 133) { syslog(LLEV,"securityalert: too long Name line in control file"); write(0,"\001", 1); lp_proxy_exit(); } Nname = strdup(cfAline+1); break; case 'P': if (x > 33) { syslog(LLEV,"securityalert: too long Person line in control file"); write(0,"\001", 1); lp_proxy_exit(); } Pname = strdup(cfAline+1); if (searchlist(Pname,validusers)) { syslog(LLEV,"deny host=%.512s/%.20s print request for user %.64s",proxy_stats.rladdr,proxy_stats.riaddr,Pname); write(0,"\001", 1); lp_proxy_exit(); } if (force) snprintf(cfAline,sizeof(cfAline),"P%.31s",proxy_stats.authuser); break; case 'T': if (x > 81) { syslog(LLEV,"securityalert: too long Title line in control file"); write(0,"\001", 1); lp_proxy_exit(); } break; case 'U': case 'c': case 'd': case 'f': case 'g': case 'l': case 'n': case 'o': case 'p': case 'r': case 't': case 'v': if ((strncmp(cfAline+1,"df",2)) || (x < 8) || (x > 39) || check_string(cfAline)) { syslog(LLEV,"lp protocol error in PRINT command: invalid data file name in %c control",cfAline[0]); write(0,"\001", 1); lp_proxy_exit(); } if (strcmp(cfAline+7,cfAhname)) { syslog(LLEV,"securityalert: host names do not match for control file and its contents, command %c: %.64s vs %.64s",cfAline[0],cfAhname,cfAline+7); write(0,"\001", 1); lp_proxy_exit(); } break; case 'S': { unsigned long dev,inode; char *p; if (!(dev = strtol(cfAline+1,NULL,10)) || !(p = index(cfAline,' ')) || !(*(++p)) || !(inode = strtol(p,NULL,10))) { syslog(LLEV,"lp protocol error in PRINT command: Symlink syntax error"); write(0,"\001", 1); lp_proxy_exit(); } } break; case '1': case '2': case '3': case '4': /* * Have no idea on what restrictions are useful here */ break; default: syslog(LLEV,"lp protocol error in PRINT command: unknown control %c",cfAline[0]); write(0,"\001", 1); lp_proxy_exit(); } icount += x; ocount += strlen(cfAline) + 1; addlist(cfAline,&cfAdata); } if (!Pname || !Hname) { syslog(LLEV,"lp protocol error in PRINT command: incomplete user identification in control file"); write(0,"\001", 1); lp_proxy_exit(); } /* * Reconstuct the command */ snprintf(buf1,sizeof(buf1),"%c%u cf%c%03u%.31s\n",'\02',ocount,cfAname[2],jobnum, cfAhname); syslog(LLEV,"control accepted: print job %03u (file=%s) for %s@%s", jobnum,Nname,Pname,Hname); server_puts(buf1); num = 0; if ((x = soread(server_fd,&r,1))!=1) { syslog(LLEV,"error reading server data %d %s",x, strerror(errno)); write(0,"\001", 1); lp_proxy_exit(); } proxy_stats.inbytes += 1; proxy_update_status(); if (r) syslog(LLEV,"PRINT CONTROL failed"); #ifdef DEBUG syslog(LLEV,"print control header accepted, outbytes now %u",proxy_stats.outbytes); #endif for (cfAp = cfAdata; *cfAp; cfAp++) { server_puts(*cfAp); server_puts("\n"); } #ifdef DEBUG syslog(LLEV,"print control data, outbytes now %u, ocount was %u",proxy_stats.outbytes,ocount); #endif write(server_fd,"\0",1); if (get_server_ack()) syslog(LLEV,"PRINT CONTROL failed"); #ifdef DEBUG syslog(LLEV,"print control data accepted"); #endif } static void job_data(char cmd,char *queue,char *buf) { unsigned int dfAsize; char* dfAname; char* dfAhname; unsigned short jobnum; char jobnumb[3]; int x; unsigned int count; char buf1[4096]; /* +----+-------+----+------+----+ * | 03 | Count | SP | Name | LF | * +----+-------+----+------+----+ * Command code - 3 * Operand 1 - Number of bytes in data file * Operand 2 - Name of data file * * The data file may contain any 8 bit values at all. The total number * of bytes in the stream may be sent as the first operand, otherwise * the field should be cleared to 0. * * We do not handle this case, though, because print data may * contain \0 so size parameter is mandatory. Please let me know * if it breaks something. */ if (!(dfAname = index(buf,' ')) || !(*(++dfAname))) { syslog(LLEV,"lp protocol error in PRINT command"); write(0,"\001", 1); lp_proxy_exit(); } *(dfAname-1) = '\0'; if (!(dfAsize = atoi(buf+1))) { syslog(LLEV,"lp protocol error in PRINT command: invalid data file size"); write(0,"\001", 1); lp_proxy_exit(); } /* * Check if data file name is correct. * According to rfc1179, it should have dfAxxxhostname syntax, * where xxx is 3-digit job number (decimal) and hostname * should not be longer than 31 octet. * Some implementations use other than dfA... names but "df" should * always be there. */ if ((strncmp(dfAname,"df",2)) || ((x = strlen(dfAname)) < 7) || (x > 38) || check_string(dfAname)) { syslog(LLEV,"lp protocol error in PRINT command: invalid data file name %s",dfAname); write(0,"\001", 1); lp_proxy_exit(); } /* * We already performed length checks, right? */ strncpy(jobnumb,dfAname+3,3); jobnum = atoi(jobnumb); dfAhname = dfAname + 6; snprintf(buf1,sizeof(buf1),"%c%u df%c%03u%.31s\n",'\03',dfAsize,dfAname[2],jobnum, dfAhname); server_puts(buf1); #ifdef DEBUG syslog(LLEV,"waiting to acknowledge dfA header"); #endif if (get_server_ack()) syslog(LLEV,"PRINT COMMAND failed"); #ifdef DEBUG syslog(LLEV,"got ack"); #endif /* * Receive and send data file itself */ count = 0; while (count <= dfAsize) { if ((x = soread(0,buf1,sizeof(buf1))) < 0) { syslog(LLEV,"error reading client data"); lp_proxy_exit(); } if (write(server_fd,buf1,x) != x) { syslog(LLEV,"error writing server data"); lp_proxy_exit(); } count += x; proxy_stats.outbytes += x; proxy_update_status(); } write(server_fd,'\0',1); #ifdef DEBUG syslog(LLEV,"waiting to acknowledge dfA data"); #endif if ((x = get_server_ack())) syslog(LLEV,"PRINT DATA failed %x",x); #ifdef DEBUG syslog(LLEV,"got ack"); #endif } void portnum_check(fd) int fd; { struct sockaddr_in c_addr; socklen_t l; uint16_t x; if (anyport) return; l = sizeof(c_addr); if (getpeername(fd, (struct sockaddr *)&c_addr, &l) < 0) { syslog(LOG_ERR, "fwtksyserr: getsockname(): %s", strerror(errno)); exit(1); } if ((x=ntohs(c_addr.sin_port)) > 1023) { syslog(LLEV,"deny host=%.512s/%.20s connect from unprivileged port %d",proxy_stats.rladdr,proxy_stats.riaddr,x); write(0,"\001", 1); exit(1); } if (lprng_client && ((x>731) || (x<721))) { syslog(LLEV,"deny host=%.512s/%.20s connect by non-lprNG client, source port %d",proxy_stats.rladdr,proxy_stats.riaddr,x); write(0,"\001", 1); exit(1); } } int permit_queue(queue_name) char *queue_name; { if(validqueues != (char **)0) { char **xp; for(xp = validqueues; *xp != (char *)0; xp++) { if(**xp == '!' && strcmp(*xp + 1,queue_name)) { syslog(LLEV,"deny host=%.512s/%.20s access to queue %.64s",proxy_stats.rladdr,proxy_stats.riaddr,queue_name); return(0); } else if (!strcmp(*xp,queue_name) || (**xp == '*')) { break; } syslog(LLEV,"deny host=%.512s/%.20s access to queue %.64s",proxy_stats.rladdr,proxy_stats.riaddr,queue_name); return(0); } } return(1); } static void setflag(list,c,flag) char **list; int c; int flag; { lp_action *act; char **entry; if (!list) return; for (entry = list; *entry; entry++) { for (act = lp_actions; act->name ; act++) if(!strcasecmp(*entry,act->name)) { act->flg |= flag; break; } if (!act->name) { syslog(LLEV,"fwtkcfgerr: config line %d: bad operand %.100s",c,*entry); exit(1); } } } void get_printer(client_queue) char *client_queue; { Cfg *cf; int x; char *host = NULL; char *myqueue = NULL; cf=cfg_get("printer",cfp); while (cf != (Cfg *)0) { if((cf->argc < 1) || (cf->argv[0][0] == '-')) { syslog(LLEV,"fwtkcfgerr: missing parameter, line %d",cf->ln); lp_proxy_exit(); } if (!(strcmp(cf->argv[0],client_queue)) || !(strcmp(cf->argv[0],"*"))) goto match; cf=cfg_get("printer",(Cfg *)0); } syslog(LLEV,"fwtkcfgerr: cannot map client queue %.512s to server", client_queue); lp_proxy_exit(); match: x=1; while(x < cf->argc) if (x >= cf->argc) { syslog(LLEV,"fwtkcfgerr: %.512s queue has no mapping", client_queue); lp_proxy_exit(); } else while (x < cf->argc) { if(!strcmp(cf->argv[x], "-host")) { if (host) { syslog(LLEV,"fwtkcfgerr: destintation host repeated, line %d",cf->ln); lp_proxy_exit(); } x++; if((x >= cf->argc) || (cf->argv[x][0] == '-')) { syslog(LLEV,"fwtkcfgerr: -host missing parameter, line %d",cf->ln); lp_proxy_exit(); } host=cf->argv[x]; } else if (!strcmp(cf->argv[x], "-printer")) { if (myqueue) { syslog(LLEV,"fwtkcfgerr: destintation queue repeated, line %d",cf->ln); lp_proxy_exit(); } x++; if((x >= cf->argc) || (cf->argv[x][0] == '-')) { syslog(LLEV,"fwtkcfgerr: -printer missing parameter, line %d",cf->ln); lp_proxy_exit(); } myqueue=cf->argv[x]; } else { syslog(LLEV,"fwtkcfgerr: invalid option %.128s, line %d",cf->argv[x],cf->ln); lp_proxy_exit(); } x++; } if (myqueue) strncpy(server_queue,myqueue,sizeof(server_queue)); if (!host) { syslog(LLEV,"server name not present in request from %s", proxy_stats.rladdr); lp_proxy_exit(); } if (myqueue) strncpy(proxy_stats.dst,host,sizeof(proxy_stats.dst)); } int main(int argc, char *argv[]) { char buf1[1024]; char *lp_queue = NULL ; char *lp_param = NULL ; int xx = 0; int i = 0; proxy_stats.port = str_to_port("printer"); proxy_init(argc,argv); proxy_update_operation("INIT"); maxrequest = proxy_conf_int(proxy_confp,"maxrequest",16,1024, maxrequest); if((cfp=proxy_conf_hosts(proxy_confp,proxy_stats.rladdr, proxy_stats.riaddr))) proxy_parse_options(cfp,options); else { write (0, "\001", 1); lp_proxy_exit(); } if (cdscp) proxy_set_dscp(0,cdscp); sotimeout(proxy_timeout); sosetline(3); signal(SIGPIPE, SIG_IGN); portnum_check(0); setflag(logops, cfp->ln, OP_LOG); setflag(denyops, cfp->ln, OP_DENY); memset(buf1,0,1024); /* Just in case.. */ if ((xx = sogets(0,buf1, 1023)) <=0) { syslog(LLEV,"error reading line printer protocol"); lp_proxy_exit(); } else { if (buf1[xx-1] != 0x0a) { syslog(LLEV,"error reading line printer protocol"); lp_proxy_exit(); } else buf1[xx-1] = 0; lp_cmd = buf1[0]; for (i=1; ((i < xx-1) && (buf1[i] != ' ')); i++); if (buf1[i] == ' ') buf1[i++] = 0; lp_queue = (char *)(&buf1[1]); lp_param = (char *)(&buf1[i]); } strlcpy(server_queue, lp_queue, sizeof(server_queue)); if(!permit_queue(lp_queue)) { lp_proxy_exit(); } if ((lp_cmd <1) || (lp_cmd >5)) { syslog(LLEV,"unknown lp command : %o", lp_cmd); lp_proxy_exit(); } if(lp_actions[(int)lp_cmd].flg & OP_DENY) { syslog(LLEV,"deny host=%.512s/%.20s access to queue %.32s cmd=%.10s",proxy_stats.rladdr,proxy_stats.riaddr,lp_queue,lp_actions[(int)lp_cmd].name); lp_proxy_exit(); } if (transparent) proxy_get_transparent_dst(proxy_stats.dst,&proxy_stats.port); if (!(*proxy_stats.dst)) get_printer(lp_queue); else strncpy(server_queue,lp_queue,sizeof(server_queue)-1); if (proxy_check_dest(validests,extendperm)) lp_proxy_exit(); syslog(LLEV,"permit host=%.512s/%.20s access to queue %.32s/%.32s@%.32s cmd=%.10s", proxy_stats.rladdr,proxy_stats.riaddr,lp_queue,server_queue,proxy_stats.dst,lp_actions[(int)lp_cmd].name); proxy_update_operation("CONNECTING"); if((server_fd = lp_conn_server(proxy_stats.dst, proxy_stats.port, 1, (char *)0)) < 0) { syslog(LLEV,"cannot connect to server %.256s lp port: %s", proxy_stats.dst, strerror(errno)); lp_proxy_exit(); } proxy_chroot_setugid(); if (sdscp) proxy_set_dscp(server_fd,sdscp); proxy_update_operation(lp_actions[(int)lp_cmd].name); lp_actions[(int)lp_cmd].handler(lp_cmd,server_queue,lp_param); lp_proxy_exit(); return(0); }