xref: /illumos-gate/usr/src/cmd/bnu/grades.c (revision f3041bfa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
22 /*	  All Rights Reserved  	*/
23 
24 /*
25  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #include "uucp.h"
30 #include <grp.h>
31 
32 #define G_EXT	0
33 #define	G_INT	1
34 #define	G_RES	2
35 #define	G_ACT	3
36 #define	G_IDF	4
37 #define	G_MAX	512	/* max number of fields in the Grades file line */
38 #define	SMBUF	128
39 
40 #define	TYPE	0
41 #define FILE1	1
42 #define	FILE2	2
43 #define	USER	3
44 #define	OPTS	4
45 #define	FILE3	5
46 
47 extern int rdfulline(), jsize(), gdirf(), gnamef();
48 extern void wfcommit();
49 
50 static void	mailAdmin();		/* Send mail to administrator. */
51 
52 /*
53  * chkgrp - checks to see the group has permission
54  *		to use a service grade queue.
55  *
56  * returns
57  *
58  *	SUCCESS - if the group has permissions
59  *	FAIL - if group does not
60  *
61  */
62 
63 static int
64 chkgrp(carray,na)
65 char **carray;
66 int na;
67 {
68 	struct group *grp;
69 	int i;
70 	gid_t gid;
71 
72 	gid = getgid();
73 	grp = getgrgid(gid);
74 
75 	for (i = G_IDF; i < na; i++)
76 			if (EQUALS(carray[i], grp->gr_name))
77 				return(SUCCESS);
78 
79 	return(FAIL);
80 }
81 
82 /*
83  * chkusr - checks the permission fields of the Grades file
84  *	    to determine if the user can queue to a particular service grade.
85  *
86  * returns
87  *
88  *	SUCCESS - if the user can queue to the service grade.
89  *	FAIL - if the user can not queue to this service grade.
90  *
91  */
92 
93 static int
94 chkusr(carray, na)
95 char **carray;
96 int na;
97 {
98 	int i;
99 
100 	/*
101 	 * start at the point where the users are supposed to be in the
102 	 * Grades file. Loop thru until the end of the user list is
103 	 * found or the user name is found. If the user name is found then
104 	 * return TRUE. If the end of the list is found, return FAIL.
105 	 */
106 
107 	DEBUG(9, "User (%s)\n", User);
108 
109 	/* check for any user and return if so */
110 
111 	if (EQUALS(carray[G_IDF], "Any"))
112 		return(SUCCESS);
113 
114 	DEBUG(9, "Members of administrator defined service grade (%s)\n", carray[G_EXT]);
115 
116 	for (i = G_IDF; i < na; i++) {
117 		DEBUG(9, "%s\n", carray[i]);
118 		if (EQUALS(User, carray[i]))
119 			return(SUCCESS);
120 	}
121 
122 	return(FAIL);
123 }
124 
125 /*
126  *	fgrade - finds the appropiate queue to queue a job into
127  *
128  *	returns
129  *		SUCCESS	-> found a queue
130  *		FAIL	-> can't find a queue
131  */
132 
133 int
134 fgrade(scfile)
135 struct cs_struct *scfile;
136 {
137 	char fdgrade();
138 	FILE *cfd;
139 	char line[BUFSIZ];
140 	char *carray[G_MAX];
141 	long climit;
142 
143 	/* Check for the default service grade first */
144 
145 	if (strcmp(scfile->sgrade, "default") == 0) {
146 		scfile->grade = fdgrade();
147 		return(SUCCESS);
148 	}
149 
150 	/* open grades file to begin a linear for the grade requested */
151 
152 	cfd = fopen(GRADES, "r");
153 
154 	/* loop until the file is empty or we find the grade we want */
155 
156 	while (rdfulline(cfd, line, BUFSIZ) != 0) {
157 		(void) getargs(line, carray, G_MAX);
158 
159 		/* check to see if this is the grade we want */
160 
161 		if (!EQUALS(scfile->sgrade, carray[G_EXT]))
162 			continue;
163 
164 		if (jsize(scfile, carray[G_RES], &climit) != FAIL) {
165 			(void) fclose(cfd);
166 			scfile->grade = *carray[G_INT];
167 			return(SUCCESS);
168 		}
169 	}
170 
171 	(void) fclose(cfd);
172 
173 	(void) fprintf(stderr, gettext("Job size (%ld bytes)"
174 	    " exceeds maximum number of bytes (%ld bytes)"
175 	    " allowed into this service grade (%s).\n"
176 	    "Job queued to default grade.\n"),
177 	    scfile->jsize, climit, scfile->sgrade);
178 
179 	scfile->grade = fdgrade();
180 	return(SUCCESS);
181 }
182 
183 /*
184  *	fdgrade - finds the default queue for this system
185  *
186  *	returns
187  *		a one char name for the default queue
188  *
189  */
190 
191 char
192 fdgrade()
193 {
194 	FILE *cfd;
195 	char line[BUFSIZ];
196 	char *carray[G_MAX];
197 
198 	/* Check for the default grade first */
199 
200 		cfd = fopen(GRADES, "r");
201 
202 		/* loop until the end of the file is read */
203 
204 		for (; rdfulline(cfd, line, BUFSIZ) != 0;) {
205 
206 			/* parse the fields of this line */
207 
208 			(void) getargs(line, carray, G_MAX);
209 
210 			/* check to see if the administrator has defined
211 			 * a default grade for the machine.
212 			 */
213 
214 			if (strcmp(carray[G_EXT], "default") != 0)
215 				continue;
216 
217 			/* default must be defined in the file
218 			 *  close the file, get the queue name, and return.
219 			 */
220 
221 			(void) fclose(cfd);
222 			return(*carray[G_INT]);
223 		}
224 
225 		/* no default defined in this file. close file.
226 		 * get our default queue and return.
227 		 */
228 
229 		(void) fclose(cfd);
230 		return(D_QUEUE);
231 }
232 
233 /*
234  * job_size - determines the size of a job
235  *
236  * returns
237  *
238  *	SUCCESS - if the size of the job can be determined
239  *	FAIL	- otherwise
240  */
241 
242 int
243 job_size(scfile)
244 struct cs_struct *scfile;
245 {
246 	extern int Dfileused;
247 	struct stat s;
248 	FILE *fp;
249 	char line[BUFSIZ];
250 	char *carray[G_MAX];
251 	int na;
252 	int nodfile = FALSE;
253 	int ret;
254 
255 	scfile->jsize = 0;
256 
257 	fp = fopen(scfile->file, "r");
258 
259 	if (fp == NULL) {
260 		toCorrupt(scfile->file);
261 		errent(Ct_OPEN, scfile->file, errno, __FILE__,  __LINE__);
262 	}
263 
264 	while (fgets(line, BUFSIZ, fp) != NULL) {
265 		na = getargs(line, carray, G_MAX);
266 
267 		if (na < 6) {
268 			(void) fclose(fp);
269 			toCorrupt(scfile->file);
270 			errent("BAD NUMBER OF ARGUMENTS", scfile->file, 0,
271 				__FILE__, __LINE__);
272 		}
273 
274 		/* if the type of a transfer is not a push
275 		 * then don't try to determine the size of
276 		 * the data file, because you can't.
277 		 */
278 
279 		if (*carray[TYPE] == 'R')
280 			continue;
281 
282 		/* find the data dile that is to be transferred */
283 
284 		if ((ret = stat(carray[FILE3], &s)) != 0) {
285 			if (errno == ENOENT) {
286 				nodfile = TRUE;
287 				ret = stat(carray[FILE1], &s);
288 			}
289 		}
290 		else
291 			Dfileused = TRUE;
292 
293 		/*
294 		 * check to see if the return code from stat was 0
295 		 * if return code was not 0, write message to error
296 		 * log and quit. Otherwise, add size of file to job
297 		 * size and continue looping.
298 		 */
299 
300 		if (ret != 0) {
301 			(void) fclose(fp);
302 			errent(Ct_STAT, nodfile ?
303 				carray[FILE1] : carray[FILE3], errno,
304 				__FILE__, __LINE__);
305 		}
306 
307 		nodfile = FALSE;
308 		scfile->jsize += s.st_size;
309 	}
310 	(void) fclose(fp);
311 	return(SUCCESS);
312 }
313 
314 static void lcase();
315 
316 /*
317  * jsize - determines whether if a job is small enough to
318  * 	   be placed in the appropiate queue.
319  *
320  * returns
321  *
322  *	SUCCESS - if the size of the job is less than or
323  *		  equal to the number of bytes in the restriction
324  *		  of the GRADES file.
325  *
326  *	FAIL	- otherwise
327  */
328 
329 int
330 jsize(scfile, climit, nlimit)
331 struct cs_struct *scfile;
332 char *climit;
333 long *nlimit;
334 {
335 #define ONE_K (1024)
336 #define ONE_MEG ((1024)*(1024))
337 
338 	char rest[SMBUF];
339 	char msg[BUFSIZ], *p;
340 
341 	if (EQUALS(climit, "Any"))
342 		return(SUCCESS);
343 
344 	lcase(climit, rest, SMBUF);
345 
346 	if (!(p = strchr(rest, 'k')) && (!(p = strchr(rest, 'm')))) {
347 
348 		for(p = climit; *p; ++p) {
349 			if (isdigit(*p))
350 				continue;
351 
352 			/* corrupt restriction field in the Grades file.
353 			 * report it to the uucp administrator.
354 			 */
355 
356 			snprintf(msg, sizeof (msg),
357 			    gettext("Error encountered in the"
358 			    " restrictions field of the Grades file."
359 			    "  Field contents (%s)."), climit);
360 			mailAdmin(msg);
361 			return(SUCCESS);
362 		}
363 
364 		*nlimit = atol(climit);
365 	}
366 	else if (*p == 'k') {
367 		*p = '\0';
368 		*nlimit = (long) (atof(rest) * ONE_K);
369 	}
370 	else {
371 		*p = '\0';
372 		*nlimit = (long) (atof(rest) * ONE_MEG);
373 	}
374 
375 	if (scfile->jsize <= *nlimit)
376 		return(SUCCESS);
377 	else
378 		return(FAIL);
379 }
380 
381 static void
382 lcase(s, t, lim)
383 char s[], t[];
384 int lim;
385 {
386 	char *p;
387 	int i;
388 
389 
390 	p = s;
391 
392 	for (i = 0; i < lim-1 && *p; i++)
393 		if (isupper(*p))
394 			t[i] = tolower(*p++);
395 		else
396 			t[i] = *p++;
397 
398 	t[i] = '\0';
399 	return;
400 }
401 
402 /*
403  * mailAdmin - mail a message to the uucp administrator.
404  *
405  * returns:
406  *
407  *	nothing
408  */
409 
410 static void
411 mailAdmin (msg)
412 
413 char *	msg;
414 
415 {
416 	char	cmd[BUFSIZ];		/* Place to build mail command. */
417 	FILE *	mail;			/* Channel to write mail on. */
418 
419 	(void) sprintf(cmd, "%s %s %s", PATH, MAIL, "uucp");
420 	if ((mail = popen(cmd, "w")) != (FILE *) NULL)
421 	{
422 		(void) fprintf(mail, "To: uucp\nSubject: %s\n\n%s\n",
423 		    gettext("Grades file problem"), msg);
424 		(void) pclose(mail);
425 	}
426 
427 	/*
428 	 * Ignore popen failure.  There is not much that we can do if
429 	 * it fails, since we are already trying to notify the administrator
430 	 * of a problem.
431 	 */
432 	return;
433 }
434 
435 /*
436  * putdfiles - moves any and all of the D. to the spool directory for
437  * 	       a C. file.
438  *
439  * returns
440  *
441  *	nothing
442  */
443 
444 void
445 putdfiles(scfile)
446 struct cs_struct scfile;
447 {
448 	FILE *fp;
449 	char line[BUFSIZ];
450 	char *carray[G_MAX];
451 	int na;
452 	struct stat s;
453 
454 	fp = fopen(scfile.file, "r");
455 
456 	if (fp == NULL) {
457 		toCorrupt(scfile.file);
458 		errent(Ct_OPEN, scfile.file, errno, __FILE__, __LINE__);
459 	}
460 
461 	while (fgets(line, BUFSIZ, fp) != NULL) {
462 
463 		na = getargs(line, carray, G_MAX);
464 		if (na < 6) {
465 			(void) fclose(fp);
466 			toCorrupt(scfile.file);
467 			errent("BAD NUMBER OF ARGUMENTS", scfile.file, 0,
468 				__FILE__, __LINE__);
469 		}
470 
471 		if (*carray[TYPE] == 'R')
472 			continue;
473 
474 	    	/* move D. file to the spool area */
475 
476 		if (stat(carray[FILE3], &s) != -1)
477 			wfcommit(carray[FILE3], carray[FILE3], scfile.sys);
478 	}
479 
480 	(void) fclose(fp);
481 	return;
482 }
483 
484 /*
485  * reads a line from a file and takes care of comment lines
486  * and continuations (\) in last column.
487  *
488  * return:
489  *	the number of chars that are placed in line.
490  */
491 
492 int
493 rdfulline(fd, line, lim)
494 FILE *fd;
495 char *line;
496 int lim;
497 {
498 	register char *p, *c;
499 	char buf[BUFSIZ];
500 	size_t blr, btox;
501 
502 	p = line;
503 	for (;fgets(buf, BUFSIZ, fd) != NULL;) {
504 		/* check to see if it is a comment */
505 
506 		if (buf[0] == '#')
507 			continue;
508 
509 		/* remove trailing white space */
510 		c = &buf[strlen(buf)-1];
511 		while (c>=buf && (*c == '\n' || *c == '\t' || *c == ' ') )
512 			*c-- = NULLCHAR;
513 
514 		if (buf[0] == '\n' || buf[0] == NULLCHAR)
515 			continue;
516 
517 		blr = lim - 1 - (p - line);
518 		btox = blr < strlen(buf) ? blr : strlen(buf);
519 
520 		if (btox <= 0)
521 			break;
522 
523 		(void) strncpy(p, buf, btox);
524 		p += btox - 1;
525 
526 		if ( *(p-1) == '\\')
527 			p--;
528 		else
529 			break;
530 	}
531 
532 	*++p = '\0';
533 	return(p-line-1);
534 }
535 
536 /*	upermit - checks to determine if the user has permissions
537  *	to use administrator defined service grade.
538  *
539  *	returns
540  *		SUCCESS -> if the user can queue to this service grade.
541  *		FAIL -> if the user cannot queue to this service grade.
542  */
543 
544 int
545 upermit(carray, na)
546 char **carray;
547 int na;
548 {
549 #define G_USR "user"
550 #define G_NUSR "non-user"
551 #define G_GRP "group"
552 #define G_NGRP "non-group"
553 
554 	char actn[SMBUF];
555 	char ufld[SMBUF];
556 	char msg[BUFSIZ];
557 
558 	(void) strcpy(actn, carray[G_ACT]);
559 
560 	lcase(actn, ufld, SMBUF);
561 
562 	if (EQUALS(ufld, G_USR))
563 		return(chkusr(carray,na));
564 
565 	if (EQUALS(ufld, G_NUSR))
566 		return((chkusr(carray, na) != SUCCESS) ? SUCCESS : FAIL);
567 
568 	if (EQUALS(ufld, G_GRP))
569 		return(chkgrp(carray, na));
570 
571 	if (EQUALS(ufld, G_NGRP))
572 		return((chkgrp(carray, na) != SUCCESS) ? SUCCESS : FAIL);
573 
574 	(void) snprintf(msg, sizeof (msg),
575 	    gettext("Error encountered in action field of"
576 	    " the Grades file. Field contents (%s)."), carray[G_ACT]);
577 	mailAdmin(msg);
578 	return(FAIL);
579 }
580 
581 /*
582  *	vergrd - verify if the grade name is a valid administrator
583  *		 defined service grade name and if the user has the
584  *		 appropiate permission to use this grade.
585  *
586  *	returns
587  *		SUCCESS	-> grade is valid and user is
588  *			   permitted to use this grade.
589  *		FAIL	-> otherwise
590  *
591  */
592 
593 int
594 vergrd(grade)
595 char *grade;
596 {
597 	FILE *cfd;
598 	char line[BUFSIZ];
599 	char *carray[G_MAX];
600 	int na;
601 
602 	/* Check for the default grade first */
603 
604 	if (EQUALS(grade, "default"))
605 		return(SUCCESS);
606 
607 	/* open grades file to begin a linear for the grade requested */
608 
609 	cfd = fopen(GRADES, "r");
610 
611 	/* loop until the file is empty or we find the grade we want */
612 
613 	while (rdfulline(cfd, line, BUFSIZ) != 0) {
614 		na = getargs(line, carray, G_MAX);
615 
616 		/* check to see if this is the grade we want */
617 
618 		if (!EQUALS(grade, carray[G_EXT]))
619 			continue;
620 
621 		/* check for the permission on this grade */
622 
623 		if (upermit(carray, na) != FAIL) {
624 			(void) fclose(cfd);
625 			return(SUCCESS);
626 		}
627 		else {
628 			(void) fclose(cfd);
629 			(void) fprintf(stderr, gettext("User does not have"
630 			    " permission to use this service grade (%s).\n"
631 			    "Job has not been queued.\n"
632 			    "Use (uuglist) to find which service grades"
633 			    " you can queue to.\n"), grade);
634 			return(FAIL);
635 		}
636 	}
637 
638 	(void) fclose(cfd);
639 
640 	(void) fprintf(stderr, gettext(
641 	    "Service grade (%s) does not exist on this machine."
642 	    "  Job not queued.\n"
643 	    "Use (uuglist) to find which service grades are available on"
644 	    " this machine.\n"), grade);
645 	return(FAIL);
646 }
647 
648 /*
649  * wfremove - removes a C. file from the Workspace directory and all of its
650  * D. files.
651  */
652 
653 void
654 wfremove(file)
655 char *file;
656 {
657 	FILE *fp;
658 	char line[BUFSIZ];
659 	char *carray[G_MAX];
660 	int na;
661 	struct stat s;
662 
663 	fp = fopen(file, "r");
664 
665 	if (fp == NULL) {
666 		toCorrupt(file);
667 		errent(Ct_OPEN, file, errno, __FILE__, __LINE__);
668 	}
669 
670 	while (fgets(line, BUFSIZ, fp) != NULL) {
671 		na = getargs(line, carray, G_MAX);
672 
673 		if (na < 6) {
674 			(void) fclose(fp);
675 			toCorrupt(file);
676 			errent("BAD NUMBER OF ARGUMENTS", file, 0,
677 				__FILE__, __LINE__);
678 		}
679 
680 		if (*carray[TYPE] == 'R')
681 			continue;
682 
683 	    	/* remove D. file */
684 
685 	    	DEBUG(4, "Removing data file (%s)\n", carray[FILE3]);
686 
687 		if ((stat(carray[FILE3], &s) != -1) && (unlink(carray[FILE3]) != 0)) {
688 			(void) fclose(fp);
689 			toCorrupt(file);
690 			toCorrupt(carray[FILE3]);
691 			errent(Ct_UNLINK, carray[FILE3], errno, __FILE__,
692 				__LINE__);
693 		}
694 	}
695 
696 	(void) fclose(fp);
697 
698 	DEBUG(4, "Removing work file (%s)\n", file);
699 
700 	if (unlink(file) != 0) {
701 		toCorrupt(file);
702 		errent(Ct_UNLINK, file, errno, __FILE__, __LINE__);
703 	}
704 	return;
705 }
706 
707 /*
708  * findgrade - finds the highest priority job grade that is not locked
709  * and that has jobs.
710  *
711  * job grade name is null, if no job grade is found.
712  */
713 
714 void
715 findgrade(dir, jobgrade)
716 char *dir, *jobgrade;
717 {
718 	char prevgrade[MAXBASENAME+1], curgrade[MAXBASENAME+1],
719 	     gradedir[MAXBASENAME+1];
720 	char lockname[MAXFULLNAME];
721 	char Cfile[MAXBASENAME+1];
722 	DIR *p, *q;
723 
724 	*prevgrade = NULLCHAR;
725 	p = opendir(dir);
726 	ASSERT(p != NULL, Ct_OPEN, dir, errno);
727 
728 	while (gdirf(p, gradedir, dir) == TRUE) {
729 		(void) sprintf(lockname, "%s.%.*s.%s", LOCKPRE, SYSNSIZE,
730 		    Rmtname, gradedir);
731 		if (cklock(lockname) == FAIL)
732 			continue;
733 		q = opendir(gradedir);
734 		ASSERT(q != NULL, Ct_OPEN, gradedir, errno);
735 		while (gnamef(q, Cfile) == TRUE) {
736 			if (Cfile[0] == CMDPRE) {
737 				if (*prevgrade == NULLCHAR) {
738 					(void) strcpy(prevgrade, gradedir);
739 					break;
740 				}
741 				(void) strcpy(curgrade, gradedir);
742 				if (strcmp(curgrade, prevgrade) < 0)
743 					(void) strcpy(prevgrade, curgrade);
744 			}
745 		}
746 		closedir(q);
747 	}
748 	closedir(p);
749 	(void) strncpy(jobgrade, prevgrade, MAXBASENAME);
750 	jobgrade[MAXBASENAME] = NULLCHAR;
751 	return;
752 }
753