| 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 | } | 
|---|