|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T u ┃
Length: 11811 (0x2e23) Types: TextFile Names: »untamo.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─ ⟦this⟧ »EUUGD11/euug-87hel/sec8/untamo/untamo.c«
#ifdef PUCC #include <sys/types.h> #include <rld.h> #endif PUCC #include <utmp.h> #include <signal.h> #include <sys/file.h> #ifndef F_OK # define F_OK 0 #endif F_OK #include <sys/ioctl.h> #include "untamo.h" #include <sys/stat.h> #ifdef PUCC #define PWIDLE 6 /*accounting bit for no idle time logout */ #define PWMULT 7 /*accounting bit for multiple logins allowed */ #include <passwd.h> struct usrpwd *getupnam(); #else PUCC #include <pwd.h> #endif PUCC #include "y.tab.h" struct user users[MAXUSERS]; struct user *pusers[MAXUSERS]; extern char *malloc(), *strcpy(), *ctime() , *strcat(); extern unsigned strlen(); extern time_t time(); struct qelem *rules, *session, *exmpt; /* lists for timeouts, session limits, and exemptions */ jmp_buf env_buf; int sleeptime; /* time to sleep between checks */ FILE *logfd; /* log file file descriptor pointer */ int m_threshold; /* number of users before multiple limits */ int s_threshold; /* number of users for session limits */ int warn_flags = IS_IDLE | IS_MULT | IS_LIMIT; /* what sorts of warnings should be accepted */ main(n_args, ppch_args) int n_args; char **ppch_args; { struct utmp utmpbuf; struct stat statbuf; #ifdef PUCC struct usrpwd *pswd; #else PUCC struct passwd *pswd; #endif PUCC struct user *user; char pathbuf[20]; int utmptr, utmpfd; time_t conf_oldstamp; int userptr; int res, td; int new; /* if the configuration file is new */ time_t tempus; int finish(), wakeup(); FILE *conffd, *freopen(), *fopen(); /* command line flags */ int fl_multiple = 1, fl_session = 1, fl_idle = 1; while( --n_args && *++ppch_args && **ppch_args == '-' ) { while( *++(*ppch_args) ){ switch( **ppch_args ){ case 'm': /* don't even think about multiple logins */ fl_multiple = 0; break; case 'i': /* don't even think about idle timeouts */ fl_idle = 0; break; case 's': /* don't even think about session limits */ fl_session = 0; break; default: fprintf( stderr, "untamo: bad flag -%c\n", **ppch_args ); break; } } } if( !fl_multiple && !fl_idle && !fl_session ){ /* do absolutely nothing!! */ exit(0); } #ifdef PUCC if ( access( "/flags/testsys" , F_OK ) == 0 ) exit(0); /* dont run in test mode */ #endif PUCC (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); (void) signal(SIGINT, SIG_IGN); #ifdef BSD4_2 (void) signal(SIGTTOU, SIG_IGN); (void) signal(SIGTSTP, SIG_IGN); #endif BSD4_2 (void) signal(SIGTERM, finish); (void) signal(SIGALRM, wakeup); conf_oldstamp = 1; /* a very old stamp */ /* * set up new header nodes for each of the lists. * The forw and back pointers must point to them * selves so the system insque routine can be used */ rules = (struct qelem *) malloc( sizeof(struct qelem) ); exmpt = (struct qelem *) malloc( sizeof(struct qelem) ); session = (struct qelem *) malloc( sizeof(struct qelem) ); rules->q_forw = rules->q_back = rules; exmpt->q_forw = exmpt->q_back = exmpt; session->q_forw = session->q_back = session; rules->q_item = session->q_item = exmpt->q_item = NULL; if ( (logfd = fopen(LOGFILE,"a")) > 0) { (void) time(&tempus); (void) fprintf(logfd,"%24.24s Untamo started\n",ctime(&tempus) ); (void) fclose(logfd); } else { (void) fprintf( stderr , "Untamo: couldn't open log file: %s\n", LOGFILE ); exit(1); } if ( (res = fork()) < 0) { (void) fprintf(stderr,"Untamo: couldn't start\n"); } if (res){ /* if the parent */ #ifdef DEBUG exit(res); #else exit(0); #endif DEBUG } /* * lose our controlling terminal */ #ifdef BSD2_9 td = open("/dev/tty", O_RDWR); #else BSD2_9 td = open("/dev/tty", O_RDWR, 0600); #endif BSD2_9 if (td >= 0){ (void) ioctl(td, TIOCNOTTY, (char *)0); (void) close( td ); } /* * now sit in an infinite loop and work */ while (1){ if ( stat(CONFIG,&statbuf) < 0) { (void) error("Untamo: couldn't stat conf file"); exit(1); } if ( statbuf.st_mtime > conf_oldstamp ) { conf_oldstamp = statbuf.st_mtime; if ( (conffd = freopen(CONFIG, "r", stdin)) < 0) { (void) error("Untamo: can't open configuration file"); exit(1); } /* * get rid of the old rules and exempt lists */ (void) freelist(rules); (void) freelist(exmpt); (void) freelist(session); m_threshold = 0; s_threshold = 0; /* * now read the configuration file and set up the * rules and exemption lists */ (void) yyparse(); new = 1; } else new = 0; #ifdef BSD2_9 if ( (utmpfd = open(UTMP, O_RDONLY)) < 0) { #else BSD2_9 if ( (utmpfd = open(UTMP, O_RDONLY, 0)) < 0) { #endif BSD2_9 (void) error("Untamo: can't open /etc/utmp"); exit(1); } /* } <-- to match ifdefed open... */ utmptr = 0; userptr = 0; /* * look through the utmp file, compare each entry to the users * array to see if an entry has changed. If it has, build a new * record for that person, if it hasn't, see if it is time to * examine him again. */ while ( (res = read(utmpfd, (char *)&utmpbuf, sizeof(struct utmp)) ) > 0 ) { if (res != sizeof(struct utmp)) { (void) error("Untamo: error reading utmp file, continuing"); continue; } (void) time(&tempus); if (utmpbuf.ut_name[0] != '\0') { user = &users[utmptr]; if ( !(strcmp(user->uid,utmpbuf.ut_name)) && (user->time_on == utmpbuf.ut_time) ) { if (new) (void) setlimits(utmptr); if (fl_idle && tempus > user->next) { (void) checkidle(utmptr); } } else { /* * build a new record */ user->warned = 0; (void) strcpy(pathbuf,DEV); (void) strcat(pathbuf,utmpbuf.ut_line); #ifdef PUCC user->rld = findrld(pathbuf); (void) strcpy(user->clust, findcluster(user->rld)); #endif PUCC (void) strcpy(user->line, pathbuf); (void) stat(pathbuf,&statbuf); (void) strcpy(user->uid, utmpbuf.ut_name); #ifdef PUCC pswd = getupnam(utmpbuf.ut_name); user->ugroup = pswd->up_gid; #else PUCC pswd = getpwnam(utmpbuf.ut_name); user->ugroup = pswd->pw_gid; #endif PUCC user->time_on = utmpbuf.ut_time; (void) setlimits(utmptr); #ifdef PUCC if( pswd->up_flags & (1l << PWMULT )) user->exempt |= IS_MULT; if( pswd->up_flags & (1l << PWIDLE )) user->exempt |= IS_IDLE; #endif PUCC user->next = tempus; } pusers[userptr++] = user; } utmptr++; } (void) close(utmpfd); (void) fclose(conffd); #ifdef PUCC /* ** check session limits */ if( fl_session ){ (void) chk_session(userptr); } #endif PUCC /* ** check for and warn multiple logins */ if( fl_multiple ){ (void) chk_multiple(userptr); } /* ** wait sleeptime minutes */ (void) sleep( (unsigned) sleeptime * 60); } } #ifdef PUCC /* * chk_session( users ) * find out how many people are on sds ports, * and try to warn enough people to get below the threshold */ chk_session( n_users ) register int n_users; { register int which_user; time_t tempus; register int n_sds_ports = 0; static int fl_sessionlimits = 0; (void) time(&tempus); for( which_user = 0; which_user < n_users ; which_user++ ){ if( pusers[which_user]->warned & IS_LIMIT ){ (void) warn(which_user,IS_LIMIT); } else if( is_sds_port( pusers[which_user]->rld ) ){ n_sds_ports++; } } if( n_sds_ports > s_threshold && !fl_sessionlimits ){ (void) close( creat( "/flags/sessionlimits", 0600 )); fl_sessionlimits = 1; } if( n_sds_ports < s_threshold && fl_sessionlimits ){ unlink( "/flags/sessionlimits" ); fl_sessionlimits = 0; } while( n_sds_ports>s_threshold && s_threshold>0 && which_user>0 ){ which_user--; if( tempus-pusers[which_user]->time_on > pusers[which_user]->session && pusers[which_user]->session > 2*60 && !(pusers[which_user]->warned & IS_LIMIT) ){ (void) warn(which_user,IS_LIMIT); n_sds_ports--; } } } int is_sds_port( rld_number ) int rld_number; { int fd, res; struct rld_data rdat; /* * Get to the right place in /etc/rlds * Complements of Jeff Smith... */ if( fd = open (RLD_FILE, O_RDONLY, 0) >= 0 ) { lseek (fd, (long) rld_number * sizeof (struct rld_data), L_SET); res = read (fd, (char *) &rdat, sizeof (struct rld_data)); (void) close(fd); if (res == sizeof(struct rld_data) && rdat.rld_tio != -1) { return 1; } } return 0; } #endif PUCC /* * chk_multiple -- given the number of users (i), warn any of * them that have multiple logins. Calls qsort(3) * to sort them by id. */ chk_multiple(i) int i; { int j, comp(); int match, skip = -1; int wait = 0; if( i < m_threshold && m_threshold > 0 ) { /* below threshold...*/ return; } (void) qsort( (char *) pusers, i, sizeof(struct user *), comp); for (j=0; j<i-1; j++) { /* * if not all the multiple logins logged out, * decide on one not to kill, clear his warned * bit, and continue. But don't look again until * we have passed all the guys with the same login. */ if ( wait == 0 ) { match = 0; skip = decide(j, i, &wait); } else wait--; if ( ( (*pusers[j]).exempt & IS_MULT) || (j == skip) ) { continue; /* he's exempt ! */ } if ( !strcmp( (*pusers[j]).uid, (*pusers[j+1]).uid) ) { match = 1; (void) warn(j,IS_MULT); } else { if ( match ) (void) warn(j,IS_MULT); match = 0; } } } /* * decide -- given a bunch of multiply logged on terminals that did * not heed the warning, decide returns the index into the * *pusers array of the user NOT to log off. Wait is the * number of ids that chk_multiple must skip before calling * decide again. Admittedly this is gross, but it works. */ decide(j, num, wait) int j, num, *wait; { int i; int count = 1; int warned = 1; int skip; /* * look through the users and find how many * of login (*pusers[i]).uid are logged on * and whether or not they have been warned */ for ( i=j; i<num; i++) { if ( !((*pusers[i]).warned & IS_MULT) ) warned = 0; if ( !strcmp( (*pusers[i]).uid, (*pusers[i+1]).uid) ) count++; else break; } /* * now, if there is a need to skip someone, do it */ *wait = count-1; if ( (warned) && (count > 1) ) { skip = j; /* * set skip to the alpha-numerical least tty */ for(i=j+1; i<j+count; i++) if (strcmp((*pusers[skip]).line,(*pusers[i]).line)>0) skip = i; (*pusers[skip]).warned &= ~IS_MULT; return(skip); } return(-1); } /* * finish -- end Untamo */ finish() { time_t tempus; FILE *logfd; (void) signal(SIGTERM, SIG_IGN); (void) time(&tempus); (void) unlink( "/flags/sessionlimits"); if ( (logfd = fopen(LOGFILE,"a")) > 0) { (void) time(&tempus); (void) fprintf(logfd,"%24.24s Untamo killed.\n",ctime(&tempus) ); (void) fclose(logfd); } exit(0); } /* * comp -- used by qsort to sort by id */ comp(h1, h2) struct user **h1, **h2; { return( strcmp((**h1).uid, (**h2).uid) ); } /* * checkidle -- given a user, see if we want to warn him about idle time. * first check the exempt vector to see if he is exempt. */ #define min(a,b) ( (a)<(b)?(a):(b) ) checkidle(i) int i; { struct stat statbuf; time_t tempus; (void) time(&tempus); (void) stat(users[i].line,&statbuf); #ifdef DEBUG { static char debugprint[80]; sprintf(debugprint,"**debug: checkidle(%d); %d %d %x\n", i, users[i].session, users[i].idle, users[i].exempt); error(debugprint); sprintf(debugprint," *debug: %s %s\n", users[i].line, users[i].uid); error(debugprint); } #endif DEBUG if (( tempus - statbuf.st_atime) < users[i].idle ) { users[i].warned &= ~IS_IDLE; } else { if (users[i].idle > 2*60 && !(users[i].exempt & IS_IDLE)) { (void) warn(i,IS_IDLE); } } users[i].next = min( statbuf.st_atime + users[i].idle, users[i].time_on + users[i].session ); }