summaryrefslogtreecommitdiff
path: root/checkpassword.c
blob: edb7ce07799d9e5850513a7dbbe408032b0c3222 (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
#define _XOPEN_SOURCE
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <shadow.h>
#include <stdio.h>
#include <alloca.h>
#ifdef __dietlibc__
#include <write12.h>
#else
extern inline void __write2(const char* message) {
  write(2,message,strlen(message));
}
#endif

extern char** environ;

unsigned int fmt_ulong(char *dest,unsigned long i) {
  register unsigned long len,tmp,len2;
  /* first count the number of bytes needed */
  for (len=1, tmp=i; tmp>9; ++len) tmp/=10;
  if (dest)
    for (tmp=i, dest+=len, len2=len+1; --len2; tmp/=10)
      *--dest = (tmp%10)+'0';
  return len;
}

int main(int argc,char* argv[]) {
  char buf[513];
  char* last;
  int len;
  char *login,*passwd,*ptr;
  struct passwd *pw;
  struct spwd *spw;

  if (!argv[1]) return 2;
  for (len=0; len<512; ) {
    int tmp;
    tmp=read(3,buf+len,512-len);
    if (tmp==-1) return 111;
    if (tmp==0) break;
    len+=tmp;
  }
  close(3);
  buf[len]=0; last=buf+len;
  login=buf;
  if ((pw=getpwnam(login))) {
    passwd=pw->pw_passwd;
    if ((spw=getspnam(login)))
      passwd=spw->sp_pwdp;
    ptr=login+strlen(login)+1;
    if (!*passwd || !strcmp(crypt(ptr,passwd),passwd)) {
      char **env,**ep;
      char buf[100];
      for (len=0; environ[len]; ++len) ;
      env=alloca((len+4)*sizeof(char*));
      ep=env;
      for (len=0; environ[len]; ++len) {
	if (!strncmp(environ[len],"USER=",5)) continue;
	if (!strncmp(environ[len],"HOME=",5)) continue;
	if (!strncmp(environ[len],"SHELL=",6)) continue;
	if (!strncmp(environ[len],"UID=",4)) continue;
	*ep=environ[len]; ++ep;
      }
      *ep=alloca(strlen(pw->pw_shell)+7); strcat(strcpy(*ep,"SHELL="),pw->pw_shell); ++ep;
      *ep=alloca(strlen(login)+6); strcat(strcpy(*ep,"USER="),login); ++ep;
      *ep=alloca(strlen(pw->pw_dir)+7); strcat(strcpy(*ep,"HOME="),pw->pw_dir); ++ep;
      strcpy(buf,"UID=");
      buf[4+fmt_ulong(buf+4,pw->pw_uid)]=0;
      *ep=buf; ++ep;
      *ep=0;

      ptr+=strlen(ptr)+1;	/* skip password */

      if (initgroups(pw->pw_name,pw->pw_gid)==-1) return 1;
/*      if (setgroups(1,&pw->pw_gid)==-1) return 1; */
      if (setgid(pw->pw_gid)==-1) return 1;
      if (ptr) {
	ptr+=strlen(ptr)+1;		/* skip timestamp */
	if (ptr>=last) ptr=0;
      }
      if (!ptr || strcmp(ptr,"nosetuid")) if (setuid(pw->pw_uid)==-1) return -1;
      if (chdir(pw->pw_dir)==-1) return 111;
      execve(argv[1],argv+1,env);
      return 111;
    }
  }
  if (isatty(0) && isatty(1)) {
    __write2("checkpassword: wrong password.\n");
    sleep(5);
  }
  return 1;
}