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