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
50EOF
51$ENV{'PATH'} = join(':',@PATH);
52
53        print "$#ARGV ".scalar(@ARGV)."\n";
54if (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
67open(LPSTAT,"/usr/bin/lpstat -t|") || die("Can't get printer list.\n");
68@printers = ();
69while (<LPSTAT>) {
70    next unless /^printer (\w+)/;
71    push(@printers,$1);
72}
73close LPSTAT;
74# Create a hash list
75@printers{@printers} = @printers;
76    
77# Untaint the printer name
78if (defined($prtname = $printers{$printer})) {
79    $printer = $prtname;
80} else {
81    die("Unknown printer: \"$printer\"\n");
82}
83
84if ($> == 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
126if ($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
153if ($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}
162