|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 9497 (0x2519) Types: TextFile Notes: UNIX file Names: »xmail.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─⟦this⟧ »cmd/xmail.c«
/* * Simple xmail command. Almost identical to mail(1). * /bin/xmail must be setuid to root. This is regarded as a failing. * If users are given xmail scans the directory /usr/spool/pubkey for their * public key files to find out if they are enrolled. * Note that because of the protection bits on /usr/spool/pubkey * that this is possible only because xmail is setuid to root. */ #include <stdio.h> #include <ctype.h> #include <timeb.h> #include <pwd.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include <time.h> #define and && #define or || #define not ! #define TRUE (0==0) #define FALSE (not TRUE) #define MMSIZE 2048 /* Maximum message size */ #define LINESIZ 256 /* Line length for fgetline() */ /* * Pkfile will be the full pathname of each recipients public knapsack key. * Pkhook is the location in pkfile where we append the recipient's name. */ char pkfile[] = "/usr/spool/pubkey/xxxxxxxxxxxxxx"; char *pkhook = &pkfile[18]; char message[MMSIZE]; /* Message buffer */ char *mp; /* Pointer to message end */ /* * Functions. */ char *str_cpy(); char *concat(); char *getlogin(); char *gethome(); char *getmyname(); FILE *xread(); FILE *xopen(); struct passwd *getpwnam(); struct passwd *getpwuid(); main(ac, av) int ac; register char *av[]; { register int valid; register char **bv; ac = 0; signal(SIGPIPE, SIG_IGN); if (*++av == NULL) { readmail('m'); /* 'm' for 'maybe' */ return; } if (av[1] == NULL and av[0][1] == '-') switch (av[0][1]) { case 'n': readmail('n'); return; case 'y': readmail('y'); return; case 'x': readmail('x'); return; default: readmail('m'); return; } /* * Check if all recipients are enrolled. Mark those who aren't (by * marking their positions in av[] with the address of pkfile). * Count the number of valid recipients. */ valid = 0; for (bv = av; *bv != NULL; ++bv) { register int n; str_cpy(pkhook, *bv); if ((n = open(pkfile, 0)) >= 0) { close(n); ++valid; continue; } fputs(*bv, stderr); fputs(" is not enrolled.\n", stderr); *bv = pkfile; /* pkfile is used as a flag here. */ } /* * If there aren't any valid recipients, die. */ if (valid == 0) exit(1); /* * Prepare the header. */ mp = message; header(); if (valid > 1) { mp = str_cpy(mp, "(cc:"); for (bv = av; *bv != NULL; ++bv) { if (*bv == pkfile) continue; *mp++ = ' '; mp = str_cpy(mp, *bv); } mp = str_cpy(mp, ")\n"); } /* * Read the message and send it to each valid recipient. */ readmsg(); for (bv = av; *bv != NULL; ++bv) { if (*bv == pkfile) continue; sendmail(*bv); } /* * Wait for all our children (xencode processes). */ wait((int *)0); } /* * Return my login name. */ char * getmyname() { register struct passwd *pwp; register char *ret; if ((ret = getlogin()) == NULL) { if ((pwp = getpwuid(getuid())) == NULL) panic("Who are you?"); ret = pwp->pw_name; } return (ret); } /* * Get the home directory of user. The data is overwritten each call. */ char * gethome(user) char *user; { register struct passwd *pwp; if ((pwp = getpwnam(user)) == NULL) return (NULL); return (pwp->pw_dir); } /* * Print out any mail we have. If `sflag' is 'n' we don't save mail, if 'y' * we save the encrypted mail in xmbox, if 'x' we save the clear mail in mbox, * otherwise we ask. Any other reply causes no action. */ readmail(sflag) int sflag; { register char *home; register char *mailbox; register char *mbox; register FILE *x; if ((home = gethome(getmyname())) == NULL) panic("Can't find $HOME"); mailbox = concat(home, "xmailbox"); x = xread(mailbox); if (sflag == 'm') { fputs("\nSave ?", stdout); fgetline(message, LINESIZ, stdin); sflag = message[0]; } switch (sflag) { case 'x': if (x == NULL) panic("Cannot save clear text, no action taken"); mbox = concat(home, "mbox"); move(mailbox, x); goto APPEND; case 'y': mbox = concat(home, "xmbox"); APPEND: append(mailbox, mbox); unlink(mbox); link(mailbox, mbox); unlink(mailbox); break; case 'n': unlink(mailbox); break; default: break; } wait((int *)0); return; } /* * Open and unlink rathole. This provides a safe place to store cleartext - * no one can get at it. Read xmail from mailbox via xdecode filter, display * and copy it to rathole. Return the (FILE *) of rathole. */ FILE * xread(mailbox) char *mailbox; { register FILE *ret, *u; register int n; static char rathole[] = "/tmp/xmxxxxxx"; struct stat stbuf; mktemp(rathole); ret = fopen(rathole, "wr"); unlink(rathole); if (stat(mailbox, &stbuf) < 0 or stbuf.st_size == (size_t)0 or (u = xopen(mailbox, 0, NULL)) == NULL) panic("No xmail"); while ((n = fgetline(message, LINESIZ, u)) != 0) { fwrite(message, 1, n, stdout); fwrite(message, 1, n, ret); } fclose(u); return (ret); } /* * Put the header on the message. */ header() { struct timeb timeb; ftime(&timeb); mp = str_cpy(mp, "\nFrom "); mp = str_cpy(mp, getmyname()); *mp++ = ' '; mp = str_cpy(mp, ctime(&timeb.time)); /* The ctime() string has a newline on the end already. */ } /* * Read the message the user wants to send and store it in message. */ readmsg() { register int n; while ((n = fgetline(mp, LINESIZ, stdin)) != 0) { if (mp[0] == '.' and mp[1] == '\n') break; mp += n; } return; } /* * Send the message to the given user. Unlike regular mail, we do not put * undeliverable mail in "dead.letter". */ sendmail(user) register char *user; { register FILE *u; register char *cp; if ((cp = gethome(user)) == NULL) { fputs("Cannot send to ", stderr); fputs(user, stderr); putc('\n', stderr); return; } cp = concat(cp, "xmailbox"); if ((u = xopen(cp, 1, user)) != NULL) { if (fwrite(message, 1, mp - message, u) != 0) notify(cp); fclose(u); } free(cp); return; } /* * Send notification of xmail to the recipient's regular mailbox. Cp is assumed * to be "$HOME/xmailbox", which we transform into "$HOME/mailbox". */ notify(cp) register char *cp; { register char *cp0; register FILE *fp; static char msg[] = "\nFrom xmail:\nYou have xmail.\n"; cp0 = &cp[strlen(cp) - 8]; /* Address of 'x' in 'x'mailbox. */ while ((*cp0 = cp0[1]) != '\0') ++cp0; fp = fopen(cp, "a"); fwrite(msg, 1, strlen(msg), fp); fclose(fp); return; } /* * Copy b to a. Return pointer to the '\0' char terminating the result. */ char * str_cpy(a, b) register char *a, *b; { while (*a++ = *b++) ; return (a - 1); } /* * Concatenate a and b. Return a pointer to the malloced result. */ char * concat(a, b) register char *a; char *b; { register char *ret; char *malloc(); ret = malloc(strlen(a) + strlen(b) + 2); if (ret == NULL) panic("Out of memory"); a = str_cpy(ret, a); *a++ = '/'; str_cpy(a, b); return (ret); } /* * Print out an error message and exit. */ panic(cp) char *cp; { fputs(cp, stderr); putc('\n', stderr); exit(1); } /* * Move the contents of the file pointed to by 'f2' to 'file'. Assume f2 is * open for reading and writing. The contents of 'file' are overwritten. */ move(file, f2) char *file; register FILE *f2; { register FILE *f1; register int n; if ((f1 = fopen(file, "w")) == NULL) return; rewind(f2); while ((n = fread(message, 1, MMSIZE, f2)) != 0) fwrite(message, 1, n, f1); fclose(f1); return; } /* * Append the contents of file2 to file1. */ append(file1, file2) char *file1, *file2; { register FILE *f1, *f2; register int n; if ((f1 = fopen(file1, "a")) == NULL) return; if ((f2 = fopen(file2, "r")) == NULL) { fclose(f1); return; } while ((n = fread(message, 1, MMSIZE, f2)) != 0) fwrite(message, 1, n, f1); fclose(f1); fclose(f2); return; } /* * Xopen reads from (mode 0) or appends to (mode 1) file. The io is filtered: * For reading, the returned (FILE *) is a pipe from the filter xdecode, for * writing it's a pipe to the filter "xencode user". */ FILE * xopen(file, mode, user) char *file; register int mode; char *user; { int pfildes[2]; char *cmd; int n; register FILE *fp; register int *pp = pfildes; if ((fp = fopen(file, (mode == 0 ? "r" : "a"))) == NULL) return (fp); if (pipe(pp) < 0) panic("Cannot make pipe"); if ((n = fork()) < 0) panic("Cannot fork"); /* * Parent. */ if (n > 0) { fclose(fp); if (mode == 0) { close(pp[1]); return (fdopen(pp[0], "r")); } else { close(pp[0]); return (fdopen(pp[1], "w")); } } /* * Now we are in the child. */ if (mode == 0) { cmd = "/bin/xdecode"; dup2(pp[1], 1); dup2(fileno(fp), 0); } else { cmd = "/bin/xencode"; dup2(pp[0], 0); dup2(fileno(fp), 1); } close(pp[0]); close(pp[1]); fclose(fp); if (mode == 0) execl(cmd, cmd, NULL); else execl(cmd, cmd, user, NULL); exit(1); } /* * fgets() isn't quite what we want, so we have our own. Fgetline() reads * from fp until a newline, an EOF or until 'lim' characters have been read. * Characters read are placed in buf. The number of chars read is returned. * The string is null-terminated. This means buf should have room for lim + 1 * characters. Once EOF is reached fgetline() continually returns 0. */ fgetline(buf, lim, fp) char *buf; int lim; register FILE *fp; { register int c; register char *cp = buf; while ((c = *cp++ = getc(fp)) != '\n') { if (c == EOF) { ungetc(c, fp); --cp; break; } if (--lim == 0) break; } *cp = '\0'; return (cp - buf); }