source: trunk/athena/bin/lpr/rmjob.c @ 12350

Revision 12350, 11.8 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 *      $Id: rmjob.c,v 1.11 1999-01-22 23:10:46 ghudson Exp $
3 */
4
5#ifndef lint
6static char *rcsid_rmjob_c = "$Id: rmjob.c,v 1.11 1999-01-22 23:10:46 ghudson Exp $";
7#endif lint
8
9/*
10 * Copyright (c) 1983 Regents of the University of California.
11 * All rights reserved.  The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
13 */
14
15#ifndef lint
16static char sccsid[] = "@(#)rmjob.c     5.1 (Berkeley) 6/6/85";
17#endif not lint
18
19/*
20 * rmjob - remove the specified jobs from the queue.
21 */
22
23#include "lp.h"
24#if defined(POSIX) && !defined(ultrix)
25#include "posix.h"
26#endif
27
28/*
29 * Stuff for handling lprm specifications
30 */
31extern char     *user[];                /* users to process */
32extern int      users;                  /* # of users in user array */
33extern int      requ[];                 /* job number of spool entries */
34extern int      requests;               /* # of spool requests */
35extern char     *person;                /* name of person doing lprm */
36
37char    root[] = "root";
38int     all = 0;                /* eliminate all files (root only) */
39int     cur_daemon;             /* daemon's pid */
40char    current[40];            /* active control file name */
41int     assasinated = 0;        /* 1 means we've killed the lpd */
42
43#if defined(KERBEROS)
44extern int      use_kerberos;
45extern int      kerberos_override;
46short KA;
47KTEXT_ST kticket;
48long kerror;
49#endif /* KERBEROS */
50
51int     iscf();
52
53rmjob()
54{
55        register int i, nitems;
56#ifdef POSIX
57        struct dirent **files;
58#else
59        struct direct **files;
60#endif
61
62        assasinated = 0;        /* Haven't killed it yet! */
63        nitems = 0;             /* Items in the local spool area */
64       
65#ifdef HESIOD
66        if ((i = pgetent(line, printer)) <= 0) {
67                if (pralias(alibuf, printer))
68                        printer = alibuf;
69                if ((i = hpgetent(line, printer)) < 1)
70                        fatal("unknown printer");
71        }
72#else
73        if ((i = pgetent(line, printer)) < 0) {
74                fatal("cannot open printer description file");
75        } else if (i == 0)
76                fatal("unknown printer");
77#endif /* HESIOD */
78        if ((SD = pgetstr("sd", &bp)) == NULL)
79                SD = DEFSPOOL;
80        if ((LO = pgetstr("lo", &bp)) == NULL)
81                LO = DEFLOCK;
82        if ((LP = pgetstr("lp", &bp)) == NULL)
83                LP = DEFDEVLP;
84        if ((RP = pgetstr("rp", &bp)) == NULL)
85                RP = DEFLP;
86        RM = pgetstr("rm", &bp);
87
88#if defined(KERBEROS)
89        KA = pgetnum("ka");
90        if (KA > 0)
91            use_kerberos = 1;
92        else
93            use_kerberos = 0;
94        if (kerberos_override > -1)
95            use_kerberos = kerberos_override;
96#endif /* KERBEROS */
97
98        /*
99         * If the format was `lprm -' and the user isn't the super-user,
100         *  then fake things to look like he said `lprm user'.
101         */
102        if (users < 0) {
103                if (getuid() == 0)
104                        all = 1;        /* all files in local queue */
105                else {
106                        user[0] = person;
107                        users = 1;
108                }
109        }
110        if (!strcmp(person, "-all")) {
111                if (from == host)
112                        fatal("The login name \"-all\" is reserved");
113                all = 1;        /* all those from 'from' */
114                person = root;
115        }
116       
117        if (chdir(SD) < 0) {
118                if (RM == (char *)0)
119                        fatal("cannot chdir to spool directory");
120        } else if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
121                fatal("cannot access spool directory");
122
123        if (nitems) {
124                /*
125                 * process the files
126                 */
127                for (i = 0; i < nitems; i++)
128                        process(files[i]->d_name);
129        }
130        chkremote();
131        /*
132         * Restart the printer daemon if it was killed
133         */
134        if (assasinated && !startdaemon(printer))
135                fatal("cannot restart printer daemon\n");
136
137        exit(0);
138}
139
140/*
141 * Process a lock file: collect the pid of the active
142 *  daemon and the file name of the active spool entry.
143 * Return boolean indicating existence of a lock file.
144 */
145lockchk(s)
146        char *s;
147{
148        register FILE *fp;
149        register int i, n;
150
151        cur_daemon = -1;        /* Initialize to no daemon */
152       
153        if ((fp = fopen(s, "r")) == NULL)
154                if (errno == EACCES)
155                        fatal("can't access lock file");
156                else
157                        return(0);
158        if (!getline(fp)) {
159                (void) fclose(fp);
160                return(0);              /* no daemon present */
161        }
162        cur_daemon = atoi(line);
163        if (kill(cur_daemon, 0) < 0) {
164                (void) fclose(fp);
165                return(0);              /* no daemon present */
166        }
167        for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
168                if (i > 5) {
169                        n = 1;
170                        break;
171                }
172                sleep(i);
173        }
174        current[n-1] = '\0';
175        (void) fclose(fp);
176        return(1);
177}
178
179/*
180 * Process a control file.
181 */
182process(file)
183        char *file;
184{
185        FILE *cfp;
186        int     flock_retry = 0;
187
188        if (!chk(file))
189                return;
190        if ((cfp = fopen(file, "r+")) == NULL)
191                fatal("cannot open %s", file);
192        while (flock(fileno(cfp), LOCK_EX|LOCK_NB) < 0) {
193                if (errno == EWOULDBLOCK) {
194                        /*
195                         * We couldn't get the lock; lpd must be
196                         * using the control file.  So try to
197                         * blow it away.
198                         *
199                         * Note: assasumes lockchk has already been
200                         * run, so cur_daemon contains valid
201                         * information.
202                         */
203                        if (!lockchk(LO))
204                                /* No daemon, must have just */
205                                /* exited.... */
206                                continue;
207                        syslog(LOG_DEBUG, "Killing printer daemon %d",
208                               cur_daemon);
209                        if (assasinated = kill(cur_daemon, SIGINT) == 0)
210                                sleep(1);
211                        else {
212                                syslog(LOG_ERR, "kill %d: %m", cur_daemon);
213#ifdef notdef
214                                fatal("cannot kill printer daemon");
215#endif
216                        }
217                        flock_retry++;
218                        if (flock_retry > 2)
219                                fatal("cannot obtain lock on control file");
220                } else {
221                        syslog(LOG_ERR, "%s: %s: %m", printer, file);
222                        return;
223                }
224        }
225        while (getline(cfp)) {
226                switch (line[0]) {
227                case 'U':  /* unlink associated files */
228                        if (from != host)
229                                printf("%s: ", host);
230                        printf(spool_unlink(line+1, 'd', 1) ? "cannot dequeue %s\n" :
231                                "%s dequeued\n", line+1);
232                }
233        }
234        (void) fclose(cfp);
235        if (from != host)
236                printf("%s: ", host);
237        printf(spool_unlink(file, 'c', 1) ?
238               "cannot dequeue %s\n" : "%s dequeued\n", file);
239}
240
241/*
242 * Do the dirty work in checking
243 */
244chk(file)
245        char *file;
246{
247        register int *r, n;
248        register char **u, *cp;
249        FILE *cfp;
250
251        /*
252         * Check for valid cf file name (mostly checking current).
253         */
254        if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
255                return(0);
256
257        if (all && (from == host || !strcmp(from, file+6)))
258                return(1);
259
260        /*
261         * get the owner's name from the control file.
262         */
263        if ((cfp = fopen(file, "r")) == NULL)
264                return(0);
265        while (getline(cfp)) {
266                if (line[0] == 'P')
267                        break;
268        }
269        (void) fclose(cfp);
270        if (line[0] != 'P')
271                return(0);
272
273        if (users == 0 && requests == 0)
274                return(!strcmp(file, current) && isowner(line+1, file));
275        /*
276         * Check the request list
277         */
278        for (n = 0, cp = file+3; isdigit(*cp) && cp != file+6; )
279                n = n * 10 + (*cp++ - '0');
280        for (r = requ; r < &requ[requests]; r++)
281                if (*r == n && isowner(line+1, file))
282                        return(1);
283        /*
284         * Check to see if it's in the user list
285         */
286        for (u = user; u < &user[users]; u++)
287                if (!strcmp(*u, line+1) && isowner(line+1, file))
288                        return(1);
289        return(0);
290}
291
292/*
293 * If root is removing a file on the local machine, allow it.
294 * If root is removing a file from a remote machine, only allow
295 * files sent from the remote machine to be removed.
296 * Normal users can only remove the file from where it was sent.
297 */
298isowner(owner, file)
299        char *owner, *file;
300{
301        if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
302                return(1);
303#ifdef KERBEROS
304        if (!strcmp(person, owner))
305                return(1);
306#else
307        if (!strcmp(person, owner) && !strcmp(from, file+6))
308                return(1);
309#endif /* KERBEROS */
310        if (from != host)
311                printf("%s: ", host);
312        printf("%s: Permission denied\n", file);
313        return(0);
314}
315
316/*
317 * Check to see if we are sending files to a remote machine. If we are,
318 * then try removing files on the remote machine.
319 */
320chkremote()
321{
322        register char *cp;
323        register int i, rem;
324        register int resp;
325        int n;
326        char buf[BUFSIZ];
327        char name[MAXHOSTNAMELEN + 1];
328        struct hostent *hp;
329
330        /* get the name of the local host */
331        gethostname (name, sizeof(name) - 1);
332        name[sizeof(name)-1] = '\0';
333
334        /* get the network standard name of the local host */
335        hp = gethostbyname (name);
336        if (hp == (struct hostent *) NULL) {
337            printf ("unable to get hostname for local machine %s\n",
338                        name);
339            return;
340        } else {
341            strncpy (name, hp->h_name, sizeof(name));
342            name[sizeof(name) - 1] = '\0';
343        }               
344
345        if (RM == (char *)0)
346                RM = name;
347        else {
348                /* get the network standard name of RM */
349                hp = gethostbyname (RM);
350                if (hp == (struct hostent *) NULL) {
351                        printf ("unable to get hostname for remote machine %s\n",
352                                RM);
353                        return;
354                }
355        }
356
357        /* if printer is not on local machine, ignore LP */
358        if (strcasecmp (name, hp->h_name) != 0)
359            LP = "";
360        else return;    /* local machine */
361
362        /*
363         * Flush stdout so the user can see what has been deleted
364         * while we wait (possibly) for the connection.
365         */
366        fflush(stdout);
367
368        sprintf(buf, "\5%.*s %.*s", 300, RP, 300, all ? "-all" : person);
369        cp = buf;
370        for (i = 0; i < users; i++) {
371                cp += strlen(cp);
372                if (cp - buf + strlen(user[i]) + 1 > sizeof(buf) - 2)
373                    break;
374                *cp++ = ' ';
375                (void) strcpy(cp, user[i]);
376        }
377        for (i = 0; i < requests; i++) {
378                cp += strlen(cp);
379                if (cp - buf + 11 > sizeof(buf) - 2)
380                    break;
381                (void) sprintf(cp, " %d", requ[i]);
382        }
383        (void) strcat(cp, "\n");
384        rem = getport(RM);
385        if (rem < 0) {
386                if (from != host)
387                        printf("%s: ", host);
388                printf("connection to %s is down\n", RM);
389        } else {
390#ifdef KERBEROS
391                if (use_kerberos) {
392                        /* If we require kerberos authentication,
393                         * then send credentials
394                         * over
395                         */
396                        (void) sprintf(line, "k%s\n", RP);
397                        n = strlen(line);
398                        if (write(rem, line, n) != n)
399                                fatal("Error sending kerberos opcode.\n");
400
401                        if ((resp = responser(rem)) != '\0') {
402                            fprintf(stderr,
403                                    "Remote printer does not support kerberos authentication\n");
404                            if(kerberos_override == 1)
405                                fprintf(stderr, "Try again without the -k flag\n");
406                            if(kerberos_override == -1)
407                                fprintf(stderr,"Try again using the -u option\n");
408                            exit(1);
409                        }
410                       
411                        kerror = krb_sendauth(0L, rem, &kticket, KLPR_SERVICE,
412                                              RM, (char *)krb_realmofhost(RM),
413                                              0, (MSG_DAT *) 0,
414                                              (CREDENTIALS *) 0,
415                                              (bit_64 *) 0,
416                                              (struct sockaddr_in *)0,
417                                              (struct sockaddr_in *)0,
418                                              "KLPRV0.1");
419                        if (kerror != KSUCCESS)
420                            fatal("Kerberos authentication failed. Use kinit and try again.\n");
421                        if ((resp = responser(rem)) != '\0') {
422                            if (resp == '\3')
423                                fatal("Authentication failed. Use kinit and then try again.\n");
424                            else fatal("Syncronization error.\n");
425                        }
426                    }
427#endif /* KERBEROS */
428                i = strlen(buf);
429                if (write(rem, buf, i) != i)
430                        fatal("Lost connection");
431                while ((i = read(rem, buf, sizeof(buf))) > 0)
432                        (void) fwrite(buf, 1, i, stdout);
433                (void) close(rem);
434        }
435}
436
437/*
438 * Return 1 if the filename begins with 'cf'
439 */
440iscf(d)
441#ifdef POSIX
442        struct dirent *d;
443#else
444        struct direct *d;
445#endif
446{
447        return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
448}
449
450/*
451 * Check to make sure there have been no errors and that both programs
452 * are in sync with eachother.
453 * Return non-zero if the connection was lost.
454 */
455
456static responser(fd)
457int fd;
458{
459        char resp;
460
461        if (read(fd, &resp, 1) != 1) {
462                fprintf(stderr,"Lost connection to printer....\n");
463                return(-1);
464        }
465        return(resp);
466}
467
468/*
469 * Wrapper for unlink() when used to remove files from the spools.
470 * These filenames are passed from the client and not necessarily
471 * trusted.
472 */
473
474int spool_unlink(afile, aflag, wflag)
475        char *afile, aflag;
476        int wflag;
477{
478        struct stat st;
479
480        if (lstat(afile, &st) == -1)
481                return(-1);
482
483        if ((st.st_mode & S_IFMT) != S_IFREG)
484                return(-2);
485         
486        if (afile[0] == '.' || strchr(afile, '/')) {
487                syslog(LOG_ERR, "lpd attempted to unlink %s", afile);
488                return(-2);
489        }
490        if (wflag &&
491            (afile[0] != aflag || afile[1] != 'f' ||
492             afile[2] != 'A' || !isxdigit(afile[3]) ||
493             !isxdigit(afile[4]) || !isxdigit(afile[5])))
494                syslog(LOG_NOTICE,
495                       "nonstandard job character for spool_unlink in %d.%d.%d.%d.%d.%d",
496                       afile[0], afile[1], afile[2], afile[3],
497                       afile[4], afile[5]);
498        return(UNLINK(afile));
499}
Note: See TracBrowser for help on using the repository browser.