#ifndef lint static char sccsid[] = "@(#)$Id: access.c,v 1.28 1994/12/03 21:54:30 sob Exp sob $"; #endif #include "common.h" #if defined(EXCELAN) || defined(TLI) #include #ifdef TLI #include #endif #endif #include #define SNETMATCH 1 #define NETMATCH 2 /* * host_access -- determine if the client has permission to * read, transfer, and/or post news. read->transfer. * We switch on socket family so as to isolate network dependent code. * * Parameters: "canread" is a pointer to storage for * an integer, which we set to 1 if the * client can read news, 0 otherwise. * * "canpost" is a pointer to storage for * an integer,which we set to 1 if the * client can post news, 0 otherwise. * * "canxfer" is a pointer to storage for * an integer,which we set to 1 if the * client can transfer news, 0 otherwise. * * "gdlist" is a comma separated list of * newsgroups/distributions which the client * can access. * * Returns: Nothing. * * Side effects: None. */ #ifdef EXCELAN extern struct sockaddr_in current_peer; #endif #ifdef TLI extern char **Argv; extern struct hostent *gethostbyname(); #endif #ifdef AUTH extern int Needauth; #endif /* AUTH */ void host_access(canread, canpost, canxfer, gdlist) int *canread, *canpost, *canxfer; char *gdlist; { int sockt; int length; struct sockaddr sa; #ifdef TLI struct sockaddr_in *sin = (struct sockaddr_in *) &sa; struct hostent *hp; int argcnt = 0; #endif int match = 0; int count; char hostornet[MAXHOSTNAMELEN]; char host_name[MAXHOSTNAMELEN]; char net_name[MAXHOSTNAMELEN]; char snet_name[MAXHOSTNAMELEN]; char readperm[MAXBUFLEN]; char postperm[MAXBUFLEN]; char groups[MAXBUFLEN]; char line[MAXBUFLEN]; register char *cp; register FILE *acs_fp; gdlist[0] = '\0'; #ifdef NO_ACCESS_CHECK /* for special debugging */ *canread = *canpost = *canxfer = 1; return; #endif *canread = *canpost = *canxfer = 0; sockt = fileno(stdin); length = sizeof (sa); #ifdef TLI if (t_getpeername(sockt, &sa, &length) < 0) { if (isatty(sockt)) { (void) strcpy(hostname, "stdin"); *canread = 1; } else { #ifdef SYSLOG syslog(LOG_ERR, "host_access: getpeername: %m"); #endif (void) strcpy(hostname, "unknown"); } return; } #else /* !TLI */ #ifdef EXCELAN if (raddr(current_peer.sin_addr) == NULL) { #else if (getpeername(sockt, &sa, &length) < 0) { #endif if (isatty(sockt)) { (void) strcpy(hostname, "stdin"); *canread = 1; } else { #ifdef SYSLOG syslog(LOG_ERR, "host_access: getpeername: %m"); #endif (void) strcpy(hostname, "unknown"); } return; } #ifdef EXCELAN else bcopy(¤t_peer,&sa,length); #endif #endif /* !TLI */ switch (sa.sa_family) { case AF_INET: inet_netnames(sockt, &sa, net_name, snet_name, host_name); break; #ifdef DECNET case AF_DECnet: dnet_netnames(sockt, &sa, net_name, snet_name, host_name); break; #endif default: #ifdef SYSLOG syslog(LOG_ERR, "unknown address family %ld", sa.sa_family); #endif return; }; /* Normalize host name to lower case */ for (cp = host_name; *cp; cp++) if (isupper(*cp)) *cp = tolower(*cp); #ifdef LOG syslog(LOG_INFO, "%s connect\n", host_name); #endif (void) strcpy(hostname, host_name); /* * We now we have host_name, snet_name, and net_name. * Our strategy at this point is: * * for each line, get the first word * * If it matches "host_name", we have a direct * match; parse and return. * * If it matches "snet_name", we have a subnet match; * parse and set flags. * * If it matches "net_name", we have a net match; * parse and set flags. * * If it matches the literal "default", note we have * a net match; parse. */ #if defined(DEBUG) && defined(SYSLOG) if (debug) syslog(LOG_DEBUG, "host_access(): host_name=%s, snet_name=%s, net_name=%s", host_name ? host_name : "NIL", snet_name ? snet_name : "NIL", net_name ? net_name : "NIL"); #endif acs_fp = fopen(accessfile, "r"); if (acs_fp == NULL) { #ifdef SYSLOG syslog(LOG_ERR, "access: fopen %s: %m", accessfile); #endif return; } while (fgets(line, sizeof(line), acs_fp) != NULL) { if ((cp = index(line, '\n')) != NULL) *cp = '\0'; if ((cp = index(line, '#')) != NULL) *cp = '\0'; if (*line == '\0') continue; count = sscanf(line, "%s %s %s %s", hostornet, readperm, postperm, groups); if (count < 4) { if (count < 3) continue; groups[0] = '\0'; /* No groups specified */ } #if defined(DEBUG) && defined(SYSLOG) if (debug) syslog(LOG_DEBUG, "host_access(): hostornet=%s, readperm=%s, postperm=%s, groups=%s", hostornet ? hostornet : "NIL", readperm ? readperm : "NIL", postperm ? postperm : "NIL", groups ? groups : "NIL"); #endif #ifdef DOMAINMATCH for (cp = hostornet; *cp; cp++) if (isupper(*cp)) *cp = tolower(*cp); if (wildmat(host_name, hostornet)) { #else if (!strcasecmp(hostornet, host_name)) { #endif *canread = (readperm[0] == 'r' || readperm[0] == 'R'); *canxfer = (readperm[0] == 'X' || readperm[0] == 'x'); if (readperm[0] == 'B' || readperm[0] == 'b') *canxfer = *canread = 1; *canpost = (postperm[0] == 'p' || postperm[0] == 'P'); (void) strcpy(gdlist, groups); break; } if (*snet_name && !strcasecmp(hostornet, snet_name)) { match = SNETMATCH; *canread = (readperm[0] == 'r' || readperm[0] == 'R'); *canxfer = (readperm[0] == 'X' || readperm[0] == 'x'); if (readperm[0] == 'B' || readperm[0] == 'b') *canxfer = *canread = 1; *canpost = (postperm[0] == 'p' || postperm[0] == 'P'); (void) strcpy(gdlist, groups); } if (match != SNETMATCH && (!strcasecmp(hostornet, net_name) || !strcasecmp(hostornet, "default"))) { match = NETMATCH; *canread = (readperm[0] == 'r' || readperm[0] == 'R'); *canxfer = (readperm[0] == 'X' || readperm[0] == 'x'); if (readperm[0] == 'B' || readperm[0] == 'b') *canxfer = *canread = 1; *canpost = (postperm[0] == 'p' || postperm[0] == 'P'); (void) strcpy(gdlist, groups); } } /* * The access check expects there to be spaces between the group names. * In the access file, there are commas between the groupnames. * Here, we change the commas to spaces. */ { char *pointer=gdlist; while (*pointer) { if (*pointer == ',') *pointer=' '; pointer++; } } (void) fclose(acs_fp); #ifdef AUTH Needauth = 0; /* do we require a userid and password for this guy? */ if (isupper(readperm[0]) || isupper(postperm[0])) Needauth = 1; #endif /* AUTH */ }