GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/radiusd/radiusd_bsdauth/../radiusd_bsdauth.c Lines: 0 168 0.0 %
Date: 2017-11-13 Branches: 0 81 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: radiusd_bsdauth.c,v 1.8 2017/08/21 21:41:13 deraadt Exp $	*/
2
3
/*
4
 * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/queue.h>
21
#include <sys/socket.h>
22
#include <sys/uio.h>
23
#include <sys/wait.h>
24
25
#include <bsd_auth.h>
26
#include <err.h>
27
#include <errno.h>
28
#include <grp.h>
29
#include <imsg.h>
30
#include <login_cap.h>
31
#include <pwd.h>
32
#include <stdbool.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <syslog.h>
37
#include <unistd.h>
38
39
#include "radiusd.h"
40
#include "radiusd_module.h"
41
42
struct module_bsdauth {
43
	struct module_base	 *base;
44
	struct imsgbuf		  ibuf;
45
	char			**okgroups;
46
};
47
48
/* IPC between priv and main */
49
enum {
50
	IMSG_BSDAUTH_OK = 1000,
51
	IMSG_BSDAUTH_NG,
52
	IMSG_BSDAUTH_USERCHECK,
53
	IMSG_BSDAUTH_GROUPCHECK
54
};
55
struct auth_usercheck_args {
56
	size_t	userlen;
57
	size_t	passlen;
58
};
59
struct auth_groupcheck_args {
60
	size_t	userlen;
61
	size_t	grouplen;
62
};
63
64
static pid_t	 module_bsdauth_main(int, int);
65
static void	 module_bsdauth_config_set(void *, const char *, int,
66
		    char * const *);
67
static void	 module_bsdauth_userpass(void *, u_int, const char *,
68
		    const char *);
69
__dead static void
70
		 fatal(const char *);
71
72
static struct module_handlers module_bsdauth_handlers = {
73
	.userpass = module_bsdauth_userpass,
74
	.config_set = module_bsdauth_config_set
75
};
76
77
int
78
main(int argc, char *argv[])
79
{
80
	int		 pipe_chld, pairsock[2], status;
81
	struct imsgbuf	 ibuf;
82
	struct imsg	 imsg;
83
	ssize_t		 n;
84
	size_t		 datalen;
85
	pid_t		 pid;
86
87
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pairsock) == -1)
88
		err(EXIT_FAILURE, "socketpair");
89
90
	pipe_chld = pairsock[1];
91
	pid = module_bsdauth_main(pairsock[0], pairsock[1]);
92
93
	/*
94
	 * Privileged process
95
	 */
96
	openlog(NULL, LOG_PID, LOG_DAEMON);
97
	setproctitle("[priv]");
98
	imsg_init(&ibuf, pipe_chld);
99
100
	if (pledge("stdio getpw rpath proc exec flock cpath wpath", NULL) == -1)
101
		err(EXIT_FAILURE, "pledge");
102
103
	for (;;) {
104
		if ((n = imsg_read(&ibuf)) <= 0 && errno != EAGAIN)
105
			break;
106
		for (;;) {
107
			if ((n = imsg_get(&ibuf, &imsg)) == -1)
108
				break;
109
			if (n == 0)
110
				break;
111
			datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
112
			switch (imsg.hdr.type) {
113
			case IMSG_BSDAUTH_USERCHECK:
114
			    {
115
				char		*user, *pass;
116
				bool		 authok = false;
117
				struct auth_usercheck_args
118
						*args;
119
120
				if (datalen < sizeof(
121
				    struct auth_usercheck_args)) {
122
					syslog(LOG_ERR, "Short message");
123
					break;
124
				}
125
				args = (struct auth_usercheck_args *)imsg.data;
126
127
				if (datalen < sizeof(struct auth_usercheck_args)
128
				    + args->userlen + args->passlen) {
129
					syslog(LOG_ERR, "Short message");
130
					break;
131
				}
132
				user = (char *)(args + 1);
133
				user[args->userlen - 1] = '\0';
134
				pass = user + args->userlen;
135
				pass[args->passlen - 1] = '\0';
136
137
				if (auth_userokay(user, NULL, NULL, pass))
138
					authok = true;
139
				explicit_bzero(pass, args->passlen);
140
141
				imsg_compose(&ibuf, (authok)
142
				    ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG,
143
				    0, 0, -1, NULL, 0);
144
				break;
145
			    }
146
			case IMSG_BSDAUTH_GROUPCHECK:
147
			    {
148
				int		 i;
149
				char		*user, *group;
150
				struct passwd   *pw;
151
				struct group	 gr0, *gr;
152
				char		 g_buf[4096];
153
				bool		 group_ok = false;
154
				struct auth_groupcheck_args
155
						*args;
156
157
				if (datalen < sizeof(
158
				    struct auth_groupcheck_args)) {
159
					syslog(LOG_ERR, "Short message");
160
					break;
161
				}
162
				args = (struct auth_groupcheck_args *)imsg.data;
163
				if (datalen < sizeof(
164
					    struct auth_groupcheck_args) +
165
				    args->userlen + args->grouplen) {
166
					syslog(LOG_ERR, "Short message");
167
					break;
168
				}
169
				user = (char *)(args + 1);
170
				user[args->userlen - 1] = '\0';
171
				group = user + args->userlen;
172
				group[args->grouplen - 1] = '\0';
173
174
				pw = getpwnam(user);
175
				if (getgrnam_r(group, &gr0, g_buf,
176
				    sizeof(g_buf), &gr) == -1 || gr == NULL)
177
					goto group_done;
178
179
				if (gr->gr_gid == pw->pw_gid) {
180
					group_ok = true;
181
					goto group_done;
182
				}
183
				for (i = 0; gr->gr_mem[i] != NULL; i++) {
184
					if (strcmp(gr->gr_mem[i], pw->pw_name)
185
					    == 0) {
186
						group_ok = true;
187
						goto group_done;
188
					}
189
				}
190
group_done:
191
				endgrent();
192
193
				imsg_compose(&ibuf, (group_ok)
194
				    ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG,
195
				    0, 0, -1, NULL, 0);
196
				break;
197
			    }
198
			    imsg_free(&imsg);
199
			}
200
			imsg_flush(&ibuf);
201
		}
202
		imsg_flush(&ibuf);
203
	}
204
	imsg_clear(&ibuf);
205
206
	while (waitpid(pid, &status, 0) == -1) {
207
		if (errno != EINTR)
208
			break;
209
	}
210
	exit(WEXITSTATUS(status));
211
}
212
213
static pid_t
214
module_bsdauth_main(int pipe_prnt, int pipe_chld)
215
{
216
	int			 i;
217
	pid_t			 pid;
218
	struct module_bsdauth	 module_bsdauth;
219
220
	pid = fork();
221
	if (pid == -1)
222
		err(EXIT_FAILURE, "fork");
223
224
	if (pid > 0) {
225
		close(pipe_prnt);
226
		return (pid);
227
	}
228
	close(pipe_chld);
229
230
	/* main process */
231
	setproctitle("[main]");
232
	openlog(NULL, LOG_PID, LOG_DAEMON);
233
	memset(&module_bsdauth, 0, sizeof(module_bsdauth));
234
	if ((module_bsdauth.base = module_create(STDIN_FILENO, &module_bsdauth,
235
	    &module_bsdauth_handlers)) == NULL)
236
		err(1, "Could not create a module instance");
237
238
	module_drop_privilege(module_bsdauth.base);
239
240
	module_load(module_bsdauth.base);
241
	imsg_init(&module_bsdauth.ibuf, pipe_prnt);
242
243
	if (pledge("stdio proc flock rpath cpath wpath", NULL) == -1)
244
		err(EXIT_FAILURE, "pledge");
245
246
	while (module_run(module_bsdauth.base) == 0)
247
		;
248
249
	module_destroy(module_bsdauth.base);
250
	imsg_clear(&module_bsdauth.ibuf);
251
252
	if (module_bsdauth.okgroups) {
253
		for (i = 0; module_bsdauth.okgroups[i] != NULL; i++)
254
			free(module_bsdauth.okgroups[i]);
255
	}
256
	free(module_bsdauth.okgroups);
257
258
	_exit(EXIT_SUCCESS);
259
}
260
261
static void
262
module_bsdauth_config_set(void *ctx, const char *name, int argc,
263
    char * const * argv)
264
{
265
	struct module_bsdauth	 *module = ctx;
266
	int			  i;
267
	char			**groups = NULL;
268
269
	if (strcmp(name, "restrict-group") == 0) {
270
		if (module->okgroups != NULL) {
271
			module_send_message(module->base, IMSG_NG,
272
			    "`restrict-group' is already defined");
273
			goto on_error;
274
		}
275
		if ((groups = calloc(sizeof(char *), argc + 1)) == NULL) {
276
			module_send_message(module->base, IMSG_NG,
277
			    "Out of memory");
278
			goto on_error;
279
		}
280
		for (i = 0; i < argc; i++) {
281
			if ((groups[i] = strdup(argv[i])) == NULL) {
282
				module_send_message(module->base,
283
				    IMSG_NG, "Out of memory");
284
				goto on_error;
285
			}
286
		}
287
		groups[i] = NULL;
288
		module->okgroups = groups;
289
		module_send_message(module->base, IMSG_OK, NULL);
290
	} else
291
		module_send_message(module->base, IMSG_NG,
292
		    "Unknown config parameter `%s'", name);
293
	return;
294
on_error:
295
	if (groups != NULL) {
296
		for (i = 0; groups[i] != NULL; i++)
297
			free(groups[i]);
298
		free(groups);
299
	}
300
	return;
301
}
302
303
304
static void
305
module_bsdauth_userpass(void *ctx, u_int q_id, const char *user,
306
    const char *pass)
307
{
308
	struct module_bsdauth	*module = ctx;
309
	struct auth_usercheck_args
310
				 usercheck;
311
	struct auth_groupcheck_args
312
				 groupcheck;
313
	struct iovec		iov[4];
314
	const char		*group;
315
	u_int			 i;
316
	const char		*reason;
317
	struct imsg		 imsg;
318
	ssize_t			 n;
319
320
	memset(&imsg, 0, sizeof(imsg));
321
	if (pass == NULL)
322
		pass = "";
323
324
	usercheck.userlen = strlen(user) + 1;
325
	usercheck.passlen = strlen(pass) + 1;
326
	iov[0].iov_base = &usercheck;
327
	iov[0].iov_len = sizeof(usercheck);
328
	iov[1].iov_base = (char *)user;
329
	iov[1].iov_len = usercheck.userlen;
330
	iov[2].iov_base = (char *)pass;
331
	iov[2].iov_len = usercheck.passlen;
332
333
	imsg_composev(&module->ibuf, IMSG_BSDAUTH_USERCHECK, 0, 0, -1, iov, 3);
334
	imsg_flush(&module->ibuf);
335
	if ((n = imsg_read(&module->ibuf)) == -1 || n == 0)
336
		fatal("imsg_read() failed in module_bsdauth_userpass()");
337
	if ((n = imsg_get(&module->ibuf, &imsg)) <= 0)
338
		fatal("imsg_get() failed in module_bsdauth_userpass()");
339
340
	if (imsg.hdr.type != IMSG_BSDAUTH_OK) {
341
		reason = "Authentication failed";
342
		goto auth_ng;
343
	}
344
	if (module->okgroups != NULL) {
345
		reason = "Group restriction is not allowed";
346
		for (i = 0; module->okgroups[i] != NULL; i++) {
347
			group = module->okgroups[i];
348
349
			groupcheck.userlen = strlen(user) + 1;
350
			groupcheck.grouplen = strlen(group) + 1;
351
			iov[0].iov_base = &groupcheck;
352
			iov[0].iov_len = sizeof(groupcheck);
353
			iov[1].iov_base = (char *)user;
354
			iov[1].iov_len = groupcheck.userlen;
355
			iov[2].iov_base = (char *)group;
356
			iov[2].iov_len = groupcheck.grouplen;
357
			imsg_composev(&module->ibuf, IMSG_BSDAUTH_GROUPCHECK,
358
			    0, 0, -1, iov, 3);
359
			imsg_flush(&module->ibuf);
360
			if ((n = imsg_read(&module->ibuf)) == -1 || n == 0)
361
				fatal("imsg_read() failed in "
362
				    "module_bsdauth_userpass()");
363
			if ((n = imsg_get(&module->ibuf, &imsg)) <= 0)
364
				fatal("imsg_get() failed in "
365
				    "module_bsdauth_userpass()");
366
			if (imsg.hdr.type == IMSG_BSDAUTH_OK)
367
				goto group_ok;
368
		}
369
		goto auth_ng;
370
	}
371
group_ok:
372
	module_userpass_ok(module->base, q_id, "Authentication succeeded");
373
	imsg_free(&imsg);
374
	return;
375
auth_ng:
376
	module_userpass_fail(module->base, q_id, reason);
377
	imsg_free(&imsg);
378
	return;
379
}
380
381
static void
382
fatal(const char *msg)
383
{
384
	syslog(LOG_ERR, "%s: %m", msg);
385
	abort();
386
}