/* * Print hURL redirect page */ void url_redirect(state *st) { char dest[BUFSIZE]; char *c; /* Basic security checking */ sstrlcpy(dest, st->req_selector + 4); if (sstrncmp(dest, "http://") != MATCH && sstrncmp(dest, "ftp://") != MATCH && sstrncmp(dest, "mailto:") != MATCH) die(st, ERR_ACCESS, "Refusing to HTTP redirect unsafe protocols"); if ((c = strchr(dest, '"'))) *c = '\0'; if ((c = strchr(dest, '?'))) *c = '\0'; /* Log the redirect */ if (st->opt_syslog) { syslog(LOG_INFO, "request for \"gopher://%s:%i/h%s\" from %s", st->server_host, st->server_port, st->req_selector, st->req_remote_addr); } log_combined(st, HTTP_OK); /* Output HTML */ printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" "<HTML>\n<HEAD>\n" " <META HTTP-EQUIV=\"Refresh\" content=\"1;URL=%1$s\">\n" " <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;charset=iso-8859-1\">\n" " <TITLE>URL Redirect page</TITLE>\n" "</HEAD>\n<BODY>\n" "<STRONG>Redirecting to <A HREF=\"%1$s\">%1$s</A></STRONG>\n" "<PRE>\n", dest); footer(st); printf("</PRE>\n</BODY>\n</HTML>\n"); }
main() { char s[100],t[100]; int n,k; printf("Enter Two Strings : "); scanf("%s%s",s,t); printf("Enter Value for n : "); scanf("%d",&n); k=sstrncmp(s,t,n); if(k==0) printf("\nThe strings are equal\n"); else printf("\nThe strings are not equal\n"); // sstrncpy(s,t,n); // printf("\nThe Copied String from %s to %s\n",t,s); // sstrncat(s,t,n); // printf("\nThe concatenated strings %s\n",s); }
/* * Get remote peer IP address */ char *get_peer_address(void) { #ifdef HAVE_IPv4 struct sockaddr_in addr; socklen_t addrsize = sizeof(addr); #endif #ifdef HAVE_IPv6 struct sockaddr_in6 addr6; socklen_t addr6size = sizeof(addr6); static char address[INET6_ADDRSTRLEN]; #endif char *c; /* Are we a CGI script? */ if ((c = getenv("REMOTE_ADDR"))) return c; /* if ((c = getenv("REMOTE_HOST"))) return c; */ /* Try IPv4 first */ #ifdef HAVE_IPv4 if (getpeername(0, (struct sockaddr *) &addr, &addrsize) == OK) { c = inet_ntoa(addr.sin_addr); if (strlen(c) > 0 && *c != '0') return c; } #endif /* IPv4 didn't work - try IPv6 */ #ifdef HAVE_IPv6 if (getpeername(0, (struct sockaddr *) &addr6, &addr6size) == OK) { if (inet_ntop(AF_INET6, &addr6.sin6_addr, address, sizeof(address))) { /* Strip ::ffff: IPv4-in-IPv6 prefix */ if (sstrncmp(address, "::ffff:") == MATCH) return (address + 7); else return address; } } #endif /* Nothing works... I'm out of ideas */ return DEFAULT_ADDR; }
/* compare strings */ static int scompare(char *buff1, const char *buff2) { int i; if (sstrlen(buff1) == sstrlen(buff2)) { if (sstrcmp(buff1,buff2) == 0) { if (fgets(buff1,4095,fp)==NULL) return -1; return 0; } return -1; } for (i=0;i<sstrlen(buff1)-sstrlen(buff2);i++) { if (buff1[i]==' ' || buff1[i]=='\t') { continue; } else if ((sstrncmp(&buff1[i],buff2,sstrlen(buff2))==0) &&((buff1[i+strlen(buff2)]==' ')||(buff1[i+strlen(buff2)]=='\t')||(buff1[i+strlen(buff2)]=='\n'))) { return i+strlen(buff2); } else return -1; } return -1; }
/* * Main */ int main(int argc, char *argv[]) { struct stat file; state st; char self[64]; char selector[BUFSIZE]; char buf[BUFSIZE]; char *dest; char *c; #ifdef HAVE_SHMEM struct shmid_ds shm_ds; shm_state *shm; int shmid; #endif /* Get the name of this binary */ if ((c = strrchr(argv[0], '/'))) sstrlcpy(self, c + 1); else sstrlcpy(self, argv[0]); /* Initialize state */ #ifdef HAVE_LOCALES setlocale(LC_TIME, DATE_LOCALE); #endif init_state(&st); srand(time(NULL) / (getpid() + getppid())); /* Handle command line arguments */ parse_args(&st, argc, argv); /* Open syslog() */ if (st.opt_syslog) openlog(self, LOG_PID, LOG_DAEMON); /* Make sure the computer is turned on */ #ifdef __HAIKU__ if (is_computer_on() != TRUE) die(&st, ERR_ACCESS, "Please turn on the computer first"); #endif /* Refuse to run as root */ #ifdef HAVE_PASSWD if (st.opt_root && getuid() == 0) die(&st, ERR_ACCESS, "Refusing to run as root"); #endif /* Try to get shared memory */ #ifdef HAVE_SHMEM if ((shmid = shmget(SHM_KEY, sizeof(shm_state), IPC_CREAT | SHM_MODE)) == ERROR) { /* Getting memory failed -> delete the old allocation */ shmctl(shmid, IPC_RMID, &shm_ds); shm = NULL; } else { /* Map shared memory */ if ((shm = (shm_state *) shmat(shmid, (void *) 0, 0)) == (void *) ERROR) shm = NULL; /* Initialize mapped shared memory */ if (shm && shm->start_time == 0) { shm->start_time = time(NULL); /* Keep server platform & description in shm */ platform(&st); sstrlcpy(shm->server_platform, st.server_platform); sstrlcpy(shm->server_description, st.server_description); } } /* For debugging shared memory issues */ if (!st.opt_shm) shm = NULL; /* Get server platform and description */ if (shm) { sstrlcpy(st.server_platform, shm->server_platform); if (!*st.server_description) sstrlcpy(st.server_description, shm->server_description); } else #endif platform(&st); /* Read selector */ if (fgets(selector, sizeof(selector) - 1, stdin) == NULL) selector[0] = '\0'; /* Remove trailing CRLF */ chomp(selector); if (st.debug) syslog(LOG_INFO, "client sent us \"%s\"", selector); /* Handle hURL: redirect page */ if (sstrncmp(selector, "URL:") == MATCH) { st.req_filetype = TYPE_HTML; sstrlcpy(st.req_selector, selector); url_redirect(&st); return OK; } /* Handle gopher+ root requests (UMN gopher client is seriously borken) */ if (sstrncmp(selector, "\t$") == MATCH) { printf("+-1" CRLF); printf("+INFO: 1Main menu\t\t%s\t%i" CRLF, st.server_host, st.server_port); printf("+VIEWS:" CRLF " application/gopher+-menu: <512b>" CRLF); printf("." CRLF); if (st.debug) syslog(LOG_INFO, "got a request for gopher+ root menu"); return OK; } /* Convert HTTP request to gopher (respond using headerless HTTP/0.9) */ if (sstrncmp(selector, "GET ") == MATCH || sstrncmp(selector, "POST ") == MATCH ) { if ((c = strchr(selector, ' '))) sstrlcpy(selector, c + 1); if ((c = strchr(selector, ' '))) *c = '\0'; st.req_protocol = PROTO_HTTP; if (st.debug) syslog(LOG_INFO, "got HTTP request for \"%s\"", selector); } /* Save default server_host & fetch session data (including new server_host) */ sstrlcpy(st.server_host_default, st.server_host); #ifdef HAVE_SHMEM if (shm) get_shm_session(&st, shm); #endif /* Loop through the selector, fix it & separate query_string */ dest = st.req_selector; if (selector[0] != '/') *dest++ = '/'; for (c = selector; *c;) { /* Skip duplicate slashes and /./ */ while (*c == '/' && *(c + 1) == '/') c++; if (*c == '/' && *(c + 1) == '.' && *(c + 2) == '/') c += 2; /* Start of a query string (either type 7 or HTTP-style)? */ if (*c == '\t' || (st.opt_query && *c == '?')) { sstrlcpy(st.req_query_string, c + 1); if ((c = strchr(st.req_query_string, '\t'))) *c = '\0'; break; } /* Start of virtual host hint? */ if (*c == ';') { if (st.opt_vhost) sstrlcpy(st.server_host, c + 1); /* Skip vhost on selector */ while (*c && *c != '\t') c++; continue; } /* Copy valid char */ *dest++ = *c++; } *dest = '\0'; /* Remove encodings from selector */ strndecode(st.req_selector, st.req_selector, sizeof(st.req_selector)); /* Deny requests for Slashdot and /../ hackers */ if (strstr(st.req_selector, "/.")) die(&st, ERR_ACCESS, "Refusing to serve out dotfiles"); /* Handle /server-status requests */ #ifdef HAVE_SHMEM if (sstrncmp(st.req_selector, SERVER_STATUS) == MATCH) { if (shm) server_status(&st, shm, shmid); return OK; } #endif /* Remove possible extra cruft from server_host */ if ((c = strchr(st.server_host, '\t'))) *c = '\0'; /* Guess request filetype so we can die() with style... */ st.req_filetype = gopher_filetype(&st, st.req_selector, FALSE); /* Convert seletor to path & stat() */ selector_to_path(&st); if (st.debug) syslog(LOG_INFO, "path to resource is \"%s\"", st.req_realpath); if (stat(st.req_realpath, &file) == ERROR) { /* Handle virtual /caps.txt requests */ if (st.opt_caps && sstrncmp(st.req_selector, CAPS_TXT) == MATCH) { #ifdef HAVE_SHMEM caps_txt(&st, shm); #else caps_txt(&st, NULL); #endif return OK; } /* Requested file not found - die() */ die(&st, ERR_NOTFOUND, NULL); } /* Fetch request filesize from stat() */ st.req_filesize = file.st_size; /* Everyone must have read access but no write access */ if ((file.st_mode & S_IROTH) == 0) die(&st, ERR_ACCESS, "File or directory not world-readable"); if ((file.st_mode & S_IWOTH) != 0) die(&st, ERR_ACCESS, "File or directory world-writeable"); /* If stat said it was a dir then it's a menu */ if ((file.st_mode & S_IFMT) == S_IFDIR) st.req_filetype = TYPE_MENU; /* Not a dir - let's guess the filetype again... */ else if ((file.st_mode & S_IFMT) == S_IFREG) st.req_filetype = gopher_filetype(&st, st.req_realpath, st.opt_magic); /* Menu selectors must end with a slash */ if (st.req_filetype == TYPE_MENU && strlast(st.req_selector) != '/') sstrlcat(st.req_selector, "/"); /* Change directory to wherever the resource was */ sstrlcpy(buf, st.req_realpath); if ((file.st_mode & S_IFMT) != S_IFDIR) c = dirname(buf); else c = buf; if (chdir(c) == ERROR) die(&st, ERR_ACCESS, NULL); /* Keep count of hits and data transfer */ #ifdef HAVE_SHMEM if (shm) { shm->hits++; shm->kbytes += st.req_filesize / 1024; /* Update user session */ update_shm_session(&st, shm); } #endif /* Log the request */ if (st.opt_syslog) { syslog(LOG_INFO, "request for \"gopher://%s:%i/%c%s\" from %s", st.server_host, st.server_port, st.req_filetype, st.req_selector, st.req_remote_addr); } /* Check file type & act accordingly */ switch (file.st_mode & S_IFMT) { case S_IFDIR: log_combined(&st, HTTP_OK); gopher_menu(&st); break; case S_IFREG: log_combined(&st, HTTP_OK); gopher_file(&st); break; default: die(&st, ERR_ACCESS, "Refusing to serve out special files"); } /* Clean exit */ return OK; }
/* * Convert gopher selector to an absolute path */ void selector_to_path(state *st) { DIR *dp; struct dirent *dir; struct stat file; #ifdef HAVE_PASSWD struct passwd *pwd; char *path = EMPTY; char *c; #endif char buf[BUFSIZE]; int i; /* Handle selector rewriting */ for (i = 0; i < st->rewrite_count; i++) { /* Match found? */ if (strstr(st->req_selector, st->rewrite[i].match) == st->req_selector) { /* Replace match with a new string */ snprintf(buf, sizeof(buf), "%s%s", st->rewrite[i].replace, st->req_selector + strlen(st->rewrite[i].match)); if (st->debug) { syslog(LOG_INFO, "rewriting selector \"%s\" -> \"%s\"", st->req_selector, buf); } sstrlcpy(st->req_selector, buf); } } #ifdef HAVE_PASSWD /* Virtual userdir (~user -> /home/user/public_gopher)? */ if (*(st->user_dir) && sstrncmp(st->req_selector, "/~") == MATCH) { /* Parse userdir login name & path */; sstrlcpy(buf, st->req_selector + 2); if ((c = strchr(buf, '/'))) { *c = '\0'; path = c + 1; } /* Check user validity */ if ((pwd = getpwnam(buf)) == NULL) die(st, ERR_NOTFOUND, "User not found"); if (pwd->pw_uid < PASSWD_MIN_UID) die(st, ERR_NOTFOUND, "User found but UID too low"); /* Generate absolute path to users own gopher root */ snprintf(st->req_realpath, sizeof(st->req_realpath), "%s/%s/%s", pwd->pw_dir, st->user_dir, path); /* Check ~public_gopher access rights */ if (stat(st->req_realpath, &file) == ERROR) die(st, ERR_NOTFOUND, NULL); if ((file.st_mode & S_IROTH) == 0) die(st, ERR_ACCESS, "~/public_gopher not world-readable"); if (file.st_uid != pwd->pw_uid) die(st, ERR_ACCESS, "~/ and ~/public_gopher owned by different users"); /* Userdirs always come from the default vhost */ if (st->opt_vhost) sstrlcpy(st->server_host, st->server_host_default); return; } #endif /* Virtual hosting */ if (st->opt_vhost) { /* Try looking for the selector from the current vhost */ snprintf(st->req_realpath, sizeof(st->req_realpath), "%s/%s%s", st->server_root, st->server_host, st->req_selector); if (stat(st->req_realpath, &file) == OK) return; /* Loop through all vhosts looking for the selector */ if ((dp = opendir(st->server_root)) == NULL) die(st, ERR_NOTFOUND, NULL); while ((dir = readdir(dp))) { /* Skip .hidden dirs and . & .. */ if (dir->d_name[0] == '.') continue; /* Special case - skip lost+found (don't ask) */ if (sstrncmp(dir->d_name, "lost+found") == MATCH) continue; /* Generate path to the found vhost */ snprintf(st->req_realpath, sizeof(st->req_realpath), "%s/%s%s", st->server_root, dir->d_name, st->req_selector); /* Did we find the selector under this vhost? */ if (stat(st->req_realpath, &file) == OK) { /* Virtual host found - update state & return */ sstrlcpy(st->server_host, dir->d_name); return; } } closedir(dp); } /* Handle normal selectors */ snprintf(st->req_realpath, sizeof(st->req_realpath), "%s%s", st->server_root, st->req_selector); }
/* * Handle gophermaps */ int gophermap(state *st, char *mapfile, int depth) { FILE *fp; struct stat file; char line[BUFSIZE]; #ifdef HAVE_POPEN char command[BUFSIZE]; #endif char *selector; char *name; char *host; char *c; char type; int port; int exe; /* Prevent include loops */ if (depth > 4) return OK; /* Try to figure out whether the map is executable */ if (stat(mapfile, &file) == OK) { if ((file.st_mode & S_IXOTH)) { #ifdef HAVE_POPEN /* Quote the command in case path has spaces */ snprintf(command, sizeof(command), "'%s'", mapfile); #endif exe = TRUE; } else exe = FALSE; } /* This must be a shell include */ else { #ifdef HAVE_POPEN /* Let's assume the shell command runs as is without quoting */ sstrlcpy(command, mapfile); #endif exe = TRUE; } /* Debug output */ if (st->debug) { if (exe) syslog(LOG_INFO, "parsing executable gophermap \"%s\"", mapfile); else syslog(LOG_INFO, "parsing static gophermap \"%s\"", mapfile); } /* Try to execute or open the mapfile */ #ifdef HAVE_POPEN if (exe) { setenv_cgi(st, mapfile); if ((fp = popen(command, "r")) == NULL) return OK; } else #endif if ((fp = fopen(mapfile, "r")) == NULL) return OK; /* Read lines one by one */ while (fgets(line, sizeof(line) - 1, fp)) { /* Parse type & name */ chomp(line); type = line[0]; name = line + 1; /* Ignore #comments */ if (type == '#') continue; /* Stop handling gophermap? */ if (type == '*') return OK; if (type == '.') return QUIT; /* Print a list of users with public_gopher */ if (type == '~') { #ifdef HAVE_PASSWD userlist(st); #endif continue; } /* Print a list of available virtual hosts */ if (type == '%') { if (st->opt_vhost) vhostlist(st); continue; } /* Hide files in menus */ if (type == '-') { if (st->hidden_count < MAX_HIDDEN) sstrlcpy(st->hidden[st->hidden_count++], name); continue; } /* Override filetype mappings */ if (type == ':') { add_ftype_mapping(st, name); continue; } /* Include gophermap or shell exec */ if (type == '=') { gophermap(st, name, depth + 1); continue; } /* Title resource */ if (type == TYPE_TITLE) { info(st, name, TYPE_TITLE); continue; } /* Print out non-resources as info text */ if (!strchr(line, '\t')) { info(st, line, TYPE_INFO); continue; } /* Parse selector */ selector = EMPTY; if ((c = strchr(name, '\t'))) { *c = '\0'; selector = c + 1; } if (!*selector) selector = name; /* Parse host */ host = st->server_host; if ((c = strchr(selector, '\t'))) { *c = '\0'; host = c + 1; } /* Parse port */ port = st->server_port; if ((c = strchr(host, '\t'))) { *c = '\0'; port = atoi(c + 1); } /* Handle remote, absolute and hURL gopher resources */ if (sstrncmp(selector, "URL:") == MATCH || selector[0] == '/' || host != st->server_host) { printf("%c%s\t%s\t%s\t%i" CRLF, type, name, selector, host, port); } /* Handle relative resources */ else { printf("%c%s\t%s%s\t%s\t%i" CRLF, type, name, st->req_selector, selector, host, port); /* Automatically hide manually defined selectors */ #ifdef ENABLE_AUTOHIDING if (st->hidden_count < MAX_HIDDEN) sstrlcpy(st->hidden[st->hidden_count++], selector); #endif } } /* Clean up & return */ #ifdef HAVE_POPEN if (exe) pclose(fp); else #endif fclose(fp); return QUIT; }
/* * Return gopher filetype for a file */ char gopher_filetype(state *st, char *file, char magic) { FILE *fp; char buf[BUFSIZE]; char *c; int i; /* If it ends with an slash it's a menu */ if (!*file) return st->default_filetype; if (strlast(file) == '/') return TYPE_MENU; /* Get file suffix */ if ((c = strrchr(file, '.'))) { c++; /* Loop through the filetype array looking for a match*/ for (i = 0; i < st->filetype_count; i++) if (strcasecmp(st->filetype[i].suffix, c) == MATCH) return st->filetype[i].type; } /* Are we allowed to look inside files? */ if (!magic) return st->default_filetype; /* Read data from the file */ if ((fp = fopen(file , "r")) == NULL) return st->default_filetype; i = fread(buf, 1, sizeof(buf) - 1, fp); buf[i] = '\0'; fclose(fp); /* GIF images */ if (sstrncmp(buf, "GIF89a") == MATCH || sstrncmp(buf, "GIF87a") == MATCH) return TYPE_GIF; /* JPEG images */ if (sstrncmp(buf, "\377\330\377\340") == MATCH) return TYPE_IMAGE; /* PNG images */ if (sstrncmp(buf, "\211PNG") == MATCH) return TYPE_IMAGE; /* mbox */ if (strstr(buf, "\nFrom: ") && strstr(buf, "\nSubject: ")) return TYPE_MIME; /* MIME */ if (strstr(buf, "\nContent-Type: ")) return TYPE_MIME; /* HTML files */ if (buf[0] == '<' && (strstr(buf, "<html") || strstr(buf, "<HTML"))) return TYPE_HTML; /* PDF and PostScript */ if (sstrncmp(buf, "%PDF-") == MATCH || sstrncmp(buf, "%!") == MATCH) return TYPE_DOC; /* compress and gzip */ if (sstrncmp(buf, "\037\235\220") == MATCH || sstrncmp(buf, "\037\213\010") == MATCH) return TYPE_GZIP; /* Unknown content - binary or text? */ if (memchr(buf, '\0', i)) return TYPE_BINARY; return st->default_filetype; }