1 | #!/bin/perl
|
---|
2 | #
|
---|
3 | # Hacked by Alan Stebbens <aks@sgi.com> to setuid to the username if
|
---|
4 | # valid on this system. Written as a secure Perl script. To enable,
|
---|
5 | #
|
---|
6 | # chown root /usr/samba/bin/sambalp
|
---|
7 | # chmod u+s,+x /usr/samba/bin/sambalp
|
---|
8 | #
|
---|
9 | # If setuidshells is not enabled on your system, you must also do this:
|
---|
10 | #
|
---|
11 | # systune -i
|
---|
12 | # nosuidshells = 0
|
---|
13 | # y
|
---|
14 | # quit
|
---|
15 | #
|
---|
16 | # reboot
|
---|
17 | #
|
---|
18 | # This script will still work as a normal user; it will not try
|
---|
19 | # to setuid in this case.
|
---|
20 | #
|
---|
21 | # If the "$PSFIX" variable is set below...
|
---|
22 | #
|
---|
23 | # Workaround Win95 printer driver/Impressario bug by removing
|
---|
24 | # the PS check for available virtual memory. Note that this
|
---|
25 | # bug appears to be in all Win95 print drivers that generate
|
---|
26 | # PostScript; but is for certain there with a QMS-PS 810 (the
|
---|
27 | # printer type I configure on the Win95-side for printing with
|
---|
28 | # Samba).
|
---|
29 | #
|
---|
30 | # the perl script fixes 3 different bugs.
|
---|
31 | # 1. remove the JCL statements added by some HP printer drivers to the
|
---|
32 | # beginning of the postscript output.
|
---|
33 | # 2. Fix a bug in output from word files with long filenames. A non-printing
|
---|
34 | # character added to the end of the title comment by word is
|
---|
35 | # removed.
|
---|
36 | # 3. The VM fix described above.
|
---|
37 | #
|
---|
38 | #
|
---|
39 | # Modified for Perl4 compatibility.
|
---|
40 | #
|
---|
41 |
|
---|
42 | $PROG = "sambalp";
|
---|
43 |
|
---|
44 | $PSFIX = 1; # set to 0 if you don't want to run
|
---|
45 | # the "psfix" portion
|
---|
46 |
|
---|
47 | # Untaint the PATH variable
|
---|
48 | @PATH = split(' ',<<EOF);
|
---|
49 | /usr/sbin /usr/bsd /sbin /usr/bin /bin /usr/lib /usr/local/bin
|
---|
50 | EOF
|
---|
51 | $ENV{'PATH'} = join(':',@PATH);
|
---|
52 |
|
---|
53 | print "$#ARGV ".scalar(@ARGV)."\n";
|
---|
54 | if (scalar(@ARGV) < 2) {
|
---|
55 | print STDERR "usage: $PROG printer file [user] [system]\n";
|
---|
56 | exit;
|
---|
57 | }
|
---|
58 |
|
---|
59 | $printer = $ARGV[0];
|
---|
60 | $file = $ARGV[1];
|
---|
61 | $user = $ARGV[2];
|
---|
62 | $system = $ARGV[3];
|
---|
63 |
|
---|
64 | $user = "nobody" unless($user);
|
---|
65 | $system = `hostname` unless($system);
|
---|
66 |
|
---|
67 | open(LPSTAT,"/usr/bin/lpstat -t|") || die("Can't get printer list.\n");
|
---|
68 | @printers = ();
|
---|
69 | while (<LPSTAT>) {
|
---|
70 | next unless /^printer (\w+)/;
|
---|
71 | push(@printers,$1);
|
---|
72 | }
|
---|
73 | close LPSTAT;
|
---|
74 | # Create a hash list
|
---|
75 | @printers{@printers} = @printers;
|
---|
76 |
|
---|
77 | # Untaint the printer name
|
---|
78 | if (defined($prtname = $printers{$printer})) {
|
---|
79 | $printer = $prtname;
|
---|
80 | } else {
|
---|
81 | die("Unknown printer: \"$printer\"\n");
|
---|
82 | }
|
---|
83 |
|
---|
84 | if ($> == 0) { # are we root?
|
---|
85 | # yes -- then perform a taint checks and possibly do a suid check
|
---|
86 |
|
---|
87 | # Untaint the file and system names (pretend to filter them)
|
---|
88 | $file = $file =~ /^(.*)/ ? $1 : die("Bad file: $file\n");
|
---|
89 | $system = $system =~ /^(.*)/ ? $1 : die("Bad system: $system\n");
|
---|
90 |
|
---|
91 | # Get the valid users
|
---|
92 | setpwent;
|
---|
93 | %users = ();
|
---|
94 | while (@pwe = getpwent()) {
|
---|
95 | $uids{$pwe[0]} = $pwe[2];
|
---|
96 | $users{$pwe[2]} = $pwe[0];
|
---|
97 | }
|
---|
98 | endpwent();
|
---|
99 |
|
---|
100 | # Check out the user -- if the user is a real user on this system,
|
---|
101 | # then become that user so that the printer header page looks right
|
---|
102 | # otherwise, remain as the default user (probably "nobody").
|
---|
103 |
|
---|
104 | if (defined($uid = $uids{$user})) {
|
---|
105 |
|
---|
106 | # before we change UID, we must ensure that the file is still
|
---|
107 | # readable after the UID change.
|
---|
108 | chown($uid, 9, $file); # make the file owned by the user
|
---|
109 |
|
---|
110 | # Now, go ahead and become the user
|
---|
111 | $name = $users{$uid};
|
---|
112 | $> = $uid; # become the user
|
---|
113 | $< = $uid;
|
---|
114 | } else { # do untaint filtering
|
---|
115 | $name = $user =~ /^(\w+)/ ? $1 : die("Bad user: $user\n");
|
---|
116 | }
|
---|
117 | } else { # otherwise, just be me
|
---|
118 | $name = $user; # whomever that is
|
---|
119 | }
|
---|
120 |
|
---|
121 | $lpcommand = "/usr/bin/lp -c -d$printer -t'$name on $system'";
|
---|
122 |
|
---|
123 | # This code is from the original "psfix" but it has been completely
|
---|
124 | # rewritten for speed.
|
---|
125 |
|
---|
126 | if ($PSFIX) { # are we running a "psfix"?
|
---|
127 | open(FILE, $file) || die("Can't read $file: $!\n");
|
---|
128 | open(LP, "|$lpcommand -") || die("Can't open pipe to \"lp\": $!\n");
|
---|
129 | select(LP);
|
---|
130 | while (<FILE>) { #
|
---|
131 | $_ =~ s/^\004//; # strip any ctrl-d's
|
---|
132 | if (/^\e%/) { # get rid of any non-postscript commands
|
---|
133 | while (<FILE>) { # remove text until next %!PS
|
---|
134 | s/^\001M//; # lenmark driver prefixes Ctrl-A M to %!PS
|
---|
135 | last if /^%!PS/;
|
---|
136 | }
|
---|
137 | last if eof(FILE);
|
---|
138 | } elsif (/^%%Title:/) { # fix bug in long titles from MS Word
|
---|
139 | s/.\r$/\r/; # remove trailing character on the title
|
---|
140 | } elsif (/^\/VM\?/) { # remove VM test
|
---|
141 | print "/VM? { pop } bind def\r\n";
|
---|
142 | while (<FILE>) { last if /def\r/; }
|
---|
143 | next; # don't print
|
---|
144 | }
|
---|
145 | print;
|
---|
146 | }
|
---|
147 | close FILE;
|
---|
148 | close LP;
|
---|
149 | } else { # we're not running psfix?
|
---|
150 | system("$lpcommand $file");
|
---|
151 | }
|
---|
152 |
|
---|
153 | if ($file =~ m(^/)) {
|
---|
154 | # $file is a fully specified path
|
---|
155 | # Remove the file only if it lives in a directory ending in /tmp.
|
---|
156 | unlink($file) if ($file =~ m(/tmp/[^/]+$));
|
---|
157 | } else {
|
---|
158 | # $file is NOT a fully specified path
|
---|
159 | # Remove the file only if current directory ends in /tmp.
|
---|
160 | unlink($file) if (`pwd` =~ m(/tmp$));
|
---|
161 | }
|
---|