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
|
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <alloca.h>
#include "md5.h"
#include "pw_defs.h"
#include "utmp_defs.h"
#include "time_defs.h"
#define fdin 3
#define fdout 4
#define ZZ(A) if (A) byte_zero(A, str_len(A))
#define FL(X,Var) *p++ = X; p += fmt_ulong(p, Var); ++p
#define FN(L,Var) p += str_copy(p,L); p += fmt_ulong(p, Var); ++p
#define FS(L,Var) p += mycat(p,L,Var); ++p
static struct passwd *pw;
static char *stored, *encrypted;
static char up[513];
static int z(int n) {
byte_zero(up, sizeof(up));
ZZ(stored);
ZZ(encrypted);
if (n==0) return 0;
close(fdin);
close(fdout);
_exit(n);
}
static void check_pass(char *program, char *tty) {
char *password; /* user name is up */
int k=0, i=0, uplen;
close(0); close(1); close(2);
errno = 0;
uplen = SAFE_IO(read, fdin, up, sizeof(up));
if (errno) z(111);
if (uplen >= (int)sizeof(up)) z(1);
close(fdin);
if (uplen==0) z(2);
while (up[i++]) if (i >= uplen) z(2);
password = up + i;
if (i >= uplen) z(2);
while (up[i++]) if (i >= uplen) z(2);
pw = nv_getpwnam(up);
if (pw) {
struct spwd *spw;
if (i<uplen &&
!str_diff("-autologin", up+i)) { k=1; goto do_it; }
if (pw->pw_passwd[0]=='*' ||
pw->pw_passwd[0]=='!') goto do_it;
spw = nv_getspnam(up);
if (spw) stored = spw->sp_pwdp;
}
if (!stored || str_len(stored) < 12) k=0;
else {
encrypted = md5crypt(password, stored);
k = !str_diff(encrypted, stored); /* 1 good password */
}
do_it:
z(0); /* zero buffers */
if (pw) log_do(up, k, program, pw->pw_name, tty);
z(!k);
}
int main(int argc, char **argv) {
int i, n = NGROUPS_MAX;
struct group *ttygr=0;
gid_t groups[NGROUPS_MAX+1];
char *p, *tty, lastlog[96];
(void)argc;
tty = ttyname(0);
if (tty==0) tty="";
if (tty && !str_diffn(tty, "/dev/", 5)) p = tty + 5;
else p = "UNKNOWN";
check_pass(strip_slash(argv[0]), p);
utmp_do(pw->pw_name, p, getppid());
lastlog_do(lastlog, pw->pw_uid, p);
get_tz(0,-1);
if (nv_getgrouplist(pw->pw_name, pw->pw_gid, groups, &n) ||
n > NGROUPS_MAX) z(5);
ttygr = nv_getgrnam("tty");
z(0);
for (p=up,i=0; i<n; i++) {
FL('g', groups[i]);
if (p-up > 440) z(1);
}
if (p-up +
str_len(pw->pw_dir) +
str_len(pw->pw_name) +
str_len(pw->pw_shell) +
str_len(tty) +
str_len(lastlog) > 400) z(1);
FL('t', ttygr ? ttygr->gr_gid : (gid_t)pw->pw_gid);
FN("UID=", pw->pw_uid);
FN("GID=", pw->pw_gid);
FS("USER=", pw->pw_name);
FS("HOME=", pw->pw_dir);
FS("SHELL=", pw->pw_shell);
FS("TTY=", tty);
p += str_copy(p, lastlog);
n = (p-up)+5;
if (n != SAFE_IO(write, fdout, up, n)) z(1);
close(fdout);
z(0);
return 0;
}
|