1*b1c7ac0eSwiz /* $NetBSD: pcnfsd_print.c,v 1.6 2002/09/29 23:23:56 wiz Exp $ */ 2457d5a17Sgwr 382b75dfdSjtc /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_print.c 1.7 92/01/24 19:58:58 SMI */ 482b75dfdSjtc /* 582b75dfdSjtc **===================================================================== 682b75dfdSjtc ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc. 782b75dfdSjtc ** @(#)pcnfsd_print.c 1.7 1/24/92 882b75dfdSjtc **===================================================================== 982b75dfdSjtc */ 1082b75dfdSjtc /* 1182b75dfdSjtc **===================================================================== 1282b75dfdSjtc ** I N C L U D E F I L E S E C T I O N * 1382b75dfdSjtc ** * 1482b75dfdSjtc ** If your port requires different include files, add a suitable * 1582b75dfdSjtc ** #define in the customization section, and make the inclusion or * 1682b75dfdSjtc ** exclusion of the files conditional on this. * 1782b75dfdSjtc **===================================================================== 1882b75dfdSjtc */ 19736ba086Slukem 2082b75dfdSjtc #include <sys/file.h> 2182b75dfdSjtc #include <sys/ioctl.h> 22736ba086Slukem #include <sys/stat.h> 23736ba086Slukem 24736ba086Slukem #include <ctype.h> 2582b75dfdSjtc #include <errno.h> 26736ba086Slukem #include <netdb.h> 27736ba086Slukem #include <pwd.h> 28736ba086Slukem #include <signal.h> 29736ba086Slukem #include <stdio.h> 30736ba086Slukem #include <stdlib.h> 3182b75dfdSjtc #include <string.h> 32736ba086Slukem #include <unistd.h> 3382b75dfdSjtc 3482b75dfdSjtc #ifndef SYSV 3582b75dfdSjtc #include <sys/wait.h> 3682b75dfdSjtc #endif 3782b75dfdSjtc 3882b75dfdSjtc #ifdef ISC_2_0 3982b75dfdSjtc #include <sys/fcntl.h> 4082b75dfdSjtc #endif 4182b75dfdSjtc 4282b75dfdSjtc #ifdef SHADOW_SUPPORT 4382b75dfdSjtc #include <shadow.h> 4482b75dfdSjtc #endif 4582b75dfdSjtc 466f885de1Sgwr #include "paths.h" 476f885de1Sgwr 48736ba086Slukem #include "common.h" 49736ba086Slukem #include "pcnfsd.h" 50736ba086Slukem #include "extern.h" 51736ba086Slukem 5282b75dfdSjtc /* 5382b75dfdSjtc **--------------------------------------------------------------------- 5482b75dfdSjtc ** Other #define's 5582b75dfdSjtc **--------------------------------------------------------------------- 5682b75dfdSjtc */ 5782b75dfdSjtc #ifndef MAXPATHLEN 5882b75dfdSjtc #define MAXPATHLEN 1024 5982b75dfdSjtc #endif 6082b75dfdSjtc 6182b75dfdSjtc /* 62*b1c7ac0eSwiz ** The following definitions give the maximum time allowed for 6382b75dfdSjtc ** an external command to run (in seconds) 6482b75dfdSjtc */ 6582b75dfdSjtc #define MAXTIME_FOR_PRINT 10 6682b75dfdSjtc #define MAXTIME_FOR_QUEUE 10 6782b75dfdSjtc #define MAXTIME_FOR_CANCEL 10 6882b75dfdSjtc #define MAXTIME_FOR_STATUS 10 6982b75dfdSjtc 7082b75dfdSjtc #define QMAX 50 7182b75dfdSjtc 7282b75dfdSjtc /* 7382b75dfdSjtc ** The following is derived from ucb/lpd/displayq.c 7482b75dfdSjtc */ 7582b75dfdSjtc #define SIZECOL 62 7682b75dfdSjtc #define FILECOL 24 7782b75dfdSjtc 78736ba086Slukem char *expand_alias __P((char *, char *, char *, char *)); 79736ba086Slukem pr_list list_virtual_printers __P((void)); 80736ba086Slukem char *map_printer_name __P((char *)); 81736ba086Slukem void substitute __P((char *, char *, char *)); 82736ba086Slukem int suspicious __P((char *)); 83736ba086Slukem int valid_pr __P((char *)); 8482b75dfdSjtc 8582b75dfdSjtc /* 8682b75dfdSjtc **--------------------------------------------------------------------- 8782b75dfdSjtc ** Misc. variable definitions 8882b75dfdSjtc **--------------------------------------------------------------------- 8982b75dfdSjtc */ 9082b75dfdSjtc 9182b75dfdSjtc struct stat statbuf; 9282b75dfdSjtc char pathname[MAXPATHLEN]; 9382b75dfdSjtc char new_pathname[MAXPATHLEN]; 9482b75dfdSjtc char sp_name[MAXPATHLEN] = SPOOLDIR; 9582b75dfdSjtc char tempstr[256]; 9682b75dfdSjtc char delims[] = " \t\r\n:()"; 9782b75dfdSjtc 9882b75dfdSjtc pr_list printers = NULL; 9982b75dfdSjtc pr_queue queue = NULL; 10082b75dfdSjtc 10182b75dfdSjtc /* 10282b75dfdSjtc **===================================================================== 10382b75dfdSjtc ** C O D E S E C T I O N * 10482b75dfdSjtc **===================================================================== 10582b75dfdSjtc */ 10682b75dfdSjtc 10782b75dfdSjtc /* 10882b75dfdSjtc * This is the latest word on the security check. The following 10982b75dfdSjtc * routine "suspicious()" returns non-zero if the character string 11082b75dfdSjtc * passed to it contains any shell metacharacters. 11182b75dfdSjtc * Callers will typically code 11282b75dfdSjtc * 11382b75dfdSjtc * if(suspicious(some_parameter)) reject(); 11482b75dfdSjtc */ 11582b75dfdSjtc 116736ba086Slukem int 117736ba086Slukem suspicious(s) 11882b75dfdSjtc char *s; 11982b75dfdSjtc { 120d87f04d7Sgwr if (strpbrk(s, ";|&<>`'#!?*()[]^/${}\n\r\"\\:") != NULL) 12182b75dfdSjtc return 1; 12282b75dfdSjtc return 0; 12382b75dfdSjtc } 12482b75dfdSjtc 12582b75dfdSjtc 12682b75dfdSjtc int 12782b75dfdSjtc valid_pr(pr) 12882b75dfdSjtc char *pr; 12982b75dfdSjtc { 13082b75dfdSjtc char *p; 13182b75dfdSjtc pr_list curr; 13282b75dfdSjtc if (printers == NULL) 13382b75dfdSjtc build_pr_list(); 13482b75dfdSjtc 13582b75dfdSjtc if (printers == NULL) 13682b75dfdSjtc return (1); /* can't tell - assume it's good */ 13782b75dfdSjtc 13882b75dfdSjtc p = map_printer_name(pr); 13982b75dfdSjtc if (p == NULL) 14082b75dfdSjtc return (1); /* must be ok is maps to NULL! */ 14182b75dfdSjtc curr = printers; 14282b75dfdSjtc while (curr) { 14382b75dfdSjtc if (!strcmp(p, curr->pn)) 14482b75dfdSjtc return (1); 14582b75dfdSjtc curr = curr->pr_next; 14682b75dfdSjtc } 14782b75dfdSjtc 14882b75dfdSjtc return (0); 14982b75dfdSjtc } 150d87f04d7Sgwr /* 151d87f04d7Sgwr * get pathname of current directory and return to client 152d87f04d7Sgwr * 153d87f04d7Sgwr * Note: This runs as root on behalf of a client request. 154d87f04d7Sgwr * As described in CERT advisory CA-96.08, be careful about 155d87f04d7Sgwr * doing a chmod on something that could be a symlink... 156d87f04d7Sgwr */ 157d87f04d7Sgwr pirstat 158d87f04d7Sgwr pr_init(sys, pr, sp) 15982b75dfdSjtc char *sys; 16082b75dfdSjtc char *pr; 16182b75dfdSjtc char **sp; 16282b75dfdSjtc { 16382b75dfdSjtc int dir_mode = 0777; 16482b75dfdSjtc int rc; 165d87f04d7Sgwr mode_t oldmask; 16682b75dfdSjtc 16782b75dfdSjtc *sp = &pathname[0]; 16882b75dfdSjtc pathname[0] = '\0'; 16982b75dfdSjtc 17082b75dfdSjtc if (suspicious(sys) || suspicious(pr)) 17182b75dfdSjtc return (PI_RES_FAIL); 17282b75dfdSjtc 173d87f04d7Sgwr /* 174d87f04d7Sgwr * Make sure the server spool directory exists. 175d87f04d7Sgwr * Never create it here - the sysadmin does that. 176d87f04d7Sgwr */ 177d87f04d7Sgwr if (stat(sp_name, &statbuf) || !S_ISDIR(statbuf.st_mode)) 178d87f04d7Sgwr goto badspool; 17982b75dfdSjtc 180d87f04d7Sgwr /* 181d87f04d7Sgwr * Create the client spool directory if needed. 182d87f04d7Sgwr * Just do the mkdir call and ignore EEXIST. 183d87f04d7Sgwr * Mode of client directory should be 777. 184d87f04d7Sgwr */ 18582b75dfdSjtc (void) sprintf(pathname, "%s/%s", sp_name, sys); 186d87f04d7Sgwr oldmask = umask(0); 18782b75dfdSjtc rc = mkdir(pathname, dir_mode); /* DON'T ignore this return code */ 188d87f04d7Sgwr umask(oldmask); 189d87f04d7Sgwr if ((rc < 0) && (errno != EEXIST)) 190d87f04d7Sgwr goto badspool; 191d87f04d7Sgwr 192d87f04d7Sgwr /* By this point the client spool dir should exist. */ 193d87f04d7Sgwr if (stat(pathname, &statbuf) || !S_ISDIR(statbuf.st_mode)) { 194d87f04d7Sgwr /* No spool directory... */ 195d87f04d7Sgwr badspool: 19682b75dfdSjtc (void) sprintf(tempstr, 19782b75dfdSjtc "rpc.pcnfsd: unable to set up spool directory %s\n", 19882b75dfdSjtc pathname); 19982b75dfdSjtc msg_out(tempstr); 20082b75dfdSjtc pathname[0] = '\0'; /* null to tell client bad vibes */ 20182b75dfdSjtc return (PI_RES_FAIL); 20282b75dfdSjtc } 203d87f04d7Sgwr /* OK, we have a spool directory. */ 204d87f04d7Sgwr if (!valid_pr(pr)) { 20582b75dfdSjtc pathname[0] = '\0'; /* null to tell client bad vibes */ 20682b75dfdSjtc return (PI_RES_NO_SUCH_PRINTER); 20782b75dfdSjtc } 20882b75dfdSjtc return (PI_RES_OK); 20982b75dfdSjtc } 210736ba086Slukem psrstat 211736ba086Slukem pr_start2(system, pr, user, fname, opts, id) 21282b75dfdSjtc char *system; 21382b75dfdSjtc char *pr; 21482b75dfdSjtc char *user; 21582b75dfdSjtc char *fname; 21682b75dfdSjtc char *opts; 21782b75dfdSjtc char **id; 21882b75dfdSjtc { 21982b75dfdSjtc char snum[20]; 22082b75dfdSjtc static char req_id[256]; 22182b75dfdSjtc char cmdbuf[256]; 22282b75dfdSjtc char resbuf[256]; 22382b75dfdSjtc FILE *fd; 22482b75dfdSjtc int i; 22582b75dfdSjtc char *xcmd; 22682b75dfdSjtc int failed = 0; 22782b75dfdSjtc 22882b75dfdSjtc #ifdef HACK_FOR_ROTATED_TRANSCRIPT 22982b75dfdSjtc char scratch[512]; 23082b75dfdSjtc #endif 23182b75dfdSjtc 23282b75dfdSjtc 23382b75dfdSjtc if (suspicious(system) || 23482b75dfdSjtc suspicious(pr) || 23582b75dfdSjtc suspicious(user) || 23682b75dfdSjtc suspicious(fname)) 23782b75dfdSjtc return (PS_RES_FAIL); 23882b75dfdSjtc 23982b75dfdSjtc (void) sprintf(pathname, "%s/%s/%s", sp_name, 24082b75dfdSjtc system, 24182b75dfdSjtc fname); 24282b75dfdSjtc 24382b75dfdSjtc *id = &req_id[0]; 24482b75dfdSjtc req_id[0] = '\0'; 24582b75dfdSjtc 246736ba086Slukem if (stat(pathname, &statbuf)) { 24782b75dfdSjtc /* 24882b75dfdSjtc **----------------------------------------------------------------- 24982b75dfdSjtc ** We can't stat the file. Let's try appending '.spl' and 25082b75dfdSjtc ** see if it's already in progress. 25182b75dfdSjtc **----------------------------------------------------------------- 25282b75dfdSjtc */ 25382b75dfdSjtc 25482b75dfdSjtc (void) strcat(pathname, ".spl"); 255736ba086Slukem if (stat(pathname, &statbuf)) { 25682b75dfdSjtc /* 25782b75dfdSjtc **---------------------------------------------------------------- 25882b75dfdSjtc ** It really doesn't exist. 25982b75dfdSjtc **---------------------------------------------------------------- 26082b75dfdSjtc */ 26182b75dfdSjtc 26282b75dfdSjtc 26382b75dfdSjtc return (PS_RES_NO_FILE); 26482b75dfdSjtc } 26582b75dfdSjtc /* 26682b75dfdSjtc **------------------------------------------------------------- 26782b75dfdSjtc ** It is already on the way. 26882b75dfdSjtc **------------------------------------------------------------- 26982b75dfdSjtc */ 27082b75dfdSjtc 27182b75dfdSjtc 27282b75dfdSjtc return (PS_RES_ALREADY); 27382b75dfdSjtc } 274736ba086Slukem if (statbuf.st_size == 0) { 27582b75dfdSjtc /* 27682b75dfdSjtc **------------------------------------------------------------- 27782b75dfdSjtc ** Null file - don't print it, just kill it. 27882b75dfdSjtc **------------------------------------------------------------- 27982b75dfdSjtc */ 28082b75dfdSjtc (void) unlink(pathname); 28182b75dfdSjtc 28282b75dfdSjtc return (PS_RES_NULL); 28382b75dfdSjtc } 28482b75dfdSjtc /* 28582b75dfdSjtc **------------------------------------------------------------- 28682b75dfdSjtc ** The file is real, has some data, and is not already going out. 28782b75dfdSjtc ** We rename it by appending '.spl' and exec "lpr" to do the 28882b75dfdSjtc ** actual work. 28982b75dfdSjtc **------------------------------------------------------------- 29082b75dfdSjtc */ 29182b75dfdSjtc (void) strcpy(new_pathname, pathname); 29282b75dfdSjtc (void) strcat(new_pathname, ".spl"); 29382b75dfdSjtc 29482b75dfdSjtc /* 29582b75dfdSjtc **------------------------------------------------------------- 29682b75dfdSjtc ** See if the new filename exists so as not to overwrite it. 29782b75dfdSjtc **------------------------------------------------------------- 29882b75dfdSjtc */ 29982b75dfdSjtc 30082b75dfdSjtc 301736ba086Slukem if (!stat(new_pathname, &statbuf)) { 30282b75dfdSjtc (void) strcpy(new_pathname, pathname); /* rebuild a new name */ 30382b75dfdSjtc (void) sprintf(snum, "%d", rand()); /* get some number */ 30482b75dfdSjtc (void) strncat(new_pathname, snum, 3); 30582b75dfdSjtc (void) strcat(new_pathname, ".spl"); /* new spool file */ 30682b75dfdSjtc } 307736ba086Slukem if (rename(pathname, new_pathname)) { 30882b75dfdSjtc /* 30982b75dfdSjtc **--------------------------------------------------------------- 31082b75dfdSjtc ** Should never happen. 31182b75dfdSjtc **--------------------------------------------------------------- 31282b75dfdSjtc */ 31382b75dfdSjtc (void) sprintf(tempstr, "rpc.pcnfsd: spool file rename (%s->%s) failed.\n", 31482b75dfdSjtc pathname, new_pathname); 31582b75dfdSjtc msg_out(tempstr); 31682b75dfdSjtc return (PS_RES_FAIL); 31782b75dfdSjtc } 318d87f04d7Sgwr if (*opts == 'd') { 31982b75dfdSjtc /* 32082b75dfdSjtc **------------------------------------------------------ 32182b75dfdSjtc ** This is a Diablo print stream. Apply the ps630 32282b75dfdSjtc ** filter with the appropriate arguments. 32382b75dfdSjtc **------------------------------------------------------ 32482b75dfdSjtc */ 325736ba086Slukem #if 0 /* XXX: Temporary fix for CERT advisory 326736ba086Slukem * CA-96.08 */ 32782b75dfdSjtc (void) run_ps630(new_pathname, opts); 328d87f04d7Sgwr #else 329d87f04d7Sgwr (void) sprintf(tempstr, 330d87f04d7Sgwr "rpc.pcnfsd: ps630 filter disabled for %s\n", pathname); 331d87f04d7Sgwr msg_out(tempstr); 332d87f04d7Sgwr return (PS_RES_FAIL); 333d87f04d7Sgwr #endif 33482b75dfdSjtc } 33582b75dfdSjtc /* 33682b75dfdSjtc ** Try to match to an aliased printer 33782b75dfdSjtc */ 33882b75dfdSjtc xcmd = expand_alias(pr, new_pathname, user, system); 33982b75dfdSjtc if (!xcmd) { 3406f885de1Sgwr #ifdef SVR4 3416f885de1Sgwr /* 3426f885de1Sgwr * Use the copy option so we can remove the orignal 3436f885de1Sgwr * spooled nfs file from the spool directory. 3446f885de1Sgwr */ 3456f885de1Sgwr sprintf(cmdbuf, "/usr/bin/lp -c -d%s %s", 3466f885de1Sgwr pr, new_pathname); 3476f885de1Sgwr #else /* SVR4 */ 3486f885de1Sgwr /* BSD way: lpr */ 34982b75dfdSjtc sprintf(cmdbuf, "%s/lpr -P%s %s", 35082b75dfdSjtc LPRDIR, pr, new_pathname); 3516f885de1Sgwr #endif /* SVR4 */ 35282b75dfdSjtc xcmd = cmdbuf; 35382b75dfdSjtc } 35482b75dfdSjtc if ((fd = su_popen(user, xcmd, MAXTIME_FOR_PRINT)) == NULL) { 35582b75dfdSjtc msg_out("rpc.pcnfsd: su_popen failed"); 35682b75dfdSjtc return (PS_RES_FAIL); 35782b75dfdSjtc } 35882b75dfdSjtc req_id[0] = '\0'; /* asume failure */ 35982b75dfdSjtc while (fgets(resbuf, 255, fd) != NULL) { 36082b75dfdSjtc i = strlen(resbuf); 36182b75dfdSjtc if (i) 36282b75dfdSjtc resbuf[i - 1] = '\0'; /* trim NL */ 36382b75dfdSjtc if (!strncmp(resbuf, "request id is ", 14)) 36482b75dfdSjtc /* New - just the first word is needed */ 36582b75dfdSjtc strcpy(req_id, strtok(&resbuf[14], delims)); 366736ba086Slukem else 367736ba086Slukem if (strembedded("disabled", resbuf)) 36882b75dfdSjtc failed = 1; 36982b75dfdSjtc } 37082b75dfdSjtc if (su_pclose(fd) == 255) 37182b75dfdSjtc msg_out("rpc.pcnfsd: su_pclose alert"); 37282b75dfdSjtc (void) unlink(new_pathname); 37382b75dfdSjtc return ((failed | interrupted) ? PS_RES_FAIL : PS_RES_OK); 37482b75dfdSjtc } 37582b75dfdSjtc /* 3766f885de1Sgwr * build_pr_list: determine which printers are valid. 37782b75dfdSjtc * on SVR4 use "lpstat -v" 3786f885de1Sgwr * on BSD use "lpc status" 3796f885de1Sgwr */ 3806f885de1Sgwr 3816f885de1Sgwr #ifdef SVR4 3826f885de1Sgwr /* 3836f885de1Sgwr * In SVR4 the command to determine which printers are 3846f885de1Sgwr * valid is lpstat -v. The output is something like this: 3856f885de1Sgwr * 3866f885de1Sgwr * device for lp: /dev/lp0 3876f885de1Sgwr * system for pcdslw: hinode 3886f885de1Sgwr * system for bletch: hinode (as printer hisname) 3896f885de1Sgwr * 3906f885de1Sgwr * On SunOS using the SysV compatibility package, the output 3916f885de1Sgwr * is more like: 3926f885de1Sgwr * 3936f885de1Sgwr * device for lp is /dev/lp0 3946f885de1Sgwr * device for pcdslw is the remote printer pcdslw on hinode 3956f885de1Sgwr * device for bletch is the remote printer hisname on hinode 3966f885de1Sgwr * 3976f885de1Sgwr * It is fairly simple to create logic that will handle either 3986f885de1Sgwr * possibility: 3996f885de1Sgwr */ 4006f885de1Sgwr int 4016f885de1Sgwr build_pr_list() 4026f885de1Sgwr { 4036f885de1Sgwr pr_list last = NULL; 4046f885de1Sgwr pr_list curr = NULL; 4056f885de1Sgwr char buff[256]; 4066f885de1Sgwr FILE *p; 4076f885de1Sgwr char *cp; 4086f885de1Sgwr int saw_system; 4096f885de1Sgwr 4106f885de1Sgwr p = popen("lpstat -v", "r"); 4116f885de1Sgwr if (p == NULL) { 4126f885de1Sgwr msg_out("rpc.pcnfsd: unable to popen() lp status"); 4136f885de1Sgwr return (0); 4146f885de1Sgwr } 4156f885de1Sgwr while (fgets(buff, 255, p) != NULL) { 4166f885de1Sgwr cp = strtok(buff, delims); 4176f885de1Sgwr if (!cp) 4186f885de1Sgwr continue; 4196f885de1Sgwr if (!strcmp(cp, "device")) 4206f885de1Sgwr saw_system = 0; 421736ba086Slukem else 422736ba086Slukem if (!strcmp(cp, "system")) 4236f885de1Sgwr saw_system = 1; 4246f885de1Sgwr else 4256f885de1Sgwr continue; 4266f885de1Sgwr cp = strtok(NULL, delims); 4276f885de1Sgwr if (!cp || strcmp(cp, "for")) 4286f885de1Sgwr continue; 4296f885de1Sgwr cp = strtok(NULL, delims); 4306f885de1Sgwr if (!cp) 4316f885de1Sgwr continue; 4326f885de1Sgwr curr = (struct pr_list_item *) 4336f885de1Sgwr grab(sizeof(struct pr_list_item)); 4346f885de1Sgwr 4356f885de1Sgwr curr->pn = strdup(cp); 4366f885de1Sgwr curr->device = NULL; 4376f885de1Sgwr curr->remhost = NULL; 4386f885de1Sgwr curr->cm = strdup("-"); 4396f885de1Sgwr curr->pr_next = NULL; 4406f885de1Sgwr 4416f885de1Sgwr cp = strtok(NULL, delims); 4426f885de1Sgwr 4436f885de1Sgwr if (cp && !strcmp(cp, "is")) 4446f885de1Sgwr cp = strtok(NULL, delims); 4456f885de1Sgwr 4466f885de1Sgwr if (!cp) { 4476f885de1Sgwr free_pr_list_item(curr); 4486f885de1Sgwr continue; 4496f885de1Sgwr } 4506f885de1Sgwr if (saw_system) { 4516f885de1Sgwr /* "system" OR "system (as printer pname)" */ 4526f885de1Sgwr curr->remhost = strdup(cp); 4536f885de1Sgwr cp = strtok(NULL, delims); 4546f885de1Sgwr if (!cp) { 4556f885de1Sgwr /* simple format */ 4566f885de1Sgwr curr->device = strdup(curr->pn); 4576f885de1Sgwr } else { 4586f885de1Sgwr /* "sys (as printer pname)" */ 4596f885de1Sgwr if (strcmp(cp, "as")) { 4606f885de1Sgwr free_pr_list_item(curr); 4616f885de1Sgwr continue; 4626f885de1Sgwr } 4636f885de1Sgwr cp = strtok(NULL, delims); 4646f885de1Sgwr if (!cp || strcmp(cp, "printer")) { 4656f885de1Sgwr free_pr_list_item(curr); 4666f885de1Sgwr continue; 4676f885de1Sgwr } 4686f885de1Sgwr cp = strtok(NULL, delims); 4696f885de1Sgwr if (!cp) { 4706f885de1Sgwr free_pr_list_item(curr); 4716f885de1Sgwr continue; 4726f885de1Sgwr } 4736f885de1Sgwr curr->device = strdup(cp); 4746f885de1Sgwr } 475736ba086Slukem } else 476736ba086Slukem if (!strcmp(cp, "the")) { 4776f885de1Sgwr /* start of "the remote printer foo on bar" */ 4786f885de1Sgwr cp = strtok(NULL, delims); 4796f885de1Sgwr if (!cp || strcmp(cp, "remote")) { 4806f885de1Sgwr free_pr_list_item(curr); 4816f885de1Sgwr continue; 4826f885de1Sgwr } 4836f885de1Sgwr cp = strtok(NULL, delims); 4846f885de1Sgwr if (!cp || strcmp(cp, "printer")) { 4856f885de1Sgwr free_pr_list_item(curr); 4866f885de1Sgwr continue; 4876f885de1Sgwr } 4886f885de1Sgwr cp = strtok(NULL, delims); 4896f885de1Sgwr if (!cp) { 4906f885de1Sgwr free_pr_list_item(curr); 4916f885de1Sgwr continue; 4926f885de1Sgwr } 4936f885de1Sgwr curr->device = strdup(cp); 4946f885de1Sgwr cp = strtok(NULL, delims); 4956f885de1Sgwr if (!cp || strcmp(cp, "on")) { 4966f885de1Sgwr free_pr_list_item(curr); 4976f885de1Sgwr continue; 4986f885de1Sgwr } 4996f885de1Sgwr cp = strtok(NULL, delims); 5006f885de1Sgwr if (!cp) { 5016f885de1Sgwr free_pr_list_item(curr); 5026f885de1Sgwr continue; 5036f885de1Sgwr } 5046f885de1Sgwr curr->remhost = strdup(cp); 5056f885de1Sgwr } else { 5066f885de1Sgwr /* the local name */ 5076f885de1Sgwr curr->device = strdup(cp); 5086f885de1Sgwr curr->remhost = strdup(""); 5096f885de1Sgwr } 5106f885de1Sgwr 5116f885de1Sgwr if (last == NULL) 5126f885de1Sgwr printers = curr; 5136f885de1Sgwr else 5146f885de1Sgwr last->pr_next = curr; 5156f885de1Sgwr last = curr; 5166f885de1Sgwr 5176f885de1Sgwr } 5186f885de1Sgwr (void) pclose(p); 5196f885de1Sgwr 5206f885de1Sgwr /* 5216f885de1Sgwr ** Now add on the virtual printers, if any 5226f885de1Sgwr */ 5236f885de1Sgwr if (last == NULL) 5246f885de1Sgwr printers = list_virtual_printers(); 5256f885de1Sgwr else 5266f885de1Sgwr last->pr_next = list_virtual_printers(); 5276f885de1Sgwr 5286f885de1Sgwr return (1); 5296f885de1Sgwr } 5306f885de1Sgwr #else /* SVR4 */ 5316f885de1Sgwr 5326f885de1Sgwr /* 5336f885de1Sgwr * BSD way: lpc stat 53482b75dfdSjtc */ 53582b75dfdSjtc int 53682b75dfdSjtc build_pr_list() 53782b75dfdSjtc { 53882b75dfdSjtc pr_list last = NULL; 53982b75dfdSjtc pr_list curr = NULL; 54082b75dfdSjtc char buff[256]; 54182b75dfdSjtc FILE *p; 54282b75dfdSjtc char *cp; 54382b75dfdSjtc 54482b75dfdSjtc sprintf(buff, "%s/lpc status", LPCDIR); 54582b75dfdSjtc p = popen(buff, "r"); 54682b75dfdSjtc if (p == NULL) { 54782b75dfdSjtc msg_out("rpc.pcnfsd: unable to popen lpc stat"); 54882b75dfdSjtc return (0); 54982b75dfdSjtc } 55082b75dfdSjtc while (fgets(buff, 255, p) != NULL) { 55182b75dfdSjtc if (isspace(buff[0])) 55282b75dfdSjtc continue; 55382b75dfdSjtc 55482b75dfdSjtc if ((cp = strtok(buff, delims)) == NULL) 55582b75dfdSjtc continue; 55682b75dfdSjtc 55782b75dfdSjtc curr = (struct pr_list_item *) 55882b75dfdSjtc grab(sizeof(struct pr_list_item)); 55982b75dfdSjtc 56082b75dfdSjtc /* XXX - Should distinguish remote printers. */ 56182b75dfdSjtc curr->pn = strdup(cp); 56282b75dfdSjtc curr->device = strdup(cp); 56382b75dfdSjtc curr->remhost = strdup(""); 56482b75dfdSjtc curr->cm = strdup("-"); 56582b75dfdSjtc curr->pr_next = NULL; 56682b75dfdSjtc 56782b75dfdSjtc if (last == NULL) 56882b75dfdSjtc printers = curr; 56982b75dfdSjtc else 57082b75dfdSjtc last->pr_next = curr; 57182b75dfdSjtc last = curr; 57282b75dfdSjtc 57382b75dfdSjtc } 57482b75dfdSjtc (void) fclose(p); 57582b75dfdSjtc 57682b75dfdSjtc /* 57782b75dfdSjtc ** Now add on the virtual printers, if any 57882b75dfdSjtc */ 57982b75dfdSjtc if (last == NULL) 58082b75dfdSjtc printers = list_virtual_printers(); 58182b75dfdSjtc else 58282b75dfdSjtc last->pr_next = list_virtual_printers(); 58382b75dfdSjtc 58482b75dfdSjtc return (1); 58582b75dfdSjtc } 5866f885de1Sgwr #endif /* SVR4 */ 5876f885de1Sgwr 588736ba086Slukem void * 589736ba086Slukem grab(n) 59082b75dfdSjtc int n; 59182b75dfdSjtc { 59282b75dfdSjtc void *p; 59382b75dfdSjtc 59482b75dfdSjtc p = (void *) malloc(n); 59582b75dfdSjtc if (p == NULL) { 59682b75dfdSjtc msg_out("rpc.pcnfsd: malloc failure"); 59782b75dfdSjtc exit(1); 59882b75dfdSjtc } 59982b75dfdSjtc return (p); 60082b75dfdSjtc } 60182b75dfdSjtc 60282b75dfdSjtc void 60382b75dfdSjtc free_pr_list_item(curr) 60482b75dfdSjtc pr_list curr; 60582b75dfdSjtc { 60682b75dfdSjtc if (curr->pn) 60782b75dfdSjtc free(curr->pn); 60882b75dfdSjtc if (curr->device) 60982b75dfdSjtc free(curr->device); 61082b75dfdSjtc if (curr->remhost) 61182b75dfdSjtc free(curr->remhost); 61282b75dfdSjtc if (curr->cm) 61382b75dfdSjtc free(curr->cm); 61482b75dfdSjtc if (curr->pr_next) 61582b75dfdSjtc free_pr_list_item(curr->pr_next); /* recurse */ 61682b75dfdSjtc free(curr); 61782b75dfdSjtc } 61882b75dfdSjtc /* 6196f885de1Sgwr * build_pr_queue: used to show the print queue. 6206f885de1Sgwr * 6216f885de1Sgwr * Note that the first thing we do is to discard any 6226f885de1Sgwr * existing queue. 62382b75dfdSjtc */ 6246f885de1Sgwr #ifdef SVR4 6256f885de1Sgwr 6266f885de1Sgwr /* 6276f885de1Sgwr ** In SVR4 the command to list the print jobs for printer 6286f885de1Sgwr ** lp is "lpstat lp" (or, equivalently, "lpstat -p lp"). 6296f885de1Sgwr ** The output looks like this: 6306f885de1Sgwr ** 6316f885de1Sgwr ** lp-2 root 939 Jul 10 21:56 6326f885de1Sgwr ** lp-5 geoff 15 Jul 12 23:23 6336f885de1Sgwr ** lp-6 geoff 15 Jul 12 23:23 6346f885de1Sgwr ** 6356f885de1Sgwr ** If the first job is actually printing the first line 6366f885de1Sgwr ** is modified, as follows: 6376f885de1Sgwr ** 6386f885de1Sgwr ** lp-2 root 939 Jul 10 21:56 on lp 6396f885de1Sgwr ** 6406f885de1Sgwr ** I don't yet have any info on what it looks like if the printer 6416f885de1Sgwr ** is remote and we're spooling over the net. However for 6426f885de1Sgwr ** the purposes of rpc.pcnfsd we can simply say that field 1 is the 6436f885de1Sgwr ** job ID, field 2 is the submitter, and field 3 is the size. 6446f885de1Sgwr ** We can check for the presence of the string " on " in the 6456f885de1Sgwr ** first record to determine if we should count it as rank 0 or rank 1, 6466f885de1Sgwr ** but it won't hurt if we get it wrong. 6476f885de1Sgwr **/ 6486f885de1Sgwr 6496f885de1Sgwr pirstat 6506f885de1Sgwr build_pr_queue(pn, user, just_mine, p_qlen, p_qshown) 6516f885de1Sgwr printername pn; 6526f885de1Sgwr username user; 6536f885de1Sgwr int just_mine; 6546f885de1Sgwr int *p_qlen; 6556f885de1Sgwr int *p_qshown; 6566f885de1Sgwr { 6576f885de1Sgwr pr_queue last = NULL; 6586f885de1Sgwr pr_queue curr = NULL; 6596f885de1Sgwr char buff[256]; 6606f885de1Sgwr FILE *p; 6616f885de1Sgwr char *owner; 6626f885de1Sgwr char *job; 6636f885de1Sgwr char *totsize; 6646f885de1Sgwr 6656f885de1Sgwr if (queue) { 6666f885de1Sgwr free_pr_queue_item(queue); 6676f885de1Sgwr queue = NULL; 6686f885de1Sgwr } 6696f885de1Sgwr *p_qlen = 0; 6706f885de1Sgwr *p_qshown = 0; 6716f885de1Sgwr 6726f885de1Sgwr pn = map_printer_name(pn); 6736f885de1Sgwr if (pn == NULL || !valid_pr(pn) || suspicious(pn)) 6746f885de1Sgwr return (PI_RES_NO_SUCH_PRINTER); 6756f885de1Sgwr 6766f885de1Sgwr sprintf(buff, "/usr/bin/lpstat %s", pn); 6776f885de1Sgwr p = su_popen(user, buff, MAXTIME_FOR_QUEUE); 6786f885de1Sgwr if (p == NULL) { 6796f885de1Sgwr msg_out("rpc.pcnfsd: unable to popen() lpstat queue query"); 6806f885de1Sgwr return (PI_RES_FAIL); 6816f885de1Sgwr } 6826f885de1Sgwr while (fgets(buff, 255, p) != NULL) { 6836f885de1Sgwr job = strtok(buff, delims); 6846f885de1Sgwr if (!job) 6856f885de1Sgwr continue; 6866f885de1Sgwr 6876f885de1Sgwr owner = strtok(NULL, delims); 6886f885de1Sgwr if (!owner) 6896f885de1Sgwr continue; 6906f885de1Sgwr 6916f885de1Sgwr totsize = strtok(NULL, delims); 6926f885de1Sgwr if (!totsize) 6936f885de1Sgwr continue; 6946f885de1Sgwr 6956f885de1Sgwr *p_qlen += 1; 6966f885de1Sgwr 6976f885de1Sgwr if (*p_qshown > QMAX) 6986f885de1Sgwr continue; 6996f885de1Sgwr 700736ba086Slukem if (just_mine && strcasecmp(owner, user)) 7016f885de1Sgwr continue; 7026f885de1Sgwr 7036f885de1Sgwr *p_qshown += 1; 7046f885de1Sgwr 7056f885de1Sgwr curr = (struct pr_queue_item *) 7066f885de1Sgwr grab(sizeof(struct pr_queue_item)); 7076f885de1Sgwr 7086f885de1Sgwr curr->position = *p_qlen; 7096f885de1Sgwr curr->id = strdup(job); 7106f885de1Sgwr curr->size = strdup(totsize); 7116f885de1Sgwr curr->status = strdup(""); 7126f885de1Sgwr curr->system = strdup(""); 7136f885de1Sgwr curr->user = strdup(owner); 7146f885de1Sgwr curr->file = strdup(""); 7156f885de1Sgwr curr->cm = strdup("-"); 7166f885de1Sgwr curr->pr_next = NULL; 7176f885de1Sgwr 7186f885de1Sgwr if (last == NULL) 7196f885de1Sgwr queue = curr; 7206f885de1Sgwr else 7216f885de1Sgwr last->pr_next = curr; 7226f885de1Sgwr last = curr; 7236f885de1Sgwr 7246f885de1Sgwr } 7256f885de1Sgwr (void) su_pclose(p); 7266f885de1Sgwr return (PI_RES_OK); 7276f885de1Sgwr } 7286f885de1Sgwr #else /* SVR4 */ 72982b75dfdSjtc 73082b75dfdSjtc pirstat 73182b75dfdSjtc build_pr_queue(pn, user, just_mine, p_qlen, p_qshown) 73282b75dfdSjtc printername pn; 73382b75dfdSjtc username user; 73482b75dfdSjtc int just_mine; 73582b75dfdSjtc int *p_qlen; 73682b75dfdSjtc int *p_qshown; 73782b75dfdSjtc { 73882b75dfdSjtc pr_queue last = NULL; 73982b75dfdSjtc pr_queue curr = NULL; 74082b75dfdSjtc char buff[256]; 74182b75dfdSjtc FILE *p; 74282b75dfdSjtc char *cp; 74382b75dfdSjtc int i; 74482b75dfdSjtc char *rank; 74582b75dfdSjtc char *owner; 74682b75dfdSjtc char *job; 74782b75dfdSjtc char *files; 74882b75dfdSjtc char *totsize; 74982b75dfdSjtc 75082b75dfdSjtc if (queue) { 75182b75dfdSjtc free_pr_queue_item(queue); 75282b75dfdSjtc queue = NULL; 75382b75dfdSjtc } 75482b75dfdSjtc *p_qlen = 0; 75582b75dfdSjtc *p_qshown = 0; 75682b75dfdSjtc pn = map_printer_name(pn); 75782b75dfdSjtc if (pn == NULL || suspicious(pn)) 75882b75dfdSjtc return (PI_RES_NO_SUCH_PRINTER); 75982b75dfdSjtc 76082b75dfdSjtc sprintf(buff, "%s/lpq -P%s", LPRDIR, pn); 76182b75dfdSjtc 76282b75dfdSjtc p = su_popen(user, buff, MAXTIME_FOR_QUEUE); 76382b75dfdSjtc if (p == NULL) { 76482b75dfdSjtc msg_out("rpc.pcnfsd: unable to popen() lpq"); 76582b75dfdSjtc return (PI_RES_FAIL); 76682b75dfdSjtc } 76782b75dfdSjtc while (fgets(buff, 255, p) != NULL) { 76882b75dfdSjtc i = strlen(buff) - 1; 76982b75dfdSjtc buff[i] = '\0'; /* zap trailing NL */ 77082b75dfdSjtc if (i < SIZECOL) 77182b75dfdSjtc continue; 772736ba086Slukem if (!strncasecmp(buff, "rank", 4)) 77382b75dfdSjtc continue; 77482b75dfdSjtc 77582b75dfdSjtc totsize = &buff[SIZECOL - 1]; 77682b75dfdSjtc files = &buff[FILECOL - 1]; 77782b75dfdSjtc cp = totsize; 77882b75dfdSjtc cp--; 77982b75dfdSjtc while (cp > files && isspace(*cp)) 78082b75dfdSjtc *cp-- = '\0'; 78182b75dfdSjtc 78282b75dfdSjtc buff[FILECOL - 2] = '\0'; 78382b75dfdSjtc 78482b75dfdSjtc cp = strtok(buff, delims); 78582b75dfdSjtc if (!cp) 78682b75dfdSjtc continue; 78782b75dfdSjtc rank = cp; 78882b75dfdSjtc 78982b75dfdSjtc cp = strtok(NULL, delims); 79082b75dfdSjtc if (!cp) 79182b75dfdSjtc continue; 79282b75dfdSjtc owner = cp; 79382b75dfdSjtc 79482b75dfdSjtc cp = strtok(NULL, delims); 79582b75dfdSjtc if (!cp) 79682b75dfdSjtc continue; 79782b75dfdSjtc job = cp; 79882b75dfdSjtc 79982b75dfdSjtc *p_qlen += 1; 80082b75dfdSjtc 80182b75dfdSjtc if (*p_qshown > QMAX) 80282b75dfdSjtc continue; 80382b75dfdSjtc 804736ba086Slukem if (just_mine && strcasecmp(owner, user)) 80582b75dfdSjtc continue; 80682b75dfdSjtc 80782b75dfdSjtc *p_qshown += 1; 80882b75dfdSjtc 80982b75dfdSjtc curr = (struct pr_queue_item *) 81082b75dfdSjtc grab(sizeof(struct pr_queue_item)); 81182b75dfdSjtc 81282b75dfdSjtc curr->position = atoi(rank); /* active -> 0 */ 81382b75dfdSjtc curr->id = strdup(job); 81482b75dfdSjtc curr->size = strdup(totsize); 81582b75dfdSjtc curr->status = strdup(rank); 81682b75dfdSjtc curr->system = strdup(""); 81782b75dfdSjtc curr->user = strdup(owner); 81882b75dfdSjtc curr->file = strdup(files); 81982b75dfdSjtc curr->cm = strdup("-"); 82082b75dfdSjtc curr->pr_next = NULL; 82182b75dfdSjtc 82282b75dfdSjtc if (last == NULL) 82382b75dfdSjtc queue = curr; 82482b75dfdSjtc else 82582b75dfdSjtc last->pr_next = curr; 82682b75dfdSjtc last = curr; 82782b75dfdSjtc 82882b75dfdSjtc } 82982b75dfdSjtc (void) su_pclose(p); 83082b75dfdSjtc return (PI_RES_OK); 83182b75dfdSjtc } 8326f885de1Sgwr #endif /* SVR4 */ 8336f885de1Sgwr 83482b75dfdSjtc void 83582b75dfdSjtc free_pr_queue_item(curr) 83682b75dfdSjtc pr_queue curr; 83782b75dfdSjtc { 83882b75dfdSjtc if (curr->id) 83982b75dfdSjtc free(curr->id); 84082b75dfdSjtc if (curr->size) 84182b75dfdSjtc free(curr->size); 84282b75dfdSjtc if (curr->status) 84382b75dfdSjtc free(curr->status); 84482b75dfdSjtc if (curr->system) 84582b75dfdSjtc free(curr->system); 84682b75dfdSjtc if (curr->user) 84782b75dfdSjtc free(curr->user); 84882b75dfdSjtc if (curr->file) 84982b75dfdSjtc free(curr->file); 85082b75dfdSjtc if (curr->cm) 85182b75dfdSjtc free(curr->cm); 85282b75dfdSjtc if (curr->pr_next) 85382b75dfdSjtc free_pr_queue_item(curr->pr_next); /* recurse */ 85482b75dfdSjtc free(curr); 85582b75dfdSjtc } 8566f885de1Sgwr #ifdef SVR4 85782b75dfdSjtc 8586f885de1Sgwr /* 8596f885de1Sgwr ** New - SVR4 printer status handling. 8606f885de1Sgwr ** 8616f885de1Sgwr ** The command we'll use for checking the status of printer "lp" 8626f885de1Sgwr ** is "lpstat -a lp -p lp". Here are some sample outputs: 8636f885de1Sgwr ** 8646f885de1Sgwr ** 8656f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991 8666f885de1Sgwr ** printer lp disabled since Thu Feb 21 22:52:36 EST 1991. available. 8676f885de1Sgwr ** new printer 8686f885de1Sgwr ** --- 8696f885de1Sgwr ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 - 8706f885de1Sgwr ** unknown reason 8716f885de1Sgwr ** printer pcdslw disabled since Fri Jul 12 22:15:37 EDT 1991. available. 8726f885de1Sgwr ** new printer 8736f885de1Sgwr ** --- 8746f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991 8756f885de1Sgwr ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available. 8766f885de1Sgwr ** --- 8776f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991 8786f885de1Sgwr ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available. 8796f885de1Sgwr ** --- 8806f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991 8816f885de1Sgwr ** printer lp disabled since Sat Jul 13 12:05:20 EDT 1991. available. 8826f885de1Sgwr ** unknown reason 8836f885de1Sgwr ** --- 8846f885de1Sgwr ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 - 8856f885de1Sgwr ** unknown reason 8866f885de1Sgwr ** printer pcdslw is idle. enabled since Sat Jul 13 12:05:28 EDT 1991. available. 8876f885de1Sgwr ** 8886f885de1Sgwr ** Note that these are actual outputs. The format (which is totally 8896f885de1Sgwr ** different from the lpstat in SunOS) seems to break down as 8906f885de1Sgwr ** follows: 8916f885de1Sgwr ** (1) The first line has the form "printername [not] accepting requests,,," 8926f885de1Sgwr ** This is trivial to decode. 8936f885de1Sgwr ** (2) The second line has several forms, all beginning "printer printername": 8946f885de1Sgwr ** (2.1) "... disabled" 8956f885de1Sgwr ** (2.2) "... is idle" 8966f885de1Sgwr ** (2.3) "... now printing jobid" 8976f885de1Sgwr ** The "available" comment seems to be meaningless. The next line 8986f885de1Sgwr ** is the "reason" code which the operator can supply when issuing 8996f885de1Sgwr ** a "disable" or "reject" command. 9006f885de1Sgwr ** Note that there is no way to check the number of entries in the 9016f885de1Sgwr ** queue except to ask for the queue and count them. 9026f885de1Sgwr */ 90382b75dfdSjtc 90482b75dfdSjtc pirstat 90582b75dfdSjtc get_pr_status(pn, avail, printing, qlen, needs_operator, status) 90682b75dfdSjtc printername pn; 90782b75dfdSjtc bool_t *avail; 90882b75dfdSjtc bool_t *printing; 90982b75dfdSjtc int *qlen; 91082b75dfdSjtc bool_t *needs_operator; 91182b75dfdSjtc char *status; 91282b75dfdSjtc { 9136f885de1Sgwr char buff[256]; 9146f885de1Sgwr char cmd[64]; 9156f885de1Sgwr FILE *p; 9166f885de1Sgwr int n; 9176f885de1Sgwr pirstat stat = PI_RES_NO_SUCH_PRINTER; 9186f885de1Sgwr 9196f885de1Sgwr /* assume the worst */ 9206f885de1Sgwr *avail = FALSE; 9216f885de1Sgwr *printing = FALSE; 9226f885de1Sgwr *needs_operator = FALSE; 9236f885de1Sgwr *qlen = 0; 9246f885de1Sgwr *status = '\0'; 9256f885de1Sgwr 9266f885de1Sgwr pn = map_printer_name(pn); 9276f885de1Sgwr if (pn == NULL || !valid_pr(pn) || suspicious(pn)) 9286f885de1Sgwr return (PI_RES_NO_SUCH_PRINTER); 9296f885de1Sgwr n = strlen(pn); 9306f885de1Sgwr 9316f885de1Sgwr sprintf(cmd, "/usr/bin/lpstat -a %s -p %s", pn, pn); 9326f885de1Sgwr 9336f885de1Sgwr p = popen(cmd, "r"); 9346f885de1Sgwr if (p == NULL) { 9356f885de1Sgwr msg_out("rpc.pcnfsd: unable to popen() lp status"); 9366f885de1Sgwr return (PI_RES_FAIL); 9376f885de1Sgwr } 9386f885de1Sgwr stat = PI_RES_OK; 9396f885de1Sgwr 9406f885de1Sgwr while (fgets(buff, 255, p) != NULL) { 9416f885de1Sgwr if (!strncmp(buff, pn, n)) { 9426f885de1Sgwr if (!strstr(buff, "not accepting")) 9436f885de1Sgwr *avail = TRUE; 9446f885de1Sgwr continue; 9456f885de1Sgwr } 9466f885de1Sgwr if (!strncmp(buff, "printer ", 8)) { 9476f885de1Sgwr if (!strstr(buff, "disabled")) 9486f885de1Sgwr *printing = TRUE; 9496f885de1Sgwr if (strstr(buff, "printing")) 9506f885de1Sgwr strcpy(status, "printing"); 951736ba086Slukem else 952736ba086Slukem if (strstr(buff, "idle")) 9536f885de1Sgwr strcpy(status, "idle"); 9546f885de1Sgwr continue; 9556f885de1Sgwr } 9566f885de1Sgwr if (!strncmp(buff, "UX:", 3)) { 9576f885de1Sgwr stat = PI_RES_NO_SUCH_PRINTER; 9586f885de1Sgwr } 9596f885de1Sgwr } 9606f885de1Sgwr (void) pclose(p); 9616f885de1Sgwr return (stat); 9626f885de1Sgwr } 9636f885de1Sgwr #else /* SVR4 */ 9646f885de1Sgwr 9656f885de1Sgwr /* 9666f885de1Sgwr * BSD way: lpc status 9676f885de1Sgwr */ 9686f885de1Sgwr pirstat 9696f885de1Sgwr get_pr_status(pn, avail, printing, qlen, needs_operator, status) 9706f885de1Sgwr printername pn; 9716f885de1Sgwr bool_t *avail; 9726f885de1Sgwr bool_t *printing; 9736f885de1Sgwr int *qlen; 9746f885de1Sgwr bool_t *needs_operator; 9756f885de1Sgwr char *status; 9766f885de1Sgwr { 97782b75dfdSjtc char cmd[128]; 97882b75dfdSjtc char buff[256]; 97982b75dfdSjtc char buff2[256]; 98082b75dfdSjtc char pname[64]; 98182b75dfdSjtc FILE *p; 98282b75dfdSjtc char *cp; 98382b75dfdSjtc char *cp1; 98482b75dfdSjtc char *cp2; 98582b75dfdSjtc int n; 98682b75dfdSjtc pirstat stat = PI_RES_NO_SUCH_PRINTER; 98782b75dfdSjtc 98882b75dfdSjtc /* assume the worst */ 98982b75dfdSjtc *avail = FALSE; 99082b75dfdSjtc *printing = FALSE; 99182b75dfdSjtc *needs_operator = FALSE; 99282b75dfdSjtc *qlen = 0; 99382b75dfdSjtc *status = '\0'; 99482b75dfdSjtc 99582b75dfdSjtc pn = map_printer_name(pn); 99682b75dfdSjtc if (pn == NULL || suspicious(pn)) 99782b75dfdSjtc return (PI_RES_NO_SUCH_PRINTER); 99882b75dfdSjtc 99982b75dfdSjtc sprintf(pname, "%s:", pn); 100082b75dfdSjtc n = strlen(pname); 100182b75dfdSjtc 100282b75dfdSjtc sprintf(cmd, "%s/lpc status %s", LPCDIR, pn); 100382b75dfdSjtc p = popen(cmd, "r"); 100482b75dfdSjtc if (p == NULL) { 100582b75dfdSjtc msg_out("rpc.pcnfsd: unable to popen() lp status"); 100682b75dfdSjtc return (PI_RES_FAIL); 100782b75dfdSjtc } 100882b75dfdSjtc while (fgets(buff, 255, p) != NULL) { 100982b75dfdSjtc if (strncmp(buff, pname, n)) 101082b75dfdSjtc continue; 101182b75dfdSjtc /* 101282b75dfdSjtc ** We have a match. The only failure now is PI_RES_FAIL if 101382b75dfdSjtc ** lpstat output cannot be decoded 101482b75dfdSjtc */ 101582b75dfdSjtc stat = PI_RES_FAIL; 101682b75dfdSjtc /* 101782b75dfdSjtc ** The next four lines are usually if the form 101882b75dfdSjtc ** 101982b75dfdSjtc ** queuing is [enabled|disabled] 102082b75dfdSjtc ** printing is [enabled|disabled] 102182b75dfdSjtc ** [no entries | N entr[y|ies] in spool area] 102282b75dfdSjtc ** <status message, may include the word "attention"> 102382b75dfdSjtc */ 102482b75dfdSjtc while (fgets(buff, 255, p) != NULL && isspace(buff[0])) { 102582b75dfdSjtc cp = buff; 102682b75dfdSjtc while (isspace(*cp)) 102782b75dfdSjtc cp++; 102882b75dfdSjtc if (*cp == '\0') 102982b75dfdSjtc break; 103082b75dfdSjtc cp1 = cp; 103182b75dfdSjtc cp2 = buff2; 103282b75dfdSjtc while (*cp1 && *cp1 != '\n') { 103382b75dfdSjtc *cp2++ = tolower(*cp1); 103482b75dfdSjtc cp1++; 103582b75dfdSjtc } 103682b75dfdSjtc *cp1 = '\0'; 103782b75dfdSjtc *cp2 = '\0'; 103882b75dfdSjtc /* 103982b75dfdSjtc ** Now buff2 has a lower-cased copy and cp points at the original; 104082b75dfdSjtc ** both are null terminated without any newline 104182b75dfdSjtc */ 104282b75dfdSjtc if (!strncmp(buff2, "queuing", 7)) { 104382b75dfdSjtc *avail = (strstr(buff2, "enabled") != NULL); 104482b75dfdSjtc continue; 104582b75dfdSjtc } 104682b75dfdSjtc if (!strncmp(buff2, "printing", 8)) { 104782b75dfdSjtc *printing = (strstr(buff2, "enabled") != NULL); 104882b75dfdSjtc continue; 104982b75dfdSjtc } 105082b75dfdSjtc if (isdigit(buff2[0]) && (strstr(buff2, "entr") != NULL)) { 105182b75dfdSjtc 105282b75dfdSjtc *qlen = atoi(buff2); 105382b75dfdSjtc continue; 105482b75dfdSjtc } 105582b75dfdSjtc if (strstr(buff2, "attention") != NULL || 105682b75dfdSjtc strstr(buff2, "error") != NULL) 105782b75dfdSjtc *needs_operator = TRUE; 105882b75dfdSjtc if (*needs_operator || strstr(buff2, "waiting") != NULL) 105982b75dfdSjtc strcpy(status, cp); 106082b75dfdSjtc } 106182b75dfdSjtc stat = PI_RES_OK; 106282b75dfdSjtc break; 106382b75dfdSjtc } 106482b75dfdSjtc (void) pclose(p); 106582b75dfdSjtc return (stat); 106682b75dfdSjtc } 10676f885de1Sgwr #endif /* SVR4 */ 106882b75dfdSjtc 10696f885de1Sgwr /* 10706f885de1Sgwr * pr_cancel: cancel a print job 10716f885de1Sgwr */ 10726f885de1Sgwr #ifdef SVR4 10736f885de1Sgwr 10746f885de1Sgwr /* 10756f885de1Sgwr ** For SVR4 we have to be prepared for the following kinds of output: 10766f885de1Sgwr ** 10776f885de1Sgwr ** # cancel lp-6 10786f885de1Sgwr ** request "lp-6" cancelled 10796f885de1Sgwr ** # cancel lp-33 10806f885de1Sgwr ** UX:cancel: WARNING: Request "lp-33" doesn't exist. 10816f885de1Sgwr ** # cancel foo-88 10826f885de1Sgwr ** UX:cancel: WARNING: Request "foo-88" doesn't exist. 10836f885de1Sgwr ** # cancel foo 10846f885de1Sgwr ** UX:cancel: WARNING: "foo" is not a request id or a printer. 10856f885de1Sgwr ** TO FIX: Cancel requests by id or by 10866f885de1Sgwr ** name of printer where printing. 10876f885de1Sgwr ** # su geoff 10886f885de1Sgwr ** $ cancel lp-2 10896f885de1Sgwr ** UX:cancel: WARNING: Can't cancel request "lp-2". 10906f885de1Sgwr ** TO FIX: You are not allowed to cancel 10916f885de1Sgwr ** another's request. 10926f885de1Sgwr ** 10936f885de1Sgwr ** There are probably other variations for remote printers. 10946f885de1Sgwr ** Basically, if the reply begins with the string 10956f885de1Sgwr ** "UX:cancel: WARNING: " 10966f885de1Sgwr ** we can strip this off and look for one of the following 10976f885de1Sgwr ** (1) 'R' - should be part of "Request "xxxx" doesn't exist." 10986f885de1Sgwr ** (2) '"' - should be start of ""foo" is not a request id or..." 10996f885de1Sgwr ** (3) 'C' - should be start of "Can't cancel request..." 11006f885de1Sgwr ** 11016f885de1Sgwr ** The fly in the ointment: all of this can change if these 11026f885de1Sgwr ** messages are localized..... :-( 11036f885de1Sgwr */ 1104736ba086Slukem pcrstat 1105736ba086Slukem pr_cancel(pr, user, id) 11066f885de1Sgwr char *pr; 11076f885de1Sgwr char *user; 11086f885de1Sgwr char *id; 11096f885de1Sgwr { 11106f885de1Sgwr char cmdbuf[256]; 11116f885de1Sgwr char resbuf[256]; 11126f885de1Sgwr FILE *fd; 11136f885de1Sgwr pcrstat stat = PC_RES_NO_SUCH_JOB; 11146f885de1Sgwr 11156f885de1Sgwr pr = map_printer_name(pr); 11166f885de1Sgwr if (pr == NULL || suspicious(pr)) 11176f885de1Sgwr return (PC_RES_NO_SUCH_PRINTER); 11186f885de1Sgwr if (suspicious(id)) 11196f885de1Sgwr return (PC_RES_NO_SUCH_JOB); 11206f885de1Sgwr 11216f885de1Sgwr sprintf(cmdbuf, "/usr/bin/cancel %s", id); 11226f885de1Sgwr if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) { 11236f885de1Sgwr msg_out("rpc.pcnfsd: su_popen failed"); 11246f885de1Sgwr return (PC_RES_FAIL); 11256f885de1Sgwr } 11266f885de1Sgwr if (fgets(resbuf, 255, fd) == NULL) 11276f885de1Sgwr stat = PC_RES_FAIL; 1128736ba086Slukem else 1129736ba086Slukem if (!strstr(resbuf, "UX:")) 11306f885de1Sgwr stat = PC_RES_OK; 1131736ba086Slukem else 1132736ba086Slukem if (strstr(resbuf, "doesn't exist")) 11336f885de1Sgwr stat = PC_RES_NO_SUCH_JOB; 1134736ba086Slukem else 1135736ba086Slukem if (strstr(resbuf, "not a request id")) 11366f885de1Sgwr stat = PC_RES_NO_SUCH_JOB; 1137736ba086Slukem else 1138736ba086Slukem if (strstr(resbuf, "Can't cancel request")) 11396f885de1Sgwr stat = PC_RES_NOT_OWNER; 1140736ba086Slukem else 1141736ba086Slukem stat = PC_RES_FAIL; 11426f885de1Sgwr 11436f885de1Sgwr if (su_pclose(fd) == 255) 11446f885de1Sgwr msg_out("rpc.pcnfsd: su_pclose alert"); 11456f885de1Sgwr return (stat); 11466f885de1Sgwr } 11476f885de1Sgwr #else /* SVR4 */ 11486f885de1Sgwr 11496f885de1Sgwr /* 11506f885de1Sgwr * BSD way: lprm 11516f885de1Sgwr */ 1152736ba086Slukem pcrstat 1153736ba086Slukem pr_cancel(pr, user, id) 115482b75dfdSjtc char *pr; 115582b75dfdSjtc char *user; 115682b75dfdSjtc char *id; 115782b75dfdSjtc { 115882b75dfdSjtc char cmdbuf[256]; 115982b75dfdSjtc char resbuf[256]; 116082b75dfdSjtc FILE *fd; 116182b75dfdSjtc int i; 116282b75dfdSjtc pcrstat stat = PC_RES_NO_SUCH_JOB; 116382b75dfdSjtc 116482b75dfdSjtc pr = map_printer_name(pr); 116582b75dfdSjtc if (pr == NULL || suspicious(pr)) 116682b75dfdSjtc return (PC_RES_NO_SUCH_PRINTER); 116782b75dfdSjtc if (suspicious(id)) 116882b75dfdSjtc return (PC_RES_NO_SUCH_JOB); 116982b75dfdSjtc 117082b75dfdSjtc sprintf(cmdbuf, "%s/lprm -P%s %s", LPRDIR, pr, id); 117182b75dfdSjtc if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) { 117282b75dfdSjtc msg_out("rpc.pcnfsd: su_popen failed"); 117382b75dfdSjtc return (PC_RES_FAIL); 117482b75dfdSjtc } 117582b75dfdSjtc while (fgets(resbuf, 255, fd) != NULL) { 117682b75dfdSjtc i = strlen(resbuf); 117782b75dfdSjtc if (i) 117882b75dfdSjtc resbuf[i - 1] = '\0'; /* trim NL */ 117982b75dfdSjtc if (strstr(resbuf, "dequeued") != NULL) 118082b75dfdSjtc stat = PC_RES_OK; 118182b75dfdSjtc if (strstr(resbuf, "unknown printer") != NULL) 118282b75dfdSjtc stat = PC_RES_NO_SUCH_PRINTER; 118382b75dfdSjtc if (strstr(resbuf, "Permission denied") != NULL) 118482b75dfdSjtc stat = PC_RES_NOT_OWNER; 118582b75dfdSjtc } 118682b75dfdSjtc if (su_pclose(fd) == 255) 118782b75dfdSjtc msg_out("rpc.pcnfsd: su_pclose alert"); 118882b75dfdSjtc return (stat); 118982b75dfdSjtc } 11906f885de1Sgwr #endif /* SVR4 */ 1191736ba086Slukem 119282b75dfdSjtc /* 119382b75dfdSjtc ** New subsystem here. We allow the administrator to define 119482b75dfdSjtc ** up to NPRINTERDEFS aliases for printer names. This is done 119582b75dfdSjtc ** using the "/etc/pcnfsd.conf" file, which is read at startup. 119682b75dfdSjtc ** There are three entry points to this subsystem 119782b75dfdSjtc ** 119882b75dfdSjtc ** void add_printer_alias(char *printer, char *alias_for, char *command) 119982b75dfdSjtc ** 120082b75dfdSjtc ** This is invoked from "config_from_file()" for each 120182b75dfdSjtc ** "printer" line. "printer" is the name of a printer; note that 120282b75dfdSjtc ** it is possible to redefine an existing printer. "alias_for" 120382b75dfdSjtc ** is the name of the underlying printer, used for queue listing 120482b75dfdSjtc ** and other control functions. If it is "-", there is no 120582b75dfdSjtc ** underlying printer, or the administrative functions are 120682b75dfdSjtc ** not applicable to this printer. "command" 120782b75dfdSjtc ** is the command which should be run (via "su_popen()") if a 120882b75dfdSjtc ** job is printed on this printer. The following tokens may be 120982b75dfdSjtc ** embedded in the command, and are substituted as follows: 121082b75dfdSjtc ** 121182b75dfdSjtc ** $FILE - path to the file containing the print data 121282b75dfdSjtc ** $USER - login of user 121382b75dfdSjtc ** $HOST - hostname from which job originated 121482b75dfdSjtc ** 121582b75dfdSjtc ** Tokens may occur multiple times. If The command includes no 121682b75dfdSjtc ** $FILE token, the string " $FILE" is silently appended. 121782b75dfdSjtc ** 121882b75dfdSjtc ** pr_list list_virtual_printers() 121982b75dfdSjtc ** 122082b75dfdSjtc ** This is invoked from build_pr_list to generate a list of aliased 122182b75dfdSjtc ** printers, so that the client that asks for a list of valid printers 122282b75dfdSjtc ** will see these ones. 122382b75dfdSjtc ** 122482b75dfdSjtc ** char *map_printer_name(char *printer) 122582b75dfdSjtc ** 122682b75dfdSjtc ** If "printer" identifies an aliased printer, this function returns 122782b75dfdSjtc ** the "alias_for" name, or NULL if the "alias_for" was given as "-". 122882b75dfdSjtc ** Otherwise it returns its argument. 122982b75dfdSjtc ** 123082b75dfdSjtc ** char *expand_alias(char *printer, char *file, char *user, char *host) 123182b75dfdSjtc ** 123282b75dfdSjtc ** If "printer" is an aliased printer, this function returns a 123382b75dfdSjtc ** pointer to a static string in which the corresponding command 123482b75dfdSjtc ** has been expanded. Otherwise ot returns NULL. 123582b75dfdSjtc */ 123682b75dfdSjtc #define NPRINTERDEFS 16 123782b75dfdSjtc int num_aliases = 0; 123882b75dfdSjtc struct { 123982b75dfdSjtc char *a_printer; 124082b75dfdSjtc char *a_alias_for; 124182b75dfdSjtc char *a_command; 124282b75dfdSjtc } alias[NPRINTERDEFS]; 124382b75dfdSjtc 124482b75dfdSjtc void 124582b75dfdSjtc add_printer_alias(printer, alias_for, command) 124682b75dfdSjtc char *printer; 124782b75dfdSjtc char *alias_for; 124882b75dfdSjtc char *command; 124982b75dfdSjtc { 125082b75dfdSjtc if (num_aliases < NPRINTERDEFS) { 125182b75dfdSjtc alias[num_aliases].a_printer = strdup(printer); 125282b75dfdSjtc alias[num_aliases].a_alias_for = 125382b75dfdSjtc (strcmp(alias_for, "-") ? strdup(alias_for) : NULL); 125482b75dfdSjtc if (strstr(command, "$FILE")) 125582b75dfdSjtc alias[num_aliases].a_command = strdup(command); 125682b75dfdSjtc else { 125782b75dfdSjtc alias[num_aliases].a_command = (char *) grab(strlen(command) + 8); 125882b75dfdSjtc strcpy(alias[num_aliases].a_command, command); 125982b75dfdSjtc strcat(alias[num_aliases].a_command, " $FILE"); 126082b75dfdSjtc } 126182b75dfdSjtc num_aliases++; 126282b75dfdSjtc } 126382b75dfdSjtc } 126482b75dfdSjtc 1265736ba086Slukem pr_list 1266736ba086Slukem list_virtual_printers() 126782b75dfdSjtc { 126882b75dfdSjtc pr_list first = NULL; 126982b75dfdSjtc pr_list last = NULL; 127082b75dfdSjtc pr_list curr = NULL; 127182b75dfdSjtc int i; 127282b75dfdSjtc 127382b75dfdSjtc 127482b75dfdSjtc if (num_aliases == 0) 127582b75dfdSjtc return (NULL); 127682b75dfdSjtc 127782b75dfdSjtc for (i = 0; i < num_aliases; i++) { 127882b75dfdSjtc curr = (struct pr_list_item *) 127982b75dfdSjtc grab(sizeof(struct pr_list_item)); 128082b75dfdSjtc 128182b75dfdSjtc curr->pn = strdup(alias[i].a_printer); 128282b75dfdSjtc if (alias[i].a_alias_for == NULL) 128382b75dfdSjtc curr->device = strdup(""); 128482b75dfdSjtc else 128582b75dfdSjtc curr->device = strdup(alias[i].a_alias_for); 128682b75dfdSjtc curr->remhost = strdup(""); 128782b75dfdSjtc curr->cm = strdup("(alias)"); 128882b75dfdSjtc curr->pr_next = NULL; 128982b75dfdSjtc if (last == NULL) 129082b75dfdSjtc first = curr; 129182b75dfdSjtc else 129282b75dfdSjtc last->pr_next = curr; 129382b75dfdSjtc last = curr; 129482b75dfdSjtc 129582b75dfdSjtc } 129682b75dfdSjtc return (first); 129782b75dfdSjtc } 129882b75dfdSjtc 129982b75dfdSjtc 130082b75dfdSjtc char * 130182b75dfdSjtc map_printer_name(printer) 130282b75dfdSjtc char *printer; 130382b75dfdSjtc { 130482b75dfdSjtc int i; 130582b75dfdSjtc for (i = 0; i < num_aliases; i++) { 130682b75dfdSjtc if (!strcmp(printer, alias[i].a_printer)) 130782b75dfdSjtc return (alias[i].a_alias_for); 130882b75dfdSjtc } 130982b75dfdSjtc return (printer); 131082b75dfdSjtc } 131182b75dfdSjtc 1312736ba086Slukem void 131382b75dfdSjtc substitute(string, token, data) 131482b75dfdSjtc char *string; 131582b75dfdSjtc char *token; 131682b75dfdSjtc char *data; 131782b75dfdSjtc { 131882b75dfdSjtc char temp[512]; 131982b75dfdSjtc char *c; 132082b75dfdSjtc 1321736ba086Slukem while ((c = strstr(string, token)) != NULL) { 132282b75dfdSjtc *c = '\0'; 132382b75dfdSjtc strcpy(temp, string); 132482b75dfdSjtc strcat(temp, data); 132582b75dfdSjtc c += strlen(token); 132682b75dfdSjtc strcat(temp, c); 132782b75dfdSjtc strcpy(string, temp); 132882b75dfdSjtc } 132982b75dfdSjtc } 133082b75dfdSjtc 133182b75dfdSjtc char * 133282b75dfdSjtc expand_alias(printer, file, user, host) 133382b75dfdSjtc char *printer; 133482b75dfdSjtc char *file; 133582b75dfdSjtc char *user; 133682b75dfdSjtc char *host; 133782b75dfdSjtc { 133882b75dfdSjtc static char expansion[512]; 133982b75dfdSjtc int i; 134082b75dfdSjtc for (i = 0; i < num_aliases; i++) { 134182b75dfdSjtc if (!strcmp(printer, alias[i].a_printer)) { 134282b75dfdSjtc strcpy(expansion, alias[i].a_command); 134382b75dfdSjtc substitute(expansion, "$FILE", file); 134482b75dfdSjtc substitute(expansion, "$USER", user); 134582b75dfdSjtc substitute(expansion, "$HOST", host); 134682b75dfdSjtc return (expansion); 134782b75dfdSjtc } 134882b75dfdSjtc } 134982b75dfdSjtc return (NULL); 135082b75dfdSjtc } 1351