home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume16
/
plp
/
part15
< prev
next >
Wrap
Text File
|
1988-09-22
|
52KB
|
1,664 lines
Subject: v16i028: Public lineprinter spooler package, Part15/16
Newsgroups: comp.sources.unix
Sender: sources
Approved: rsalz@uunet.UU.NET
Submitted-by: papowell@julius.cs.umn.edu
Posting-number: Volume 16, Issue 28
Archive-name: plp/part15
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 15 (of 16)."
# Contents: src/lp.h src/utils.c
# Wrapped by papowell@attila on Wed Aug 10 10:45:12 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/lp.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/lp.h'\"
else
echo shar: Extracting \"'src/lp.h'\" \(23350 characters\)
sed "s/^X//" >'src/lp.h' <<'END_OF_FILE'
X/*************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X *************************************************************************
X * MODULE: lp.h
X * Includes and definitions for all programs
X *************************************************************************
X * Revision History: Created Sun Jan 3 15:37:08 CST 1988
X * $Header: lp.h,v 3.2 88/06/24 17:15:52 papowell Exp $
X * $Log: lp.h,v $
X * Revision 3.2 88/06/24 17:15:52 papowell
X * MODS for VAX 4.3BSD UNIX
X *
X *
X * Revision 3.1 88/06/18 09:34:30 papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X *
X * Revision 2.3 88/05/29 13:09:55 papowell
X * Added Header string for RCS purposes
X *
X * Revision 2.2 88/05/14 10:18:16 papowell
X * Use long format for job file names;
X * Added 'fd', no forward flag;
X * Control file has to have hostname and origination agree.
X *
X * Revision 2.1 88/05/09 10:10:48 papowell
X * PLP: Released Version
X *
X * Revision 1.12 88/05/09 10:03:39 papowell
X * Revised effects of -h option
X *
X * Revision 1.11 88/05/05 20:08:53 papowell
X * Added a NOHEADER option that allows user to suppress banner
X *
X * Revision 1.10 88/04/29 07:48:55 papowell
X * Added USE_LOCKF flags
X *
X * Revision 1.9 88/04/28 17:32:47 papowell
X * fixed Data General Options
X *
X * Revision 1.8 88/04/21 21:49:40 papowell
X * BADSETREUID: this flag is provided for situations where setreuid()
X * does not allow changing back to root after changing to a user.
X * This is a problem in security, and should be avoided.
X *
X * Revision 1.7 88/04/07 12:29:13 papowell
X * Removed AF_UNIX socket definitions
X *
X * Revision 1.6 88/04/07 09:09:23 papowell
X * Apollo Workstation Modifications
X *
X * Revision 1.5 88/04/06 12:13:40 papowell
X * Minor updates, changes in error message formats.
X * Elimination of the AF_UNIX connections, use AF_INET only.
X * Better error messages.
X *
X * Revision 1.4 88/03/25 14:59:54 papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * apparently they open files and then assume that they will stay
X * open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X *
X * Revision 1.3 88/03/11 19:29:10 papowell
X * Minor Changes, Updates
X *
X * Revision 1.2 88/03/05 15:02:09 papowell
X * Minor Corrections, Lint Problems
X *
X * Revision 1.1 88/03/01 12:42:54 papowell
X * Initial revision
X *
X *************************************************************************/
X
X/*************************************************************************
X * Make sure that you set the DEBUG flag if XPERIMENT is set
X *
X *************************************************************************/
X#ifdef XPERIMENT
X#define DEBUG 1
X#endif XPERIMENT
X/*************************************************************************
X * Portability Definitions
X * Several systems do not have the same definitions for these items.
X * You will have to add your own local definitions.
X * Ahh... Dream of the day of a standard set of definitions
X *************************************************************************/
X#ifdef IS_SUN
X#define uid_t int /* keep lint on the sun happy */
X#endif IS_SUN
X
X#ifdef IS_VAX4BSD
X#define SETREUID4BSD 1
X#endif IS_VAX4BSD
X
X#ifdef IS_DATAGEN
X#define fd_set int /* keep lint happy */
X#define uid_t int /* keep lint happy */
X#define NOSYMLINK /* no symbolic links */
X#define USE_LOCKF /* use the lockf() function for locking */
X#define F_TLOCK 2 /* test and lock a section (non-blocking) */
X#endif IS_DATAGEN
X
X#ifdef IS_UMAX
X#undef B19200
X#undef B38400
X#define B19200 EXTA
X#define B38400 EXTB
X#define time_t long
X#define uid_t int
X#endif IS_UMAX
X
X#ifdef IS_APOLLO
X#undef B19200
X#undef B38400
X#define B19200 EXTA
X#define B38400 EXTB
X#define uid_t int
X#define USE_STRINGS /* use <strings.h> instead of <string.h> */
X#define NO_A_OUT_H /* no a.out.h include file */
X#endif IS_APOLLO
X
X/******************************************************************
X * System Include Files
X ******************************************************************/
X#include <stdio.h>
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/dir.h>
X#include <sys/time.h>
X#include <sys/stat.h>
X#include <sys/socket.h>
X#include <sys/resource.h>
X#include <netinet/in.h>
X#include <netdb.h>
X#include <pwd.h>
X#include <signal.h>
X#include <sys/wait.h>
X#include <sgtty.h>
X#include <ctype.h>
X#ifdef USE_STRINGS
X#include <strings.h>
X#else USE_STRINGS
X#include <string.h>
X#endif USE_STRINGS
X#include <errno.h>
X#include <grp.h>
X
X
X/******************************************************************
X * Declare Standard Routines.
X * Note: most of these are not declared in include files.
X * This leads to some interesting problems with LINT. Declare these
X * here. Some specialized routines are declared in the individual
X * routines that use them.
X ******************************************************************/
extern char *malloc(), *realloc();
extern char *getenv();
extern char *gets();
extern int errno, sys_nerr;
extern char *sys_errlist[];
extern char *index(), *rindex();
extern char *sprintf(); /* sigh... sprintf strikes again */
extern long lseek(), atol();
X
extern uid_t getuid(), geteuid();
extern time_t time(); /* watch this one */
X
X/*
X * This should be declared in <signal.h>
X */
X#ifndef sigmask
X#define sigmask(m) (1 << ((m)-1))
X#endif
X
X/*************************************************************************
X * PRINTCAP entries and associated variables.
X * Each printcap entry has a corresponding variable; for example
X * ":af=accnt:"
X * -> AF = "accnt";
X *************************************************************************/
extern int AB; /* Always have a banner flag, ignore lpr -h option */
extern char *AF; /* accounting file */
extern char *BP; /* banner printer filter */
extern int BK; /* Berkeley compatible remote and local */
extern int BR; /* baud rate if lp is a tty */
extern int CO; /* cost of printing in dollars */
extern char *EP; /* end printer filter */
extern int FD; /* No forwarding, accept only from original site */
extern int FO; /* print a form feed when device is opened */
extern int FC; /* flags to clear if lp is a tty */
extern char *FF; /* form feed string */
extern int FJ; /* send control file first to remote site */
extern int FQ; /* form feed on quitting */
extern int FS; /* flags to set if lp is a tty */
extern char *FX; /* allowable formats */
extern char *LD; /* leader string on opening */
extern char *LF; /* log file for error messages */
extern int LH; /* use long host name */
extern char *LO; /* lock file name */
extern char *LN; /* group allowed to use links */
extern char *LP; /* line printer device name */
extern int MC; /* maximum number of copies allowed */
extern int MX; /* maximum number of blocks to copy */
extern int NW; /* Networked file system, do not make copies */
extern int PL; /* page length */
extern char *PR; /* pr program name name */
extern char *PS; /* printer status file name */
extern int PW; /* page width */
extern int PX; /* page width in pixels */
extern int PY; /* page length in pixels */
extern char *QH; /* queue handler */
extern char *RG; /* restrict use to group */
extern char *RM; /* remote machine name */
extern char *RP; /* remote printer name */
extern int RT; /* max retries */
extern int RW; /* open LP for reading and writing */
extern int SB; /* short banner instead of normal header */
extern int SC; /* suppress multiple copies */
extern char *SD; /* spool directory */
extern int SF; /* suppress FF on each print job */
extern int SH; /* suppress header page */
extern char *SS; /* name of queue that the server serves */
extern char *ST; /* status file name */
extern char *SV; /* names of servers */
extern char *TR; /* trailer string to be output when Q empties */
extern char *TY; /* terminal characteristics, stty options */
extern int XC; /* flags to clear for local mode */
extern int XS; /* flags to set for local mode */
extern char *XT; /* format checked for text only */
extern char *XU; /* restrict use to users whose names are in file */
X/*
X * Filter_name[] is an array of filter names, indexed by the first letter
X * of the printcap tag. For example:
X * ":if=/usr/lib/iffilter -n -a:"
X * -> Filter_name['i'-'a'] = "/usr/lib/iffilter -n -a";
X */
extern char *Filter_name[26];
X#define IF (Filter_name['i'-'a'])
X#define OF (Filter_name['o'-'a'])
X/*
X * Prefilter_name[] is similar to Filter_name[], but for prefilter entries.
X */
extern char *Prefilter_name[26];
X
X/**********************************************************************
X * Globally accessed variables and routines
X **********************************************************************/
extern char *Name; /* program name */
extern char *Printer; /* printer name */
extern char *Person; /* user name */
extern char Host[64]; /* Host machine name */
extern char *From; /* client's machine name */
extern int Debug; /* Debugging level */
extern int Echo_on_stdout; /* stderr output on stdout as well */
extern char *First_name; /* first name in printcap entry */
extern FILE *Lfd; /* lock file */
extern int Optind, Opterr; /* option index, error message suppression */
extern char *Optarg; /* option value */
extern char *Opt_flag; /* option staring flags */
extern char Lpdlogf[]; /* = DEFLPDLOGF; */
extern char Masterlock[]; /* = MASTERLOCK; */
extern int Lpr_port_num; /* port number to connect to */
extern int Maxportno; /* = MAXPORTNO; */
extern int Minportno; /* = MINPORTNO; */
extern char Permfile[]; /* = PERMFILE; */
extern char Printcap[]; /* = PRINTCAP; */
extern char Last_errormsg[]; /* last errormessage */
extern int Request; /* current lpd request code */
extern int Print_fd; /* output printer FILE */
extern int Short_format; /* short status format */
extern int Is_root; /* is this the root user? */
extern int Is_local; /* doing this locally or remotely? */
extern struct stat LO_statb; /* used to stat lockfile */
extern void Print_close(), Link_close(); /* close these things */
extern int Daemon_uid; /* daemon UID */
extern int Daemon_gid; /* daemon GID */
extern char *estrcp(); /* handy form of strcp() */
extern char *Time_str(); /* ctime with \n removed */
extern char *Setup_filter(); /* set up argv for a filter */
extern int Reapchild(); /* wait3() for a child */
extern int Getopt(); /* get command line option */
extern char *Errormsg(); /* printable error message */
extern int Errorcode; /* exit() value on fatal termination */
extern char *Decode_status(); /* decode a status returned by wait() */
extern FILE *fopen_daemon(); /* open a file as daemon */
extern int open_daemon(); /* open a file as daemon */
X
X/*******************************************************************
X * struct queue
X * used to record entries in the spool directory for printing
X * and status reporting.
X * NOTE: control and data file names in spool directory have the form
X * c f <priority> <job number> <Hostname> <terminating 0>
X * d f <seq> <job number> <Hostname> <terminating 0>
X * 1 1 1 3 max 64 1
X * eg: dfA001attila.cs.umn.edu (attila the SUN, of course)
X * eg: cfZ001attila.cs.umn.edu (attila the SUN, of course)
X *******************************************************************/
X#define CFNAMELEN (sizeof(Host)+8) /* control or data file name length */
X/*
X * fields in the name
X */
X#define STARTPR 2 /* df[] */
X#define STARTID 3 /* dfX[] */
X#define IDLEN 3 /* dfX[NNN] */
X#define STARTFR 6 /* dfXNNN[] */
X#define MAXPARMLEN 80
struct queue {
X char q_name[CFNAMELEN+1]; /* name of the control file */
X time_t q_time; /* modification time */
X time_t q_sp; /* spooled at time */
X time_t q_unsp; /* unspool at time */
X int q_priority; /* priority */
X long q_size; /* size of the data files */
X char q_user[32]; /* user name */
X int q_num; /* job number */
X char q_data[MAXPARMLEN+1]; /* data files name */
X int q_daemon; /* daemon for this entry */
X char *q_server; /* server for this entry */
X};
X
X#define q_from q_name[STARTFR]
extern int Getq(); /* find queue entries */
extern struct queue *Jobentry; /* current job entry in queue */
extern struct queue *Queue; /* Getq generates an array of jobs */
extern int Jobcount; /* and returns the number of jobs */
X
extern int Rec_cnt; /* number of files in a job */
X
X/********************************************************************
X * File Permissions
X ********************************************************************/
X
X#define LFMODE 0644 /* log file permissions */
X#define FILMOD 0600 /* spooling directory file permission */
X
X/*
X * Queue Control is done by using the permissions of the lock file
X * for the queue. The following permissions are used:
X * Disable Printing: owner execute or 0100
X * Disable Queing: group execute or 0010
X * Queue handler active (antique) 0001
X */
X#define DISABLE_PRINT (0100)
X#define ENABLE_PRINT (0777 & ~ DISABLE_PRINT)
X#define DISABLE_QUEUE (0010)
X#define ENABLE_QUEUE (0777 & ~ DISABLE_QUEUE)
X#define FORCE_REQUE (0001)
X#define CLEAR_REQUE (0777 & ~ FORCE_REQUE)
X
X/*
X * syslog(8) message priorities. These are defined by the values of
X * global variables. The variables are initialized either with values
X * in the <syslog.h> include file, or by a set of default values according
X * to the NOSYSLOG option in the Makefile.
X */
extern int XLOG_ERR; /*4 synonym of LOG_ERROR */
extern int XLOG_CRIT; /*5 critical information */
extern int XLOG_WARNING; /*6 warning */
extern int XLOG_NOTICE; /*7 important information */
extern int XLOG_INFO; /*8 informational message */
extern int XLOG_DEBUG; /*9 Debug level info */
X
X/*******************************************************************
X * Printcap Data Structures
X * The printcap file information is extracted using a single pass of
X * the printcap database. As each entry is found, it is looked up
X * in a table which has the entry tag, the type of entry,
X * a default value, and the variable used to hold the value.
X *
X * The table is sorted alphabetically by the tag values and the update
X * routines use a modified binary search. The time taken to read the
X * printcap entry is proportional to
X * K log( M ), where K is the length of the printcap file and M is
X * the number of printcap variables. Note that this appears to be
X * a much simpler and easier way to implement printcap information
X * extraction. The "initialization" of the entire set of variables
X * is extremely fast, apparently taking about the same time as reading
X * two variables using the original "termcap" code.
X *******************************************************************/
typedef struct pc_entry{
X char pc_name[3]; /* two character name, and the last char */
X int kind; /* the kind of entry */
X# define PC_NUM 0 /* integer */
X# define PC_FLAG 1 /* integer */
X# define PC_STRING 2 /* string */
X int idefault; /* this is the default integer or flag value */
X char *sdefault; /* this is the default integer or flag value */
X /*
X * the variable is assumed to be a pointer to char;
X * this is cast to pointer to int if neccessary.
X */
X char **var;
X} PC_ENTRY;
X
X/*
X * Routines to look up printer names and printcap entries
X * char ** All_printers(): reads the printcap database and extracts the
X * names of all the printer entries.
X * char *First_printer(): gets name of first printer
X * Get_pc_entry(): given name of a printer and an array of PC_ENTRIES,
X * it finds the printcap entry and extracts all the information
X * for the variables listed in the array.
X * Set_pc_entry(): same functionality, does not initialize variables.
X */
X#define PRNAMELEN 32 /* Maximum of 32 characters for printer name */
X#define MAXPCNAMES 100 /* Maximum of 100 printers */
extern int Get_pc_entry( /* char *name; PC_ENTRY *pc_vars; int pc_len */);
extern int Set_pc_entry( /* char *name; PC_ENTRY *pc_vars; int pc_len */);
extern char **All_printers(); /* returns array printer names */
extern char *First_printer(); /* returns array printer names */
X/*
X * All_pc_vars[]: all printcap variables, and is used by lpr and lpd;
X * Status_pc_vars[]: a short set needed by lpq, lprm, and lpc.
X * Server_pc_vars[]: a few needed by servers only
X */
extern PC_ENTRY All_pc_vars[ /* All_pc_len */ ];
extern int All_pc_len;
extern PC_ENTRY Status_pc_vars[ /* Status_pc_len */ ];
extern int Status_pc_len;
extern PC_ENTRY Server_pc_vars[ /* Server_pc_len */ ];
extern int Server_pc_len;
X
X/***********************************************************************
X * File Locking Support:
X * see lockfile.c for details.
X ***********************************************************************/
extern FILE *Readlockfile(); /* reads file, returns FILE * */
extern FILE *Getlockfile(); /* locks file, returns FILE * */
extern int Checklockfile(); /* checks for lock and daemon */
extern FILE *Lockcf(); /* lock a control file */
extern int Exlockcf(); /* create and lock a control file */
X
X/***********************************************************************
X * Parameter List Support
X * struct parm parmlist[]
X * is used when parsing a command received from a remote Host
X * It is also used by lpr to determine the command file, and to keep
X * track of the file/datafile name correspondence.
X ***********************************************************************/
X#define MAXPARMS 50
struct parm{
X char *str; /* string parameter */
X int num; /* number parameter */
X char filename[CFNAMELEN+1]; /* file name for parameter */
X long size; /* size of file */
X};
extern struct parm Parms[MAXPARMS]; /* array of parmaters */
extern int Parmcount; /* number of parameters */
X
X/***********************************************************************
X * Request types
X * A request sent to the LPD daemon has the format:
X * \Xprinter [options], where \X is a single character or byte value.
X * The following are the values and commands
X ***********************************************************************/
X#define REQ_START 1 /* start printer */
X#define REQ_RECV 2 /* transfer a job to the Host from a remote site */
X#define REQ_DSHORT 3 /* print short form of queue status */
X#define REQ_DLONG 4 /* print long form of queue status */
X#define REQ_REMOVE 5 /* remove jobs */
X#define REQ_CONTROL 6 /* do control operation */
X/**************************************************************************
X * Control file format
X * First character is kind of entry, remainder of line is
X * the argument.
X *
X * 1 -- "R font file" for troff -ignore
X * 2 -- "I font file" for troff -ignore
X * 3 -- "B font file" for troff -ignore
X * 4 -- "S font file" for troff -ignore
X * C -- "class name" on banner page
X * H -- "Host name" of machine where lpr was done
X * I -- "indent" amount to indent output
X * J -- "job name" on banner page
X * L -- "literal" user's name to print on banner
X * M -- "mail" to user when done printing
X * N -- "name" of file (used by lpq)
X * P -- "Person" user's login name
X * R -- account id for charging
X * U -- "unlink" name of file to remove after we print it
X * W -- "width" page width for PR
X * X -- "header" header title for PR
X * Z -- xtra options to filters
X *
X * Lower case letters are formats
X * f -- "file name" name of text file to print
X * l -- "file name" text file with control chars
X * p -- "file name" text file to print with pr(1)
X * t -- "file name" troff(1) file to print
X * n -- "file name" ditroff(1) file to print
X * d -- "file name" dvi file to print
X * g -- "file name" plot(1G) file to print
X * v -- "file name" plain raster file to print
X * c -- "file name" cifplot file to print
X *
X * CFparm is used to hold the upper case parameters
X */
extern char CFparm[26][MAXPARMLEN+1];
X#define CLASSNAME CFparm['C'-'A']
X#define WHENSP CFparm['D'-'A']
X#define FROMHOST CFparm['H'-'A']
X#define INDENT CFparm['I'-'A']
X#define JOBNAME CFparm['J'-'A']
X#define BNRNAME CFparm['L'-'A']
X#define FILENAME CFparm['N'-'A']
X#define MAILNAME CFparm['M'-'A']
X#define LOGNAME CFparm['P'-'A']
X#define ACCNTNAME CFparm['R'-'A']
X#define NOHEADER CFparm['S'-'A']
X#define WHENUNSP CFparm['T'-'A']
X#define UNLNKFILE CFparm['U'-'A']
X#define PWIDTH CFparm['W'-'A']
X#define PRTITLE CFparm['X'-'A']
X#define ZOPTS CFparm['Z'-'A']
X
X/*
X * printjob return codes
X */
X#define JBUSY -1 /* being done by other means */
X#define JFAIL 0 /* repeat with retry */
X#define JSUCC 1 /* done */
X#define JABORT 2 /* done, but problems */
X
X/*
X * Mail program
X */
X#ifndef MAIL
X#define MAIL "/usr/lib/sendmail"
X#endif MAIL
X
X/*
X * File Transfer Protocol Flags
X */
X#define CEND 5 /* last file */
X#define CNAME 4 /* control file */
X#define DFILE 3 /* data file */
X#define CFILE 2 /* control file */
X
X/*
X * Local parameters to the spooling system
X * Defaults for line printer capabilities data base
X */
X#define DEFLOGF "log"
X#define DEFLOCK "lock"
X#define DEFSTAT "status"
X#define DEFACCT "acct"
X#define DEFFORMATS "flp" /* default formats */
X#define DEFMX 1000
X#define DEFRETRY 3 /* maximum number of retries */
X#define DEFMAXCOPIES 0
X#define DEFFF "\f"
X#define DEFWIDTH 132
X#define DEFLENGTH 66
X#define DAEMON "daemon" /* daemon user id */
X#define DEFPRICE 20 /* cost in dollars per thousand pages */
X#define DEFPRIORITY 'Z' /* default priority level */
X#define DEFPR "/bin/pr" /* default pr program */
X
X/*
X * REAL, not TEST version
X */
X
X/*
X * path name of files created by lpd.
X */
X#define RMASTERLOCK "/usr/spool/lpd/lpd.lock."
X#define RDEFLPDLOGF "/usr/spool/lpd/lpd.log."
X#ifdef ETCPC
X# define RPRINTCAP ETCPC
X#else
X# define RPRINTCAP "/usr/spool/lpd/printcap."
X#endif
X/*
X * connection services to be used
X */
X#define SERVERNAME "printer"
X#define SERVERPROT "tcp"
X/* name of the printer permissions file */
X#ifdef ETCPERMS
X# define RPERMFILE ETCPERMS
X#else
X# define RPERMFILE "/usr/spool/lpd/printer_perms."
X#endif
X/*
X * The remote client must call from a port in the following range.
X * This is used for authentication purposes. The ports less than
X * IPPORT_RESERVED are accessible only to SU processes.
X */
X#define RMINPORTNO (IPPORT_RESERVED/2)
X#define RMAXPORTNO (IPPORT_RESERVED)
X
X/*
X * DEBUG Version, use to avoid screwing up normal operations
X * path name of files created by lpd.
X */
X#define TMASTERLOCK "/tmp/lpd.lock."
X#define TDEFLPDLOGF "/tmp/lpd.log."
X#define TPRINTCAP "/tmp/printcap."
X/*
X * connection services to be used
X */
X#define TSERVICENAME "testlpr"
X#define TPORTNUM 1600 /* test port number */
X/* name of the printer permissions file */
X#define TPERMFILE "/tmp/printer_perms."
X/*
X * The remote client must call from a port in the following range.
X * This is used for authentication purposes. The ports less than
X * IPPORT_RESERVED are accessible only to SU processes.
X */
X#define TMINPORTNO (IPPORT_RESERVED+1)
X#define TMAXPORTNO (2*IPPORT_RESERVED)
END_OF_FILE
if test 23350 -ne `wc -c <'src/lp.h'`; then
echo shar: \"'src/lp.h'\" unpacked with wrong size!
fi
# end of 'src/lp.h'
fi
if test -f 'src/utils.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/utils.c'\"
else
echo shar: Extracting \"'src/utils.c'\" \(25393 characters\)
sed "s/^X//" >'src/utils.c' <<'END_OF_FILE'
X/***************************************************************************
X * U. Minnesota LPD Software * Copyright 1987, 1988, Patrick Powell
X ***************************************************************************
X * MODULE: utils.c
X * Utility routines used by several programs
X ***************************************************************************
X * Revision History: Created Sat Jan 9 15:02:12 CST 1988
X * $Log: utils.c,v $
X * Revision 3.2 88/06/24 17:55:27 papowell
X * MODS for VAX 4.3BSD UNIX
X *
X * Revision 3.1 88/06/18 09:35:55 papowell
X * Version 3.0- Distributed Sat Jun 18 1988
X *
X * Revision 2.4 88/05/19 10:34:26 papowell
X * Fixed open() calls to have a 0 parameter, ie: open(f, perms, 0), where needed
X *
X * Revision 2.3 88/05/16 12:09:27 papowell
X * Spelling mistake in error messages
X *
X * Revision 2.2 88/05/14 10:18:31 papowell
X * Use long format for job file names;
X * Added 'fd', no forward flag;
X * Control file has to have hostname and origination agree.
X *
X * Revision 2.1 88/05/09 10:10:42 papowell
X * PLP: Released Version
X *
X * Revision 1.7 88/04/27 20:27:34 papowell
X * Modified to remove unused variables
X *
X * Revision 1.6 88/04/15 13:06:55 papowell
X * Std_environ() call added, to ensure that fd 0 (stdin), 1 (stdout), 2(stderr)
X * have valid file descriptors; if not open, then /dev/null is used.
X *
X * Revision 1.5 88/03/25 15:01:57 papowell
X * Debugged Version:
X * 1. Added the PLP control file first transfer
X * 2. Checks for MX during file transfers
X * 3. Found and fixed a mysterious bug involving the SYSLOG facilities;
X * apparently they open files and then assume that they will stay
X * open.
X * 4. Made sure that stdin, stdout, stderr was available at all times.
X *
X * Revision 1.4 88/03/12 10:03:45 papowell
X * *** empty log message ***
X *
X * Revision 1.3 88/03/11 19:29:25 papowell
X * Minor Changes, Updates
X *
X * Revision 1.2 88/03/05 15:01:28 papowell
X * Minor Corrections, Lint Problems
X *
X * Revision 1.1 88/03/01 11:09:27 papowell
X * Initial revision
X *
X ***************************************************************************/
X#ifndef lint
static char id_str1[] =
X "$Header: utils.c,v 3.2 88/06/24 17:55:27 papowell Exp $ PLP Copyright 1988 Patrick Powell";
X#endif lint
X
X#include "lp.h"
X/*
X * Time_str: return ctime() value, but without terminating '\n'
X */
char *
Time_str()
X{
X time_t tvec; /* time */
X char *ctime();
X static char s[40];
X
X (void)time(&tvec);
X (void)strcpy(s,ctime(&tvec));
X s[strlen(s)-1] = 0;
X return( s );
X}
X
X/***************************************************************************
X * Remove_job( FILE *fp; struct queue *q )
X * Remove a job and all associated files; if success == JSUCC, remove
X * U links as well
X * ACTIONS:
X * 1. Read the control file
X * 2. get data file names and unlink them if they match the job
X * 3. Unlink the control file
X ***************************************************************************/
X
Remove_job( fp, q )
X FILE *fp;
X struct queue *q;
X{
X char parm[BUFSIZ]; /* line buffer */
X char *arg; /* pointer to the argument */
X int c; /* ACME Integers, Inc. */
X
X if(Debug>5)log(XLOG_DEBUG,"Remove_job: %s", q->q_name );
X clearerr( fp );
X if( fseek( fp, 0L, 0 ) < 0 ){
X logerr_die( XLOG_INFO,
X "Remove_job: fseek failed (%s)", q->q_name );
X } else {
X /*
X * read through the file, looking for things to remove
X */
X while(fgets( parm, sizeof(parm), fp )){
X if( (arg = index(parm, '\n')) == 0 ){
X log( XLOG_INFO, "Remove_job: file bad (%s), no endline",
X q->q_name);
X continue;
X }
X *arg = 0;
X arg = parm+1;
X c = parm[0];
X /*
X * is it a format line?
X */
X if( !isascii( c ) || !islower( c ) ){
X continue;
X }
X if( Job_match( q->q_name, arg ) == 0){
X if(Debug>4)log(XLOG_DEBUG,"Remove_job: bad file name '%s'",
X arg );
X continue;
X }
X (void)unlink_daemon( arg );
X }
X }
X if( unlink_daemon( q->q_name ) < 0 ){
X logerr( XLOG_INFO, "Remove_job: cannot unlink %s", q->q_name );
X }
X}
X/***************************************************************************
X * int Getq();
X * Scan the spool directory and make a list of server files sorted by
X * priority, creation time, etc.
X * Returns: the number of entries
X * Side Effects: sets struct queue *Queue to point to an array of pointers
X * to queue entries
X ***************************************************************************/
static int arraysz; /* number of entries in array */
static struct queue qb; /* for zeroing purposes */
X
Getq()
X{
X struct direct *d; /* directory entry */
X int nitems; /* ACME Integers, Inc. */
X struct stat stbuf; /* for statting files */
X int compar(); /* for sorting files */
X DIR *dirp; /* used by directory routines */
X char l[BUFSIZ]; /* for reading the control file */
X char fullname[BUFSIZ]; /* for the full pathname */
X char *filepart; /* end of the pathname */
X FILE *cfp; /* control file FP */
X struct queue *q; /* pointer to queue entry */
X char *bp, *ep; /* ACME Pointers, Inc. */
X
X if (SD == 0 || *SD == 0 ){
X fatal( XLOG_INFO, "no directory entry" );
X }
X if ((dirp = opendir(SD)) == NULL){
X logerr_die( XLOG_INFO, "cannot open spool directory %s", SD );
X }
X
X /*
X * get the directory name and copy to buffer
X */
X if( strlen(SD) + sizeof(q->q_name) + 2 > sizeof(fullname) ){
X logerr_die( XLOG_NOTICE,"INTERNAL: Getq, file name too big" );
X }
X (void)strcpy(fullname,SD);
X filepart = &fullname[strlen(fullname)];
X *filepart++ = '/';
X /*
X * assume you have 100 entries to start with
X */
X if( arraysz == 0 ){
X arraysz = 100;
X Queue = (struct queue *)malloc(
X (unsigned)(arraysz * sizeof(struct queue)));
X if (Queue == NULL){
X logerr_die( XLOG_INFO, "Getq: malloc failed" );
X }
X }
X /*
X * set the item count to 0 and scan the directory
X */
X nitems = 0;
X while ((d = readdir(dirp)) != NULL) {
X if(Debug>5)log(XLOG_DEBUG,"Getq: file %s", d->d_name );
X
X if (d->d_name[0] != 'c' || d->d_name[1] != 'f'){
X continue; /* server control files only */
X }
X /*
X * Check to make sure the array has space left and
X * realloc the maximum size.
X */
X if( nitems >= arraysz ){
X /* try to get another buffer */
X arraysz = arraysz + 20;
X Queue = (struct queue *)realloc((char *)Queue,
X (unsigned)((arraysz)*sizeof(struct queue)));
X if (Queue == NULL){
X logerr_die(XLOG_NOTICE,"malloc failed in Getq" );
X }
X }
X /*
X * get next queue entry and clear it
X */
X q = &Queue[nitems];
X *q = qb; /* zero it out the easy way */
X
X if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s", d->d_name );
X
X /* copy the name of the file */
X if( strlen( d->d_name ) >= CFNAMELEN){
X logerr_die(XLOG_NOTICE,"control file name %s too long", d->d_name );
X }
X (void)strcpy(q->q_name, d->d_name);
X (void)strcpy(filepart,d->d_name);
X if (stat(fullname, &stbuf) < 0){
X continue; /* Doesn't exist */
X }
X /* get the modification time */
X q->q_time = stbuf.st_mtime;
X /* set a priority */
X q->q_priority = d->d_name[2];
X /* get the job number */
X q->q_num = atoi( &d->d_name[3] );
X
X /*
X * now we open the control file and read the information
X */
X if( (cfp = fopen_daemon( fullname, "r" )) == NULL ){
X /* it disappeared */
X continue;
X }
X if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s readable", d->d_name );
X bp = q->q_data;
X ep = bp + sizeof(q->q_data);
X while( fgets( l, sizeof(l), cfp) ){
X /* clobber the \n */
X l[strlen(l)-1] = 0;
X if( islower( l[0] ) ){
X /* get size of file to be printed */
X (void)strcpy(filepart, &l[1] );
X if( stat( fullname, &stbuf) < 0){
X (void)fclose(cfp);
X if(Debug>5)log(XLOG_DEBUG,
X "Getq: data file %s does not exist", l );
X } else {
X q->q_size += stbuf.st_size;
X }
X } else switch( l[0] ){
X case 'N': /* name of file */
X bp = estrcp( bp, &l[1], ep );
X bp = estrcp( bp, " ", ep );
X break;
X case 'P': /* name of user */
X (void)strncpy( q->q_user, &l[1], sizeof(q->q_user)-1);
X break;
X case 'D': /* when spooled */
X q->q_sp = (time_t)atol( &l[1] );
X break;
X case 'T': /* when to be unspooled */
X q->q_unsp = (time_t)atol( &l[1] );
X break;
X default: break;
X }
X }
X if(Debug>5)log(XLOG_DEBUG,"Getq: control file %s is ok", d->d_name );
X
X (void)fclose(cfp);
X ++nitems;
X }
X closedir(dirp);
X
X /*
X * sort the queue
X */
X if (nitems){
X qsort((char *)Queue, nitems, sizeof(struct queue), compar);
X }
X return(nitems);
X}
X
X
X/*
X * Compare queue entries by
X * 1. Priority
X * 2. Time
X */
static
compar(c1, c2)
X char *c1, *c2;
X{
X struct queue *p1, *p2;
X
X p1 = (struct queue *)c1;
X p2 = (struct queue *)c2;
X if ((p1)->q_priority < (p2)->q_priority)
X return(-1);
X if ((p1)->q_priority > (p2)->q_priority)
X return(1);
X if ((p1)->q_time < (p2)->q_time)
X return(-1);
X if ((p1)->q_time > (p2)->q_time)
X return(1);
X return(0);
X}
X
X/***************************************************************************
X * Match_entry( struct queue *q )
X * check the user name and job number against the parmlist starting at start;
X * Return: 1 if match found, 0 otherwise
X ***************************************************************************/
int
Match_entry( q )
X struct queue *q;
X{
X int i; /* ACME Integer, Inc. */
X
X if(Debug>4)log(XLOG_DEBUG,"Match_entry on %s, %d", q->q_user, q->q_num );
X for( i = 0; i < Parmcount; ++i ){
X if( (Parms[i].num >= 0 && Parms[i].num == q->q_num)
X || strcmp( Parms[i].str, q->q_user ) == 0 ){
X return(1);
X }
X }
X return(0);
X}
X
X/***************************************************************************
X * bpread( int fd ; char *buf; int size )
X * Almost bombproof way to read command line from socket
X * Returns: -1 if unable to read a line terminated with \n
X * 0 if 0 length line or first character is null (i.e.- no input)
X * otherwise: length of line
X ***************************************************************************/
bpread( fd, buf, size )
X int fd;
X char *buf;
X int size;
X{
X int n; /* ACME Integer, Inc. */
X int i;
X
X /*
X * Bombproof line reading
X */
X for( i = 0; i < size; ++i ){
X n = read(fd, &buf[i], 1);
X if( n < 0 ){
X logerr(XLOG_INFO,"bpread: lost connection");
X return( -1 );
X } else if( n == 0 ){
X log(XLOG_INFO,"bpread: bad format %s", buf );
X return( 0 );
X }
X if( buf[i] == '\n' ){
X buf[i] = 0;
X if(Debug>3)log(XLOG_DEBUG,"bpread: '%d' %s", buf[0], &buf[1]);
X return( i );
X } else if( buf[i] == 0 && i == 0 ){
X if(Debug>3)log(XLOG_DEBUG,"bpread: zero byte first");
X return( i );
X }
X }
X log(XLOG_INFO,"bpread: bad line %s", buf );
X return( -1 );
X}
X/***************************************************************************
X * estrcp(char *s, *t, *e)
X * copies t to s, and returns the end position
X * Returns: end of string if the result is shorter than e, NULL otherwise
X * Note: this is a very useful routine. Think about adding it to string
X * functions.
X ***************************************************************************/
char *
estrcp( s,t,e )
X char *s, *t, *e;
X{
X if( s ){
X while( (*s++ = *t++) && (s < e) );
X if( s < e ){
X return( s-1 );
X } else {
X return( (char *)0 );
X }
X }
X return( s );
X}
X/***************************************************************************
X * splitline( char *line )
X * splits a line into tokens, and places them in the Parms[] array.
X * if firstarg is present then it is set to the first argument
X * Side Effects: modifies Parms, Parmcount
X ***************************************************************************/
X
splitline( bp )
X char *bp;
X{
X /* find the start */
X while (*bp) {
X while( *bp && isspace(*bp))
X bp++;
X if( *bp ){
X if( Parmcount >= MAXPARMS ){
X fatal(XLOG_INFO,"splitline: too many requests");
X }
X Parms[Parmcount].str = bp;
X if (isdigit(*bp)) {
X Parms[Parmcount].num = atoi(bp);
X } else {
X Parms[Parmcount].num = -1;
X }
X Parmcount++;
X }
X while( *bp && !isspace(*bp))
X bp++;
X if( *bp )
X *bp++ = 0;
X }
X}
X/**********************************************************************
X * Shift_parms( int n )
X * left shift the entries in the Parms[] array by n
X * Side Effects: modifies Parms and Parmcount
X **********************************************************************/
Shift_parms( n )
X int n;
X{
X int i; /* ACME Chain and Integer, Inc. */
X while( Parmcount > 0 && n > 0 ){
X for( i = 1; i < Parmcount; ++i ){
X Parms[i-1] = Parms[i];
X }
X --Parmcount;
X --n;
X }
X}
X
printstatus()
X{
X if( ST && *ST ){
X if(Debug>4)log(XLOG_DEBUG,"printstatus: ST %s", ST );
X pr_stat_file( ST );
X }
X if( PS && *PS ){
X if(Debug>4)log(XLOG_DEBUG,"printstatus: PS %s", PS );
X pr_stat_file( PS );
X }
X}
X
pr_stat_file( file )
X char *file;
X{
X FILE *fp;
X char buf[BUFSIZ];
X
X if( (fp = fopen_daemon( file, "r" )) != NULL ){
X while( fgets( buf, sizeof(buf), fp) != NULL ){
X (void)fprintf(stdout, " %s", buf );
X }
X (void)fflush(stdout);
X (void)fclose( fp );
X }
X}
X/***************************************************************************
X * char *Sigstr(n)
X * Return a printable form the the signal
X ***************************************************************************/
X
struct signame{
X char *str;
X int value;
X} signals[] = {
X{ "SIGHUP", SIGHUP }, { "SIGINT", SIGINT }, { "SIGQUIT", SIGQUIT },
X{ "SIGILL", SIGILL }, { "SIGTRAP", SIGTRAP }, { "SIGIOT", SIGIOT },
X{ "SIGEMT", SIGEMT }, { "SIGFPE", SIGFPE }, { "SIGKILL", SIGKILL },
X{ "SIGBUS", SIGBUS }, { "SIGSEGV", SIGSEGV }, { "SIGSYS", SIGSYS },
X{ "SIGPIPE", SIGPIPE }, { "SIGALRM", SIGALRM }, { "SIGTERM", SIGTERM },
X{ "SIGURG", SIGURG }, { "SIGSTOP", SIGSTOP }, { "SIGTSTP", SIGTSTP },
X{ "SIGCONT", SIGCONT }, { "SIGCHLD", SIGCHLD }, { "SIGTTIN", SIGTTIN },
X{ "SIGTTOU", SIGTTOU }, { "SIGIO", SIGIO }, { "SIGXCPU", SIGXCPU },
X{ "SIGXFSZ", SIGXFSZ }, { "SIGVTALRM", SIGVTALRM }, { "SIGPROF", SIGPROF } };
int nsignals = sizeof( signals )/ sizeof( struct signame );
char *
Sigstr( n )
X int n;
X{
X int i;
X static char buf[40];
X
X for( i = 0; i < nsignals; ++i ){
X if( signals[i].value == n ){
X return( signals[i].str );
X }
X }
X (void)sprintf(buf,"unknown signal (%d)", n );
X return( buf );
X}
X/***************************************************************************
X * Decode_status( union wait *status )
X * returns a printable string encoding return status
X ***************************************************************************/
X
char *
Decode_status( status )
X union wait *status;
X{
X static char msg[BUFSIZ];
X
X (void)sprintf( msg, "user: %d, system: %d%s",
X status->w_retcode, status->w_termsig,
X status->w_coredump ? ", core dump, " : ", " );
X if( status->w_termsig ){
X (void)sprintf(msg+strlen(msg),"error- %s",
X Sigstr((int)status->w_termsig));
X }
X return( msg );
X}
X
X/*
X * Checkactive()
X * find the currently active files in the spool queue.
X * 1. check for the single server possibility first.
X * 2. find the Names of the servers
X * 3. find the active files for each of the servers
X */
X
int
Checkactive()
X{
X int i; /* ACME Integers, Inc. */
X char buf[BUFSIZ]; /* Name of active file */
X static char server[BUFSIZ]; /* Name of server file */
X char *sp, *ep; /* ACME Pointer */
X int pid;
X
X pid = 0;
X buf[0] = 0;
X if(Checklockfile(LO,&pid,buf,sizeof(buf),&LO_statb) && buf[0] ){
X for( i = 0; i < Jobcount; ++i ){
X if( strcmp( buf, Queue[i].q_name ) == 0 ){
X Queue[i].q_daemon = pid;
X Queue[i].q_server = Printer;
X } else {
X Queue[i].q_daemon = 0;
X Queue[i].q_server = 0;
X }
X }
X }
X /*
X * check for each of the servers
X */
X if( SV && *SV ){
X (void)strcpy( server, SV );
X for( sp = server; sp; sp = ep ){
X if( ep = index( sp, ',' ) ){
X *ep = 0;
X ++ep;
X }
X /*
X * get the lock file and the status from the server
X */
X buf[0] = 0;
X if(Checklockfile(sp,&pid,buf,sizeof(buf),(struct stat *)0)
X && buf[0] ){
X for( i = 0; i < Jobcount; ++i ){
X if( strcmp( buf, Queue[i].q_name ) == 0 ){
X Queue[i].q_daemon = pid;
X Queue[i].q_server = sp;
X } else {
X Queue[i].q_daemon = 0;
X Queue[i].q_server = 0;
X }
X }
X }
X }
X }
X return(pid);
X}
X
X
X/***************************************************************************
X * Get_Daemon()
X * Get the DAEMON uid and gid
X * Assume password entry has both values set for the user daemon
X ***************************************************************************/
Get_Daemon()
X{
X struct passwd *passwd, *getpwnam();
X if( Daemon_uid == 0 ){
X if( (passwd = getpwnam(DAEMON)) == 0 ){
X logerr_die( XLOG_INFO,"Get_Daemon: getpwnam(%s) failed", DAEMON );
X }
X Daemon_uid = passwd->pw_uid;
X Daemon_gid = passwd->pw_gid;
X if(Debug>4)log(XLOG_INFO,"Get_Daemon: uid=%d, gid=%d",
X Daemon_uid, Daemon_gid);
X }
X}
X
X/***************************************************************************
X * Job_match( char *control, *data)
X * Check to see if the control and data file names are matching
X * 1. data file must start with "df"
X * 2. next must be letter
X * 3. next must be 3 digit sequence number
X * 4. control and data file sequence number must match
X * return 1 if OK, 0 if not
X ***************************************************************************/
X
Job_match( control, data )
X char *control;
X char *data;
X{
X int c, i, j; /* ACME Chain and Integers, Inc. */
X
X i = strlen( data );
X for( j = 0; j < i ; ++j ){
X c = data[j];
X if( !isascii( c ) || !isprint( c ) ){
X log(XLOG_INFO, "Job_match: bad char in '%s'", data );
X return( 0 );
X }
X }
X if( index( data, '/' ) ){
X /*
X * tried to embed a / in the file name
X */
X log(XLOG_INFO, "Job_match: / present '%s'", data );
X return( 0 );
X }
X if( i > CFNAMELEN
X || i <= STARTFR
X || i != strlen( control )
X || index( "cd", data[0] ) == 0
X || (data[1] != 'f')
X || !isalpha( data[STARTPR] )
X || strcmp( control+STARTID, data+STARTID ) ){
X log(XLOG_INFO, "Job_match: bad match control '%s', data '%s'",
X control, data );
X return( 0 );
X }
X for( j = 0; j < IDLEN; ++ j ){
X if( !isdigit( data[j+STARTID] ) ){
X log(XLOG_INFO, "Job_match: bad sequence control '%s', data '%s'",
X control, data );
X return( 0 );
X }
X }
X if(Debug>5)log(XLOG_DEBUG,"Job_match: OK control '%s', data '%s'",
X control, data );
X return( 1 );
X}
X
X/***************************************************************************
X * Std_environ()
X * Make sure that fd 0, 1, 2 exist by opening /dev/null for them if they
X * have not been provided.
X * Set up the Host information as well
X ***************************************************************************/
X
Std_environ()
X{
X int fd;
X struct hostent *host_ent; /* host entry from data base */
X
X /*
X * close all file descriptors up to NOFILE
X */
X for (fd = 3; fd < NOFILE; fd++){
X (void) close(fd);
X }
X while( (fd = open( "/dev/null", O_RDWR, 0 )) >= 0 && fd < 3 );
X if( fd < 0 ){
X logerr_die( XLOG_CRIT, "Std_environ: cannot open /dev/null" );
X } else {
X (void)close(fd);
X }
X /*
X * get the Host computer Name
X */
X if( gethostname(Host, sizeof(Host)) < 0 ){
X logerr_die( XLOG_INFO, "Std_environ: gethostname failed" );
X }
X host_ent = gethostbyname( Host );
X if( host_ent == 0 ){
X fatal( XLOG_INFO, "Std_environ: host entry for '%' not found", Host );
X }
X if( strlen( host_ent->h_name ) > sizeof( Host ) ){
X fatal( XLOG_INFO, "Std_enviorn: host name is too long: '%s'",
X host_ent->h_name);
X }
X (void)strcpy(Host, host_ent->h_name );
X /*
X * Get Daemon UID
X */
X Get_Daemon();
X}
X
X/***************************************************************************
X * int open_daemon()
X * FILE *fopen_daemon()
X * int unlink_daemon()
X * Do the above actions as DAEMON.
X * Note that this is very difficult to do, and ensure that all the error
X * conditions are met. What you want to do is perform the following as
X * an uninterrupted critical section.
X * 1. setreuid( root, daemon)
X * 2. perform the action
X * 3. setreuid( whatever, root )
X * This will only work if
X * 1. you are really root
X * 2. you do not ever get interrupts
X ***************************************************************************/
static uid_t ruid, euid; /* real and effective UIDs */
static int uid_parm; /* must be able to hold -1 */
static int omask; /* block these signals */
X
X
void
Set_uid( new_uid )
X int new_uid;
X{
X /*
X * get the DAEMON UID, GID
X */
X omask = sigblock(sigmask(SIGCHLD)|sigmask(SIGHUP)
X |sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
X ruid = getuid();
X euid = geteuid();
X
X# ifdef SETREUID4BSD
X uid_parm = euid;
X# else
X uid_parm = -1;
X# endif SETREUID4BSD
X /*
X * check to see if we are running without SUID
X */
X if( euid && euid != getuid() && euid != new_uid ){
X log( XLOG_INFO, "Set_uid: euid %d, ruid %d, bad SUID?",
X euid, getuid() );
X /*
X * NOTE: do not try and take normal exit!!!
X */
X exit(1);
X } else if( euid == 0 && setreuid( uid_parm, new_uid ) < 0 ){
X logerr( XLOG_INFO, "Set_uid: setreuid( %d, %d) failed",
X uid_parm, new_uid );
X exit(1);
X }
X if(Debug>4)log(XLOG_DEBUG,"Set_uid: uid_parm %d, uid %d, euid %d",
X uid_parm, getuid(), geteuid());
X}
X/*
X * set the UID to DAEMON
X */
void
Set_daemon()
X{
X /*
X * get the DAEMON UID, GID
X */
X Get_Daemon();
X Set_uid( Daemon_uid );
X}
X/*
X * set UID back to normal. Note that there are two versions of setreuid
X * available. The VAX 4.2/4.3 version allows you to swap RUID/EUID
X * and will allow you only to set your UID if you are EUID root.
X * The SUN 3.X and others will allow you ONE call to the SUID function,
X * and will allow you to set the UID back to the original. The
X * uid_parm flag determines which strategy to use.
X * If uid_parm is -1, then you have to use setreuid( -1, euid )
X * If it is not, then we have to swap the EUID/UID, then set
X * the UID and EUID explicitly
X */
void
Clear_uid()
X{
X /*
X * handle the easy one first: set euid back to original
X */
X if( uid_parm == -1 ){
X if( setreuid( -1, euid ) < 0 ){
X logerr( XLOG_INFO,
X "Clear_uid: setreuid( %d, %d) from %d, %d failed",
X -1, euid, getuid(), geteuid() );
X /*
X * avoid problems, exit early
X */
X exit(1);
X }
X (void)sigsetmask(omask);
X return;
X }
X /*
X * otherwise we swap the UID and EUID, but first make sure that it is
X * consistent; uid should be the old (original) euid on entry to set_uid
X */
X if( getuid() != euid ){
X logerr( XLOG_INFO,
X "Clear_uid: uid is %d, euid is %d, and uid should be %d",
X getuid(), geteuid(), euid );
X exit(1);
X }
X /*
X * swap the RUID and EUID
X */
X if( setreuid( geteuid(), getuid() ) < 0 ){
X logerr( XLOG_INFO,
X "Clear_uid: setreuid( %d, %d) from %d, %d failed",
X geteuid(), getuid(), getuid(), geteuid() );
X /*
X * avoid problems, exit early
X */
X exit(1);
X }
X /*
X * Set the RUID and EUID explicitly
X */
X if( setreuid( ruid, euid ) < 0 ){
X logerr( XLOG_INFO,
X "Clear_uid: setreuid( %d, %d) from %d, %d failed",
X ruid, euid, getuid(), geteuid() );
X /*
X * avoid problems, exit early
X */
X exit(1);
X }
X (void)sigsetmask(omask);
X}
X
X/*
X * Open a file as daemon.
X */
int
open_daemon( name, flag, perms )
X char *name;
X int flag;
X int perms;
X{
X int fd, err;
X /*
X * establish UID
X */
X Set_daemon();
X /*
X * now for the plunge into the unknown
X */
X fd = open( name, flag, perms );
X err = errno;
X Clear_uid();
X errno = err;
X return( fd );
X}
X
X/*
X * fopen a file; the file has been created, and we want to do this as
X * daemon for permissions reasons.
X */
XFILE *
fopen_daemon( name, how )
X char *name;
X char *how;
X{
X int err;
X FILE *fp;
X /*
X * establish UID
X */
X Set_daemon();
X /*
X * now for the plunge into the unknown
X * NOTE: we are assuming that we only use this to READ a file already
X * created.
X */
X fp = fopen( name, how );
X err = errno;
X /*
X * done with the daemon stuff
X */
X Clear_uid();
X errno = err;
X return( fp );
X}
X
X/*
X * UNLINK a file as DAEMON
X */
unlink_daemon( name )
X char *name;
X{
X int f, err;
X /*
X * establish UID
X */
X Set_daemon();
X /*
X * now for the plunge into the unknown
X */
X f = unlink( name );
X err = errno;
X /*
X * done with the daemon stuff
X */
X Clear_uid();
X errno = err;
X return( f );
X}
X
X
X/*
X * CHMOD a file as DAEMON
X */
chmod_daemon( name, perms )
X char *name;
X int perms;
X{
X int f, err;
X /*
X * establish UID
X */
X Set_daemon();
X /*
X * now for the plunge into the unknown
X */
X f = chmod( name, perms );
X err = errno;
X /*
X * done with the daemon stuff
X */
X Clear_uid();
X errno = err;
X return( f );
X}
X
X/***************************************************************************
X * Rename_cf( char *tf )
X * rename the temporary file to a control file
X ***************************************************************************/
X
Rename_cf( tf )
X char *tf;
X{
X char from[MAXPATHLEN+1];
X char to[MAXPATHLEN+1];
X int i, err;
X
X (void)sprintf( from, "%s/%s", SD, tf );
X (void)sprintf( to, "%s/c%s", SD, tf+1 );
X if(Debug>4)log(XLOG_DEBUG,"Rename_cf: from '%s' to '%s'",from, to);
X Set_daemon();
X i = rename( from, to );
X err = errno;
X Clear_uid();
X errno = err;
X if( i < 0 ){
X logerr_die(XLOG_INFO,"Rename_cf: rename '%s' to '%s' failed",from, to);
X }
X}
X
X/***************************************************************************
X * Tailor_names()
X * Appends the Host information to several file names.
X ***************************************************************************/
static
append_name( s, t )
X char *s, *t;
X{
X if( (strlen(s) + strlen(t) + 2) > MAXPATHLEN ){
X fatal( XLOG_INFO,"append_name: names too long 's' + 't'", s, t);
X }
X (void)strcat( s, t);
X}
Tailor_names()
X{
X append_name( Lpdlogf, Host );
X append_name( Masterlock, Host );
X append_name( Permfile, Host );
X append_name( Printcap, Host );
X}
END_OF_FILE
if test 25393 -ne `wc -c <'src/utils.c'`; then
echo shar: \"'src/utils.c'\" unpacked with wrong size!
fi
# end of 'src/utils.c'
fi
echo shar: End of archive 15 \(of 16\).
cp /dev/null ark15isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 16 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0