home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Header: /source/users/msg/msg/RCS/msg.c,v 1.24 91/08/18 18:37:29 dgharriss Exp $
- */
-
- /*
- * msg.c
- * MSG re-written to use a daemon
- * John Sellens, University of Waterloo
- */
-
- #include "msg.h"
- #include <pwd.h>
- #include <strings.h>
-
- #ifdef REALUSER
- #include <mfcf/libuw/standard.h>
- #endif
-
- /* global */ char hostname[80];
- private char *progname;
- #define USERIDSPACE (80) /* lots of room */
- private char sender[USERIDSPACE];
- private char loginname[USERIDSPACE];
- private int uid; /* effective */
- private int ruid; /* real */
-
- private char msg_file[80];
- private char pmsg_file[80];
-
- extern char *syserr();
- extern char *ttyname();
-
- private int getsender(), sendmsg();
- private void replywarn();
- private void usage();
- private void getprevious();
- private void putprevious();
- extern void fatal();
-
- #define SU (0) /* uid of super-user */
-
- main( argc, argv )
- int argc;
- char *argv[];
- {
- register int i;
- register int exitcode = 0;
- int fromroot;
- int useprevious = 0; /* send previous text as msg */
- int cmdlinemsg = 0; /* msg is on cmd line */
- char *p;
- char message[1024]; /* to hold message */
- char rawmsg[1024]; /* to hold unclean message */
- char *tname; /* name of current tty */
- char *reply = NULL, *reply_to();
-
-
- int c;
- extern int optind;
- extern char *optarg;
-
-
- progname = argv[0];
- if ( argc == 1 )
- usage();
-
- if ( gethostname( hostname, (int)sizeof(hostname) ) )
- fatal( "Couldn't gethostname(): %s", syserr() );
-
- fromroot = getsender();
- strcpy( msg_file, MSGFILE );
- strcat( msg_file, loginname );
- strcpy( pmsg_file, PMSGFILE );
- strcat( pmsg_file, loginname );
-
- while (( c = getopt(argc, argv, "lm:prt")) != EOF ) {
- switch( c ) {
- case 'l':
- list_msg();
- break;
- case 'm':
- strcpy( rawmsg, optarg ); /* hope they don't have a giant msg */
- cmdlinemsg++;
- break;
- case 'p':
- useprevious++;
- break;
- case 'r':
- if ( (reply = reply_to()) == NULL ) {
- fatal( "Nobody to reply to in last message file '%s'",
- msg_file );
- }
- break;
- case 't':
- list_msgtime();
- break;
- default:
- usage();
- }
- }
- if ( useprevious && cmdlinemsg )
- fatal( "-m and -p can't be used together" );
-
- /* Tell 'em now so that the lastmsg comes before you get the replying
- message, and tell them so they know who they're sending to, in
- case it's wrong. */
- if ( reply != NULL )
- errprintf("Replying to '%s'", reply);
-
- /*
- * Simpler to pretend the options weren't there. Skip over 'em.
- * argv/argc is now a vector of user names.
- */
- argc -= optind;
- argv += optind;
-
-
- if ( (cmdlinemsg||useprevious) && reply == NULL && argc == 0 )
- fatal( "No one to send message to" );
-
- /*
- * Quietly exit if no recipients and no reply. This covers the case
- * where all we got was the -l option.
- */
- if ( reply == NULL && argc == 0 )
- exit(0);
-
- /* Old behaviour used - as last argument to indicate msg on stdin */
- if ( strcmp("-", argv[argc-1]) == 0 ) {
- errprintf( "'-' as last argument is obsolete - ignored" );
- argc--;
- }
-
- if ( useprevious ) {
- getprevious( rawmsg, (int)sizeof(rawmsg) );
- } else if ( ! cmdlinemsg ) {
- if ( fgets( rawmsg, (int)sizeof(rawmsg), stdin ) == NULL ) {
- /* assume user changed their mind */
- return(0);
- }
- p = index(rawmsg, '\n');
- if (p == NULL)
- errprintf("Message truncated to %d characters.", sizeof(rawmsg) );
- else
- *p = NULL;
- }
-
- if ( *rawmsg == '\0' ) /* No message to send. */
- return(0);
- sanitize( rawmsg, message );
-
- if ( useprevious )
- printf( "Sending: %s\n", message );
- else
- putprevious( message );
-
- if( (tname=ttyname(0)) || (tname=ttyname(1)) || (tname=ttyname(2)) )
- replywarn(tname); /* warn if can't get replies on this tty */
- #if 0
- /* Is this a good idea? -IAN! */
- else
- errmsg( NO_TTY );
- #endif
-
- /*
- * Send a reply if -r was used, also send to all other
- * recipients on the command line.
- */
-
- if ( reply != NULL && sendmsg(reply, message, fromroot) != OK )
- exitcode++;
-
- while ( --argc >= 0 ) {
- /* sendmsg() will destroy the argv[i] */
- if ( sendmsg( *argv++, message, fromroot ) != OK )
- exitcode++;
- }
- return( exitcode!=0 );
- }
-
-
- /*
- * Find out who the sender is. Try getlogin(), and if that
- * differs from the REAL uid, make sure both names appear.
- * Return 1 if we are root, 0 otherwise.
- */
- static int
- getsender()
- {
- extern char *getlogin(), *getenv();
- struct passwd *pw;
- char pwname[USERIDSPACE];
- char *glog;
-
- ruid = uid = getuid();
-
- /* Check out who we're running as */
- if ( (pw=getpwuid(uid)) == NULL )
- fatal("Your uid number (%d) isn't recognized.\n", uid);
- if(pw->pw_name == NULL || pw->pw_name[0] == '\0')
- fatal("No pwname is associated with uid %d.\n", uid);
- #ifdef REALUSER
- (void) strcpy( pwname, realuser( pw ) );
- #else
- (void) strcpy( pwname, pw->pw_name );
- #endif
-
- /* see if we can use getlogin() to see who it is */
- (void) strcpy( loginname, (glog=getlogin()) == 0 ? "" : glog );
- if ( *loginname ) {
- /* check the passwd file for this guy */
- pw = getpwnam( loginname );
- if ( pw ) {
- ruid = pw->pw_uid;
- #ifdef DUMBSHORT
- {
- struct utmp *ut;
- if ( strncmp( pwname, loginname, sizeof(ut->ut_name) ) == 0 )
- (void) strcpy( loginname, pwname );
- }
- #endif
- #ifdef REALUSER
- (void) strcpy( loginname, realuser( pw ) );
- #endif
- }
- } else {
- /* no better guess at real identity, use USER if we're root */
- if ( uid == SU && (glog=getenv("USER"))!=(char *)NULL && *glog ) {
- /* look up the pw entry for USER */
- if ( (pw=getpwnam(glog)) != (struct passwd *)NULL ) {
- ruid = pw->pw_uid;
- #ifdef REALUSER
- glog = realuser( pw );
- #endif
- }
- strcpy( loginname, glog );
- } else
- strcpy( loginname, pwname );
- }
-
- if (
- #ifdef REALUSER
- ! sameuser( pwname, loginname )
- #else
- strcmp( pwname, loginname ) != 0
- #endif
- && uid != SU ) {
- /* Names differ, and user isn't SU, so send both */
- (void) sprintf(sender, "%s(%s)@%s", loginname, pwname, hostname);
- } else {
- (void) sprintf(sender, "%s@%s", loginname, hostname);
- }
-
- return( uid == SU );
- }
-
-
- private int
- sendmsg( recipient, message, fromroot )
- char *recipient, *message;
- int fromroot;
- {
- register char *p, *user, *host;
- #ifndef REMOTE
- int local = FALSE;
- #endif
- int errcode;
- if ( (p = index( recipient, '@' )) != CPNULL ) {
- user = recipient;
- host = p+1;
- *p = '\0';
- } else if ( (p = index( recipient, '!' )) != CPNULL ) {
- user = p+1;
- host = recipient;
- *p = '\0';
- } else {
- user = recipient;
- host = hostname;
- }
- /* always go via the daemon, because it means we don't have to be
- setuid, and it makes things a little bit simpler. I hope - jms.
- wrong - jms */
- #ifndef REMOTE
- /* this only works if they use the full host name, not an alias, but
- that's okay ... */
- if ( strcmp( host, hostname ) == 0 )
- local = TRUE;
- if ( local )
- errcode = deliver( sender, user, message, fromroot );
- else
- #endif
- errcode = remote( sender, user, host, message );
- return( errcode );
- }
-
-
-
- /* Warn user on tname if he/she can't receive messages.
- */
- private void
- replywarn(tname)
- char *tname;
- {
- struct utmp ut;
- struct stat sbuf;
- FILE *fp;
- char *p;
- char terminal[80]; /* should be enough ... */
-
- if( (fp=fopen( UTMP, "r" )) == FPNULL ) {
- errmsg( NO_UTMP, hostname, syserr() );
- } else {
- if( (p=rindex(tname,'/')) != NULL )
- tname = p + 1;
- while ( fread((char*)&ut,sizeof(struct utmp),1,fp) != 0 ){
- if( strncmp(tname,ut.ut_line,(int)sizeof(ut.ut_line)) == 0 ){
- (void) sprintf( terminal, "%s%s", DEV, tname );
- if ( stat(terminal,&sbuf)!=-1 && ((sbuf.st_mode&ALLOW)==0) )
- errmsg( NO_REPLY, loginname, tname );
- #ifdef ANSWERBACK
- answerback( ANS_WARN, loginname, tname );
- #endif
- break; /* only need to check the first match */
- }
- }
- (void) fclose( fp );
- }
- }
-
-
- private void
- usage()
- {
- errprintf( "Usage: %s [-l] [-m message] [-p] [-r] [-t] [user ...]",
- progname );
- exit( BAD_ARGS );
- }
-
-
- #ifdef VARARGS
- errprintf( s, va_alist )
- char *s;
- va_dcl
- {
- va_list ap;
- (void) fprintf( stderr, "%s: ", progname );
- va_start( ap );
- (void) vfprintf( stderr, s, ap );
- va_end( ap );
- (void) fputc( '\n', stderr );
- }
-
- void
- fatal( s, va_alist )
- char *s;
- va_dcl
- {
- va_list ap;
- (void) fprintf( stderr, "%s: ", progname );
- va_start( ap );
- (void) vfprintf( stderr, s, ap );
- va_end( ap );
- (void) fputc( '\n', stderr );
- exit( FATAL );
- }
-
- /* VARARGS1 */
- errmsg( msgnum, va_alist )
- int msgnum;
- va_dcl
- {
- va_list ap;
- (void) fprintf( stderr, "%s: ", progname );
- va_start( ap );
- (void) vfprintf( stderr, errmessages[msgnum], ap );
- va_end( ap );
- (void) fputc( '\n', stderr );
- }
- #else
- /* VARARGS1 */
- errprintf( a, b, c, d, e, f, g, h, i, j, k )
- char *a;
- {
- (void) fprintf( stderr, "%s: ", progname );
- fprintf( stderr, a, b, c, d, e, f, g, h, i, j, k );
- (void) fputc( '\n', stderr );
- }
-
- /* VARARGS1 */
- void
- fatal( a, b, c, d, e, f, g, h, i, j, k )
- char *a;
- {
- (void) fprintf( stderr, "%s: ", progname );
- fprintf( stderr, a, b, c, d, e, f, g, h, i, j, k );
- (void) fputc( '\n', stderr );
- exit( FATAL );
- }
-
- /* VARARGS1 */
- errmsg( msgnum, a, b, c, d, e )
- int msgnum;
- char *a, *b, *c, *d, *e;
- {
- errprintf( errmessages[msgnum], a, b, c, d, e );
- }
- #endif /* VARARGS */
-
- list_msgtime()
- {
- /*
- * List time last msg was received.
- */
- struct stat statbuf;
-
- if (stat(msg_file, &statbuf) == -1)
- errprintf("can't get date of message file '%s': %s",
- msg_file, syserr());
- else
- printf("last message received %s", ctime(&statbuf.st_mtime));
- }
-
-
- list_msg()
- {
- /*
- * List message to which we are replying.
- * Just cat the last msg file.
- */
-
- FILE *fp;
- int c;
-
- if ( (fp = fopen(msg_file, "r")) == NULL ) {
- errprintf("Cannot read last message file '%s'", msg_file );
- } else {
- while ( (c = getc(fp)) != EOF ) {
- putchar(c);
- }
- }
- }
-
-
- private void
- getprevious( buf, size )
- char *buf;
- int size;
- {
- struct stat sbuf;
- FILE *pfp;
- int count;
- if ( stat( pmsg_file, &sbuf ) == -1 )
- fatal( "Could not stat previous message file '%s': %s",
- pmsg_file, syserr() );
- if ( sbuf.st_uid != ruid )
- fatal( "You do not own previous message file '%s'", pmsg_file );
- if ( (pfp = fopen( pmsg_file, "r" )) == (FILE *)NULL )
- fatal( "Could not fopen previous message file '%s' for read: %s",
- pmsg_file, syserr() );
- if ( fgets( buf, size, pfp ) == NULL )
- fatal( "Could not read previous message from file '%s' (empty?)",
- pmsg_file );
- /* In case the file didn't end with a \n, we want to make sure that
- we don't complain above that it has been truncated. This is kind
- of gross. */
- if ( strlen( buf ) < size )
- strcat( buf, "\n" );
- (void) fclose( pfp );
- }
-
- private void
- putprevious( msg )
- char *msg;
- {
- FILE *pfp;
- if ( (pfp = fopen( pmsg_file, "w" )) == (FILE *)NULL ) {
- errprintf( "Could not fopen previous message file '%s' for write: %s",
- pmsg_file, syserr() );
- } else {
- fprintf( pfp, "%s\n", msg );
- fclose( pfp );
- chown( pmsg_file, ruid, -1 );
- chmod( pmsg_file, 0600 );
- }
- }
-
-
-
-
- /*
- * reply_to - look in MSGFILE to see who sent us
- * the last message.
- */
-
- char *
- reply_to()
- {
- register char *p;
- char *index();
- static char buf[80]; /* Static 'cause we return what's in it. */
- char userfrom[40], whocares[40], hostfrom[40];
- FILE *f;
-
- if ( (f = fopen(msg_file, "r")) == NULL ) {
- return( NULL );
- }
-
- if ( fgets(buf, sizeof(buf),f) == NULL )
- return( NULL );
- /*
- * The file can look like
- * user@host: msg
- * or
- * user(somebody)@host: msg
- * Scan this in a basically cheap way.
- * I suppose some goofball exceptions could slip through
- * here if people had () in their login or host name, blah.
- */
-
-
- if ( (p = index(buf, ':')) == NULL ) {
- return( NULL ); /* Bad format. */
- }
- *p = '\0';
-
- /*
- * Now see which format we have. Strip out intermediate name.
- * there are probably more rigorous ways to do this
- */
- p = index(buf, '(');
-
- if ( p != NULL ) {
- *p++ = '\0'; /* First part is username */
- p = index(p, ')'); /* Skip middle bit. */
- if ( p == NULL ) {
- return(NULL); /* Bad format */
- }
-
- if ( *++p != '@' )
- return(NULL);
-
- strcat(buf, p); /* Tack on hostname. */
- }
-
- return( buf );
- }
-