#ifndef lint static char *sccsid = "@(#)$Id: inews.c,v 1.6 1992/08/03 04:51:45 sob Exp sob $"; #endif /* This software is Copyright 1992 by Stan Barber. * * Permission is hereby granted to copy, reproduce, redistribute or otherwise * use this software as long as: there is no monetary profit gained * specifically from the use or reproduction of this software, it is not * sold, rented, traded or otherwise marketed, and this copyright notice is * included prominently in any copy made. * * The author make no claims as to the fitness or correctness of this software * for any use whatsoever, and it is provided as is. Any use of this software * is at the user's own risk. */ #include #include #include "config.h" #include "nntp.h" #include "nntpclnt.h" #ifdef GETPWENT #include #ifndef __STDC__ extern struct passwd *getpwuid(); extern struct passwd *getpwnam(); #endif #endif #ifdef USG #include #else /* not USG */ #include #endif /* not USG */ /* for gen_frompath() */ #define FROM 1 #define PATH 2 #define MAX_SIGNATURE 4 extern FILE *ser_wr_fp; extern char *getlogin(); #if defined(AUTHSIMPLE) || defined(AUTHOLD) FILE *passfile; #endif /* AUTHSIMPLE || AUTHOLD */ char host_name[256]; char *username; #ifdef GETPWENT struct passwd *passwd; #else char passwd[BUFSIZ]; char *homedir; char *fullname; #endif main(argc, argv) int argc; char *argv[]; { char line[NNTP_STRLEN], s[NNTP_STRLEN]; int seen_fromline, in_header, seen_header, seen_pathline, put_newline, invalid_line_ok; /* last 2 reikel 1/18/97 */ int response; char *server; char *getserverbyfile(); register char *cp; #ifndef GETPWENT int i; #endif int suppress_signature = 0; /* reikel 1/3/97 */ /* find out who they REALLY are */ username = getlogin(); if (username == NULL) #ifdef GETPWENT { passwd = getpwuid(getuid()); username = passwd->pw_name; } else passwd = getpwnam(username); if (passwd == NULL){ fprintf(stderr,"Can't get user information. Please contact your system adminstrator.\n"); exit(1); } #else { int i; if (getpw(getuid(), passwd) != 0){ fprintf(stderr,"Can't get user information. Please contact your system adminstrator.\n"); exit(1); } cp = index(passwd,':'); *cp = '\0'; username = passwd; } else { FILE *pfp = fopen("/etc/passwd","r"); int foundit = 0; if (pfp == NULL) { fprintf(stderr,"Can't open password file. Please contact your system adminstrator.\n"); exit(1); } while (fgets(passwd,sizeof passwd,pfp) != NULL) { if (strncmp(username,passwd,strlen(username))) continue; if (passwd[(strlen(username)-1)] != ':') continue; foundit = 1; break; } fclose(pfp); if (foundit == 0) { fprintf(stderr,"%s appears to be an invalid username.\n", username); exit(1); } cp = index(passwd,':'); *cp = '\0'; } cp++; for (fullname=cp, i=4; i; i--) { /* magic cookie XXX */ if (fullname) fullname = index(s,':')+1; } cp = index(fullname,':'); *cp = '\0'; cp++; homedir = cp; cp = index(homedir,':'); *cp = '\0'; #endif #if defined(AUTHSIMPLE) || defined(AUTHOLD) /* * we have to be setuid to news to open the file, but not afterwards */ passfile = fopen(PASSFILE, "r"); #ifdef SETEUID seteuid(getuid()); setegid(getgid()); #else setuid(getuid()); setgid(getgid()); #endif #endif /* AUTHSIMPLE || AUTHOLD */ ++argv; while (argc > 1) if ((*argv)[0] == '-') { if ((*argv)[1] == 's') suppress_signature = 1; ++argv; --argc; } else break; if (argc > 1) { if (freopen(*argv, "r", stdin) == NULL) { perror(*argv); exit(1); } } uname(host_name); server = getserverbyfile(SERVER_FILE); if (server == NULL) { fprintf(stderr, "Can't get the name of the news server from %s.\n", SERVER_FILE); fprintf(stderr, "Either fix this file, or put NNTPSERVER in your enviroment.\n"); exit(1); } response = server_init(server); if (response < 0) { printf("Couldn't connect to %s news server, try again later.\n", server); exit(1); } if (handle_server_response(response, server) < 0 || response == OK_NOPOST) { close_server(); exit(1); } again: put_server("POST"); (void) get_server(line, sizeof(line)); if (*line != CHAR_CONT) { if (atoi(line) == ERR_NOPOST) { close_server(); fprintf(stderr, "Sorry, you can't post from this machine.\n"); exit(1); } #ifdef AUTH if ((atoi(line) == ERR_AUTHSYS) #ifdef AUTHOLD ||(atoi(line) == ERR_OLDNOAUTH) #endif ) { if (postauth(server,line) < 0){ close_server(); fprintf(stderr,"Authorization failed. Posting aborted.\n"); exit(1); } goto again; } #endif close_server(); fprintf(stderr, "Remote error: %s\n", line); exit(1); } in_header = 1; seen_header = 0; seen_fromline = 0; seen_pathline = 0; while (fgets(s, sizeof(s), stdin) != NULL) { put_newline = 0; /* reikel 1/18/97 */ /* Strip trailing newline */ cp = s + strlen(s) - 1; if (cp >= s && *cp == '\n') { *cp = '\0'; put_newline = 1; } if ((s[0] == '.') && (strlen(s) == 1)) /* Single . is eof, so put in extra one */ (void) fputc('.', ser_wr_fp); if (in_header && !strncasecmp(s, "From:", sizeof("From:")-1)) { seen_header = 1; seen_fromline = 1; } if (in_header && !strncasecmp(s, "Path:", sizeof("Path:")-1)) { seen_header = 1; seen_pathline = 1; } if (in_header && s[0] == '\0') { if (seen_header) { in_header = 0; if (!seen_pathline) gen_frompath(PATH); if (!seen_fromline) gen_frompath(FROM); else fprintf(ser_wr_fp, "Originator: %s@%s\r\n", username, host_name); } else { continue; } } else if (in_header) { if (valid_header(s)) seen_header = 1; else if (!invalid_line_ok) continue; } /* if the line overran the buffer, don't append a */ /* newline; and the next line needn't be a valid header */ if (put_newline) { fprintf(ser_wr_fp, "%s\r\n", s); invalid_line_ok = 0; } else { fprintf(ser_wr_fp, "%s", s); invalid_line_ok = 1; } } if (in_header) { /* Still in header after EOF? Hmm... */ in_header = 0; if (!seen_pathline) gen_frompath(PATH); if (!seen_fromline) gen_frompath(FROM); else fprintf(ser_wr_fp, "Originator: %s@%s\r\n", username, host_name); fprintf(ser_wr_fp, "\r\n"); } if (!suppress_signature) append_signature(); fprintf(ser_wr_fp, ".\r\n"); (void) fflush(ser_wr_fp); (void) get_server(line, sizeof(line)); if (*line != CHAR_OK) { if (atoi(line) == ERR_POSTFAIL) { close_server(); printf("Article not accepted by server; not posted.\n"); for (cp = line + 4; *cp && *cp != '\r'; cp++) if (*cp == '\\') putchar('\n'); else putchar(*cp); exit(1); } else { close_server(); fprintf(stderr, "Remote error: %s\n", line); exit(1); } } /* * Close server sends the server a * "quit" command for us, which is why we don't send it. */ close_server(); exit(0); } /* * append_signature -- append the person's .signature file if * they have one. Limit .signature to MAX_SIGNATURE lines. * The rn-style DOTDIR environmental variable is used if present. */ append_signature() { char line[256], sigfile[256]; char *cp; FILE *fp; char *index(), *getenv(); int count = 0; char *dotdir; if (passwd == NULL) return; #ifdef DO_DOTDIR if ((dotdir = getenv("DOTDIR")) == NULL) #endif { #ifdef GETPWENT dotdir = passwd->pw_dir; #else dotdir = homedir; #endif } if (dotdir[0] == '~') { #ifdef GETPWENT (void) strcpy(sigfile, passwd->pw_dir); #else (void) strcpy(sigfile, homedir); #endif (void) strcat(sigfile, &dotdir[1]); } else { (void) strcpy(sigfile, dotdir); } (void) strcat(sigfile, "/"); (void) strcat(sigfile, ".signature"); #ifdef DEBUG fprintf(stderr,"sigfile = '%s'\n", sigfile); #endif fp = fopen(sigfile, "r"); if (fp == NULL) return; #ifdef DEBUG fprintf(stderr,"sigfile opened OK\n"); #endif fprintf(ser_wr_fp, "-- \r\n"); while (fgets(line, sizeof (line), fp)) { count++; if (count > MAX_SIGNATURE) { fprintf(stderr, "Warning: .signature files should be no longer than %d lines.\n", MAX_SIGNATURE); fprintf(stderr, "(Only %d lines of your .signature were posted.)\n", MAX_SIGNATURE); break; } /* Strip trailing newline */ cp = line + strlen(line) - 1; if (cp >= line && *cp == '\n') *cp = '\0'; fprintf(ser_wr_fp, "%s\r\n", line); } (void) fclose(fp); #ifdef DEBUG printf(".signature appended (from %s)\n", sigfile); #endif } /* * gen_frompath -- generate From: and Path: lines, in the form * * From: user@host.domain (full_name) * Path: host!user * * This routine should only be called if the message doesn't have * a From: line in it. */ gen_frompath(which) int which; { char *s; char *cp; char *index(), *getenv(); s = getenv("NAME"); if (s == NULL) { #ifdef GETPWENT s = passwd->pw_gecos; #else s = fullname; #endif #ifdef BERKNAMES if ((cp = index(s, ',')) != NULL) *cp = '\0'; if ((cp = index(s, ';')) != NULL) *cp = '\0'; #else #ifdef USGNAMES if ((cp = index(s, '(')) != NULL) *cp = '\0'; if ((cp = index(s, '-')) != NULL) s = cp; #else { FILE * tmpfp; char namefile[BUFSIZ]; char buf[BUFSIZ]; #ifdef GETPWENT sprintf(namefile,"%s/.fullname",passwd->pw_dir); #else sprintf(namefile,"%s/.fullname",homedir); #endif if ((tmpfp=fopen(namefile,"r")) != NULL) { fgets(buf,sizeof buf,tmpfp); fclose(tmpfp); buf[strlen(buf)-1] = '\0'; s = buf; } else s = ""; } #endif #endif } if (which == FROM){ #if defined(DOMAIN) /* A heuristic to see if we should tack on a domain */ cp = index(host_name, '.'); if (cp) fprintf(ser_wr_fp, "From: %s@%s (", username, host_name); else fprintf(ser_wr_fp, "From: %s@%s.%s (", username, host_name, DOMAIN); #else fprintf(ser_wr_fp, "From: %s@%s (", username, host_name); #endif /* DOMAIN */ for (cp = s; *cp != '\0'; ++cp) if (*cp != '&') putc(*cp, ser_wr_fp); else { /* Stupid & hack. God damn it. */ putc(toupper(username[0]), ser_wr_fp); fprintf(ser_wr_fp, username+1); } fprintf(ser_wr_fp, ")\r\n"); } if (which == PATH){ /* Only the login name - nntp server will add uucp name */ /* Folks aren't supposed to the Paths for replies, so we don't */ /* care if it generates something inaccurate for replies! */ fprintf(ser_wr_fp, "Path: %s\r\n", username); } } /* * valid_header -- determine if a line is a valid header line * * Parameters: "h" is the header line to be checked. * * Returns: 1 if valid, 0 otherwise * * Side Effects: none * */ int valid_header(h) register char *h; { char *index(); char *colon, *space; /* * blank or tab in first position implies this is a continuation header */ if (h[0] == ' ' || h[0] == '\t') return (1); /* * just check for initial letter, colon, and space to make * sure we discard only invalid headers */ colon = index(h, ':'); space = index(h, ' '); if (isalpha(h[0]) && colon && space == colon + 1) return (1); /* * anything else is a bad header -- it should be ignored */ return (0); } #ifndef STRNCASECMP /* * lower -- convert a character to lower case, if it's * upper case. * * Parameters: "c" is the character to be * converted. * * Returns: "c" if the character is not * upper case, otherwise the lower * case eqivalent of "c". * * Side effects: None. */ char lower(c) register char c; { if (isascii(c) && isupper(c)) c = c - 'A' + 'a'; return(c); } /* * strncasecmp -- determine if two strings are equal in the first n * characters, ignoring case. * * Parameters: "a" and "b" are the pointers * to characters to be compared. * "n" is the number of characters to compare. * * Returns: 0 if the strings are equal, 1 otherwise. * * Side effects: None. */ strncasecmp(a, b, n) register char *a, *b; int n; { char lower(); while (n && lower(*a) == lower(*b)) { if (*a == '\0') return (0); a++; b++; n--; } if (n) return (1); else return (0); } #endif