Add a new command to 'lpc' called 'setstatus', which would be used to

change the status message of a print queue.  This includes some minor
changes to the upstat() routine, so that error messages are not printed
while seteuid(priv-user).

Reviewed by:	freebsd-audit and freebsd-print@bostonradio.org
MFC after:	10 days
This commit is contained in:
Garance A Drosehn 2002-06-15 22:51:58 +00:00
parent 4ce86ffd17
commit 54032d1198
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=98267
6 changed files with 140 additions and 28 deletions

View File

@ -79,6 +79,7 @@ static const char rcsid[] =
#define KQT_KILLOK 1
static void abortpr(struct printer *_pp, int _dis);
static char *args2line(int argc, char **argv);
static int doarg(char *_job);
static int doselect(struct dirent *_d);
static int kill_qtask(const char *lf);
@ -87,7 +88,7 @@ static int sortq(const void *_a, const void *_b);
static void startpr(struct printer *_pp, int _chgenable);
static int touch(struct jobqueue *_jq);
static void unlinkf(char *_name);
static void upstat(struct printer *_pp, const char *_msg);
static void upstat(struct printer *_pp, const char *_msg, int _notify);
static void wrapup_clean(int _laststatus);
/*
@ -103,11 +104,12 @@ enum qsel_val { /* how a given ptr was selected */
static enum qsel_val generic_qselect; /* indicates how ptr was selected */
static int generic_initerr; /* result of initrtn processing */
static char *generic_msg; /* if a -msg was specified */
static char *generic_nullarg;
static void (*generic_wrapup)(int _last_status); /* perform rtn wrap-up */
void
generic(void (*specificrtn)(struct printer *_pp),
generic(void (*specificrtn)(struct printer *_pp), int cmdopts,
void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[])
{
int cmdstatus, more, targc;
@ -115,7 +117,10 @@ generic(void (*specificrtn)(struct printer *_pp),
char **targv;
if (argc == 1) {
printf("usage: %s {all | printer ...}\n", argv[0]);
printf("usage: %s {all | printer ...}", argv[0]);
if (cmdopts & LPC_MSGOPT)
printf(" [-msg <text> ...]");
printf("\n");
return;
}
@ -136,6 +141,24 @@ generic(void (*specificrtn)(struct printer *_pp),
if (generic_nullarg == NULL)
generic_nullarg = strdup("");
/*
* Some commands accept a -msg argument, which indicates that
* all remaining arguments should be combined into a string.
*/
generic_msg = NULL;
if (cmdopts & LPC_MSGOPT) {
targc = argc;
targv = argv;
while (--targc) {
++targv;
if (strcmp(*targv, "-msg") == 0) {
argc -= targc;
generic_msg = args2line(targc - 1, targv + 1);
break;
}
}
}
/* call initialization routine, if there is one for this cmd */
if (initrtn != NULL) {
generic_initerr = 0;
@ -209,7 +232,34 @@ generic(void (*specificrtn)(struct printer *_pp),
if (generic_wrapup) {
(*generic_wrapup)(cmdstatus);
}
if (generic_msg)
free(generic_msg);
}
/*
* Convert an argv-array of character strings into a single string.
*/
static char *
args2line(int argc, char **argv)
{
char *cp1, *cend;
const char *cp2;
char buf[1024];
if (argc <= 0)
return strdup("\n");
cp1 = buf;
cend = buf + sizeof(buf) - 1; /* save room for '\0' */
while (--argc >= 0) {
cp2 = *argv++;
while ((cp1 < cend) && (*cp1++ = *cp2++))
;
cp1[-1] = ' ';
}
cp1[-1] = '\n';
*cp1 = '\0';
return strdup(buf);
}
/*
@ -242,7 +292,10 @@ abortpr(struct printer *pp, int dis)
printf("\tcannot disable printing: %s\n",
strerror(errno));
else {
upstat(pp, "printing disabled\n");
/* ..call newer upstat() in obsolete code.. */
upstat(pp, "printing disabled\n", 0);
/* ..the new upstat() did a setuid(uid).. */
seteuid(euid);
printf("\tprinting disabled\n");
}
} else if (errno == ENOENT) {
@ -252,7 +305,10 @@ abortpr(struct printer *pp, int dis)
strerror(errno));
else {
(void) close(fd);
upstat(pp, "printing disabled\n");
/* ..call newer upstat() in obsolete code.. */
upstat(pp, "printing disabled\n", 0);
/* ..the new upstat() did a setuid(uid).. */
seteuid(euid);
printf("\tprinting disabled\n");
printf("\tno daemon to abort\n");
}
@ -377,14 +433,16 @@ kill_qtask(const char *lf)
* Write a message into the status file.
*/
static void
upstat(struct printer *pp, const char *msg)
upstat(struct printer *pp, const char *msg, int notifyuser)
{
register int fd;
int fd;
char statfile[MAXPATHLEN];
status_file_name(pp, statfile, sizeof statfile);
umask(0);
seteuid(euid);
fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
seteuid(uid);
if (fd < 0) {
printf("\tcannot create status file: %s\n", strerror(errno));
return;
@ -395,6 +453,12 @@ upstat(struct printer *pp, const char *msg)
else
(void) write(fd, msg, strlen(msg));
(void) close(fd);
if (notifyuser) {
if ((msg == (char *)NULL) || (strcmp(msg, "\n") == 0))
printf("\tstatus message is now set to nothing.\n");
else
printf("\tstatus message is now: %s", msg);
}
}
/*
@ -442,11 +506,8 @@ abort_q(struct printer *pp)
break;
}
if (setres >= 0) {
seteuid(euid);
upstat(pp, "printing disabled\n");
seteuid(uid);
}
if (setres >= 0)
upstat(pp, "printing disabled\n", 0);
}
/*
@ -1132,6 +1193,31 @@ restart_q(struct printer *pp)
printf("\tdaemon restarted\n");
}
/*
* Set the status message of each queue listed. Requires a "-msg"
* parameter to indicate the end of the queue list and start of msg text.
*/
void
setstatus_gi(int argc __unused, char *argv[] __unused)
{
if (generic_msg == NULL) {
printf("You must specify '-msg' before the text of the new status message.\n");
generic_initerr = 1;
}
}
void
setstatus_q(struct printer *pp)
{
char lf[MAXPATHLEN];
lock_file_name(pp, lf, sizeof lf);
printf("%s:\n", pp->printer);
upstat(pp, generic_msg, 1);
}
/*
* Enable printing on the specified printer and startup the daemon.
*/
@ -1279,7 +1365,7 @@ stop(struct printer *pp)
printf("\tcannot disable printing: %s\n",
strerror(errno));
else {
upstat(pp, "printing disabled\n");
upstat(pp, "printing disabled\n", 0);
printf("\tprinting disabled\n");
}
} else if (errno == ENOENT) {
@ -1289,7 +1375,7 @@ stop(struct printer *pp)
strerror(errno));
else {
(void) close(fd);
upstat(pp, "printing disabled\n");
upstat(pp, "printing disabled\n", 0);
printf("\tprinting disabled\n");
}
} else
@ -1312,11 +1398,8 @@ stop_q(struct printer *pp)
setres = set_qstate(SQS_STOPP, lf);
if (setres >= 0) {
seteuid(euid);
upstat(pp, "printing disabled\n");
seteuid(uid);
}
if (setres >= 0)
upstat(pp, "printing disabled\n", 0);
}
struct jobqueue **queue;

View File

@ -55,6 +55,8 @@ char downhelp[] = "do a 'stop' followed by 'disable' and put a message in status
char helphelp[] = "get help on commands";
char quithelp[] = "exit lpc";
char restarthelp[] = "kill (if possible) and restart a spooling daemon";
char setstatushelp[] = "set the status message of a queue, requires\n"
"\t\t\"-msg\" before the text of the new message";
char starthelp[] = "enable printing and start a spooling daemon";
char statushelp[] = "show status of daemon and queue";
char stophelp[] = "stop a spooling daemon after current job completes and disable printing";
@ -62,7 +64,9 @@ char tcleanhelp[] = "test to see what files a clean cmd would remove";
char topqhelp[] = "put job at top of printer queue";
char uphelp[] = "enable everything and restart spooling daemon";
#define PR 1 /* a privileged command */
/* Use some abbreviations so entries won't need to wrap */
#define PR LPC_PRIVCMD
#define M LPC_MSGOPT
struct cmd cmdtab[] = {
{ "abort", aborthelp, PR, 0, abort_q },
@ -76,6 +80,7 @@ struct cmd cmdtab[] = {
{ "restart", restarthelp, 0, 0, restart_q },
{ "start", starthelp, PR, 0, start_q },
{ "status", statushelp, 0, 0, status },
{ "setstatus", setstatushelp, PR|M, setstatus_gi, setstatus_q },
{ "stop", stophelp, PR, 0, stop_q },
{ "tclean", tcleanhelp, 0, init_tclean, clean_q },
{ "topq", topqhelp, PR, topq, 0 },

View File

@ -47,7 +47,7 @@ void clean_q(struct printer *_pp);
void disable_q(struct printer *_pp);
void down(int _argc, char *_argv[]);
void enable_q(struct printer *_pp);
void generic(void (*_specificrtn)(struct printer *_pp),
void generic(void (*_specificrtn)(struct printer *_pp), int _cmdopts,
void (*_initcmd)(int _argc, char *_argv[]),
int _argc, char *_argv[]);
void help(int _argc, char *_argv[]);
@ -55,6 +55,8 @@ void init_clean(int _argc, char *_argv[]);
void init_tclean(int _argc, char *_argv[]);
void quit(int _argc, char *_argv[]);
void restart_q(struct printer *_pp);
void setstatus_gi(int _argc, char *_argv[]);
void setstatus_q(struct printer *_pp);
void start_q(struct printer *_pp);
void status(struct printer *_pp);
void stop_q(struct printer *_pp);

View File

@ -32,7 +32,7 @@
.\" @(#)lpc.8 8.5 (Berkeley) 4/28/95
.\" $FreeBSD$
.\"
.Dd June 20, 2001
.Dd June 15, 2002
.Dt LPC 8
.Os
.Sh NAME
@ -58,7 +58,11 @@ disable or enable a printer's spooling queue,
rearrange the order of jobs in a spooling queue,
.It
find the status of printers, and their associated
spooling queues and printer daemons.
spooling queues and printer daemons,
.It
change the status message for printer queues (the status message
may be seen by users as part of the output of the
.Xr lpq 1 utility).
.El
.Pp
Without any arguments,
@ -139,6 +143,17 @@ will report that there is no daemon present when this condition occurs.
If the user is the super-user,
try to abort the current daemon first (i.e., kill and restart a stuck daemon).
.Pp
.It Ic setstatus Bro Cm all | Ar printer Brc Cm -msg Ar message ...
Set the status message for the specified printers.
The
.Ic -msg
argument is required to separate the list of printers from the text
that will be the new status message.
This is normally used to change the status message when the printer
queue is no longer active after printing has been disabled, and you
want to change what users will see in the output of the
.Xr lpq 1 utility.
.Pp
.It Ic start Brq Cm all | Ar printer
Enable printing and start a spooling daemon for the listed printers.
.Pp

View File

@ -110,12 +110,14 @@ main(int argc, char *argv[])
printf("?Invalid command\n");
exit(1);
}
if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
if ((c->c_opts & LPC_PRIVCMD) && getuid() &&
ingroup(LPR_OPER) == 0) {
printf("?Privileged command\n");
exit(1);
}
if (c->c_generic != 0)
generic(c->c_generic, c->c_handler, argc, argv);
generic(c->c_generic, c->c_opts, c->c_handler,
argc, argv);
else
(*c->c_handler)(argc, argv);
exit(0);
@ -210,7 +212,8 @@ cmdscanner(void)
printf("?Invalid command\n");
continue;
}
if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
if ((c->c_opts & LPC_PRIVCMD) && getuid() &&
ingroup(LPR_OPER) == 0) {
printf("?Privileged command\n");
continue;
}
@ -223,7 +226,8 @@ cmdscanner(void)
* initial parameter processing.
*/
if (c->c_generic != 0)
generic(c->c_generic, c->c_handler, margc, margv);
generic(c->c_generic, c->c_opts, c->c_handler,
margc, margv);
else
(*c->c_handler)(margc, margv);
}

View File

@ -40,10 +40,13 @@
*/
struct printer;
#define LPC_PRIVCMD 0x0001 /* a privileged command */
#define LPC_MSGOPT 0x0002 /* command recognizes -msg option */
struct cmd {
const char *c_name; /* command name */
const char *c_help; /* help message */
const int c_priv; /* privileged command */
const int c_opts; /* flags (eg: privileged command) */
/* routine to do all the work for plain cmds, or
* initialization work for generic-printer cmds: */
void (*c_handler)(int, char *[]);