-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgopherd.c
141 lines (126 loc) · 2.58 KB
/
gopherd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <pwd.h>
#include <err.h>
#include <unistd.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#ifdef __linux__
#include <grp.h>
#endif
int serve(int);
int tcpbind(const char *, int);
void session(int, const char *);
char* ipport(char *str, int *port)
{
char *p;
p = strchr(str, ':');
if (p != NULL) {
*p++ = '\0';
*port = atoi(p);
}
return str;
}
static void usage(char *prog)
{
fprintf(stderr, "Usage: %s <ip>[:<port>] [rootpath] [hostname]\n",
prog);
exit(1);
}
/* main: simple gopher daemon */
int main(int argc, char **argv)
{
int sfd;
struct passwd *pw;
gid_t gid;
uid_t uid;
char *root = "/var/gopher";
int port = 70;
char *ip;
char *hostname = NULL;
struct stat sb;
struct in_addr ipa;
struct hostent *he;
if (argc < 2 || argc > 4)
usage(argv[0]);
if (argc == 4)
hostname = argv[3];
if (argc >= 3)
root = argv[2];
ip = ipport(argv[1], &port);
if (strcmp(ip, "*") == 0)
ip = "0.0.0.0";
if (hostname == NULL) {
he = gethostbyaddr(&ipa, sizeof(ipa), AF_INET);
if (he == NULL) {
warnx("warn: no name associated with %s", ip);
hostname = ip;
} else {
hostname = he->h_name;
warnx("warn: using hostname %s", hostname);
}
}
openlog(argv[0], 0, LOG_MAIL);
syslog(LOG_INFO, "started");
sfd = tcpbind(ip, port);
pw = getpwnam("daemon");
if (stat(root, &sb) != 0) {
warn("stat %s", root);
usage(argv[0]);
}
if (!(S_ISDIR(sb.st_mode) || S_ISLNK(sb.st_mode)))
errx(1, "%s: not a directory", root);
if (access(root, R_OK | X_OK) != 0)
err(1, "access %s", root);
#ifdef __OpenBSD__
if (unveil(root, "r") != 0)
err(1, "unveil %s", root);
if (unveil(NULL, NULL) != 0)
err(1, "unveil");
if (chdir(root) != 0)
err(1, "chdir %s", root);
#else
if (chroot(root) != 0 || chdir("/") != 0)
err(1, "chroot %s", root);
#endif
uid = pw->pw_uid;
gid = pw->pw_gid;
setgroups(1, &gid);
setresgid(gid, gid, gid);
setresuid(uid, uid, uid);
if (daemon(0, 0) < 0)
err(1, "daemon");
#ifdef __OpenBSD__
if (pledge("stdio rpath inet proc", NULL) < 0)
err(1, "pledge");
#endif
for (;;) {
int fd, status;
pid_t pid;
fd = serve(sfd);
if (fd < 0)
continue;
if ((pid = fork()) == 0) {
alarm(10); /* session expire time */
#ifdef __OpenBSD__
setproctitle("session");
#endif
#ifdef __OpenBSD__
if (pledge("stdio rpath", NULL) < 0)
err(1, "pledge");
#endif
session(fd, hostname);
exit(127);
}
close(fd);
if (pid != -1)
wait(&status);
}
return 0;
}