1 /*
2  * Simple demonstration application that supports one-time passwords
3  *
4  * Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/>
5  */
6 
7 #define _XOPEN_SOURCE     /* to get crypt() from <unistd.h> */
8 
9 #define SHADOW_PW         /* define if the shadow password system is used */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <pwd.h>
15 #include <time.h>
16 #include <sys/time.h>
17 #include <unistd.h>
18 #include <termios.h>
19 #include <assert.h>
20 #include <termios.h>
21 #include <errno.h>
22 #ifdef SHADOW_PW
23 #include <shadow.h>
24 #endif
25 #include "otpw.h"
26 
main(int argc,char ** argv)27 int main(int argc, char **argv)
28 {
29   char username[81] = "", password[81];
30   struct termios term, term_old;
31   int stdin_is_tty = 0, use_otpw, result;
32   struct otpw_pwdbuf *user;
33   struct challenge ch;
34   int i, debug = 0;
35 #ifdef SHADOW_PW
36   struct spwd* spwd;
37 #endif
38 
39   for (i = 1; i < argc; i++) {
40     if (argv[i][0] == '-')
41       switch (argv[i][1]) {
42       case 'd':
43 	debug = 1;
44 	break;
45       default:
46 	fprintf(stderr, "usage: %s [-d] [username][/]\n", argv[0]);
47 	exit(1);
48       }
49     else {
50       /* get user name from command line */
51       strncpy(username, argv[i], sizeof(username));
52       username[sizeof(username) - 1] = 0;
53     }
54   }
55 
56   if (!*username) {
57     printf("Append a slash (/) to your user name to activate OTPW.\n\n");
58     /* ask for the user name */
59     printf("login: ");
60     fgets(username, sizeof(username), stdin);
61     /* remove '\n' */
62     username[strlen(username) - 1] = 0;
63   }
64 
65   /* check if one-time password mode was requested by appending slash */
66   use_otpw = username[strlen(username) - 1] == '/';
67   /* if yes, remove slash from entered username */
68   if (use_otpw)
69     username[strlen(username) - 1] = 0;
70 
71   /* read the user database entry */
72   otpw_getpwnam(username, &user);
73 
74   /* in one-time password mode, set lock and output challenge string */
75   if (use_otpw) {
76     ch.challenge[0] = 0;
77     if (user) otpw_prepare(&ch, &user->pwd, debug ? OTPW_DEBUG : 0);
78     if (!ch.challenge[0]) {
79       printf("Sorry, one-time password entry not possible at the moment.\n");
80       exit(1);
81     }
82     /* ask for the password */
83     printf("Password %s: ", ch.challenge);
84   } else
85     printf("Password: ");
86 
87   /* disable echo if stdin is a terminal */
88   if (tcgetattr(fileno(stdin), &term)) {
89     if (errno != ENOTTY) {
90       perror("tcgetattr");
91       if (use_otpw) otpw_verify(&ch, password);
92       exit(2);
93     }
94   } else {
95     stdin_is_tty = 1;
96     term_old = term;
97     term.c_lflag &= ~(ECHO | ECHOE | ECHOK);
98     term.c_lflag |= ECHONL;
99     if (tcsetattr(fileno(stdin), TCSAFLUSH, &term)) {
100       perror("tcsetattr");
101       return 1;
102     }
103   }
104   /* read the password */
105   fgets(password, sizeof(password), stdin);
106   /* remove '\n' */
107   password[strlen(password) - 1] = 0;
108   /* reenable echo */
109   if (stdin_is_tty)
110     tcsetattr(fileno(stdin), TCSANOW, &term_old);
111 
112   /* check password */
113   if (use_otpw) {
114     /* one-time password check */
115     result = otpw_verify(&ch, password);
116     if (result == OTPW_OK) {
117       printf("Login correct\n");
118       if (ch.entries > 2 * ch.remaining)
119 	printf("Only %d one-time passwords left (%d%%), please generate "
120 	       "new list.\n", ch.remaining, ch.remaining * 100 / ch.entries);
121     }
122     else
123       printf("Login incorrect\n");
124   } else {
125     /* old-style many-time password check */
126 #ifdef SHADOW_PW
127     spwd = getspnam(username);
128     if (user && spwd) user->pwd.pw_passwd = spwd->sp_pwdp;
129     if (geteuid() != 0)
130       fprintf(stderr, "Shadow password access requires root priviliges.\n");
131 #endif
132     if (!user || strcmp(crypt(password, user->pwd.pw_passwd),
133 			user->pwd.pw_passwd))
134       printf("Login incorrect\n");
135     else
136       printf("Login correct\n");
137   }
138 
139   return 0;
140 }
141