-
Notifications
You must be signed in to change notification settings - Fork 0
/
nhlaunch.c
259 lines (227 loc) · 4.81 KB
/
nhlaunch.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* nhlaunch.c -- Handle logging in and launching nethack
Author: Shawn Betts
Copyright (c) 2004,2005 Shawn Betts
To build on linux:
gcc -D__LINUX__ nhlaunch.c -o nhlaunch -lcrypt
To build on OpenBSD
gcc nhlaunch.c -o nhlaunch -lcrypto
*/
#ifdef __LINUX__
#include <crypt.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#ifndef BUFSIZ
# define BUFSIZ 256
#endif
#define UNKNOWN_USER 0
#define BAD_PASSWD 1
#define SUCCESS 2
/* Config values. Tweak these to fit your system */
#define USER_FILE "/etc/nh-login"
#define CHROOT_DIR "/home/sabetts/src/nethack-el/gl"
#define SHED_UID 1000
#define SHED_GID 1000
struct game_t
{
char *name;
char *path;
};
/* This structure describes the games are playable on this server. The
MUST be at least one entry. */
struct game_t games[] = {{"nethack", "/usr/games/nethack"},
{"slashem", "/usr/games/slashem"},
/* The last entry must be NULL. */
{NULL, NULL}};
char *
find_program(char *game)
{
struct game_t *i;
for (i=games; i->name; i++)
{
if (!strcmp(game, i->name))
return i->path;
}
/* No match? pick the first one in the list. */
return games[0].path;
}
void
list_programs()
{
struct game_t *i;
for (i=games; i->name; i++)
printf("%s\n", i->name);
}
int
valid_user_p(char *username, char *passwd)
{
FILE *fd;
char line[BUFSIZ];
if ((fd = fopen(USER_FILE, "r")) == NULL)
exit(100);
while (fgets(line, BUFSIZ, fd) != NULL)
{
char *n;
char *p;
n = (char *)strtok(line, ",");
p = (char *)strtok(NULL, "\n");
if (!strcmp(n, username))
{
fclose(fd);
if (!strcmp(crypt(passwd,passwd),p))
return SUCCESS;
else
return BAD_PASSWD;
}
}
fclose(fd);
return UNKNOWN_USER;
}
void
add_user(char *username, char *passwd)
{
FILE *fd, *fpl;
/* Always lock the file before writting. */
fpl = fopen("/var/lock/nh-lock","r");
if (!fpl) exit(101);
if (flock(fileno(fpl),LOCK_SH)) exit(102);
if ((fd = fopen(USER_FILE, "a+")) == NULL)
exit(103);
fprintf(fd, "%s,%s\n", username, crypt(passwd,passwd));
fclose(fd);
/* Unlock. */
flock(fileno(fpl),LOCK_UN);
fclose(fpl);
}
int logged_in = 0;
char *player_name = NULL;
void
read_cmd()
{
char line[BUFSIZ];
/* The client disconnected. */
if (fgets(line, BUFSIZ, stdin) == NULL)
exit(0);
if (!strncmp(line, "login", 5))
{
char *name, *pass, *cmd;
int ret;
cmd = (char *)strtok(line, " ");
name = (char *)strtok(NULL, " ");
pass = (char *)strtok(NULL, " ");
if (!name || !pass)
{
printf ("Error parsing name and password.\n");
}
else
{
ret = valid_user_p(name, pass);
if (ret == SUCCESS)
{
if (logged_in)
{
printf("You are already logged in.\n");
}
else
{
logged_in = 1;
if (player_name != NULL)
free(player_name);
player_name = (char *)strdup(name);
printf("Welcome back %s.\n", name);
}
}
else if (ret == BAD_PASSWD)
{
printf("Failed to login %s.\n", name);
}
else
{
printf("Unknown user %s.\n", name);
}
}
}
else if (!strncmp(line, "list", 4))
{
list_programs();
}
else if (!strncmp(line, "play", 4))
{
if (logged_in)
{
int pid;
char *cmd, *game, *program;
/* Find out which game to play. */
cmd = (char *)strtok(line, " \n");
game = (char *)strtok(NULL, " \n");
if (game)
program = find_program(game);
else
program = find_program("");
/* Fork and run the game. */
pid = fork();
if (pid == 0)
execlp(program, program, "-u", player_name, (char *)NULL);
else
waitpid(pid, NULL, 0);
exit(0);
}
else
printf("You must login first.\n");
}
else if (!strncmp(line, "new", 3))
{
char *name, *pass, *cmd;
cmd = (char *)strtok(line, " ");
name = (char *)strtok(NULL, " ");
pass = (char *)strtok(NULL, " ");
if (!name || !pass || strchr(name,','))
{
printf ("Error parsing name and password.\n");
}
else if (valid_user_p(name, pass) == UNKNOWN_USER)
{
add_user(name, pass);
printf ("User %s added successfully.\n", name);
}
else
{
printf ("User %s already exists.\n", name);
}
}
else
{
printf("Unknown command\n");
}
}
void
repl()
{
while(1)
{
read_cmd();
fflush(stdout);
}
}
int
main(int argc, char **argv)
{
/* chroot */
if (chroot (CHROOT_DIR))
perror ("cannot change root directory");
if (chdir ("/"))
perror ("cannot chdir to root directory");
/* shed privs. this is done immediately after chroot. */
setgid(SHED_UID);
setuid(SHED_GID);
printf("Welcome to the nethack-el server.\n");
fflush(stdout);
repl();
return 0;
}