/*----------------------------------------------------------------------------- * ConvertChannelName -- * * Convert a requested channel name to one of the standard channel ids. * * Parameters: * o interp - Errors are returned in result. * o channelName - Desired channel, one of "stdin", "stdout" or "stderr". * o handleIdPtr - One of STD_{INPUT|OUTPUT|ERROR}_HANDLE is returned. * Returns: * TCL_OK or TCL_ERROR. * FIX: Make Unix version parallel this one. *----------------------------------------------------------------------------- */ static int ConvertChannelName (Tcl_Interp *interp, char *channelName, DWORD *handleIdPtr) { if (channelName [0] == 's') { if (STREQU (channelName, "stdin")) *handleIdPtr = STD_INPUT_HANDLE; else if (STREQU (channelName, "stdout")) *handleIdPtr = STD_OUTPUT_HANDLE; else if (STREQU (channelName, "stderr")) *handleIdPtr = STD_ERROR_HANDLE; } else if (STRNEQU (channelName, "file", 4) || STRNEQU (channelName, "sock", 4)) { TclX_AppendObjResult (interp, "on MS Windows, only stdin, ", "stdout or stderr maybe the dup target", (char *) NULL); return TCL_ERROR; } else { TclX_AppendObjResult (interp, "invalid channel id: ", channelName, (char *) NULL); return TCL_ERROR; } return TCL_OK; }
USER * getuser ( char * user ) { int limit; /* root and lp do not get a limit */ if (STREQU(user, "root") || STREQU(user, LPUSER)) { usr.priority_limit = 0; return(&usr); } if (!loaded) { if (!(ppri_tbl = ld_priority_file(Lp_Users))) return((USER *)0); loaded = 1; } for (limit = PRI_MIN; limit <= PRI_MAX; limit++) if (bang_searchlist(user, ppri_tbl->users[limit - PRI_MIN])) { usr.priority_limit = limit; return(&usr); } usr.priority_limit = ppri_tbl->deflt_limit; return(&usr); }
void s_move_dest(char *m, MESG *md) { char *dest; char *fromdest; RSTATUS *rp; char *found = (char *)0; short num_ok = 0; (void) getmessage(m, S_MOVE_DEST, &fromdest, &dest); syslog(LOG_DEBUG, "s_move_dest(%s, %s)", (fromdest ? fromdest : "NULL"), (dest ? dest : "NULL")); if (!search_pstatus(fromdest) && !search_cstatus(fromdest)) { mputm(md, R_MOVE_DEST, MNODEST, fromdest, 0); return; } if (!(search_pstatus(dest)) && !(search_cstatus(dest))) { mputm(md, R_MOVE_DEST, MNODEST, dest, 0); return; } if (STREQU(dest, fromdest)) { mputm(md, R_MOVE_DEST, MOK, "", 0); return; } for (rp = Request_List; rp != NULL; rp = rp->next) { if ((STREQU(rp->request->destination, fromdest)) && (!(rp->request->outcome & (RS_DONE|RS_CHANGING|RS_NOTIFYING)))) { if (mv_file(rp, dest) == MOK) { num_ok++; continue; } } if (found) mputm(md, R_MOVE_DEST, MMORERR, found, 0); found = rp->secure->req_id; } if (found) mputm(md, R_MOVE_DEST, MERRDEST, found, num_ok); else mputm(md, R_MOVE_DEST, MOK, "", num_ok); }
/*----------------------------------------------------------------------------- * SigNameToNum -- * Converts a UNIX signal name to its number, returns -1 if not found. * the name may be upper or lower case and may optionally have the leading * "SIG" omitted. * * Parameters: * o interp - Errors are returned in result. * o sigName - Name of signal to convert. * o sigNumPtr - Signal number is returned here. * Returns: * TCL_OK or TCL_ERROR. *----------------------------------------------------------------------------- */ static int SigNameToNum (Tcl_Interp *interp, char *sigName, int *sigNumPtr) { char sigNameUp [SIG_NAME_MAX+1]; /* Upshifted signal name */ char *sigNamePtr; int idx; /* * Copy and upshift requested name. */ if (strlen (sigName) > SIG_NAME_MAX) goto invalidSignal; /* Name too long */ TclX_UpShift (sigNameUp, sigName); if (STRNEQU (sigNameUp, "SIG", 3)) sigNamePtr = &sigNameUp [3]; else sigNamePtr = sigNameUp; for (idx = 0; sigNameTable [idx].num != -1; idx++) { if (STREQU (sigNamePtr, sigNameTable [idx].name)) { *sigNumPtr = sigNameTable [idx].num; return TCL_OK; } } invalidSignal: TclX_AppendObjResult (interp, "invalid signal \"", sigName, "\"", (char *) NULL); return TCL_ERROR; }
void s_cancel(char *m, MESG *md) { char *req_id; char *user; char *destination; char *rid; char *nrid; int nerrno; int oerrno; (void) getmessage(m, S_CANCEL, &destination, &user, &req_id); syslog(LOG_DEBUG, "s_cancel(%s, %s, %s)", (destination ? destination : "NULL"), (user ? user : "******"), (req_id ? req_id : "NULL")); if (STREQU(destination, NAME_ALL)) destination = ""; if (STREQU(req_id, NAME_ALL)) req_id = ""; if (rid = _cancel(md, destination, user, req_id)) { oerrno = errno; while ((nrid = _cancel(md, NULL, NULL, NULL)) != NULL) { nerrno = errno; mputm(md, R_CANCEL, MOKMORE, oerrno, rid); Free(rid); rid = nrid; oerrno = nerrno; } mputm(md, R_CANCEL, MOK, oerrno, rid); Free(rid); return; } mputm(md, R_CANCEL, MOK, MUNKNOWN, ""); }
int one_printer_with_charsets(RSTATUS *prs) { /* * This little function answers the question: Is a request * that needs a character set destined for a particular * printer that has selectable character sets instead of * mountable print wheels? */ return ( STREQU(prs->request->destination, prs->printer->printer->name) && !prs->printer->printer->daisy ); }
/* * s_paper_changed() */ void s_paper_changed(char *m, MESG *md) { short trayNum, mode, pagesPrinted; char *printer, *paper; ushort status; short chgd = 0; register PSTATUS *pps; register FSTATUS *pfs,*pfsWas; getmessage(m, S_PAPER_CHANGED, &printer, &trayNum, &paper, &mode, &pagesPrinted); syslog(LOG_DEBUG, "s_paper_changed(%s, %d, %s, %d, %d)", (printer ? printer : "NULL"), trayNum, (paper ? paper : "NULL"), mode, pagesPrinted); if (!(pps = search_ptable(printer))) status = MNODEST; else if ((trayNum <=0) || (trayNum > pps->numForms)) status = MNOTRAY; else { status = MOK; if (*paper && (pfsWas = pps->forms[trayNum-1].form) && (!STREQU(pfsWas->form->paper,paper))) { pfs = search_fptable(paper); if (pfs) { remount_form(pps, pfs, trayNum); chgd = 1; } else status = MNOMEDIA; } if ( status == MOK ) { pps->forms[trayNum].isAvailable = mode; if ((chgd || !mode) && (!pagesPrinted) && LP_KILL_NO_PAPER && pps->exec) { if (pps->request) pps->request->request->outcome |= RS_STOPPED; terminate(pps->exec); schedule(EV_LATER, 1, EV_INTERF, pps); } } } mputm(md, R_PAPER_CHANGED, status); }
static int max_requests_needing_pwheel_mounted(char *pwheel_name) { PSTATUS * pps; RSTATUS * prs; int max = 0; int i; /* * For each printer that doesn't have this print-wheel mounted, * count the number of requests needing this print-wheel and * assigned to the printer. Find the maximum across all such * printers. Sorry, the code actually has a different loop * (it steps through the requests) but the description of what * happens below is easier to understand as given. (Looping * through the printers would result in #printers x #requests * steps, whereas this entails #requests steps.) */ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) PStatus[i]->nrequests = 0; for (prs = Request_List; prs != NULL; prs = prs->next) if ((prs->pwheel_name != NULL) && (STREQU(prs->pwheel_name, pwheel_name)) && ((pps = prs->printer) != NULL) && pps->printer->daisy && (!SAME(pps->pwheel_name, pwheel_name))) if (++pps->nrequests >= max) max = pps->nrequests; if (NewRequest) if ( ((pps = NewRequest->printer) != NULL) && pps->printer->daisy && !SAME(pps->pwheel_name, pwheel_name) ) if (++pps->nrequests >= max) max = pps->nrequests; return (max); }
void s_move_request(char *m, MESG *md) { RSTATUS *rp; short err; char *req_id; char *dest; (void) getmessage(m, S_MOVE_REQUEST, &req_id, &dest); syslog(LOG_DEBUG, "s_move_request(%s, %s)", (req_id ? req_id : "NULL"), (dest ? dest : "NULL")); if (!(search_pstatus(dest)) && !(search_cstatus(dest))) { mputm(md, R_MOVE_REQUEST, MNODEST, 0L); return; } if ((rp = request_by_id(req_id))) { if (STREQU(rp->request->destination, dest)) { mputm(md, R_MOVE_REQUEST, MOK, 0L); return; } if (rp->request->outcome & (RS_DONE|RS_NOTIFYING)) { mputm(md, R_MOVE_REQUEST, M2LATE, 0L); return; } if (rp->request->outcome & RS_CHANGING) { mputm(md, R_MOVE_REQUEST, MBUSY, 0L); return; } if ((err = mv_file(rp, dest)) == MOK) { mputm(md, R_MOVE_REQUEST, MOK, 0L); return; } mputm(md, R_MOVE_REQUEST, err, chkprinter_result); return; } mputm(md, R_MOVE_REQUEST, MUNKNOWN, 0L); }
int putclass(char *name, CLASS *clsbufp) { char *file; int fd; if (!name || !*name) { errno = EINVAL; return (-1); } if (STREQU(NAME_ALL, name)) { errno = EINVAL; return (-1); } /* * Open the class file and write out the class members. */ if (!(file = getclassfile(name))) return (-1); if ((fd = open_locked(file, "w", MODE_READ)) < 0) { Free (file); return (-1); } Free (file); errno = 0; fdprintlist(fd, clsbufp->members); if (errno != 0) { close(fd); return (-1); } close(fd); return (0); }
/*----------------------------------------------------------------------------- * ParseSignalList -- * * Parse a list of signal names or numbers. Also handles the special case * of the signal being a single entry of "*". * * Parameters: * o interp - Interpreter for returning errors. * o signalListObjPtr - The Tcl list object of signals to convert. * o signals - Boolean array indexed by signal number that indicates * which signals are set. * Returns: * TCL_OK or TCL_ERROR. *----------------------------------------------------------------------------- */ static int ParseSignalList (Tcl_Interp *interp, Tcl_Obj *signalListObjPtr, unsigned char signals [MAXSIG]) { Tcl_Obj **signalObjv; char *signalStr; int signalObjc, signalNum, idx; if (Tcl_ListObjGetElements (interp, signalListObjPtr, &signalObjc, &signalObjv) != TCL_OK) return TCL_ERROR; if (signalObjc == 0) { TclX_AppendObjResult (interp, "signal list may not be empty", (char *) NULL); return TCL_ERROR; } memset (signals, FALSE, sizeof (unsigned char) * MAXSIG); /* * Handle the wild card signal. Don't return signals that can't be * modified. */ signalStr = Tcl_GetStringFromObj (signalObjv [0], NULL); if (STREQU (signalStr, "*")) { if (signalObjc != 1) goto wildMustBeAlone; for (idx = 0; sigNameTable [idx].name != NULL; idx++) { signalNum = sigNameTable [idx].num; #ifdef SIGKILL if ((signalNum == SIGKILL) || (signalNum == SIGSTOP)) continue; #endif signals [signalNum] = TRUE; } goto okExit; } /* * Handle individually specified signals. */ for (idx = 0; idx < signalObjc; idx++) { signalStr = Tcl_GetStringFromObj (signalObjv [idx], NULL); if (STREQU (signalStr, "*")) goto wildMustBeAlone; signalNum = ParseSignalSpec (interp, signalStr, FALSE); /* Zero not valid */ if (signalNum < 0) return TCL_ERROR; signals [signalNum] = TRUE; } okExit: return TCL_OK; wildMustBeAlone: TclX_AppendObjResult (interp, "when \"*\" is specified in the signal ", "list, no other signals may be specified", (char *) NULL); return TCL_ERROR; }
static char * _cancel(MESG *md, char *dest, char *user, char *req_id) { static RSTATUS *rp; static char *s_dest; static char *s_user; static char *s_req_id; static int current; RSTATUS *crp; char *creq_id; syslog(LOG_DEBUG, "_cancel(%s, %s, %s)", (dest ? dest : "NULL"), (user ? user : "******"), (req_id ? req_id : "NULL")); if (dest || user || req_id) { s_dest = dest; if (STREQU(user, "!")) s_user = strdup("all!all"); else s_user = user; s_req_id = req_id; rp = Request_List; current = 0; if (STREQU(s_req_id, CURRENT_REQ)) { current = 1; s_req_id = NULL; } } while (rp != NULL) { crp = rp; rp = rp->next; if (*s_dest && !STREQU(s_dest, crp->request->destination)) continue; if (current && !(crp->request->outcome & RS_PRINTING)) continue; if (s_req_id && *s_req_id && !STREQU(s_req_id, crp->secure->req_id)) continue; if (*s_user && !bangequ(s_user, crp->secure->user)) continue; if (!md->admin && md->uid != crp->secure->uid) { errno = MNOPERM; return (Strdup(crp->secure->req_id)); } /* * For Trusted Extensions, we need to check the * sensitivity label of the * connection and job before we try to cancel it. */ if ((md->admin == 0) && (is_system_labeled()) && (md->slabel != NULL) && (crp->secure->slabel != NULL) && (!STREQU(md->slabel, crp->secure->slabel))) continue; crp->reason = MOK; creq_id = Strdup(crp->secure->req_id); syslog(LOG_DEBUG, "cancel reqid (%s) uid: %d, secureuid: %d", creq_id, md->uid, crp->secure->uid); if (cancel(crp, (md->uid != crp->secure->uid))) errno = MOK; else errno = M2LATE; return (creq_id); } errno = MUNKNOWN; return (NULL); }
void s_end_change_request(char *m, MESG *md) { char *req_id; RSTATUS *rp; off_t size; off_t osize; short err; short status; REQUEST *r = 0; REQUEST oldr; int call_schedule = 0; int move_ok = 0; char *path; char tmpName[BUFSIZ]; struct stat tmpBuf; (void) getmessage(m, S_END_CHANGE_REQUEST, &req_id); syslog(LOG_DEBUG, "s_end_change_request(%s)", (req_id ? req_id : "NULL")); if (!(rp = request_by_id(req_id))) status = MUNKNOWN; else if ((md->admin == 0) && (is_system_labeled()) && (md->slabel != NULL) && (rp->secure->slabel != NULL) && (!STREQU(md->slabel, rp->secure->slabel))) status = MUNKNOWN; else if (!(rp->request->outcome & RS_CHANGING)) status = MNOSTART; else { path = makepath(Lp_Tmp, rp->req_file, (char *)0); (void) chownmod(path, Lp_Uid, Lp_Gid, 0644); Free(path); #ifdef LP_USE_PAPI_ATTR /* * Check if the PAPI job attribute file exists, * if it does change the permission and the ownership * of the file to be "Lp_Uid". */ snprintf(tmpName, sizeof (tmpName), "%s-%s", strtok(strdup(rp->req_file), "-"), LP_PAPIATTRNAME); path = makepath(Lp_Tmp, tmpName, (char *)0); if (stat(path, &tmpBuf) == 0) { syslog(LOG_DEBUG, "s_end_change_request: attribute file ='%s'", path); /* * IPP job attribute file exists for this job so * change permissions and ownership of the file */ (void) chownmod(path, Lp_Uid, Lp_Gid, 0644); Free(path); } else { syslog(LOG_DEBUG, "s_end_change_request: no attribute file"); } #endif rp->request->outcome &= ~(RS_CHANGING); del_flt_act(md, FLT_CHANGE); /* * The RS_CHANGING bit may have been the only thing * preventing this request from filtering or printing, * so regardless of what happens below, * we must check to see if the request can proceed. */ call_schedule = 1; if (!(r = Getrequest(rp->req_file))) status = MNOOPEN; else { oldr = *(rp->request); *(rp->request) = *r; move_ok = STREQU(oldr.destination, r->destination); /* * Preserve the current request status! */ rp->request->outcome = oldr.outcome; /* * Here's an example of the dangers one meets * when public flags are used for private * purposes. ".actions" (indeed, anything in the * REQUEST structure) is set by the person * changing the job. However, lpsched uses * ".actions" as place to indicate that a job * came from a remote system and we must send * back job completion--this is a strictly * private flag that we must preserve. */ rp->request->actions |= (oldr.actions & ACT_NOTIFY); if ((rp->request->actions & ACT_SPECIAL) == ACT_HOLD) { rp->request->outcome |= RS_HELD; /* * To be here means either the user owns * the request or he or she is the * administrator. Since we don't want to * set the RS_ADMINHELD flag if the user * is the administrator, the following * compare will work. */ if (md->uid != rp->secure->uid) rp->request->outcome |= RS_ADMINHELD; } if ((rp->request->actions & ACT_SPECIAL) == ACT_RESUME) { if ((rp->request->outcome & RS_ADMINHELD) && !md->admin) { status = MNOPERM; goto Return; } rp->request->outcome &= ~(RS_ADMINHELD|RS_HELD); } if ((rp->request->actions & ACT_SPECIAL) == ACT_IMMEDIATE) { if (!md->admin) { status = MNOPERM; goto Return; } rp->request->outcome |= RS_IMMEDIATE; } size = chfiles(rp->request->file_list, Lp_Uid, Lp_Gid); if (size < 0) { status = MUNKNOWN; goto Return; } if (!(rp->request->outcome & RS_HELD) && size == 0) { status = MNOPERM; goto Return; } osize = rp->secure->size; rp->secure->size = size; if (move_ok == 0) { char *dest = strdup(r->destination); if ((status = mv_file(rp, dest)) == MOK) rp->secure->size = osize; free(dest); } else if ((err = validate_request(rp, (char **)0, move_ok)) != MOK) { status = err; rp->secure->size = osize; } else { status = MOK; if ((rp->request->outcome & RS_IMMEDIATE) || (rp->request->priority != oldr.priority)) { remover(rp); insertr(rp); } freerequest(&oldr); (void) putrequest(rp->req_file, rp->request); /* * fix for bugid 1103890. * use Putsecure instead. */ (void) Putsecure(rp->req_file, rp->secure); } } } Return: if (status != MOK && rp) { if (r) { freerequest(r); *(rp->request) = oldr; } if (status != MNOSTART) (void) putrequest(rp->req_file, rp->request); } if (call_schedule) maybe_schedule(rp); mputm(md, R_END_CHANGE_REQUEST, status, chkprinter_result); }
void s_start_change_request(char *m, MESG *md) { char *req_id; char *req_file = ""; short status; RSTATUS *rp; char *path; char tmpName[BUFSIZ]; struct stat tmpBuf; (void) getmessage(m, S_START_CHANGE_REQUEST, &req_id); syslog(LOG_DEBUG, "s_start_change_request(%s)", (req_id ? req_id : "NULL")); if (!(rp = request_by_id(req_id))) status = MUNKNOWN; else if ((md->admin == 0) && (is_system_labeled()) && (md->slabel != NULL) && (rp->secure->slabel != NULL) && (!STREQU(md->slabel, rp->secure->slabel))) status = MUNKNOWN; else if (rp->request->outcome & RS_DONE) status = M2LATE; else if (!md->admin && md->uid != rp->secure->uid) status = MNOPERM; else if (rp->request->outcome & RS_CHANGING) status = MNOOPEN; else if (rp->request->outcome & RS_NOTIFYING) status = MBUSY; else { status = MOK; if (rp->request->outcome & RS_FILTERING && !(rp->request->outcome & RS_STOPPED)) { rp->request->outcome |= (RS_REFILTER|RS_STOPPED); terminate(rp->exec); } if (rp->request->outcome & RS_PRINTING && !(rp->request->outcome & RS_STOPPED)) { rp->request->outcome |= RS_STOPPED; terminate(rp->printer->exec); } rp->request->outcome |= RS_CHANGING; /* * Change the ownership of the request file to be "md->uid". * Either this is identical to "rp->secure->uid", or it is * "Lp_Uid" or it is root. The idea is that the * person at the other end needs access, and that may not * be who queued the request. */ path = makepath(Lp_Tmp, rp->req_file, (char *)0); (void) Chown(path, md->uid, rp->secure->gid); Free(path); #ifdef LP_USE_PAPI_ATTR /* * Check if the PAPI job attribute file exists, if it does * change the ownership of the file to be "md->uid". * Either this is identical to "rp->secure->uid", or it is * "Lp_Uid" or it is root. The idea is that the * person at the other end needs access, and that may not * be who queued the request. */ snprintf(tmpName, sizeof (tmpName), "%s-%s", strtok(strdup(rp->req_file), "-"), LP_PAPIATTRNAME); path = makepath(Lp_Tmp, tmpName, (char *)0); if (stat(path, &tmpBuf) == 0) { syslog(LOG_DEBUG, "s_start_change_request: attribute file ='%s'", path); /* * IPP job attribute file exists for this job so * change permissions and ownership of the file */ (void) Chown(path, md->uid, rp->secure->gid); Free(path); } else { syslog(LOG_DEBUG, "s_start_change_request: no attribute file"); } #endif add_flt_act(md, FLT_CHANGE, rp); req_file = rp->req_file; } mputm(md, R_START_CHANGE_REQUEST, status, req_file); }
SCALED _getsdn(char *str, char **p_after, int is_cpi) { static SCALED sdn = { 0.0 , 0 }; char * rest; /* * A nonzero "errno" is our only method of indicating error. */ errno = 0; if (is_cpi && STREQU(str, NAME_PICA)) { sdn.val = 10; sdn.sc = 0; if (p_after) *p_after = str + strlen(NAME_PICA); } else if (is_cpi && STREQU(str, NAME_ELITE)) { sdn.val = 12; sdn.sc = 0; if (p_after) *p_after = str + strlen(NAME_ELITE); } else if (is_cpi && STREQU(str, NAME_COMPRESSED)) { sdn.val = N_COMPRESSED; sdn.sc = 0; if (p_after) *p_after = str + strlen(NAME_COMPRESSED); } else { sdn.val = strtod(str, &rest); if (sdn.val <= 0) { lp_errno = LP_EBADSDN; errno = EINVAL; return (sdn); } while (*rest && *rest == ' ') rest++; switch (*rest) { case 0: sdn.sc = 0; if (p_after) *p_after = rest; break; case 'i': case 'c': sdn.sc = *rest++; if (p_after) *p_after = rest; break; default: lp_errno = LP_EBADSDN; errno = EINVAL; sdn.sc = 0; break; } } return (sdn); }
int pickfilter(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs) { register char ** pp; register char ** pl; register PSTATUS * pps = pc->pps; char * pipes[2] = { 0 , 0 }; char * cp; char * output_type; char ** modes = 0; char ** parms = 0; char ** valid_printer_types; char ** p_cpi = 0; char ** p_lpi = 0; char ** p_pwid = 0; char ** p_plen = 0; FILTERTYPE ret = fl_none; int got_cpi = 0; int got_lpi = 0; int got_plen = 0; int got_pwid = 0; int must_have_filter= 0; unsigned long chk; /* fix for bugid 1097387 */ output_type = (char *) NULL; /* * The bulk of the code below is building a parameter list "parms" * to send to "insfilter()". */ if (prs->request->modes) { cp = Strdup(prs->request->modes); transform_WS_to_SEP(cp); modes = getlist(cp, "", LP_SEP); Free (cp); } pp = parms = (char **)Malloc( 2 * (NPARM_SPEC + lenlist(modes) + 1) * sizeof(char *) ); /* * Add to the parameter list the appropriate cpi/lpi/etc. * characteristics (aka ``stuff'') that will be used for * this job. The printer defaults are questionable. * Take this opportunity to also save the ``stuff'' in * the request structure. */ unload_str (&(prs->cpi)); unload_str (&(prs->lpi)); unload_str (&(prs->plen)); unload_str (&(prs->pwid)); /* * If a form is involved, pick up its page size and print * spacing requirements. */ if (pfs) { if (pfs->cpi) { *pp++ = PARM_CPI; *pp++ = prs->cpi = pfs->cpi; got_cpi = 1; } if (pfs->lpi) { *pp++ = PARM_LPI; *pp++ = prs->lpi = pfs->lpi; got_lpi = 1; } if (pfs->plen) { *pp++ = PARM_LENGTH; *pp++ = prs->plen = pfs->plen; got_plen = 1; } if (pfs->pwid) { *pp++ = PARM_WIDTH; *pp++ = prs->pwid = pfs->pwid; got_pwid = 1; } /* * If no form is involved, pick up whatever page size and print * spacing requirements were given by the user. */ } else { if (o_cpi) { *pp++ = PARM_CPI; *pp++ = prs->cpi = o_cpi; got_cpi = 1; } if (o_lpi) { *pp++ = PARM_LPI; *pp++ = prs->lpi = o_lpi; got_lpi = 1; } if (o_length) { *pp++ = PARM_LENGTH; *pp++ = prs->plen = o_length; got_plen = 1; } if (o_width) { *pp++ = PARM_WIDTH; *pp++ = prs->pwid = o_width; got_pwid = 1; } } /* * Pick up whatever page size and print spacing requirements * haven't been specified yet from the printer defaults. * * Note: The following cpi/lpi/etc are guaranteed to work * for at least one type of the printer at hand, but not * necessarily all types. Once we pick a type that works * we'll verify that the cpi/lpi/etc stuff works, too. * The code that does that assumes that we do the following last, * after picking up the form and/or user stuff. If this changes, * then the later code will have to be changed, too. */ if (!got_cpi && pps->cpi) { *pp++ = PARM_CPI; *(p_cpi = pp++) = prs->cpi = pps->cpi; } if (!got_lpi && pps->lpi) { *pp++ = PARM_LPI; *(p_lpi = pp++) = prs->lpi = pps->lpi; } if (!got_plen && pps->plen) { *pp++ = PARM_LENGTH; *(p_plen = pp++) = prs->plen = pps->plen; } if (!got_pwid && pps->pwid) { *pp++ = PARM_WIDTH; *(p_pwid = pp++) = prs->pwid = pps->pwid; } /* * Pick up the number of pages, character set (the form's * or the user's), the form name, the number of copies, * and the modes. */ if (prs->request->pages) { *pp++ = PARM_PAGES; *pp++ = prs->request->pages; must_have_filter = 1; } if (prs->request->charset) { *pp++ = PARM_CHARSET; *pp++ = prs->request->charset; } else if (pfs && pfs->form->chset) { *pp++ = PARM_CHARSET; *pp++ = pfs->form->chset; } if (prs->request->form) { *pp++ = PARM_FORM; *pp++ = prs->request->form; } if (prs->request->copies > 1) { *pp++ = PARM_COPIES; sprintf ((*pp++ = BIGGEST_NUMBER_S), "%d", prs->request->copies); } if (modes) { for (pl = modes; *pl; pl++) { *pp++ = PARM_MODES; *pp++ = *pl; } must_have_filter = 1; } *pp = 0; /* null terminated list! */ /* * If the printer type(s) are not ``unknown'', then include * them as possible ``output'' type(s) to match * with the user's input type (directly, or through a filter). */ if (!STREQU(*(pps->printer->printer_types), NAME_UNKNOWN)) valid_printer_types = pc->printer_types; else { valid_printer_types = 0; must_have_filter = 0; } pc->fast = 0; pc->slow = 0; pc->output_type = 0; pc->flags = 0; ret = fl_none; /* * If we don't really need a filter and the types match, * then that's good enough. Some ``broadly defined'' * filters might match our needs, but if the printer * can do what we need, then why pull in a filter? * Besides, Section 3.40 in the requirements imply * that we don't use a filter if the printer can handle * the file. */ if (!must_have_filter ) { if ( valid_printer_types && searchlist_with_terminfo( prs->request->input_type, valid_printer_types ) ) { ret = fl_both; /* not really, but ok */ pc->printer_type = Strdup(prs->request->input_type); } else if ( pps->printer->input_types && searchlist_with_terminfo( prs->request->input_type, pps->printer->input_types ) ) { ret = fl_both; /* not really, but ok */ /* * (1) There is one printer type, might even * be ``unknown''; * (2) There are several printer types, but that * means only one input type, ``simple'', * which any of the printer types can handle. */ pc->printer_type = Strdup(*(pc->printer_types)); } } /* * Don't try using a filter if the user doesn't want * a filter to be used! He or she would rather see an * error message than (heaven forbid!) a filter being * used. */ if (ret == fl_none && !(prs->request->actions & ACT_RAW)) { /* * For each printer type, and each input type the printer * accepts, see if we have a filter that matches the * request to the printer. Each time we try, save the * output type we use in case of success; we just might * need that value later.... */ for ( pl = valid_printer_types; pl && *pl && ret == fl_none; pl++ ) ret = insfilter( pipes, prs->request->input_type, (output_type = *pl), *pl, pps->printer->name, parms, &(pc->flags) ); if (ret != fl_none) pc->printer_type = Strdup(*pl); for ( pl = pps->printer->input_types; pl && *pl && ret == fl_none; pl++ ) /* * Don't waste time with check we've already made. */ if ((must_have_filter == 1) || !valid_printer_types || !searchlist(*pl, valid_printer_types) ) /* * Either we have one (or less) printer * types and many input types, or we have * one input type, ``simple''; regardless, * using the first printer type is OK. */ ret = insfilter( pipes, prs->request->input_type, (output_type = *pl), *(pc->printer_types), pps->printer->name, parms, &(pc->flags) ); if (ret != fl_none) pc->printer_type = Strdup(*(pc->printer_types)); } /* * If we were successful, check that the printer type * we picked can handle the PRINTER'S cpi/lpi/etc. defaults. * (We know that ALL the printer's types can handle the stuff * the user gave or the stuff in the form.) * Each printer's default that doesn't pass muster gets dropped. * This may mean re-instantiating the filter(s) (if any). */ if (ret != fl_none && (p_cpi || p_lpi || p_pwid || p_plen)) { #define NZ(X) ((X)? *(X) : (char *)0) chk = chkprinter( pc->printer_type, NZ(p_cpi), NZ(p_lpi), NZ(p_plen), NZ(p_pwid), (char *)0 ); if (chk) { register char ** _pp; char * hole = ""; /* * Remove the offending printer defaults from the * request list of cpi/lpi/etc. stuff, and punch * (non-null!) holes in the parameter list. */ #define DROP(P,R) if (P) {P[-1] = P[0] = hole; R = 0;} else/*EMPTY*/ if (chk & PCK_CPI) DROP (p_cpi, prs->cpi); if (chk & PCK_LPI) DROP (p_lpi, prs->lpi); if (chk & PCK_WIDTH) DROP (p_pwid, prs->pwid); if (chk & PCK_LENGTH) DROP (p_plen, prs->plen); /* * If there are filters, we have to re-instantiate * them. (Can't check "ret" here, because it may * be misleading.) */ if (pipes[0] || pipes[1]) { /* * First, close up the gaps we punched in * the parameter list. */ for (pp = _pp = parms; *pp; pp++) if (*pp != hole) *_pp++ = *pp; *_pp = 0; /* * Re-instantiate the filter(s). This * CAN'T fail, because it is not mandatory * that filters handle cpi/lpi/etc. stuff. */ ret = insfilter( pipes, prs->request->input_type, output_type, pc->printer_type, pps->printer->name, parms, &(pc->flags) ); } } } /* * Save the filters, if any. Note: although "ret" can be * misleading, i.e. set to "fl_both" when there really aren't * any filters, the declaration of "pipes" ensured they'd be * zero if not set. */ if (ret == fl_both || ret == fl_slow) pc->slow = pipes[0]; if (ret == fl_both || ret == fl_fast) pc->fast = pipes[1]; if (ret != fl_none) pc->output_type = Strdup (output_type); /* * Wait until now to allocate storage for the cpi/etc. * stuff, to make life easier above. */ if (prs->cpi) prs->cpi = Strdup(prs->cpi); if (prs->lpi) prs->lpi = Strdup(prs->lpi); if (prs->plen) prs->plen = Strdup(prs->plen); if (prs->pwid) prs->pwid = Strdup(prs->pwid); if (parms) Free ((char *)parms); if (modes) freelist (modes); return ((ret != fl_none)); }
/*----------------------------------------------------------------------------- * TclX_ServerAcceptCmd -- * Implements the TCL server_accept command: * * server_accept ?options? file * * Accepts an IP connection request to a socket created by server_create. * Options maybe -buf orr -nobuf. * * Results: * If successful, a Tcl fileid. *----------------------------------------------------------------------------- */ static int TclX_ServerAcceptCmd (ClientData clientData, Tcl_Interp *interp, int argc, const char **argv) { Tcl_Channel channel; unsigned options; int acceptSocketFD; socklen_t addrLen; int socketFD = -1; int nextArg; struct sockaddr_in connectSocket; /* * Parse arguments. */ nextArg = 1; options = SERVER_BUF; while ((nextArg < argc) && (argv [nextArg][0] == '-')) { if (STREQU ("-buf", argv [nextArg])) { options &= ~SERVER_NOBUF; options |= SERVER_BUF; } else if (STREQU ("-nobuf", argv [nextArg])) { options &= ~SERVER_BUF; options |= SERVER_NOBUF; } else { TclX_AppendObjResult (interp, "expected \"-buf\" or \"-nobuf\", ", "got \"", argv [nextArg], "\"", (char *) NULL); return TCL_ERROR; } nextArg++; } if (nextArg != argc - 1) { TclX_AppendObjResult (interp, tclXWrongArgs, argv[0], " ?options? fileid", (char *) NULL); return TCL_ERROR; } /* * Accept a socket connection on the socket created by server_create. */ bzero ((VOID *) &connectSocket, sizeof (connectSocket)); channel = TclX_GetOpenChannel (interp, argv [nextArg], 0); if (channel == NULL) return TCL_ERROR; if (Tcl_GetChannelHandle (channel, TCL_READABLE, (ClientData *)&acceptSocketFD) == TCL_ERROR) { if (Tcl_GetChannelHandle (channel, TCL_WRITABLE, (ClientData *)&acceptSocketFD) == TCL_ERROR) return TCL_ERROR; } if (acceptSocketFD < 0) return TCL_ERROR; addrLen = sizeof (connectSocket); socketFD = accept (acceptSocketFD, (struct sockaddr *)&connectSocket, &addrLen); if (socketFD < 0) goto unixError; /* * Set up channels and we are done. */ return BindFileHandles (interp, options, socketFD); /* * Exit points for errors. */ unixError: TclX_AppendObjResult (interp, Tcl_PosixError (interp), (char *) NULL); if (socketFD >= 0) close (socketFD); return TCL_ERROR; }
/*VARARGS1*/ int exec(int type, ...) { va_list args; int i; int procuid; int procgid; int ret; int fr_flg; char *cp; char *infile; char *outfile; char *errfile; char *sep; char **listp; char **file_list; char *printerName; char *printerNameToShow; static char nameBuf[100]; char *clean_title; PSTATUS *printer; RSTATUS *request; FSTATUS *form; EXEC *ep; PWSTATUS *pwheel; time_t now; struct passwd *pwp; #ifdef LP_USE_PAPI_ATTR struct stat tmpBuf; char tmpName[BUFSIZ]; char *path = NULL; #endif char *av[ARG_MAX]; char **envp = NULL; int ac = 0; char *mail_zonename = NULL; char *slabel = NULL; syslog(LOG_DEBUG, "exec(%s)", _exec_name(type)); memset(av, 0, sizeof (*av)); va_start (args, type); switch (type) { case EX_INTERF: printer = va_arg(args, PSTATUS *); request = printer->request; ep = printer->exec; break; case EX_FAULT_MESSAGE: printer = va_arg(args, PSTATUS *); request = va_arg(args, RSTATUS *); if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) { return(0); } ep = printer->fault_exec; printerName = (printer->printer && printer->printer->name ? printer->printer->name : "??"); snprintf(nameBuf, sizeof (nameBuf), "%s (on %s)\n", printerName, Local_System); printerNameToShow = nameBuf; (void) time(&now); (void) strftime(time_buf, sizeof (time_buf), NULL, localtime(&now)); break; case EX_SLOWF: request = va_arg(args, RSTATUS *); ep = request->exec; break; case EX_NOTIFY: request = va_arg(args, RSTATUS *); if (request->request->actions & ACT_NOTIFY) { errno = EINVAL; return (-1); } ep = request->exec; break; case EX_ALERT: printer = va_arg(args, PSTATUS *); if (!(printer->printer->fault_alert.shcmd)) { errno = EINVAL; return(-1); } ep = printer->alert->exec; break; case EX_PALERT: pwheel = va_arg(args, PWSTATUS *); ep = pwheel->alert->exec; break; case EX_FORM_MESSAGE: (void) time(&now); (void) strftime(time_buf, sizeof (time_buf), NULL, localtime(&now)); /*FALLTHRU*/ case EX_FALERT: form = va_arg(args, FSTATUS *); ep = form->alert->exec; break; default: errno = EINVAL; return(-1); } va_end (args); if (!ep || (ep->pid > 0)) { errno = EBUSY; return(-1); } ep->flags = 0; key = ep->key = getkey(); switch ((ep->pid = Fork1(ep))) { case -1: relock (); return(-1); case 0: /* * We want to be able to tell our parent how we died. */ lp_alloc_fail_handler = child_mallocfail; break; default: switch(type) { case EX_INTERF: request->request->outcome |= RS_PRINTING; break; case EX_NOTIFY: request->request->outcome |= RS_NOTIFYING; break; case EX_SLOWF: request->request->outcome |= RS_FILTERING; request->request->outcome &= ~RS_REFILTER; break; } return(0); } for (i = 0; i < NSIG; i++) (void)signal (i, SIG_DFL); (void)signal (SIGALRM, SIG_IGN); (void)signal (SIGTERM, sigtrap); closelog(); for (i = 0; i < OpenMax; i++) if (i != ChildMd->writefd) Close (i); openlog("lpsched", LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR); setpgrp(); /* Set a default path */ addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin"); /* copy locale related variables */ addenv (&envp, "TZ", getenv("TZ")); addenv (&envp, "LANG", getenv("LANG")); addenv (&envp, "LC_ALL", getenv("LC_ALL")); addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE")); addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE")); addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES")); addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY")); addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC")); addenv (&envp, "LC_TIME", getenv("LC_TIME")); sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key); addenv (&envp, "SPOOLER_KEY", cp); #if defined(DEBUG) addenv (&envp, "LPDEBUG", (debug? "1" : "0")); #endif /* * Open the standard input, standard output, and standard error. */ switch (type) { case EX_SLOWF: case EX_INTERF: /* * stdin: /dev/null * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF) * stderr: req# */ infile = 0; outfile = 0; errfile = makereqerr(request); break; case EX_NOTIFY: /* * stdin: req# * stdout: /dev/null * stderr: /dev/null */ infile = makereqerr(request); outfile = 0; errfile = 0; break; case EX_ALERT: case EX_FALERT: case EX_PALERT: case EX_FAULT_MESSAGE: case EX_FORM_MESSAGE: /* * stdin: /dev/null * stdout: /dev/null * stderr: /dev/null */ infile = 0; outfile = 0; errfile = 0; break; } if (infile) { if (Open(infile, O_RDONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } else { if (Open("/dev/null", O_RDONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } if (outfile) { if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) Done (EXEC_EXIT_NOPEN, errno); } else { /* * If EX_INTERF, this is still needed to cause the * standard error channel to be #2. */ if (Open("/dev/null", O_WRONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } if (errfile) { if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1) Done (EXEC_EXIT_NOPEN, errno); } else { if (Open("/dev/null", O_WRONLY) == -1) Done (EXEC_EXIT_NOPEN, errno); } switch (type) { case EX_INTERF: /* * Opening a ``port'' can be dangerous to our health: * * - Hangups can occur if the line is dropped. * - The printer may send an interrupt. * - A FIFO may be closed, generating SIGPIPE. * * We catch these so we can complain nicely. */ trap_fault_signals (); (void)Close (1); if (strchr (request->request->user, '@')) { procuid = Lp_Uid; procgid = Lp_Gid; } else { procuid = request->secure->uid; procgid = request->secure->gid; } if (printer->printer->dial_info) { ret = open_dialup(request->printer_type, printer->printer); if (ret == 0) do_undial = 1; } else { ret = open_direct(request->printer_type, printer->printer); do_undial = 0; /* this is a URI */ if (is_printer_uri(printer->printer->device) == 0) addenv(&envp, "DEVICE_URI", printer->printer->device); } addenv(&envp, "DEVICE_URI", printer->printer->device); if (ret != 0) Done (ret, errno); if (!(request->request->outcome & RS_FILTERED)) file_list = request->request->file_list; else { register int count = 0; register char * num = BIGGEST_REQID_S; register char * prefix; prefix = makestr( Lp_Temp, "/F", getreqno(request->secure->req_id), "-", (char *)0 ); file_list = (char **)Malloc( (lenlist(request->request->file_list) + 1) * sizeof(char *) ); for ( listp = request->request->file_list; *listp; listp++ ) { sprintf (num, "%d", count + 1); file_list[count] = makestr( prefix, num, (char *)0 ); count++; } file_list[count] = 0; } #ifdef LP_USE_PAPI_ATTR /* * Check if the PAPI job attribute file exists, if it does * pass the file's pathname to the printer interface script * in an environment variable. This file is created when * print jobs are submitted via the PAPI interface. */ snprintf(tmpName, sizeof (tmpName), "%s-%s", getreqno(request->secure->req_id), LP_PAPIATTRNAME); path = makepath(Lp_Temp, tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { /* * IPP job attribute file exists for this job so * set the environment variable */ addenv(&envp, "ATTRPATH", path); } Free(path); /* * now set environment variable for the printer's PostScript * Printer Description (PPD) file, this is used by the filter * when forming the print data for this printer. */ if ((request->printer != NULL) && (request->printer->printer != NULL) && (request->printer->printer->name != NULL)) { snprintf(tmpName, sizeof (tmpName), "%s.ppd", request->printer->printer->name); path = makepath(ETCDIR, "ppd", tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { addenv(&envp, "PPD", path); } Free(path); } #endif if (request->printer_type) addenv(&envp, "TERM", request->printer_type); if (!(printer->printer->daisy)) { register char * chset = 0; register char * csp; if ( request->form && request->form->form->chset && request->form->form->mandatory && !STREQU(NAME_ANY, request->form->form->chset) ) chset = request->form->form->chset; else if ( request->request->charset && !STREQU(NAME_ANY, request->request->charset) ) chset = request->request->charset; if (chset) { csp = search_cslist( chset, printer->printer->char_sets ); /* * The "strtok()" below wrecks the string * for future use, but this is a child * process where it won't be needed again. */ addenv (&envp, "CHARSET", (csp? strtok(csp, "=") : chset) ); } } if (request->fast) addenv(&envp, "FILTER", request->fast); /* * Add the sensitivity label to the environment for * banner page and header/footer processing */ if (is_system_labeled() && request->secure->slabel != NULL) addenv(&envp, "SLABEL", request->secure->slabel); /* * Add the system name to the user name (ala system!user) * unless it is already there. RFS users may have trouble * here, sorry! */ cp = strchr(request->secure->user, '@'); allTraysWithForm(printer, request->form); /* * Fix for 4137389 * Remove double quotes from title string. */ fr_flg = 1; clean_title = strdup(NB(request->request->title)); if (clean_title == NULL) { /* * strdup failed. We're probably hosed * but try setting clean_title * to original title and continuing. */ clean_title = NB(request->request->title); fr_flg = 0; } else if (strcmp(clean_title, "") != 0) { char *ct_p; for (ct_p = clean_title; *ct_p != NULL; ct_p++) { if (*ct_p == '"') *ct_p = ' '; } } av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces, printer->printer->name); av[ac++] = arg_string(TRUSTED, "%s", request->secure->req_id); av[ac++] = arg_string(UNTRUSTED, "%s", request->request->user); av[ac++] = arg_string(TRUSTED, "%s", clean_title); av[ac++] = arg_string(TRUSTED, "%d", request->copies); if (fr_flg) free (clean_title); sep = ""; /* * Do the administrator defined key=value pair options */ argbuf[0] = '\0'; if (printer->printer->options) { char **tmp = printer->printer->options; while(*tmp != NULL) { STRLCAT(argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT(argbuf, *tmp++, sizeof (argbuf)); } } /* * Do the administrator defined ``stty'' stuff before * the user's -o options, to allow the user to override. */ if (printer->printer->stty) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "stty='", sizeof (argbuf)); STRLCAT (argbuf, printer->printer->stty, sizeof (argbuf)); STRLCAT (argbuf, "'", sizeof (argbuf)); } /* * Do all of the user's options except the cpi/lpi/etc. * stuff, which is done separately. */ if (request->request->options) { listp = dashos(request->request->options); while (*listp) { if ( !STRNEQU(*listp, "cpi=", 4) && !STRNEQU(*listp, "lpi=", 4) && !STRNEQU(*listp, "width=", 6) && !STRNEQU(*listp, "length=", 7) ) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, *listp, sizeof (argbuf)); } listp++; } } /* * The "pickfilter()" routine (from "validate()") * stored the cpi/lpi/etc. stuff that should be * used for this request. It chose form over user, * and user over printer. */ if (request->cpi) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "cpi=", sizeof (argbuf)); STRLCAT (argbuf, request->cpi, sizeof (argbuf)); } if (request->lpi) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "lpi=", sizeof (argbuf)); STRLCAT (argbuf, request->lpi, sizeof (argbuf)); } if (request->pwid) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "width=", sizeof (argbuf)); STRLCAT (argbuf, request->pwid, sizeof (argbuf)); } if (request->plen) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "length=", sizeof (argbuf)); STRLCAT (argbuf, request->plen, sizeof (argbuf)); } /* * Do the ``raw'' bit last, to ensure it gets * done. If the user doesn't want this, then he or * she can do the correct thing using -o stty= * and leaving out the -r option. */ if (request->request->actions & ACT_RAW) { STRLCAT (argbuf, sep, sizeof (argbuf)); sep = " "; STRLCAT (argbuf, "stty=-opost", sizeof (argbuf)); } /* the "options" */ av[ac++] = arg_string(UNTRUSTED, "%s", argbuf); for (listp = file_list; *listp; listp++) av[ac++] = arg_string(TRUSTED, "%s", *listp); (void)chfiles (file_list, procuid, procgid); break; case EX_SLOWF: if (request->slow) addenv(&envp, "FILTER", request->slow); if (strchr (request->request->user, '@')) { procuid = Lp_Uid; procgid = Lp_Gid; } else { procuid = request->secure->uid; procgid = request->secure->gid; } cp = _alloc_files( lenlist(request->request->file_list), getreqno(request->secure->req_id), procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter); av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_Temp, cp); for (listp = request->request->file_list; *listp; listp++) av[ac++] = arg_string(TRUSTED, "%s", *listp); (void)chfiles (request->request->file_list, procuid, procgid); #ifdef LP_USE_PAPI_ATTR /* * Check if the PAPI job attribute file exists, if it does * pass the file's pathname to the slow-filters in an * environment variable. Note: this file is created when * print jobs are submitted via the PAPI interface. */ snprintf(tmpName, sizeof (tmpName), "%s-%s", getreqno(request->secure->req_id), LP_PAPIATTRNAME); path = makepath(Lp_Temp, tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { /* * IPP job attribute file exists for this job so * set the environment variable */ addenv(&envp, "ATTRPATH", path); } Free(path); /* * now set environment variable for the printer's PostScript * Printer Description (PPD) file, this is used by the filter * when forming the print data for this printer. */ if ((request->printer != NULL) && (request->printer->printer != NULL) && (request->printer->printer->name != NULL)) { snprintf(tmpName, sizeof (tmpName), "%s.ppd", request->printer->printer->name); path = makepath(ETCDIR, "ppd", tmpName, (char *)0); if ((path != NULL) && (stat(path, &tmpBuf) == 0)) { addenv(&envp, "PPD", path); } Free(path); } #endif break; case EX_ALERT: procuid = Lp_Uid; procgid = Lp_Gid; (void)Chown (printer->alert->msgfile, procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, printer->printer->name, ALERTSHFILE); av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); break; case EX_PALERT: procuid = Lp_Uid; procgid = Lp_Gid; (void)Chown (pwheel->alert->msgfile, procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels, pwheel->pwheel->name, ALERTSHFILE); av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); break; case EX_FALERT: procuid = Lp_Uid; procgid = Lp_Gid; (void)Chown (form->alert->msgfile, procuid, procgid); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, form->form->name, ALERTSHFILE); av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile); break; case EX_FORM_MESSAGE: procuid = Lp_Uid; procgid = Lp_Gid; av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults); av[ac++] = arg_string(TRUSTED, "%s", form->form->name); av[ac++] = arg_string(TRUSTED, "%s", time_buf); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms, form->form->name, FORMMESSAGEFILE); break; case EX_FAULT_MESSAGE: procuid = Lp_Uid; procgid = Lp_Gid; av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults); av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow); av[ac++] = arg_string(TRUSTED, "%s", time_buf); av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers, printerName, FAULTMESSAGEFILE); break; case EX_NOTIFY: if (request->request->alert) { if (strchr(request->request->user, '@')) { procuid = Lp_Uid; procgid = Lp_Gid; } else { procuid = request->secure->uid; procgid = request->secure->gid; } av[ac++] = arg_string(TRUSTED, "%s", request->request->alert); } else { char *user = strdup(request->request->user); clean_string(user); slabel = request->secure->slabel; if (request->request->actions & ACT_WRITE) { av[ac++] = arg_string(TRUSTED, "%s", BINWRITE); snprintf(argbuf, sizeof (argbuf), "%s %s || %s %s", BINWRITE, user, BINMAIL, user ); av[ac++] = arg_string(TRUSTED, "/bin/sh"); av[ac++] = arg_string(TRUSTED, "-c"); av[ac++] = arg_string(TRUSTED, "%s", argbuf); } else if ((getzoneid() == GLOBAL_ZONEID) && is_system_labeled() && (slabel != NULL)) { /* * If in the global zone and the system is * labeled, mail is handled via a local * labeled zone that is the same label as * the request. */ if ((mail_zonename = get_labeled_zonename(slabel)) == (char *)-1) { /* * Cannot find labeled zone, just * return 0. */ return(0); } } if (mail_zonename == NULL) { procuid = Lp_Uid; procgid = Lp_Gid; av[ac++] = arg_string(TRUSTED, "%s", BINMAIL); av[ac++] = arg_string(UNTRUSTED, "%s", user); } else { procuid = getuid(); procgid = getgid(); av[ac++] = arg_string(TRUSTED, "%s", "/usr/sbin/zlogin"); av[ac++] = arg_string(TRUSTED, "%s", mail_zonename); av[ac++] = arg_string(TRUSTED, "%s", BINMAIL); av[ac++] = arg_string(UNTRUSTED, "%s", user); Free(mail_zonename); } free(user); } break; } av[ac++] = NULL; Fork2 (); /* only the child returns */ /* * Correctly set up the supplemental group list * for proper file access (before execl the interface program) */ pwp = getpwuid(procuid); if (pwp == NULL) { note("getpwuid(%d) call failed\n", procuid); } else if (initgroups(pwp->pw_name, procgid) < 0) { note("initgroups() call failed %d\n", errno); } setgid (procgid); setuid (procuid); /* * The shell doesn't allow the "trap" builtin to set a trap * for a signal ignored when the shell is started. Thus, don't * turn off signals in the last child! */ #ifdef DEBUG for (i = 0; av[i] != NULL; i++) note("exec(%s): av[%d] = %s", _exec_name(type), i, av[i]); for (i = 0; envp[i] != NULL; i++) note("exec(%s): envp[%d] = %s", _exec_name(type), i, envp[i]); #endif execvpe(av[0], av, envp); Done (EXEC_EXIT_NEXEC, errno); /*NOTREACHED*/ return (0); }
void s_inquire_request_rank(char *m, MESG *md) { char *form; char *dest; char *pwheel; char *user; char *req_id; RSTATUS *rp; RSTATUS *found = NULL; int found_rank = 0; short prop; char files[BUFSIZ]; int i; (void) getmessage(m, S_INQUIRE_REQUEST_RANK, &prop, &form, &dest, &req_id, &user, &pwheel); syslog(LOG_DEBUG, "s_inquire_request_rank(%d, %s, %s, %s, %s, %s)", prop, (form ? form : "NULL"), (dest ? dest : "NULL"), (req_id ? req_id : "NULL"), (user ? user : "******"), (pwheel ? pwheel : "NULL")); for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) PStatus[i]->nrequests = 0; for (rp = Request_List; rp != NULL; rp = rp->next) { if (rp->printer && !(rp->request->outcome & RS_DONE)) rp->printer->nrequests++; if (*form && !SAME(form, rp->request->form)) continue; if (*dest && !STREQU(dest, rp->request->destination)) { if (!rp->printer) continue; if (!STREQU(dest, rp->printer->printer->name)) continue; } if (*req_id && !STREQU(req_id, rp->secure->req_id)) continue; if (*user && !bangequ(user, rp->secure->user)) continue; if (*pwheel && !SAME(pwheel, rp->pwheel_name)) continue; /* * For Trusted Extensions, we need to check the sensitivity * label of the connection and job before we return it to the * client. */ if ((md->admin <= 0) && (is_system_labeled()) && (md->slabel != NULL) && (rp->secure->slabel != NULL) && (!STREQU(md->slabel, rp->secure->slabel))) continue; if (found) { GetRequestFiles(found->request, files, sizeof (files)); mputm(md, R_INQUIRE_REQUEST_RANK, MOKMORE, found->secure->req_id, found->request->user, /* bgolden 091996, bug 1257405 */ found->secure->slabel, found->secure->size, found->secure->date, found->request->outcome, found->printer->printer->name, (found->form? found->form->form->name : ""), NB(found->pwheel_name), found_rank, files); } found = rp; found_rank = found->printer->nrequests; } if (found) { GetRequestFiles(found->request, files, sizeof (files)); mputm(md, R_INQUIRE_REQUEST_RANK, MOK, found->secure->req_id, found->request->user, /* bgolden 091996, bug 1257405 */ found->secure->slabel, found->secure->size, found->secure->date, found->request->outcome, found->printer->printer->name, (found->form? found->form->form->name : ""), NB(found->pwheel_name), found_rank, files); } else mputm(md, R_INQUIRE_REQUEST_RANK, MNOINFO, "", "", "", 0L, 0L, 0, "", "", "", 0, ""); }
/*----------------------------------------------------------------------------- * ProcessSignalListEntry -- * * Parse a keyed list entry used to describe a signal state and set the * signal to that state. If the signal action is specified as "unknown", * it is ignored. * * Parameters:: * o interp - Error messages are returned here. * o signalName - Signal name. * o stateObjPtr - Signal state information from keyed list. * Returns: * TCL_OK or TCL_ERROR; *----------------------------------------------------------------------------- */ static int ProcessSignalListEntry (Tcl_Interp *interp, char *signalName, Tcl_Obj *stateObjPtr) { Tcl_Obj **stateObjv; int stateObjc; char *actionStr, *cmdStr; int signalNum, blocked; signalProcPtr_t actionFunc = NULL; int restart = FALSE; unsigned char signals [MAXSIG]; /* * Get state list. */ if (Tcl_ListObjGetElements (interp, stateObjPtr, &stateObjc, &stateObjv) != TCL_OK) return TCL_ERROR; if (stateObjc < 2 || stateObjc > 4) goto invalidEntry; /* * Parse the signal name and action. */ if (SigNameToNum (interp, signalName, &signalNum) != TCL_OK) return TCL_ERROR; actionStr = Tcl_GetStringFromObj (stateObjv [0], NULL); cmdStr = NULL; if (stateObjc > 2) { cmdStr = Tcl_GetStringFromObj (stateObjv [2], NULL); if (cmdStr[0] == '\0') { cmdStr = NULL; } } if (STREQU (actionStr, SIGACT_DEFAULT)) { actionFunc = SIG_DFL; if (cmdStr != NULL) goto invalidEntry; } else if (STREQU (actionStr, SIGACT_IGNORE)) { actionFunc = SIG_IGN; if (cmdStr != NULL) goto invalidEntry; } else if (STREQU (actionStr, SIGACT_ERROR)) { actionFunc = SignalTrap; if (cmdStr != NULL) goto invalidEntry; } else if (STREQU (actionStr, SIGACT_TRAP)) { actionFunc = SignalTrap; if (cmdStr == NULL) /* Must have command */ goto invalidEntry; } else if (STREQU (actionStr, SIGACT_UNKNOWN)) { if (cmdStr != NULL) goto invalidEntry; return TCL_OK; /* Ignore non-Tcl signals */ } if (Tcl_GetBooleanFromObj (interp, stateObjv [1], &blocked) != TCL_OK) return TCL_ERROR; if (stateObjc > 3) { if (Tcl_GetBooleanFromObj (interp, stateObjv [3], &restart) != TCL_OK) return TCL_ERROR; } memset (signals, FALSE, sizeof (unsigned char) * MAXSIG); signals [signalNum] = TRUE; /* * Set signal actions and handle blocking if its supported on this * system. If the signal is to be blocked, we do it before setting up * the handler. If its to be unblocked, we do it after. */ #ifndef NO_SIGACTION if (blocked) { if (BlockSignals (interp, SIG_BLOCK, signals) != TCL_OK) return TCL_ERROR; } #endif if (SetSignalActions (interp, signals, actionFunc, restart, cmdStr) != TCL_OK) return TCL_ERROR; #ifndef NO_SIGACTION if (!blocked) { if (BlockSignals (interp, SIG_UNBLOCK, signals) != TCL_OK) return TCL_ERROR; } #endif return TCL_OK; invalidEntry: TclX_AppendObjResult (interp, "invalid signal keyed list entry for ", signalName, (char *) NULL); return TCL_ERROR; }
/*----------------------------------------------------------------------------- * ReturnStatItem -- * * Return a single file status item. * * Parameters: * o interp (I) - Item or error returned in result. * o channel (I) - Channel the file is assoicated with. * o ttyDev (O) - A boolean indicating if the device is associated with a * tty. * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat. * o itemName (I) - The name of the desired item. * Returns: * TCL_OK or TCL_ERROR. *----------------------------------------------------------------------------- */ static int ReturnStatItem (Tcl_Interp *interp, Tcl_Channel channel, int ttyDev, struct stat *statBufPtr, char *itemName) { Tcl_Obj *objPtr; if (STREQU (itemName, "dev")) objPtr = Tcl_NewIntObj ((int) statBufPtr->st_dev); else if (STREQU (itemName, "ino")) objPtr = Tcl_NewIntObj ((int) statBufPtr->st_ino); else if (STREQU (itemName, "mode")) objPtr = Tcl_NewIntObj ((int) statBufPtr->st_mode); else if (STREQU (itemName, "nlink")) objPtr = Tcl_NewIntObj ((int) statBufPtr->st_nlink); else if (STREQU (itemName, "uid")) objPtr = Tcl_NewIntObj ((int) statBufPtr->st_uid); else if (STREQU (itemName, "gid")) objPtr = Tcl_NewIntObj ((int) statBufPtr->st_gid); else if (STREQU (itemName, "size")) objPtr = Tcl_NewLongObj ((long) statBufPtr->st_size); else if (STREQU (itemName, "atime")) objPtr = Tcl_NewLongObj ((long) statBufPtr->st_atime); else if (STREQU (itemName, "mtime")) objPtr = Tcl_NewLongObj ((long) statBufPtr->st_mtime); else if (STREQU (itemName, "ctime")) objPtr = Tcl_NewLongObj ((long) statBufPtr->st_ctime); else if (STREQU (itemName, "type")) objPtr = Tcl_NewStringObj (StrFileType (statBufPtr), -1); else if (STREQU (itemName, "tty")) objPtr = Tcl_NewBooleanObj (ttyDev); else if (STREQU (itemName, "remotehost")) { objPtr = TclXGetHostInfo (interp, channel, TRUE); if (objPtr == NULL) return TCL_ERROR; } else if (STREQU (itemName, "localhost")) { objPtr = TclXGetHostInfo (interp, channel, FALSE); if (objPtr == NULL) return TCL_ERROR; } else { TclX_AppendObjResult (interp, "Got \"", itemName, "\", expected one of ", "\"atime\", \"ctime\", \"dev\", \"gid\", ", "\"ino\", \"mode\", \"mtime\", \"nlink\", ", "\"size\", \"tty\", \"type\", \"uid\", ", "\"remotehost\", or \"localhost\"", (char *) NULL); return TCL_ERROR; } Tcl_SetObjResult (interp, objPtr); return TCL_OK; }
int putprinter(char *name, PRINTER *prbufp) { register char * path; register char * stty; register char * speed; int fdin, fdout; int fld; char buf[BUFSIZ]; struct stat statbuf1, statbuf2; badprinter = 0; if (!name || !*name) { errno = EINVAL; return (-1); } if (STREQU(NAME_ALL, name)) { errno = EINVAL; return (-1); } /* * First go through the structure and see if we have * anything strange. */ if (!okprinter(name, prbufp, 1)) { errno = EINVAL; return (-1); } if (!Lp_A_Printers || !Lp_A_Interfaces) { getadminpaths (LPUSER); if (!Lp_A_Printers || !Lp_A_Interfaces) return (0); } /* * Create the parent directory for this printer * if it doesn't yet exist. */ if (!(path = getprinterfile(name, (char *)0))) return (-1); if (Stat(path, &statbuf1) == 0) { if (!S_ISDIR(statbuf1.st_mode)) { Free (path); errno = ENOTDIR; return (-1); } } else if (errno != ENOENT || mkdir_lpdir(path, MODE_DIR) == -1) { Free (path); return (-1); } Free (path); /* * Create the copy of the interface program, unless * that would be silly or not desired. * Conversely, make sure the interface program doesn't * exist for a remote printer. */ if (prbufp->remote) { if (!(path = makepath(Lp_A_Interfaces, name, (char *)0))) return (-1); (void)rmfile (path); Free (path); } if (prbufp->interface && (ignprinter & BAD_INTERFACE) == 0) { if (Stat(prbufp->interface, &statbuf1) == -1) return (-1); if (!(path = makepath(Lp_A_Interfaces, name, (char *)0))) return (-1); if ( Stat(path, &statbuf2) == -1 || statbuf1.st_dev != statbuf2.st_dev || statbuf1.st_ino != statbuf2.st_ino ) { register int n; if ((fdin = open_locked(prbufp->interface, "r", 0)) < 0) { Free (path); return (-1); } if ((fdout = open_locked(path, "w", MODE_EXEC)) < 0) { Free (path); close(fdin); return (-1); } while ((n = read(fdin, buf, BUFSIZ)) > 0) write (fdout, buf, n); close(fdout); close(fdin); } Free (path); } #ifdef LP_USE_PAPI_ATTR /* * Handle PPD (Postscript Printer Definition) file for printer * if this printer has been configured with one */ if ((prbufp->ppd != NULL) && (ppdopt)) { if (addPrintersPPD(name, prbufp) != 0) { /* failed to added the printers PPD file */ return (-1); } } #endif /* * If this printer is dialed up, remove any baud rates * from the stty option list and move the last one to * the ".speed" member if the ".speed" member isn't already * set. Conversely, if this printer is directly connected, * move any value from the ".speed" member to the stty list. */ stty = (prbufp->stty? Strdup(prbufp->stty) : 0); if (prbufp->speed) speed = Strdup(prbufp->speed); else speed = 0; if (prbufp->dial_info && stty) { register char *newstty, *p, *q; register int len; if (!(q = newstty = Malloc(strlen(stty) + 1))) { Free (stty); errno = ENOMEM; return (-1); } newstty[0] = 0; /* start with empty copy */ for ( p = strtok(stty, " "); p; p = strtok((char *)0, " ") ) { len = strlen(p); if (strspn(p, "0123456789") == len) { /* * If "prbufp->speed" isn't set, then * use the speed we just found. Don't * check "speed", because if more than * one speed was given in the list, we * want the last one. */ if (!prbufp->speed) { if (speed) Free (speed); speed = Strdup(p); } } else { /* * Not a speed, so copy it to the * new stty string. */ if (q != newstty) *q++ = ' '; strcpy (q, p); q += len; } } Free (stty); stty = newstty; } else if (!prbufp->dial_info && speed) { register char *newstty; newstty = Malloc(strlen(stty) + 1 + strlen(speed) + 1); if (!newstty) { if (stty) Free (stty); errno = ENOMEM; return (-1); } if (stty) { strcpy (newstty, stty); strcat (newstty, " "); strcat (newstty, speed); Free (stty); } else strcpy (newstty, speed); Free (speed); speed = 0; stty = newstty; } /* * Open the configuration file and write out the printer * configuration. */ if (!(path = getprinterfile(name, CONFIGFILE))) { if (stty) Free (stty); if (speed) Free (speed); return (-1); } if ((fdout = open_locked(path, "w", MODE_READ)) < 0) { Free (path); if (stty) Free (stty); if (speed) Free (speed); return (-1); } Free (path); errno = 0; for (fld = 0; fld < PR_MAX; fld++) { if (prbufp->remote && !prtrheadings[fld].okremote) continue; switch (fld) { #define HEAD prtrheadings[fld].v case PR_BAN: { char *ptr = NAME_ON; switch (prbufp->banner) { case BAN_ALWAYS: ptr = NAME_ON; break; case BAN_NEVER: ptr = NAME_OFF; break; case BAN_OPTIONAL: ptr = NAME_OPTIONAL; break; } (void)fdprintf(fdout, "%s %s\n", HEAD, ptr); } break; case PR_CPI: print_sdn(fdout, HEAD, prbufp->cpi); break; case PR_CS: if (!emptylist(prbufp->char_sets)) print_l(fdout, HEAD, prbufp->char_sets); break; case PR_ITYPES: /* * Put out the header even if the list is empty, * to distinguish no input types from the default. */ print_l(fdout, HEAD, prbufp->input_types); break; case PR_DEV: print_str(fdout, HEAD, prbufp->device); break; case PR_DIAL: print_str(fdout, HEAD, prbufp->dial_info); break; case PR_RECOV: print_str(fdout, HEAD, prbufp->fault_rec); break; case PR_INTFC: print_str(fdout, HEAD, prbufp->interface); break; case PR_LPI: print_sdn(fdout, HEAD, prbufp->lpi); break; case PR_LEN: print_sdn(fdout, HEAD, prbufp->plen); break; case PR_LOGIN: if (prbufp->login & LOG_IN) (void)fdprintf(fdout, "%s\n", HEAD); break; case PR_PTYPE: { char **printer_types; /* * For backward compatibility for those who * use only "->printer_type", we have to play * some games here. */ if (prbufp->printer_type && !prbufp->printer_types) printer_types = getlist( prbufp->printer_type, LP_WS, LP_SEP ); else printer_types = prbufp->printer_types; if (!printer_types || !*printer_types) print_str(fdout, HEAD, NAME_UNKNOWN); else print_l(fdout, HEAD, printer_types); if (printer_types != prbufp->printer_types) freelist (printer_types); break; } case PR_REMOTE: print_str(fdout, HEAD, prbufp->remote); break; case PR_SPEED: print_str(fdout, HEAD, speed); break; case PR_STTY: print_str(fdout, HEAD, stty); break; case PR_WIDTH: print_sdn(fdout, HEAD, prbufp->pwid); break; #if defined(CAN_DO_MODULES) case PR_MODULES: /* * Put out the header even if the list is empty, * to distinguish no modules from the default. */ print_l(fdout, HEAD, prbufp->modules); break; #endif case PR_OPTIONS: print_l(fdout, HEAD, prbufp->options); break; case PR_PPD: { print_str(fdout, HEAD, prbufp->ppd); break; } } } if (stty) Free (stty); if (speed) Free (speed); if (errno != 0) { close(fdout); return (-1); } close(fdout); /* * If we have a description of the printer, * write it out to a separate file. */ if (prbufp->description) { if (!(path = getprinterfile(name, COMMENTFILE))) return (-1); if (dumpstring(path, prbufp->description) == -1) { Free (path); return (-1); } Free (path); } /* * Now write out the alert condition. */ if ( prbufp->fault_alert.shcmd && putalert(Lp_A_Printers, name, &(prbufp->fault_alert)) == -1 ) return (-1); return (0); }
void notify(register RSTATUS *prs, char *errbuf, int k, int e, int slow) { register char *cp; char *file; int fd; /* * Screen out cases where no notification is needed. */ if (!(prs->request->outcome & RS_NOTIFY)) return; if ( !(prs->request->actions & (ACT_MAIL|ACT_WRITE|ACT_NOTIFY)) && !prs->request->alert && !(prs->request->outcome & RS_CANCELLED) && !e && !k && !errbuf /* exited normally */ ) return; /* * Create the notification message to the user. */ file = makereqerr(prs); if ((fd = open_locked(file, "w", MODE_NOREAD)) >= 0) { fdprintf(fd, N_Msg[0], prs->secure->req_id, prs->secure->req_id, prs->request->destination, STREQU(prs->request->destination, NAME_ANY)? " printer" : ""); if (prs->request) { char file[BUFSIZ]; GetRequestFiles(prs->request, file, sizeof(file)); fdprintf(fd, "\nThe job title was:\t%s\n", file); fdprintf(fd, " submitted by:\t%s\n", prs->request->user); fdprintf(fd, " at:\t%s\n", ctime(&prs->secure->date)); } if (prs->request->outcome & RS_PRINTED) fdprintf(fd, N_Msg[1], prs->printer->printer->name); if (prs->request->outcome & RS_CANCELLED) fdprintf(fd, N_Msg[2], (prs->request->outcome & RS_FAILED)? ", and" : "."); if (prs->request->outcome & RS_FAILED) { if (slow) fdprintf(fd, N_Msg[3]); else fdprintf(fd, N_Msg[4], prs->printer->printer->name); if (e > 0) fdprintf(fd, N_Msg[slow? 5 : 6], e); else if (k) fdprintf(fd, N_Msg[slow? 7 : 8], k); } if (errbuf) { for (cp = errbuf; *cp && *cp == '\n'; cp++) ; fdprintf(fd, N_Msg[9], cp); if (prs->request->outcome & RS_CANCELLED) fdprintf(fd, "\n"); } /* start fix for bugid 1100252 */ if (prs->request->outcome & RS_CANCELLED) { print_reason (fd, prs->reason); } close(fd); schedule (EV_NOTIFY, prs); } if (file) Free (file); return; }
/*----------------------------------------------------------------------------- * TclX_ServerCreateCmd -- * Implements the TCL server_create command: * * server_create ?options? * * Creates a socket, binds the address and port on the local machine * (optionally specified by the caller), and starts the port listening * for connections by calling listen (2). * * Options may be "-myip ip_address", "-myport port_number", * "-myport reserved", and "-backlog backlog". * * Results: * If successful, a Tcl fileid is returned. * *----------------------------------------------------------------------------- */ static int TclX_ServerCreateCmd (ClientData clientData, Tcl_Interp *interp, int argc, const char **argv) { int socketFD = -1, nextArg; struct sockaddr_in local; int myPort, value; int backlog = 5; int getReserved = FALSE; Tcl_Channel channel = NULL; /* * Parse arguments. */ bzero ((VOID *) &local, sizeof (local)); local.sin_family = AF_INET; local.sin_addr.s_addr = INADDR_ANY; nextArg = 1; while ((nextArg < argc) && (argv [nextArg][0] == '-')) { if (STREQU ("-myip", argv [nextArg])) { if (nextArg >= argc - 1) goto missingArg; nextArg++; if (TclXOSInetAtoN (interp, argv [nextArg], &local.sin_addr) == TCL_ERROR) return TCL_ERROR; } else if (STREQU ("-myport", argv [nextArg])) { if (nextArg >= argc - 1) goto missingArg; nextArg++; if (STREQU (argv [nextArg], "reserved")) { getReserved = TRUE; } else { if (Tcl_GetInt (interp, argv [nextArg], &myPort) != TCL_OK) return TCL_ERROR; local.sin_port = htons (myPort); } } else if (STREQU ("-backlog", argv [nextArg])) { if (nextArg >= argc - 1) goto missingArg; nextArg++; if (Tcl_GetInt (interp, argv [nextArg], &backlog) != TCL_OK) return TCL_ERROR; } else if (STREQU ("-reuseaddr", argv [nextArg])) { /* Ignore for compatibility */ } else { TclX_AppendObjResult (interp, "expected ", "\"-myip\", \"-myport\", or \"-backlog\", ", "got \"", argv [nextArg], "\"", (char *) NULL); return TCL_ERROR; } nextArg++; } if (nextArg != argc) { TclX_AppendObjResult (interp, tclXWrongArgs, argv[0], " ?options?", (char *) NULL); return TCL_ERROR; } /* * Allocate a reserved port if requested. */ if (getReserved) { int port; if (rresvport (&port) < 0) goto unixError; local.sin_port = port; } /* * Open a socket and bind an address and port to it. */ socketFD = socket (local.sin_family, SOCK_STREAM, 0); if (socketFD < 0) goto unixError; value = 1; if (setsockopt (socketFD, SOL_SOCKET, SO_REUSEADDR, (void*) &value, sizeof (value)) < 0) { goto unixError; } if (bind (socketFD, (struct sockaddr *) &local, sizeof (local)) < 0) { goto unixError; } if (listen (socketFD, backlog) < 0) goto unixError; channel = Tcl_MakeTcpClientChannel ((ClientData) socketFD); Tcl_RegisterChannel (interp, channel); TclX_AppendObjResult (interp, Tcl_GetChannelName (channel), (char *) NULL); return TCL_OK; /* * Exit points for errors. */ missingArg: TclX_AppendObjResult (interp, "missing argument for ", argv [nextArg], (char *) NULL); return TCL_ERROR; unixError: TclX_AppendObjResult (interp, Tcl_PosixError (interp), (char *) NULL); CloseForError (interp, channel, socketFD); return TCL_ERROR; }