aboutsummaryrefslogtreecommitdiff
path: root/riemann.fmi.uni-sofia.bg/programs/nlogin-0.3-pre/nlogin-auth.c
blob: e275531858cbc867d29a58007ffb183868706953 (plain)
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;
}