GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/authenticate.c Lines: 0 254 0.0 %
Date: 2017-11-07 Branches: 0 207 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: authenticate.c,v 1.26 2016/05/26 15:51:37 millert Exp $	*/
2
3
/*-
4
 * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. All advertising materials mentioning features or use of this software
15
 *    must display the following acknowledgement:
16
 *	This product includes software developed by Berkeley Software Design,
17
 *	Inc.
18
 * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
19
 *    or promote products derived from this software without specific prior
20
 *    written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 *	BSDI $From: authenticate.c,v 2.21 1999/09/08 22:33:26 prb Exp $
35
 */
36
37
#include <sys/stat.h>
38
39
#include <ctype.h>
40
#include <err.h>
41
#include <fcntl.h>
42
#include <limits.h>
43
#include <login_cap.h>
44
#include <paths.h>
45
#include <pwd.h>
46
#include <stdarg.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <syslog.h>
51
#include <unistd.h>
52
53
#include <bsd_auth.h>
54
55
static int _auth_checknologin(login_cap_t *, int);
56
57
char *
58
auth_mkvalue(char *value)
59
{
60
	char *big, *p;
61
62
	big = malloc(strlen(value) * 4 + 1);
63
	if (big == NULL)
64
		return (NULL);
65
	/*
66
	 * XXX - There should be a more standardized
67
	 * routine for doing this sort of thing.
68
	 */
69
	for (p = big; *value; ++value) {
70
		switch (*value) {
71
		case '\r':
72
			*p++ = '\\';
73
			*p++ = 'r';
74
			break;
75
		case '\n':
76
			*p++ = '\\';
77
			*p++ = 'n';
78
			break;
79
		case '\\':
80
			*p++ = '\\';
81
			*p++ = *value;
82
			break;
83
		case '\t':
84
		case ' ':
85
			if (p == big)
86
				*p++ = '\\';
87
			*p++ = *value;
88
			break;
89
		default:
90
			if (!isprint((unsigned char)*value)) {
91
				*p++ = '\\';
92
				*p++ = ((*value >> 6) & 0x3) + '0';
93
				*p++ = ((*value >> 3) & 0x7) + '0';
94
				*p++ = ((*value     ) & 0x7) + '0';
95
			} else
96
				*p++ = *value;
97
			break;
98
		}
99
	}
100
	*p = '\0';
101
	return (big);
102
}
103
DEF_WEAK(auth_mkvalue);
104
105
void
106
auth_checknologin(login_cap_t *lc)
107
{
108
	if (_auth_checknologin(lc, 1))
109
		exit(1);
110
}
111
DEF_WEAK(auth_checknologin);
112
113
static int
114
_auth_checknologin(login_cap_t *lc, int print)
115
{
116
	struct stat sb;
117
	char *nologin;
118
	int mustfree;
119
120
	if (login_getcapbool(lc, "ignorenologin", 0))
121
		return (0);
122
123
	/*
124
	 * If we fail to get the nologin file due to a database error,
125
	 * assume there should have been one...
126
	 */
127
	nologin = login_getcapstr(lc, "nologin", "", NULL);
128
	mustfree = nologin && *nologin != '\0';
129
	if (nologin == NULL)
130
		goto print_nologin;
131
132
	/* First try the nologin file specified in login.conf. */
133
	if (*nologin != '\0' && stat(nologin, &sb) == 0)
134
		goto print_nologin;
135
	if (mustfree) {
136
		free(nologin);
137
		mustfree = 0;
138
	}
139
140
	/* If that doesn't exist try _PATH_NOLOGIN. */
141
	if (stat(_PATH_NOLOGIN, &sb) == 0) {
142
		nologin = _PATH_NOLOGIN;
143
		goto print_nologin;
144
	}
145
146
	/* Couldn't stat any nologin files, must be OK to login. */
147
	return (0);
148
149
print_nologin:
150
	if (print) {
151
		if (!nologin || *nologin == '\0' || auth_cat(nologin) == 0) {
152
			puts("Logins are not allowed at this time.");
153
			fflush(stdout);
154
		}
155
	}
156
	if (mustfree)
157
		free(nologin);
158
	return (-1);
159
}
160
161
int
162
auth_cat(char *file)
163
{
164
	int fd, nchars;
165
	char tbuf[8192];
166
167
	if ((fd = open(file, O_RDONLY, 0)) < 0)
168
		return (0);
169
	while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
170
		(void)write(fileno(stdout), tbuf, nchars);
171
	(void)close(fd);
172
	return (1);
173
}
174
DEF_WEAK(auth_cat);
175
176
int
177
auth_approval(auth_session_t *as, login_cap_t *lc, char *name, char *type)
178
{
179
	int close_on_exit, close_lc_on_exit, len;
180
	struct passwd pwstore, *pwd;
181
	char *approve, *s, path[PATH_MAX], pwbuf[_PW_BUF_LEN];
182
183
	pwd = NULL;
184
	close_on_exit = as == NULL;
185
	close_lc_on_exit = lc == NULL;
186
187
	if (as != NULL && name == NULL)
188
		name = auth_getitem(as, AUTHV_NAME);
189
190
	if (as != NULL)
191
		pwd = auth_getpwd(as);
192
193
	if (pwd == NULL) {
194
		if (name != NULL) {
195
			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
196
		} else {
197
			getpwuid_r(getuid(), &pwstore, pwbuf, sizeof(pwbuf),
198
			    &pwd);
199
			if (pwd == NULL) {
200
				syslog(LOG_ERR, "no such user id %u", getuid());
201
				warnx("cannot approve who we don't recognize");
202
				return (0);
203
			}
204
			name = pwd->pw_name;
205
		}
206
	}
207
208
	if (name == NULL)
209
		name = pwd->pw_name;
210
211
	if (lc == NULL) {
212
		if (strlen(name) >= PATH_MAX) {
213
			syslog(LOG_ERR, "username to login %.*s...",
214
			    PATH_MAX, name);
215
			warnx("username too long");
216
			return (0);
217
		}
218
		if (pwd == NULL && (approve = strchr(name, '.')) != NULL) {
219
			strlcpy(path, name, sizeof path);
220
			path[approve-name] = '\0';
221
			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
222
		}
223
		lc = login_getclass(pwd ? pwd->pw_class : NULL);
224
		if (lc == NULL) {
225
			warnx("unable to classify user");
226
			return (0);
227
		}
228
	}
229
230
	if (!type)
231
		type = LOGIN_DEFSERVICE;
232
	else {
233
		if (strncmp(type, "approve-", 8) == 0)
234
			type += 8;
235
236
		len = snprintf(path, sizeof(path), "approve-%s", type);
237
		if (len < 0 || len >= sizeof(path)) {
238
			if (close_lc_on_exit)
239
				login_close(lc);
240
			syslog(LOG_ERR, "approval path too long %.*s...",
241
			    PATH_MAX, type);
242
			warnx("approval script path too long");
243
			return (0);
244
		}
245
	}
246
247
	if ((approve = login_getcapstr(lc, s = path, NULL, NULL)) == NULL)
248
		approve = login_getcapstr(lc, s = "approve", NULL, NULL);
249
250
	if (approve && approve[0] != '/') {
251
		if (close_lc_on_exit)
252
			login_close(lc);
253
		syslog(LOG_ERR, "Invalid %s script: %s", s, approve);
254
		warnx("invalid path to approval script");
255
		free(approve);
256
		return (0);
257
	}
258
259
	if (as == NULL && (as = auth_open()) == NULL) {
260
		if (close_lc_on_exit)
261
			login_close(lc);
262
		syslog(LOG_ERR, "%m");
263
		warn(NULL);
264
		free(approve);
265
		return (0);
266
	}
267
268
	auth_setstate(as, AUTH_OKAY);
269
	if (auth_setitem(as, AUTHV_NAME, name) < 0) {
270
		syslog(LOG_ERR, "%m");
271
		warn(NULL);
272
		goto out;
273
	}
274
	if (auth_check_expire(as) < 0)	/* is this account expired */
275
		goto out;
276
	if (_auth_checknologin(lc,
277
	    auth_getitem(as, AUTHV_INTERACTIVE) != NULL)) {
278
		auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
279
		goto out;
280
	}
281
	if (login_getcapbool(lc, "requirehome", 0) && pwd && pwd->pw_dir &&
282
	    pwd->pw_dir[0]) {
283
		struct stat sb;
284
285
		if (stat(pwd->pw_dir, &sb) < 0 || !S_ISDIR(sb.st_mode) ||
286
		    (pwd->pw_uid && sb.st_uid == pwd->pw_uid &&
287
		    (sb.st_mode & S_IXUSR) == 0)) {
288
			auth_setstate(as, (auth_getstate(as) & ~AUTH_ALLOW));
289
			goto out;
290
		}
291
	}
292
	if (approve)
293
		auth_call(as, approve, strrchr(approve, '/') + 1, name,
294
		    lc->lc_class, type, (char *)NULL);
295
296
out:
297
	free(approve);
298
	if (close_lc_on_exit)
299
		login_close(lc);
300
301
	if (close_on_exit)
302
		return (auth_close(as));
303
	return (auth_getstate(as) & AUTH_ALLOW);
304
}
305
DEF_WEAK(auth_approval);
306
307
auth_session_t *
308
auth_usercheck(char *name, char *style, char *type, char *password)
309
{
310
	char namebuf[LOGIN_NAME_MAX + 1 + NAME_MAX + 1];
311
	char pwbuf[_PW_BUF_LEN];
312
	auth_session_t *as;
313
	login_cap_t *lc;
314
	struct passwd pwstore, *pwd = NULL;
315
	char *slash;
316
317
	if (strlcpy(namebuf, name, sizeof(namebuf)) >= sizeof(namebuf))
318
		return (NULL);
319
	name = namebuf;
320
321
	/*
322
	 * Split up user:style names if we were not given a style
323
	 */
324
	if (style == NULL && (style = strchr(name, ':')) != NULL)
325
		*style++ = '\0';
326
327
	/*
328
	 * Cope with user/instance.  We are only using this to get
329
	 * the class so it is okay if we strip a /root instance
330
	 * The actual login script will pay attention to the instance.
331
	 */
332
	getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
333
	if (pwd == NULL) {
334
		if ((slash = strchr(name, '/')) != NULL) {
335
			*slash = '\0';
336
			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
337
			*slash = '/';
338
		}
339
	}
340
	if ((lc = login_getclass(pwd ? pwd->pw_class : NULL)) == NULL)
341
		return (NULL);
342
343
	if ((style = login_getstyle(lc, style, type)) == NULL) {
344
		login_close(lc);
345
		return (NULL);
346
	}
347
348
	if (password) {
349
		if ((as = auth_open()) == NULL) {
350
			login_close(lc);
351
			return (NULL);
352
		}
353
		auth_setitem(as, AUTHV_SERVICE, "response");
354
		auth_setdata(as, "", 1);
355
		auth_setdata(as, password, strlen(password) + 1);
356
		explicit_bzero(password, strlen(password));
357
	} else
358
		as = NULL;
359
	as = auth_verify(as, style, name, lc->lc_class, (char *)NULL);
360
	login_close(lc);
361
	return (as);
362
}
363
DEF_WEAK(auth_usercheck);
364
365
int
366
auth_userokay(char *name, char *style, char *type, char *password)
367
{
368
	auth_session_t *as;
369
370
	as = auth_usercheck(name, style, type, password);
371
372
	return (as != NULL ? auth_close(as) : 0);
373
}
374
DEF_WEAK(auth_userokay);
375
376
auth_session_t *
377
auth_userchallenge(char *name, char *style, char *type, char **challengep)
378
{
379
	char namebuf[LOGIN_NAME_MAX + 1 + NAME_MAX + 1];
380
	auth_session_t *as;
381
	login_cap_t *lc;
382
	struct passwd pwstore, *pwd = NULL;
383
	char *slash, pwbuf[_PW_BUF_LEN];
384
385
	if (strlen(name) >= sizeof(namebuf))
386
		return (NULL);
387
	strlcpy(namebuf, name, sizeof namebuf);
388
	name = namebuf;
389
390
	/*
391
	 * Split up user:style names if we were not given a style
392
	 */
393
	if (style == NULL && (style = strchr(name, ':')) != NULL)
394
		*style++ = '\0';
395
396
	/*
397
	 * Cope with user/instance.  We are only using this to get
398
	 * the class so it is okay if we strip a /root instance
399
	 * The actual login script will pay attention to the instance.
400
	 */
401
	getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
402
	if (pwd == NULL) {
403
		if ((slash = strchr(name, '/')) != NULL) {
404
			*slash = '\0';
405
			getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pwd);
406
			*slash = '/';
407
		}
408
	}
409
	if ((lc = login_getclass(pwd ? pwd->pw_class : NULL)) == NULL)
410
		return (NULL);
411
412
	if ((style = login_getstyle(lc, style, type)) == NULL ||
413
	    (as = auth_open()) == NULL) {
414
		login_close(lc);
415
		return (NULL);
416
	}
417
	if (auth_setitem(as, AUTHV_STYLE, style) < 0 ||
418
	    auth_setitem(as, AUTHV_NAME, name) < 0 ||
419
	    auth_setitem(as, AUTHV_CLASS, lc->lc_class) < 0) {
420
		auth_close(as);
421
		login_close(lc);
422
		return (NULL);
423
	}
424
	login_close(lc);
425
	*challengep = auth_challenge(as);
426
	return (as);
427
}
428
DEF_WEAK(auth_userchallenge);
429
430
int
431
auth_userresponse(auth_session_t *as, char *response, int more)
432
{
433
	char path[PATH_MAX];
434
	char *style, *name, *challenge, *class;
435
	int len;
436
437
	if (as == NULL)
438
		return (0);
439
440
	auth_setstate(as, 0);
441
442
	if ((style = auth_getitem(as, AUTHV_STYLE)) == NULL ||
443
	    (name = auth_getitem(as, AUTHV_NAME)) == NULL) {
444
		if (more == 0)
445
			return (auth_close(as));
446
		return(0);
447
	}
448
449
	len = snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
450
	if (len < 0 || len >= sizeof(path)) {
451
		if (more == 0)
452
			return (auth_close(as));
453
		return (0);
454
	}
455
456
	challenge = auth_getitem(as, AUTHV_CHALLENGE);
457
	class = auth_getitem(as, AUTHV_CLASS);
458
459
	if (challenge)
460
		auth_setdata(as, challenge, strlen(challenge) + 1);
461
	else
462
		auth_setdata(as, "", 1);
463
	if (response) {
464
		auth_setdata(as, response, strlen(response) + 1);
465
		explicit_bzero(response, strlen(response));
466
	} else
467
		auth_setdata(as, "", 1);
468
469
	auth_call(as, path, style, "-s", "response", name, class, (char *)NULL);
470
471
	/*
472
	 * If they authenticated then make sure they did not expire
473
	 */
474
	if (auth_getstate(as) & AUTH_ALLOW)
475
		auth_check_expire(as);
476
	if (more == 0)
477
		return (auth_close(as));
478
	return (auth_getstate(as) & AUTH_ALLOW);
479
}
480
DEF_WEAK(auth_userresponse);
481
482
/*
483
 * Authenticate name with the specified style.
484
 * If ``as'' is NULL a new session is formed with the default service.
485
 * Returns NULL only if ``as'' is NULL and we were unable to allocate
486
 * a new session.
487
 *
488
 * Use auth_close() or auth_getstate() to determine if the authentication
489
 * worked.
490
 */
491
auth_session_t *
492
auth_verify(auth_session_t *as, char *style, char *name, ...)
493
{
494
	va_list ap;
495
	char path[PATH_MAX];
496
497
	if ((name == NULL || style == NULL) && as == NULL)
498
		return (as);
499
500
	if (as == NULL && (as = auth_open()) == NULL)
501
		return (NULL);
502
	auth_setstate(as, 0);
503
504
	if (style != NULL && auth_setitem(as, AUTHV_STYLE, style) < 0)
505
		return (as);
506
507
	if (name != NULL && auth_setitem(as, AUTHV_NAME, name) < 0)
508
		return (as);
509
510
	style = auth_getitem(as, AUTHV_STYLE);
511
	name = auth_getitem(as, AUTHV_NAME);
512
513
	snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
514
	va_start(ap, name);
515
	auth_set_va_list(as, ap);
516
	auth_call(as, path, auth_getitem(as, AUTHV_STYLE), "-s",
517
	    auth_getitem(as, AUTHV_SERVICE), name, (char *)NULL);
518
	va_end(ap);
519
	return (as);
520
}
521
DEF_WEAK(auth_verify);