#include #include #include #include #include #include #include #include #include #include #include #include void copyfile(char *path, char *text, FILE *fp) { FILE *in; char *cp; char buf[BUFSIZ]; if ((in = fopen(path, "r"))) { fprintf(fp, "%s:\r\n", text); while (fgets(buf, sizeof buf - 1, in)) { if ((cp = strchr(buf, '\n'))) { *cp++ = '\r'; *cp++ = '\n'; *cp = '\0'; } fputs(buf, fp); } } else { fprintf(fp, "No %s.\r\n", text); } } void reply(int fd) { struct passwd *pw; char buf[BUFSIZ]; char *cp; FILE *fp; if (!(fp = fdopen(fd, "r+"))) { perror("fdopen"); exit(1); } fgets(buf, sizeof(buf), fp); for (cp=buf; *cp; cp++) { if (*cp=='\r' || *cp=='\n') { *cp = '\0'; break; } } /* Refuse {C} queries */ if (*buf == '\0') { fprintf(fp, "Finger online user list denied.\r\n"); exit(1); } /* Ignore and skip `/W' */ cp = buf; if (strncmp(buf, "/W ", 3)==0) { for (cp=buf+3; *cp && *cp==' '; cp++) { ; } } /* Refuse {Q2} queries */ if (strchr(cp, '@')) { fprintf(fp, "Finger forwarding service denied.\r\n"); exit(1); } pw = getpwnam(cp); if (!pw) { fprintf(fp, "No such user.\r\n"); exit(1); } /* ** Refuse queries for users who don't want to get fingered ** This is senseless in our setup, because home directories have mode 0700. ** We would refuse all queries to users other than oneself. ** snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, ".nofinger"); struct stat sb; int ret = stat(buf, &sb); if (ret != -1 || (ret == -1 && errno != ENOENT)) { fprintf(fp, "User does not want to be fingered.\r\n"); exit(1); } */ /* Eventually, reply. */ fprintf(fp, "login: %s\t\trealname: %s\r\n", pw->pw_name, pw->pw_gecos); fprintf(fp, "home: %s\t\tshell: %s\r\n", pw->pw_dir, pw->pw_shell); snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, ".project"); copyfile(buf, "project", fp); snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, ".plan"); copyfile(buf, "plan", fp); snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, ".pubkey"); copyfile(buf, "public key", fp); } int main(int argc, char *argv[]) { int sd, fd; pid_t pid; short port = 7979; if (argc == 2) { if ((port = atoi(argv[1])) <= 0) { fprintf(stderr, "port must be a positive number\n"); exit(1); } } if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } int optval = 1; if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) == -1) { perror("setsockopt"); exit(1); } struct sockaddr_in address = {0}; address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_ANY); address.sin_port = htons(port); if (bind(sd, (struct sockaddr *)&address, sizeof address) == -1) { perror("bind"); exit(1); } if (listen(sd, SOMAXCONN) == -1) { perror("listen"); exit(1); } /* don't create zombies */ signal(SIGCHLD, SIG_IGN); /* Now, wait for incoming connections */ while ((fd = accept(sd, 0, 0)) != -1) { /* we have a connection */ if ((pid = fork()) == -1) { perror("fork"); exit(1); } else if (pid == 0) { /* child */ reply(fd); exit(0); } /* parent */ close(fd); } return 0; }