On Mon, Jan 20, 2014 at 12:51:47PM -0700, Tobias Stoeckmann wrote:
> CVSROOT: /cvs
> Module name: src
> Changes by: [email protected] 2014/01/20 12:51:47
>
> Modified files:
> usr.sbin/lpr/lpd: printjob.c
>
> Log message:
> Fix race condition during symlink check. If there was no symbolic link
> requested, use O_NOFOLLOW, otherwise make sure afterwards that the
> correct file has been referenced (device/inode supplied by 'S' line).
>
> diff basically from and ok millert@, ok guenther@
This change has broken remote printing for me.
With a printcap like this:
lp|remote line printer:\
:lp=:rm=10.197.84.33:rp=lp:sd=/var/spool/output:lf=/var/log/lpd-errs:
I get the following when trying to send jobs to the remote printer:
# lpr /tmp/ppuf.pdf
# lpq
ted.stsp.name: no space on remote; waiting for queue to drain
Rank Owner Job Files
Total Size
1st root 87 /tmp/ppuf.pdf
1537701 bytes
If I revert the above commit, it works again:
# lpq
ted.stsp.name: sending to 10.197.84.33
Rank Owner Job Files
Total Size
1st stsp 90 /tmp/ppuf.pdf
1537701 bytes
FWIW, this diff reverts the change.
I cannot spot the problem in the diff. Any ideas?
Index: printjob.c
===================================================================
RCS file: /cvs/src/usr.sbin/lpr/lpd/printjob.c,v
retrieving revision 1.51
diff -u -p -r1.51 printjob.c
--- printjob.c 20 Jan 2014 19:52:45 -0000 1.51
+++ printjob.c 7 Feb 2014 18:23:36 -0000
@@ -226,9 +226,6 @@ again:
continue;
errcnt = 0;
restart:
- fdev = (dev_t)-1;
- fino = (ino_t)-1;
-
(void)lseek(lfd, pidoff, SEEK_SET);
if ((i = snprintf(line, sizeof(line), "%s\n", q->q_name)) >=
sizeof(line) || i == -1)
@@ -541,30 +538,20 @@ print(int format, char *file)
int fd, status, serrno;
int n, fi, fo, p[2], stopped = 0, nofile;
- if (fdev != (dev_t)-1 && fino != (ino_t)-1) {
- /* symbolic link */
- PRIV_START;
- fi = safe_open(file, O_RDONLY, 0);
- PRIV_END;
- if (fi != -1) {
- /*
- * The symbolic link should still point to the same file
- * or someone is trying to print something he shouldn't.
- */
- if (fstat(fi, &stb) == -1 ||
- stb.st_dev != fdev || stb.st_ino != fino) {
- close(fi);
- return(ACCESS);
- }
- }
- } else {
- /* regular file */
- PRIV_START;
- fi = safe_open(file, O_RDONLY|O_NOFOLLOW, 0);
+ PRIV_START;
+ if (lstat(file, &stb) < 0 || (fi = safe_open(file, O_RDONLY, 0)) < 0) {
PRIV_END;
- }
- if (fi == -1)
return(ERROR);
+ }
+ PRIV_END;
+ /*
+ * Check to see if data file is a symbolic link. If so, it should
+ * still point to the same file or someone is trying to print
+ * something he shouldn't.
+ */
+ if (S_ISLNK(stb.st_mode) && fstat(fi, &stb) == 0 &&
+ (stb.st_dev != fdev || stb.st_ino != fino))
+ return(ACCESS);
if (!SF && !tof) { /* start on a fresh page */
(void)write(ofd, FF, strlen(FF));
tof = 1;
@@ -888,30 +875,20 @@ sendfile(int type, char *file)
char buf[BUFSIZ];
int sizerr, resp;
- if (fdev != (dev_t)-1 && fino != (ino_t)-1) {
- /* symbolic link */
- PRIV_START;
- f = safe_open(file, O_RDONLY, 0);
+ PRIV_START;
+ if (lstat(file, &stb) < 0 || (f = safe_open(file, O_RDONLY, 0)) < 0) {
PRIV_END;
- if (f != -1) {
- /*
- * The symbolic link should still point to the same file
- * or someone is trying to print something he shouldn't.
- */
- if (fstat(f, &stb) == -1 ||
- stb.st_dev != fdev || stb.st_ino != fino) {
- close(f);
- return(ACCESS);
- }
- }
- } else {
- /* regular file */
- PRIV_START;
- f = safe_open(file, O_RDONLY|O_NOFOLLOW, 0);
- PRIV_END;
- }
- if (f == -1)
return(ERROR);
+ }
+ PRIV_END;
+ /*
+ * Check to see if data file is a symbolic link. If so, it should
+ * still point to the same file or someone is trying to print something
+ * he shouldn't.
+ */
+ if (S_ISLNK(stb.st_mode) && fstat(f, &stb) == 0 &&
+ (stb.st_dev != fdev || stb.st_ino != fino))
+ return(ACCESS);
if ((amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type,
(long long)stb.st_size, file)) >= sizeof(buf) || amt == -1)
return (ACCESS); /* XXX hack */