1 // PAM module for two-factor authentication.
2 //
3 // Copyright 2010 Google Inc.
4 // Author: Markus Gutschke
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 // http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 #include "config.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <pwd.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <syslog.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #ifdef HAVE_SYS_FSUID_H
34 // We much rather prefer to use setfsuid(), but this function is unfortunately
35 // not available on all systems.
36 #include <sys/fsuid.h>
37 #endif
38
39 #ifndef PAM_EXTERN
40 #define PAM_EXTERN
41 #endif
42
43 #if !defined(LOG_AUTHPRIV) && defined(LOG_AUTH)
44 #define LOG_AUTHPRIV LOG_AUTH
45 #endif
46
47 #define PAM_SM_AUTH
48 #include <security/pam_appl.h>
49 #include <security/pam_modules.h>
50
51 #include "base32.h"
52 #include "hmac.h"
53 #include "sha1.h"
54 #include "util.h"
55
56 #define MODULE_NAME "pam_google_authenticator"
57 #define SECRET "~/.google_authenticator"
58 #define CODE_PROMPT "Verification code: "
59 #define PWCODE_PROMPT "Password & verification code: "
60
61 typedef struct Params {
62 const char *secret_filename_spec;
63 const char *authtok_prompt;
64 enum { NULLERR=0, NULLOK, SECRETNOTFOUND } nullok;
65 int noskewadj;
66 int echocode;
67 int fixed_uid;
68 int no_increment_hotp;
69 uid_t uid;
70 enum { PROMPT = 0, TRY_FIRST_PASS, USE_FIRST_PASS } pass_mode;
71 int forward_pass;
72 int debug;
73 int no_strict_owner;
74 int allowed_perm;
75 time_t grace_period;
76 int allow_readonly;
77 } Params;
78
79 static char oom;
80
81 static const char* nobody = "nobody";
82
83 #if defined(DEMO) || defined(TESTING)
84 static char* error_msg = NULL;
85
86 const char *get_error_msg(void) __attribute__((visibility("default")));
get_error_msg(void)87 const char *get_error_msg(void) {
88 if (!error_msg) {
89 return "";
90 }
91 return error_msg;
92 }
93 #endif
94
log_message(int priority,pam_handle_t * pamh,const char * format,...)95 static void log_message(int priority, pam_handle_t *pamh,
96 const char *format, ...) {
97 char *service = NULL;
98 if (pamh)
99 pam_get_item(pamh, PAM_SERVICE, (void *)&service);
100 if (!service)
101 service = "";
102
103 char logname[80];
104 snprintf(logname, sizeof(logname), "%s(" MODULE_NAME ")", service);
105
106 va_list args;
107 va_start(args, format);
108 #if !defined(DEMO) && !defined(TESTING)
109 openlog(logname, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
110 vsyslog(priority, format, args);
111 closelog();
112 #else
113 if (!error_msg) {
114 error_msg = strdup("");
115 }
116 {
117 char buf[1000];
118 vsnprintf(buf, sizeof buf, format, args);
119 const int newlen = strlen(error_msg) + 1 + strlen(buf) + 1;
120 char* n = malloc(newlen);
121 if (n) {
122 snprintf(n, newlen, "%s%s%s", error_msg, strlen(error_msg)?"\n":"",buf);
123 free(error_msg);
124 error_msg = n;
125 } else {
126 fprintf(stderr, "Failed to malloc %d bytes for log data.\n", newlen);
127 }
128 }
129 #endif
130
131 va_end(args);
132
133 if (priority == LOG_EMERG) {
134 // Something really bad happened. There is no way we can proceed safely.
135 _exit(1);
136 }
137 }
138
converse(pam_handle_t * pamh,int nargs,PAM_CONST struct pam_message ** message,struct pam_response ** response)139 static int converse(pam_handle_t *pamh, int nargs,
140 PAM_CONST struct pam_message **message,
141 struct pam_response **response) {
142 struct pam_conv *conv;
143 int retval = pam_get_item(pamh, PAM_CONV, (void *)&conv);
144 if (retval != PAM_SUCCESS) {
145 return retval;
146 }
147 return conv->conv(nargs, message, response, conv->appdata_ptr);
148 }
149
get_user_name(pam_handle_t * pamh,const Params * params)150 static const char *get_user_name(pam_handle_t *pamh, const Params *params) {
151 // Obtain the user's name
152 const char *username;
153 if (pam_get_user(pamh, &username, NULL) != PAM_SUCCESS ||
154 !username || !*username) {
155 log_message(LOG_ERR, pamh,
156 "pam_get_user() failed to get a user name"
157 " when checking verification code");
158 return NULL;
159 }
160 if (params->debug) {
161 log_message(LOG_INFO, pamh, "debug: start of google_authenticator for \"%s\"", username);
162 }
163 return username;
164 }
165
166 /*
167 * Return rhost as a string. Return value must not be free()ed.
168 * Returns NULL if PAM_RHOST is not known.
169 */
170 static const char *
get_rhost(pam_handle_t * pamh,const Params * params)171 get_rhost(pam_handle_t *pamh, const Params *params) {
172 // Get the remote host
173 PAM_CONST void *rhost;
174 if (pam_get_item(pamh, PAM_RHOST, &rhost) != PAM_SUCCESS) {
175 log_message(LOG_ERR, pamh, "pam_get_rhost() failed to get the remote host");
176 return NULL;
177 }
178 if (params->debug) {
179 log_message(LOG_INFO, pamh, "debug: google_authenticator for host \"%s\"",
180 rhost);
181 }
182 return (const char *)rhost;
183 }
184
185 static size_t
getpwnam_buf_max_size()186 getpwnam_buf_max_size()
187 {
188 #ifdef _SC_GETPW_R_SIZE_MAX
189 const ssize_t len = sysconf(_SC_GETPW_R_SIZE_MAX);
190 if (len <= 0) {
191 return 4096;
192 }
193 return len;
194 #else
195 return 4096;
196 #endif
197 }
198
get_secret_filename(pam_handle_t * pamh,const Params * params,const char * username,uid_t * uid)199 static char *get_secret_filename(pam_handle_t *pamh, const Params *params,
200 const char *username, uid_t *uid) {
201 if (!username) {
202 return NULL;
203 }
204
205 // Check whether the administrator decided to override the default location
206 // for the secret file.
207 const char *spec = params->secret_filename_spec
208 ? params->secret_filename_spec : SECRET;
209
210 // Obtain the user's id and home directory
211 // NOTE: These variables need to be here because of their lifetimes.
212 struct passwd *pw = NULL; // Used
213 struct passwd pwbuf; // Here because `pw` points into it.
214 char *buf = NULL; // Here because `pw` members use it.
215 char *secret_filename = NULL; // Here because goto jumps.
216
217 if (!params->fixed_uid) {
218 const int len = getpwnam_buf_max_size();
219 buf = malloc(len);
220 *uid = -1;
221 if (buf == NULL) {
222 log_message(LOG_ERR, pamh, "Short (%d) mem allocation failed", len);
223 goto errout;
224 }
225
226 const int rc = getpwnam_r(username, &pwbuf, buf, len, &pw);
227 if (rc) {
228 log_message(LOG_ERR, pamh, "getpwnam_r(\"%s\")!=0: %d", username, rc);
229 goto errout;
230 }
231
232 if (!pw) {
233 log_message(LOG_ERR, pamh, "user(\"%s\") not found", username);
234 goto errout;
235 }
236
237 if (!pw->pw_dir) {
238 log_message(LOG_ERR, pamh, "user(\"%s\") has no home dir", username);
239 goto errout;
240 }
241
242 if (*pw->pw_dir != '/') {
243 log_message(LOG_ERR, pamh, "User \"%s\" home dir not absolute", username);
244 goto errout;
245 }
246 }
247
248 // Expand filename specification to an actual filename.
249 if ((secret_filename = strdup(spec)) == NULL) {
250 log_message(LOG_ERR, pamh, "Short (%d) mem allocation failed", strlen(spec));
251 goto errout;
252 }
253 int allow_tilde = 1;
254 for (int offset = 0; secret_filename[offset];) {
255 char *cur = secret_filename + offset;
256 char *var = NULL;
257 size_t var_len = 0;
258 const char *subst = NULL;
259 if (allow_tilde && *cur == '~') {
260 var_len = 1;
261 if (!pw) {
262 log_message(LOG_ERR, pamh,
263 "Home dir in 'secret' not implemented when 'user' set");
264 goto errout;
265 }
266 subst = pw->pw_dir;
267 var = cur;
268 } else if (secret_filename[offset] == '$') {
269 if (!memcmp(cur, "${HOME}", 7)) {
270 var_len = 7;
271 if (!pw) {
272 log_message(LOG_ERR, pamh,
273 "Home dir in 'secret' not implemented when 'user' set");
274 goto errout;
275 }
276 subst = pw->pw_dir;
277 var = cur;
278 } else if (!memcmp(cur, "${USER}", 7)) {
279 var_len = 7;
280 subst = username;
281 var = cur;
282 }
283 }
284 if (var) {
285 const size_t subst_len = strlen(subst);
286 if (subst_len > 1000000) {
287 log_message(LOG_ERR, pamh, "Unexpectedly large path name: %d", subst_len);
288 goto errout;
289 }
290 const int varidx = var - secret_filename;
291 char *resized = realloc(secret_filename,
292 strlen(secret_filename) + subst_len + 1);
293 if (!resized) {
294 log_message(LOG_ERR, pamh, "Short mem allocation failed");
295 goto errout;
296 }
297 var = resized + varidx;
298 secret_filename = resized;
299 memmove(var + subst_len, var + var_len, strlen(var + var_len) + 1);
300 memmove(var, subst, subst_len);
301 offset = var + subst_len - resized;
302 allow_tilde = 0;
303 } else {
304 allow_tilde = *cur == '/';
305 ++offset;
306 }
307 }
308
309 *uid = params->fixed_uid ? params->uid : pw->pw_uid;
310 free(buf);
311 return secret_filename;
312
313 errout:
314 free(secret_filename);
315 free(buf);
316 return NULL;
317 }
318
setuser(int uid)319 static int setuser(int uid) {
320 #ifdef HAVE_SETFSUID
321 // The semantics for setfsuid() are a little unusual. On success, the
322 // previous user id is returned. On failure, the current user id is returned.
323 int old_uid = setfsuid(uid);
324 if (uid != setfsuid(uid)) {
325 setfsuid(old_uid);
326 return -1;
327 }
328 #else
329 #ifdef linux
330 #error "Linux should have setfsuid(). Refusing to build."
331 #endif
332 int old_uid = geteuid();
333 if (old_uid != uid && seteuid(uid)) {
334 return -1;
335 }
336 #endif
337 return old_uid;
338 }
339
setgroup(int gid)340 static int setgroup(int gid) {
341 #ifdef HAVE_SETFSGID
342 // The semantics of setfsgid() are a little unusual. On success, the
343 // previous group id is returned. On failure, the current groupd id is
344 // returned.
345 int old_gid = setfsgid(gid);
346 if (gid != setfsgid(gid)) {
347 setfsgid(old_gid);
348 return -1;
349 }
350 #else
351 int old_gid = getegid();
352 if (old_gid != gid && setegid(gid)) {
353 return -1;
354 }
355 #endif
356 return old_gid;
357 }
358
359 // Drop privileges and return 0 on success.
drop_privileges(pam_handle_t * pamh,const char * username,int uid,int * old_uid,int * old_gid)360 static int drop_privileges(pam_handle_t *pamh, const char *username, int uid,
361 int *old_uid, int *old_gid) {
362 // Try to become the new user. This might be necessary for NFS mounted home
363 // directories.
364
365 // First, look up the user's default group
366 #ifdef _SC_GETPW_R_SIZE_MAX
367 int len = sysconf(_SC_GETPW_R_SIZE_MAX);
368 if (len <= 0) {
369 len = 4096;
370 }
371 #else
372 int len = 4096;
373 #endif
374 char *buf = malloc(len);
375 if (!buf) {
376 log_message(LOG_ERR, pamh, "Out of memory");
377 return -1;
378 }
379 struct passwd pwbuf, *pw;
380 if (getpwuid_r(uid, &pwbuf, buf, len, &pw) || !pw) {
381 log_message(LOG_ERR, pamh, "Cannot look up user id %d", uid);
382 free(buf);
383 return -1;
384 }
385 gid_t gid = pw->pw_gid;
386 free(buf);
387
388 int gid_o = setgroup(gid);
389 int uid_o = setuser(uid);
390 if (uid_o < 0) {
391 if (gid_o >= 0) {
392 if (setgroup(gid_o) < 0 || setgroup(gid_o) != gid_o) {
393 // Inform the caller that we were unsuccessful in resetting the group.
394 *old_gid = gid_o;
395 }
396 }
397 log_message(LOG_ERR, pamh, "Failed to change user id to \"%s\"",
398 username);
399 return -1;
400 }
401 if (gid_o < 0 && (gid_o = setgroup(gid)) < 0) {
402 // In most typical use cases, the PAM module will end up being called
403 // while uid=0. This allows the module to change to an arbitrary group
404 // prior to changing the uid. But there are many ways that PAM modules
405 // can be invoked and in some scenarios this might not work. So, we also
406 // try changing the group _after_ changing the uid. It might just work.
407 if (setuser(uid_o) < 0 || setuser(uid_o) != uid_o) {
408 // Inform the caller that we were unsuccessful in resetting the uid.
409 *old_uid = uid_o;
410 }
411 log_message(LOG_ERR, pamh,
412 "Failed to change group id for user \"%s\" to %d", username,
413 (int)gid);
414 return -1;
415 }
416
417 *old_uid = uid_o;
418 *old_gid = gid_o;
419 return 0;
420 }
421
422 // open secret file, return 0 on success.
open_secret_file(pam_handle_t * pamh,const char * secret_filename,struct Params * params,const char * username,int uid,struct stat * orig_stat)423 static int open_secret_file(pam_handle_t *pamh, const char *secret_filename,
424 struct Params *params, const char *username,
425 int uid, struct stat *orig_stat) {
426 // Try to open "~/.google_authenticator"
427 const int fd = open(secret_filename, O_RDONLY);
428 if (fd < 0 ||
429 fstat(fd, orig_stat) < 0) {
430 if (params->nullok != NULLERR && errno == ENOENT) {
431 // The user doesn't have a state file, but the administrator said
432 // that this is OK. We still return an error from open_secret_file(),
433 // but we remember that this was the result of a missing state file.
434 params->nullok = SECRETNOTFOUND;
435 } else {
436 log_message(LOG_ERR, pamh, "Failed to read \"%s\" for \"%s\": %s",
437 secret_filename, username, strerror(errno));
438 }
439 error:
440 if (fd >= 0) {
441 close(fd);
442 }
443 return -1;
444 }
445
446 if (params->debug) {
447 log_message(LOG_INFO, pamh,
448 "debug: Secret file permissions are %04o."
449 " Allowed permissions are %04o",
450 orig_stat->st_mode & 03777, params->allowed_perm);
451 }
452
453 // Check permissions on "~/.google_authenticator".
454 if (!S_ISREG(orig_stat->st_mode)) {
455 log_message(LOG_ERR, pamh, "Secret file \"%s\" is not a regular file",
456 secret_filename);
457 goto error;
458 }
459 if (orig_stat->st_mode & 03777 & ~params->allowed_perm) {
460 log_message(LOG_ERR, pamh,
461 "Secret file \"%s\" permissions (%04o)"
462 " are more permissive than %04o", secret_filename,
463 orig_stat->st_mode & 03777, params->allowed_perm);
464 goto error;
465 }
466
467 if (!params->no_strict_owner && (orig_stat->st_uid != (uid_t)uid)) {
468 char buf[80];
469 if (params->fixed_uid) {
470 snprintf(buf, sizeof buf, "user id %d", params->uid);
471 username = buf;
472 }
473 log_message(LOG_ERR, pamh,
474 "Secret file \"%s\" must be owned by \"%s\"",
475 secret_filename, username);
476 goto error;
477 }
478
479 // Sanity check for file length
480 if (orig_stat->st_size < 1 || orig_stat->st_size > 64*1024) {
481 log_message(LOG_ERR, pamh,
482 "Invalid file size for \"%s\"", secret_filename);
483 goto error;
484 }
485
486 return fd;
487 }
488
489 // Read secret file contents.
490 // If there's an error the file is closed, NULL is returned, and errno set.
read_file_contents(pam_handle_t * pamh,const Params * params,const char * secret_filename,int * fd,off_t filesize)491 static char *read_file_contents(pam_handle_t *pamh,
492 const Params *params,
493 const char *secret_filename, int *fd,
494 off_t filesize) {
495 // Arbitrary limit to prevent integer overflow.
496 if (filesize > 1000000) {
497 close(*fd);
498 errno = E2BIG;
499 return NULL;
500 }
501
502 // Read file contents
503 char *buf = malloc(filesize + 1);
504 if (!buf) {
505 log_message(LOG_ERR, pamh, "Failed to malloc %d+1", filesize);
506 goto out;
507 }
508
509 if (filesize != read(*fd, buf, filesize)) {
510 log_message(LOG_ERR, pamh, "Could not read \"%s\"", secret_filename);
511 goto out;
512 }
513 close(*fd);
514 *fd = -1;
515
516 // The rest of the code assumes that there are no NUL bytes in the file.
517 if (memchr(buf, 0, filesize)) {
518 log_message(LOG_ERR, pamh, "Invalid file contents in \"%s\"",
519 secret_filename);
520 goto out;
521 }
522
523 // Terminate the buffer with a NUL byte.
524 buf[filesize] = '\000';
525
526 if(params->debug) {
527 log_message(LOG_INFO, pamh, "debug: \"%s\" read", secret_filename);
528 }
529 return buf;
530
531 out:
532 // If we have any data, erase it.
533 if (buf) {
534 explicit_bzero(buf, filesize);
535 }
536 free(buf);
537 if (*fd >= 0) {
538 close(*fd);
539 *fd = -1;
540 }
541 return NULL;
542 }
543
is_totp(const char * buf)544 static int is_totp(const char *buf) {
545 return !!strstr(buf, "\" TOTP_AUTH");
546 }
547
548 // Wrap write() making sure that partial writes don't break everything.
549 // Return 0 on success, errno otherwise.
550 static int
full_write(int fd,const char * buf,size_t len)551 full_write(int fd, const char* buf, size_t len) {
552 const char* p = buf;
553 int errors = 0;
554 for (;;) {
555 const ssize_t left = len - (p - buf);
556 const ssize_t rc = write(fd, p, left);
557 if (rc == left) {
558 return 0;
559 }
560 if (rc < 0) {
561 switch (errno) {
562 case EAGAIN:
563 case EINTR:
564 if (errors++ < 3) {
565 continue;
566 }
567 }
568 return errno;
569 }
570 p += rc;
571 }
572 }
573
574 // Safely overwrite the old secret file.
575 // Return 0 on success, errno otherwise.
write_file_contents(pam_handle_t * pamh,const Params * params,const char * secret_filename,struct stat * orig_stat,const char * buf)576 static int write_file_contents(pam_handle_t *pamh,
577 const Params *params,
578 const char *secret_filename,
579 struct stat *orig_stat,
580 const char *buf) {
581 int err = 0;
582 int fd = -1;
583 const size_t fnlength = strlen(secret_filename) + 1 + 6 + 1;
584
585 char *tmp_filename = malloc(fnlength);
586 if (tmp_filename == NULL) {
587 err = errno;
588 goto cleanup;
589 }
590
591 if (fnlength - 1 != snprintf(tmp_filename, fnlength,
592 "%s~XXXXXX", secret_filename)) {
593 err = ERANGE;
594 goto cleanup;
595 }
596 const mode_t old_mask = umask(077);
597 fd = mkstemp(tmp_filename);
598 umask(old_mask);
599 if (fd < 0) {
600 err = errno;
601 log_message(LOG_ERR, pamh, "Failed to create tempfile \"%s\": %s",
602 tmp_filename, strerror(err));
603
604 // Couldn't open file; don't try to delete it later.
605 free(tmp_filename);
606 tmp_filename = NULL;
607 goto cleanup;
608 }
609 if (fchmod(fd, 0400)) {
610 err = errno;
611 goto cleanup;
612 }
613
614 // Make sure the secret file is still the same. This prevents attackers
615 // from opening a lot of pending sessions and then reusing the same
616 // scratch code multiple times.
617 //
618 // (except for the brief race condition between this stat and the
619 // `rename` below)
620 {
621 struct stat sb;
622 if (stat(secret_filename, &sb) != 0) {
623 err = errno;
624 goto cleanup;
625 }
626
627 if (sb.st_ino != orig_stat->st_ino ||
628 sb.st_size != orig_stat->st_size ||
629 sb.st_mtime != orig_stat->st_mtime) {
630 err = EAGAIN;
631 log_message(LOG_ERR, pamh,
632 "Secret file \"%s\" changed while trying to use "
633 "scratch code\n", secret_filename);
634 goto cleanup;
635 }
636 }
637
638 // Write the new file contents.
639 if ((err = full_write(fd, buf, strlen(buf)))) {
640 goto cleanup;
641 }
642 if (fsync(fd)) {
643 err = errno;
644 goto cleanup;
645 }
646 if (close(fd)) {
647 err = errno;
648 goto cleanup;
649 }
650 fd = -1; // Prevent double-close.
651 if (rename(tmp_filename, secret_filename) != 0) {
652 err = errno;
653 goto cleanup;
654 }
655 free(tmp_filename);
656 tmp_filename = NULL; // Prevent unlink & double-free.
657
658 if (params->debug) {
659 log_message(LOG_INFO, pamh, "debug: \"%s\" written", secret_filename);
660 }
661
662 cleanup:
663 if (fd >= 0) {
664 close(fd);
665 }
666 if (tmp_filename) {
667 if (unlink(tmp_filename)) {
668 log_message(LOG_ERR, pamh, "Failed to delete tempfile \"%s\": %s",
669 tmp_filename, strerror(errno));
670 }
671 }
672 free(tmp_filename);
673
674 if (err) {
675 log_message(LOG_ERR, pamh, "Failed to update secret file \"%s\": %s",
676 secret_filename, strerror(err));
677 return err;
678 }
679 return 0;
680 }
681
682 // given secret file content (buf), extract the secret and base32 decode it.
683 //
684 // Return pointer to `malloc()`'d secret on success (caller frees),
685 // NULL on error. Length of secret stored in *secretLen.
get_shared_secret(pam_handle_t * pamh,const Params * params,const char * secret_filename,const char * buf,int * secretLen)686 static uint8_t *get_shared_secret(pam_handle_t *pamh,
687 const Params *params,
688 const char *secret_filename,
689 const char *buf, int *secretLen) {
690 if (!buf) {
691 return NULL;
692 }
693 // Decode secret key
694 const int base32Len = strcspn(buf, "\n");
695
696 // Arbitrary limit to prevent integer overflow.
697 if (base32Len > 100000) {
698 return NULL;
699 }
700
701 *secretLen = (base32Len*5 + 7)/8;
702 uint8_t *secret = malloc(base32Len + 1);
703 if (secret == NULL) {
704 *secretLen = 0;
705 return NULL;
706 }
707 memcpy(secret, buf, base32Len);
708 secret[base32Len] = '\000';
709 if ((*secretLen = base32_decode(secret, secret, base32Len)) < 1) {
710 log_message(LOG_ERR, pamh,
711 "Could not find a valid BASE32 encoded secret in \"%s\"",
712 secret_filename);
713 explicit_bzero(secret, base32Len);
714 free(secret);
715 return NULL;
716 }
717 memset(secret + *secretLen, 0, base32Len + 1 - *secretLen);
718
719 if(params->debug) {
720 log_message(LOG_INFO, pamh, "debug: shared secret in \"%s\" processed", secret_filename);
721 }
722 return secret;
723 }
724
725 #ifdef TESTING
726 static time_t current_time;
727 void set_time(time_t t) __attribute__((visibility("default")));
set_time(time_t t)728 void set_time(time_t t) {
729 current_time = t;
730 }
731
get_time(void)732 static time_t get_time(void) {
733 return current_time;
734 }
735 #else
get_time(void)736 static time_t get_time(void) {
737 return time(NULL);
738 }
739 #endif
740
comparator(const void * a,const void * b)741 static int comparator(const void *a, const void *b) {
742 return *(unsigned int *)a - *(unsigned int *)b;
743 }
744
get_cfg_value(pam_handle_t * pamh,const char * key,const char * buf)745 static char *get_cfg_value(pam_handle_t *pamh, const char *key,
746 const char *buf) {
747 const size_t key_len = strlen(key);
748 for (const char *line = buf; *line; ) {
749 const char *ptr;
750 if (line[0] == '"' && line[1] == ' ' && !strncmp(line+2, key, key_len) &&
751 (!*(ptr = line+2+key_len) || *ptr == ' ' || *ptr == '\t' ||
752 *ptr == '\r' || *ptr == '\n')) {
753 ptr += strspn(ptr, " \t");
754 size_t val_len = strcspn(ptr, "\r\n");
755 char *val = malloc(val_len + 1);
756 if (!val) {
757 log_message(LOG_ERR, pamh, "Out of memory");
758 return &oom;
759 } else {
760 memcpy(val, ptr, val_len);
761 val[val_len] = '\000';
762 return val;
763 }
764 } else {
765 line += strcspn(line, "\r\n");
766 line += strspn(line, "\r\n");
767 }
768 }
769 return NULL;
770 }
771
set_cfg_value(pam_handle_t * pamh,const char * key,const char * val,char ** buf)772 static int set_cfg_value(pam_handle_t *pamh, const char *key, const char *val,
773 char **buf) {
774 const size_t key_len = strlen(key);
775 char *start = NULL;
776 char *stop = NULL;
777
778 // Find an existing line, if any.
779 for (char *line = *buf; *line; ) {
780 char *ptr;
781 if (line[0] == '"' && line[1] == ' ' && !strncmp(line+2, key, key_len) &&
782 (!*(ptr = line+2+key_len) || *ptr == ' ' || *ptr == '\t' ||
783 *ptr == '\r' || *ptr == '\n')) {
784 start = line;
785 stop = start + strcspn(start, "\r\n");
786 stop += strspn(stop, "\r\n");
787 break;
788 } else {
789 line += strcspn(line, "\r\n");
790 line += strspn(line, "\r\n");
791 }
792 }
793
794 // If no existing line, insert immediately after the first line.
795 if (!start) {
796 start = *buf + strcspn(*buf, "\r\n");
797 start += strspn(start, "\r\n");
798 stop = start;
799 }
800
801 // Replace [start..stop] with the new contents.
802 const size_t val_len = strlen(val);
803 const size_t total_len = key_len + val_len + 4;
804 if (total_len <= stop - start) {
805 // We are decreasing out space requirements. Shrink the buffer and pad with
806 // NUL characters.
807 const size_t tail_len = strlen(stop);
808 memmove(start + total_len, stop, tail_len + 1);
809 memset(start + total_len + tail_len, 0, stop - start - total_len + 1);
810 } else {
811 // Must resize existing buffer. We cannot call realloc(), as it could
812 // leave parts of the buffer content in unused parts of the heap.
813 const size_t buf_len = strlen(*buf);
814 const size_t tail_len = buf_len - (stop - *buf);
815 char *resized = malloc(buf_len - (stop - start) + total_len + 1);
816 if (!resized) {
817 log_message(LOG_ERR, pamh, "Out of memory");
818 return -1;
819 }
820 memcpy(resized, *buf, start - *buf);
821 memcpy(resized + (start - *buf) + total_len, stop, tail_len + 1);
822 memset(*buf, 0, buf_len);
823 free(*buf);
824 start = start - *buf + resized;
825 *buf = resized;
826 }
827
828 // Fill in new contents.
829 start[0] = '"';
830 start[1] = ' ';
831 memcpy(start + 2, key, key_len);
832 start[2+key_len] = ' ';
833 memcpy(start+3+key_len, val, val_len);
834 start[3+key_len+val_len] = '\n';
835
836 // Check if there are any other occurrences of "value". If so, delete them.
837 for (char *line = start + 4 + key_len + val_len; *line; ) {
838 char *ptr;
839 if (line[0] == '"' && line[1] == ' ' && !strncmp(line+2, key, key_len) &&
840 (!*(ptr = line+2+key_len) || *ptr == ' ' || *ptr == '\t' ||
841 *ptr == '\r' || *ptr == '\n')) {
842 start = line;
843 stop = start + strcspn(start, "\r\n");
844 stop += strspn(stop, "\r\n");
845 size_t tail_len = strlen(stop);
846 memmove(start, stop, tail_len + 1);
847 memset(start + tail_len, 0, stop - start);
848 line = start;
849 } else {
850 line += strcspn(line, "\r\n");
851 line += strspn(line, "\r\n");
852 }
853 }
854
855 return 0;
856 }
857
step_size(pam_handle_t * pamh,const char * secret_filename,const char * buf)858 static int step_size(pam_handle_t *pamh, const char *secret_filename,
859 const char *buf) {
860 const char *value = get_cfg_value(pamh, "STEP_SIZE", buf);
861 if (!value) {
862 // Default step size is 30.
863 return 30;
864 } else if (value == &oom) {
865 // Out of memory. This is a fatal error.
866 return 0;
867 }
868
869 char *endptr;
870 errno = 0;
871 const int step = (int)strtoul(value, &endptr, 10);
872 if (errno || !*value || value == endptr ||
873 (*endptr && *endptr != ' ' && *endptr != '\t' &&
874 *endptr != '\n' && *endptr != '\r') ||
875 step < 1 || step > 60) {
876 free((void *)value);
877 log_message(LOG_ERR, pamh, "Invalid STEP_SIZE option in \"%s\"",
878 secret_filename);
879 return 0;
880 }
881 free((void *)value);
882 return step;
883 }
884
get_timestamp(pam_handle_t * pamh,const char * secret_filename,const char ** buf)885 static int get_timestamp(pam_handle_t *pamh, const char *secret_filename,
886 const char **buf) {
887 const int step = step_size(pamh, secret_filename, *buf);
888 if (!step) {
889 return 0;
890 }
891 return get_time()/step;
892 }
893
get_hotp_counter(pam_handle_t * pamh,const char * buf)894 static long get_hotp_counter(pam_handle_t *pamh, const char *buf) {
895 if (!buf) {
896 return -1;
897 }
898 const char *counter_str = get_cfg_value(pamh, "HOTP_COUNTER", buf);
899 if (counter_str == &oom) {
900 // Out of memory. This is a fatal error
901 return -1;
902 }
903
904 long counter = 0;
905 if (counter_str) {
906 counter = strtol(counter_str, NULL, 10);
907 }
908 free((void *)counter_str);
909
910 return counter;
911 }
912
rate_limit(pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf)913 static int rate_limit(pam_handle_t *pamh, const char *secret_filename,
914 int *updated, char **buf) {
915 const char *value = get_cfg_value(pamh, "RATE_LIMIT", *buf);
916 if (!value) {
917 // Rate limiting is not enabled for this account
918 return 0;
919 } else if (value == &oom) {
920 // Out of memory. This is a fatal error.
921 return -1;
922 }
923
924 // Parse both the maximum number of login attempts and the time interval
925 // that we are looking at.
926 const char *endptr = value, *ptr;
927 int attempts, interval;
928 errno = 0;
929 if (((attempts = (int)strtoul(ptr = endptr, (char **)&endptr, 10)) < 1) ||
930 ptr == endptr ||
931 attempts > 100 ||
932 errno ||
933 (*endptr != ' ' && *endptr != '\t') ||
934 ((interval = (int)strtoul(ptr = endptr, (char **)&endptr, 10)) < 1) ||
935 ptr == endptr ||
936 interval > 3600 ||
937 errno) {
938 free((void *)value);
939 log_message(LOG_ERR, pamh, "Invalid RATE_LIMIT option. Check \"%s\".",
940 secret_filename);
941 return -1;
942 }
943
944 // Parse the time stamps of all previous login attempts.
945 const unsigned int now = get_time();
946 unsigned int *timestamps = malloc(sizeof(int));
947 if (!timestamps) {
948 oom:
949 free((void *)value);
950 log_message(LOG_ERR, pamh, "Out of memory");
951 return -1;
952 }
953 timestamps[0] = now;
954 int num_timestamps = 1;
955 while (*endptr && *endptr != '\r' && *endptr != '\n') {
956 unsigned int timestamp;
957 errno = 0;
958 if ((*endptr != ' ' && *endptr != '\t') ||
959 ((timestamp = (int)strtoul(ptr = endptr, (char **)&endptr, 10)),
960 errno) ||
961 ptr == endptr) {
962 free((void *)value);
963 free(timestamps);
964 log_message(LOG_ERR, pamh, "Invalid list of timestamps in RATE_LIMIT. "
965 "Check \"%s\".", secret_filename);
966 return -1;
967 }
968 num_timestamps++;
969 unsigned int *tmp = (unsigned int *)realloc(timestamps,
970 sizeof(int) * num_timestamps);
971 if (!tmp) {
972 free(timestamps);
973 goto oom;
974 }
975 timestamps = tmp;
976 timestamps[num_timestamps-1] = timestamp;
977 }
978 free((void *)value);
979 value = NULL;
980
981 // Sort time stamps, then prune all entries outside of the current time
982 // interval.
983 qsort(timestamps, num_timestamps, sizeof(int), comparator);
984 int start = 0, stop = -1;
985 for (int i = 0; i < num_timestamps; ++i) {
986 if (timestamps[i] < now - interval) {
987 start = i+1;
988 } else if (timestamps[i] > now) {
989 break;
990 }
991 stop = i;
992 }
993
994 // Error out, if there are too many login attempts.
995 int exceeded = 0;
996 if (stop - start + 1 > attempts) {
997 exceeded = 1;
998 start = stop - attempts + 1;
999 }
1000
1001 // Construct new list of timestamps within the current time interval.
1002 char* list;
1003 {
1004 const size_t list_size = 25 * (2 + (stop - start + 1)) + 4;
1005 list = malloc(list_size);
1006 if (!list) {
1007 free(timestamps);
1008 goto oom;
1009 }
1010 snprintf(list, list_size, "%d %d", attempts, interval);
1011 char *prnt = strchr(list, '\000');
1012 for (int i = start; i <= stop; ++i) {
1013 prnt += snprintf(prnt, list_size-(prnt-list), " %u", timestamps[i]);
1014 }
1015 free(timestamps);
1016 }
1017
1018 // Try to update RATE_LIMIT line.
1019 if (set_cfg_value(pamh, "RATE_LIMIT", list, buf) < 0) {
1020 free(list);
1021 return -1;
1022 }
1023 free(list);
1024
1025 // Mark the state file as changed.
1026 *updated = 1;
1027
1028 // If necessary, notify the user of the rate limiting that is in effect.
1029 if (exceeded) {
1030 log_message(LOG_ERR, pamh,
1031 "Too many concurrent login attempts (\"%s\"). Please try again.", secret_filename);
1032 return -1;
1033 }
1034
1035 return 0;
1036 }
1037
get_first_pass(pam_handle_t * pamh)1038 static char *get_first_pass(pam_handle_t *pamh) {
1039 PAM_CONST void *password = NULL;
1040 if (pam_get_item(pamh, PAM_AUTHTOK, &password) == PAM_SUCCESS &&
1041 password) {
1042 return strdup((const char *)password);
1043 }
1044 return NULL;
1045 }
1046
1047 // Show error message to the user.
1048 static void
conv_error(pam_handle_t * pamh,const char * text)1049 conv_error(pam_handle_t *pamh, const char* text) {
1050 PAM_CONST struct pam_message msg = {
1051 .msg_style = PAM_ERROR_MSG,
1052 .msg = text,
1053 };
1054 PAM_CONST struct pam_message *msgs = &msg;
1055 struct pam_response *resp = NULL;
1056 const int retval = converse(pamh, 1, &msgs, &resp);
1057 if (retval != PAM_SUCCESS) {
1058 log_message(LOG_ERR, pamh, "Failed to inform user of error");
1059 }
1060 free(resp);
1061 }
1062
request_pass(pam_handle_t * pamh,int echocode,PAM_CONST char * prompt)1063 static char *request_pass(pam_handle_t *pamh, int echocode,
1064 PAM_CONST char *prompt) {
1065 // Query user for verification code
1066 PAM_CONST struct pam_message msg = { .msg_style = echocode,
1067 .msg = prompt };
1068 PAM_CONST struct pam_message *msgs = &msg;
1069 struct pam_response *resp = NULL;
1070 int retval = converse(pamh, 1, &msgs, &resp);
1071 char *ret = NULL;
1072 if (retval != PAM_SUCCESS || resp == NULL || resp->resp == NULL ||
1073 *resp->resp == '\000') {
1074 log_message(LOG_ERR, pamh, "Did not receive verification code from user");
1075 if (retval == PAM_SUCCESS && resp && resp->resp) {
1076 ret = resp->resp;
1077 }
1078 } else {
1079 ret = resp->resp;
1080 }
1081
1082 // Deallocate temporary storage
1083 if (resp) {
1084 if (!ret) {
1085 free(resp->resp);
1086 }
1087 free(resp);
1088 }
1089
1090 return ret;
1091 }
1092
1093 /* Checks for possible use of scratch codes. Returns -1 on error, 0 on success,
1094 * and 1, if no scratch code had been entered, and subsequent tests should be
1095 * applied.
1096 */
check_scratch_codes(pam_handle_t * pamh,const Params * params,const char * secret_filename,int * updated,char * buf,int code)1097 static int check_scratch_codes(pam_handle_t *pamh,
1098 const Params *params,
1099 const char *secret_filename,
1100 int *updated, char *buf, int code) {
1101 // Skip the first line. It contains the shared secret.
1102 char *ptr = buf + strcspn(buf, "\n");
1103
1104 // Check if this is one of the scratch codes
1105 char *endptr = NULL;
1106 for (;;) {
1107 // Skip newlines and blank lines
1108 while (*ptr == '\r' || *ptr == '\n') {
1109 ptr++;
1110 }
1111
1112 // Skip any lines starting with double-quotes. They contain option fields
1113 if (*ptr == '"') {
1114 ptr += strcspn(ptr, "\n");
1115 continue;
1116 }
1117
1118 // Try to interpret the line as a scratch code
1119 errno = 0;
1120 const int scratchcode = (int)strtoul(ptr, &endptr, 10);
1121
1122 // Sanity check that we read a valid scratch code. Scratchcodes are all
1123 // numeric eight-digit codes. There must not be any other information on
1124 // that line.
1125 if (errno ||
1126 ptr == endptr ||
1127 (*endptr != '\r' && *endptr != '\n' && *endptr) ||
1128 scratchcode < 10*1000*1000 ||
1129 scratchcode >= 100*1000*1000) {
1130 break;
1131 }
1132
1133 // Check if the code matches
1134 if (scratchcode == code) {
1135 // Remove scratch code after using it
1136 while (*endptr == '\n' || *endptr == '\r') {
1137 ++endptr;
1138 }
1139 memmove(ptr, endptr, strlen(endptr) + 1);
1140 memset(strrchr(ptr, '\000'), 0, endptr - ptr + 1);
1141
1142 // Mark the state file as changed
1143 *updated = 1;
1144
1145 // Successfully removed scratch code. Allow user to log in.
1146 if(params->debug) {
1147 log_message(LOG_INFO, pamh, "debug: scratch code %d used and removed from \"%s\"", code, secret_filename);
1148 }
1149 return 0;
1150 }
1151 ptr = endptr;
1152 }
1153
1154 // No scratch code has been used. Continue checking other types of codes.
1155 if(params->debug) {
1156 log_message(LOG_INFO, pamh, "debug: no scratch code used from \"%s\"", secret_filename);
1157 }
1158 return 1;
1159 }
1160
window_size(pam_handle_t * pamh,const char * secret_filename,const char * buf)1161 static int window_size(pam_handle_t *pamh, const char *secret_filename,
1162 const char *buf) {
1163 const char *value = get_cfg_value(pamh, "WINDOW_SIZE", buf);
1164 if (!value) {
1165 // Default window size is 3. This gives us one STEP_SIZE second
1166 // window before and after the current one.
1167 return 3;
1168 } else if (value == &oom) {
1169 // Out of memory. This is a fatal error.
1170 return 0;
1171 }
1172
1173 char *endptr;
1174 errno = 0;
1175 const int window = (int)strtoul(value, &endptr, 10);
1176 if (errno || !*value || value == endptr ||
1177 (*endptr && *endptr != ' ' && *endptr != '\t' &&
1178 *endptr != '\n' && *endptr != '\r') ||
1179 window < 1 || window > 100) {
1180 free((void *)value);
1181 log_message(LOG_ERR, pamh, "Invalid WINDOW_SIZE option in \"%s\"",
1182 secret_filename);
1183 return 0;
1184 }
1185 free((void *)value);
1186 return window;
1187 }
1188
1189 /* If the DISALLOW_REUSE option has been set, record timestamps have been
1190 * used to log in successfully and disallow their reuse.
1191 *
1192 * Returns -1 on error, and 0 on success.
1193 */
invalidate_timebased_code(int tm,pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf)1194 static int invalidate_timebased_code(int tm, pam_handle_t *pamh,
1195 const char *secret_filename,
1196 int *updated, char **buf) {
1197 char *disallow = get_cfg_value(pamh, "DISALLOW_REUSE", *buf);
1198 if (!disallow) {
1199 // Reuse of tokens is not explicitly disallowed. Allow the login request
1200 // to proceed.
1201 return 0;
1202 } else if (disallow == &oom) {
1203 // Out of memory. This is a fatal error.
1204 return -1;
1205 }
1206
1207 // Allow the user to customize the window size parameter.
1208 const int window = window_size(pamh, secret_filename, *buf);
1209 if (!window) {
1210 // The user configured a non-standard window size, but there was some
1211 // error with the value of this parameter.
1212 free((void *)disallow);
1213 return -1;
1214 }
1215
1216 // The DISALLOW_REUSE option is followed by all known timestamps that are
1217 // currently unavailable for login.
1218 for (char *ptr = disallow; *ptr;) {
1219 // Skip white-space, if any
1220 ptr += strspn(ptr, " \t\r\n");
1221 if (!*ptr) {
1222 break;
1223 }
1224
1225 // Parse timestamp value.
1226 char *endptr;
1227 errno = 0;
1228 const int blocked = (int)strtoul(ptr, &endptr, 10);
1229
1230 // Treat syntactically invalid options as an error
1231 if (errno ||
1232 ptr == endptr ||
1233 (*endptr != ' ' && *endptr != '\t' &&
1234 *endptr != '\r' && *endptr != '\n' && *endptr)) {
1235 free((void *)disallow);
1236 return -1;
1237 }
1238
1239 if (tm == blocked) {
1240 // The code is currently blocked from use. Disallow login.
1241 free((void *)disallow);
1242 const int step = step_size(pamh, secret_filename, *buf);
1243 if (!step) {
1244 return -1;
1245 }
1246 log_message(LOG_ERR, pamh,
1247 "Trying to reuse a previously used time-based code. (\"%s\")"
1248 "Retry again in %d seconds. "
1249 "Warning! This might mean, you are currently subject to a "
1250 "man-in-the-middle attack.", secret_filename, step);
1251 return -1;
1252 }
1253
1254 // If the blocked code is outside of the possible window of timestamps,
1255 // remove it from the file.
1256 if (blocked - tm >= window || tm - blocked >= window) {
1257 endptr += strspn(endptr, " \t");
1258 memmove(ptr, endptr, strlen(endptr) + 1);
1259 } else {
1260 ptr = endptr;
1261 }
1262 }
1263
1264 // Add the current timestamp to the list of disallowed timestamps.
1265 {
1266 const size_t resized_size = strlen(disallow) + 40;
1267 char *resized = realloc(disallow, resized_size);
1268 if (!resized) {
1269 free((void *)disallow);
1270 log_message(LOG_ERR, pamh,
1271 "Failed to allocate memory when updating \"%s\"",
1272 secret_filename);
1273 return -1;
1274 }
1275 disallow = resized;
1276 char* pos = strrchr(disallow, '\000');
1277 snprintf(pos, resized_size-(pos-disallow), " %d" + !*disallow, tm);
1278 if (set_cfg_value(pamh, "DISALLOW_REUSE", disallow, buf) < 0) {
1279 free((void *)disallow);
1280 return -1;
1281 }
1282 free((void *)disallow);
1283 }
1284
1285 // Mark the state file as changed
1286 *updated = 1;
1287
1288 // Allow access.
1289 return 0;
1290 }
1291
1292 /* Given an input value, this function computes the hash code that forms the
1293 * expected authentication token.
1294 */
1295 #ifdef TESTING
1296 int compute_code(const uint8_t *secret, int secretLen, unsigned long value)
1297 __attribute__((visibility("default")));
1298 #else
1299 static
1300 #endif
compute_code(const uint8_t * secret,int secretLen,unsigned long value)1301 int compute_code(const uint8_t *secret, int secretLen, unsigned long value) {
1302 uint8_t val[8];
1303 for (int i = 8; i--; value >>= 8) {
1304 val[i] = value;
1305 }
1306 uint8_t hash[SHA1_DIGEST_LENGTH];
1307 hmac_sha1(secret, secretLen, val, 8, hash, SHA1_DIGEST_LENGTH);
1308 explicit_bzero(val, sizeof(val));
1309 const int offset = hash[SHA1_DIGEST_LENGTH - 1] & 0xF;
1310 unsigned int truncatedHash = 0;
1311 for (int i = 0; i < 4; ++i) {
1312 truncatedHash <<= 8;
1313 truncatedHash |= hash[offset + i];
1314 }
1315 explicit_bzero(hash, sizeof(hash));
1316 truncatedHash &= 0x7FFFFFFF;
1317 truncatedHash %= 1000000;
1318 return truncatedHash;
1319 }
1320
1321 /* If a user repeated attempts to log in with the same time skew, remember
1322 * this skew factor for future login attempts.
1323 */
check_time_skew(pam_handle_t * pamh,int * updated,char ** buf,int skew,int tm)1324 static int check_time_skew(pam_handle_t *pamh,
1325 int *updated, char **buf, int skew, int tm) {
1326 int rc = -1;
1327
1328 // Parse current RESETTING_TIME_SKEW line, if any.
1329 char *resetting = get_cfg_value(pamh, "RESETTING_TIME_SKEW", *buf);
1330 if (resetting == &oom) {
1331 // Out of memory. This is a fatal error.
1332 return -1;
1333 }
1334
1335 // If the user can produce a sequence of three consecutive codes that fall
1336 // within a day of the current time. And if he can enter these codes in
1337 // quick succession, then we allow the time skew to be reset.
1338 // N.B. the number "3" was picked so that it would not trigger the rate
1339 // limiting limit if set up with default parameters.
1340 unsigned int tms[3];
1341 int skews[sizeof(tms)/sizeof(int)];
1342
1343 int num_entries = 0;
1344 if (resetting) {
1345 char *ptr = resetting;
1346
1347 // Read the three most recent pairs of time stamps and skew values into
1348 // our arrays.
1349 while (*ptr && *ptr != '\r' && *ptr != '\n') {
1350 char *endptr;
1351 errno = 0;
1352 const unsigned int i = (int)strtoul(ptr, &endptr, 10);
1353 if (errno || ptr == endptr || (*endptr != '+' && *endptr != '-')) {
1354 break;
1355 }
1356 ptr = endptr;
1357 int j = (int)strtoul(ptr + 1, &endptr, 10);
1358 if (errno ||
1359 ptr == endptr ||
1360 (*endptr != ' ' && *endptr != '\t' &&
1361 *endptr != '\r' && *endptr != '\n' && *endptr)) {
1362 break;
1363 }
1364 if (*ptr == '-') {
1365 j = -j;
1366 }
1367 if (num_entries == sizeof(tms)/sizeof(int)) {
1368 memmove(tms, tms+1, sizeof(tms)-sizeof(int));
1369 memmove(skews, skews+1, sizeof(skews)-sizeof(int));
1370 } else {
1371 ++num_entries;
1372 }
1373 tms[num_entries-1] = i;
1374 skews[num_entries-1] = j;
1375 ptr = endptr;
1376 }
1377
1378 // If the user entered an identical code, assume they are just getting
1379 // desperate. This doesn't actually provide us with any useful data,
1380 // though. Don't change any state and hope the user keeps trying a few
1381 // more times.
1382 if (num_entries &&
1383 tm + skew == tms[num_entries-1] + skews[num_entries-1]) {
1384 free((void *)resetting);
1385 return -1;
1386 }
1387 }
1388 free((void *)resetting);
1389
1390 // Append new timestamp entry
1391 if (num_entries == sizeof(tms)/sizeof(int)) {
1392 memmove(tms, tms+1, sizeof(tms)-sizeof(int));
1393 memmove(skews, skews+1, sizeof(skews)-sizeof(int));
1394 } else {
1395 ++num_entries;
1396 }
1397 tms[num_entries-1] = tm;
1398 skews[num_entries-1] = skew;
1399
1400 // Check if we have the required amount of valid entries.
1401 if (num_entries == sizeof(tms)/sizeof(int)) {
1402 unsigned int last_tm = tms[0];
1403 int last_skew = skews[0];
1404 int avg_skew = last_skew;
1405 for (int i = 1; i < sizeof(tms)/sizeof(int); ++i) {
1406 // Check that we have a consecutive sequence of timestamps with no big
1407 // gaps in between. Also check that the time skew stays constant. Allow
1408 // a minor amount of fuzziness on all parameters.
1409 if (tms[i] <= last_tm || tms[i] > last_tm+2 ||
1410 last_skew - skew < -1 || last_skew - skew > 1) {
1411 goto keep_trying;
1412 }
1413 last_tm = tms[i];
1414 last_skew = skews[i];
1415 avg_skew += last_skew;
1416 }
1417 avg_skew /= (int)(sizeof(tms)/sizeof(int));
1418
1419 // The user entered the required number of valid codes in quick
1420 // succession. Establish a new valid time skew for all future login
1421 // attempts.
1422 char time_skew[40];
1423 snprintf(time_skew, sizeof time_skew, "%d", avg_skew);
1424 if (set_cfg_value(pamh, "TIME_SKEW", time_skew, buf) < 0) {
1425 return -1;
1426 }
1427 rc = 0;
1428 keep_trying:;
1429 }
1430
1431 // Set the new RESETTING_TIME_SKEW line, while the user is still trying
1432 // to reset the time skew.
1433 {
1434 const size_t reset_size = 80 * (sizeof(tms)/sizeof(int));
1435 char reset[reset_size];
1436 *reset = '\000';
1437 if (rc) {
1438 for (int i = 0; i < num_entries; ++i) {
1439 char* pos = strrchr(reset, '\000');
1440 snprintf(pos, reset_size-(pos-reset), " %d%+d" + !*reset, tms[i], skews[i]);
1441 }
1442 }
1443 if (set_cfg_value(pamh, "RESETTING_TIME_SKEW", reset, buf) < 0) {
1444 return -1;
1445 }
1446 }
1447
1448 // Mark the state file as changed
1449 *updated = 1;
1450
1451 return rc;
1452 }
1453
1454 /* Checks for time based verification code. Returns -1 on error, 0 on success,
1455 * and 1, if no time based code had been entered, and subsequent tests should
1456 * be applied.
1457 */
check_timebased_code(pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf,const uint8_t * secret,int secretLen,int code,Params * params)1458 static int check_timebased_code(pam_handle_t *pamh, const char*secret_filename,
1459 int *updated, char **buf, const uint8_t*secret,
1460 int secretLen, int code, Params *params) {
1461 if (!is_totp(*buf)) {
1462 // The secret file does not actually contain information for a time-based
1463 // code. Return to caller and see if any other authentication methods
1464 // apply.
1465 return 1;
1466 }
1467
1468 if (code < 0 || code >= 1000000) {
1469 // All time based verification codes are no longer than six digits.
1470 return 1;
1471 }
1472
1473 // Compute verification codes and compare them with user input
1474 const int tm = get_timestamp(pamh, secret_filename, (const char **)buf);
1475 if (!tm) {
1476 return -1;
1477 }
1478 const char *skew_str = get_cfg_value(pamh, "TIME_SKEW", *buf);
1479 if (skew_str == &oom) {
1480 // Out of memory. This is a fatal error
1481 return -1;
1482 }
1483
1484 int skew = 0;
1485 if (skew_str) {
1486 skew = (int)strtol(skew_str, NULL, 10);
1487 }
1488 free((void *)skew_str);
1489
1490 const int window = window_size(pamh, secret_filename, *buf);
1491 if (!window) {
1492 return -1;
1493 }
1494 for (int i = -((window-1)/2); i <= window/2; ++i) {
1495 const unsigned int hash = compute_code(secret, secretLen, tm + skew + i);
1496 if (hash == (unsigned int)code) {
1497 return invalidate_timebased_code(tm + skew + i, pamh, secret_filename,
1498 updated, buf);
1499 }
1500 }
1501
1502 if (!params->noskewadj) {
1503 // The most common failure mode is for the clocks to be insufficiently
1504 // synchronized. We can detect this and store a skew value for future
1505 // use.
1506 skew = 1000000;
1507 for (int i = 0; i < 25*60; ++i) {
1508 unsigned int hash = compute_code(secret, secretLen, tm - i);
1509 if (hash == (unsigned int)code && skew == 1000000) {
1510 // Don't short-circuit out of the loop as the obvious difference in
1511 // computation time could be a signal that is valuable to an attacker.
1512 skew = -i;
1513 }
1514 hash = compute_code(secret, secretLen, tm + i);
1515 if (hash == (unsigned int)code && skew == 1000000) {
1516 skew = i;
1517 }
1518 }
1519 if (skew != 1000000) {
1520 if(params->debug) {
1521 log_message(LOG_INFO, pamh, "debug: time skew adjusted");
1522 }
1523 return check_time_skew(pamh, updated, buf, skew, tm);
1524 }
1525 }
1526
1527 return 1;
1528 }
1529
1530 /*
1531 * Add a 'config' variable that says we logged in from a particular place
1532 * at a particular time. Only remembers the last 10 logins, which
1533 * are replaced in LRU order.
1534 *
1535 * Returns 0 on success.
1536 */
1537 int
update_logindetails(pam_handle_t * pamh,const Params * params,char ** buf)1538 update_logindetails(pam_handle_t *pamh, const Params *params, char **buf) {
1539 const char *rhost = get_rhost(pamh, params);
1540 const time_t now = get_time();
1541 time_t oldest = now; // Oldest entry seen so far.
1542 int oldest_index = -1; // Index of oldest entry, due for replacement.
1543 int found = 0; // Entry for this rhost found.
1544 char name[] = "LAST "; // Config name template.
1545
1546 if (rhost == NULL) {
1547 return -1;
1548 }
1549
1550 for (int i = 0; i < 10; i++) {
1551 //
1552 // Get LAST<n> cfg value.
1553 //
1554 name[4] = i + '0';
1555 char *line = get_cfg_value(pamh, name, *buf);
1556 if (line == &oom) {
1557 /* Fatal! */
1558 return -1;
1559 }
1560
1561 if (!line) {
1562 /* Make first empty line the oldest */
1563 if (oldest) {
1564 oldest_index = i;
1565 oldest = 0;
1566 }
1567 continue;
1568 }
1569
1570 //
1571 // Parse value.
1572 //
1573
1574 // Max len of ipv6 address is 8*4 digits plus 7 colons.
1575 // Plus trailing NUL is 40.
1576 // But RHOST can be FQDN, and by RFC1035 that's 255 characters as max.
1577 char host[256];
1578 unsigned long when = 0; // Timestamp of current entry.
1579 const int scanf_rc = sscanf(line, " %255[0-9a-zA-Z:.-] %lu ", host, &when);
1580 free(line);
1581
1582 if (scanf_rc != 2) {
1583 log_message(LOG_ERR, pamh, "Malformed LAST%d line", i);
1584 continue;
1585 }
1586
1587 if (!strcmp(host, rhost)) {
1588 found = 1;
1589 break;
1590 }
1591
1592 if (when < oldest) {
1593 oldest_index = i;
1594 oldest = when;
1595 }
1596 }
1597
1598 if (!found) {
1599 /* Loop completed all ten iterations */
1600 name[4] = oldest_index + '0';
1601 }
1602
1603 /*
1604 * Max length in decimal digits of a 64 bit number is (64 log 2) + 1
1605 * Plus space and NUL termination, is 23.
1606 * Max len of hostname is 255.
1607 */
1608 char value[255+23+1];
1609 memset(value, 0, sizeof value);
1610
1611 snprintf(value, sizeof value, "%s %lu", rhost, (unsigned long)now);
1612 if (set_cfg_value(pamh, name, value, buf) < 0) {
1613 log_message(LOG_WARNING, pamh, "Failed to set cfg value for login host");
1614 }
1615
1616 return 0;
1617 }
1618
1619 /*
1620 * Return non-zero if the last login from the same host as this one was
1621 * successfully authenticated within the grace period.
1622 */
1623 int
within_grace_period(pam_handle_t * pamh,const Params * params,const char * buf)1624 within_grace_period(pam_handle_t *pamh, const Params *params,
1625 const char *buf) {
1626 const char *rhost = get_rhost(pamh, params);
1627 const time_t now = get_time();
1628 const time_t grace = params->grace_period;
1629 unsigned long when = 0;
1630 char match[128];
1631
1632 if (rhost == NULL) {
1633 return 0;
1634 }
1635 snprintf(match, sizeof match, " %s %%lu ", rhost);
1636
1637 for (int i = 0; i < 10; i++) {
1638 static char name[] = "LAST0";
1639 name[4] = i + '0';
1640 char* line = get_cfg_value(pamh, name, buf);
1641
1642 if (line == &oom) {
1643 /* Fatal! */
1644 return 0;
1645 }
1646 if (!line) {
1647 continue;
1648 }
1649 if (sscanf(line, match, &when) == 1) {
1650 free(line);
1651 break;
1652 }
1653 free(line);
1654 }
1655
1656 if (when == 0) {
1657 /* No match */
1658 return 0;
1659 }
1660
1661 return (when + grace > now);
1662 }
1663
1664 /* Checks for counter based verification code. Returns -1 on error, 0 on
1665 * success, and 1, if no counter based code had been entered, and subsequent
1666 * tests should be applied.
1667 */
check_counterbased_code(pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf,const uint8_t * secret,int secretLen,int code,long hotp_counter,int * must_advance_counter)1668 static int check_counterbased_code(pam_handle_t *pamh,
1669 const char*secret_filename, int *updated,
1670 char **buf, const uint8_t*secret,
1671 int secretLen, int code,
1672 long hotp_counter,
1673 int *must_advance_counter) {
1674 if (hotp_counter < 1) {
1675 // The secret file did not actually contain information for a counter-based
1676 // code. Return to caller and see if any other authentication methods
1677 // apply.
1678 return 1;
1679 }
1680
1681 if (code < 0 || code >= 1000000) {
1682 // All counter based verification codes are no longer than six digits.
1683 return 1;
1684 }
1685
1686 // Compute [window_size] verification codes and compare them with user input.
1687 // Future codes are allowed in case the user computed but did not use a code.
1688 const int window = window_size(pamh, secret_filename, *buf);
1689 if (!window) {
1690 return -1;
1691 }
1692 for (int i = 0; i < window; ++i) {
1693 const unsigned int hash = compute_code(secret, secretLen, hotp_counter + i);
1694 if (hash == (unsigned int)code) {
1695 char counter_str[40];
1696 snprintf(counter_str, sizeof counter_str, "%ld", hotp_counter + i + 1);
1697 if (set_cfg_value(pamh, "HOTP_COUNTER", counter_str, buf) < 0) {
1698 return -1;
1699 }
1700 *updated = 1;
1701 *must_advance_counter = 0;
1702 return 0;
1703 }
1704 }
1705
1706 *must_advance_counter = 1;
1707 return 1;
1708 }
1709
1710 // parse a user name.
1711 // input: user name
1712 // output: uid
1713 // return: 0 on success.
parse_user(pam_handle_t * pamh,const char * name,uid_t * uid)1714 static int parse_user(pam_handle_t *pamh, const char *name, uid_t *uid) {
1715 char *endptr;
1716 errno = 0;
1717 const long l = strtol(name, &endptr, 10);
1718 if (!errno && endptr != name && l >= 0 && l <= INT_MAX) {
1719 *uid = (uid_t)l;
1720 return 0;
1721 }
1722 const size_t len = getpwnam_buf_max_size();
1723 char *buf = malloc(len);
1724 if (!buf) {
1725 log_message(LOG_ERR, pamh, "Out of memory");
1726 return -1;
1727 }
1728 struct passwd pwbuf, *pw;
1729 if (getpwnam_r(name, &pwbuf, buf, len, &pw) || !pw) {
1730 free(buf);
1731 log_message(LOG_ERR, pamh, "Failed to look up user \"%s\"", name);
1732 return -1;
1733 }
1734 *uid = pw->pw_uid;
1735 free(buf);
1736 return 0;
1737 }
1738
parse_args(pam_handle_t * pamh,int argc,const char ** argv,Params * params)1739 static int parse_args(pam_handle_t *pamh, int argc, const char **argv,
1740 Params *params) {
1741 params->debug = 0;
1742 params->echocode = PAM_PROMPT_ECHO_OFF;
1743 for (int i = 0; i < argc; ++i) {
1744 if (!strncmp(argv[i], "secret=", 7)) {
1745 params->secret_filename_spec = argv[i] + 7;
1746 } else if (!strncmp(argv[i], "authtok_prompt=", 15)) {
1747 params->authtok_prompt = argv[i] + 15;
1748 } else if (!strncmp(argv[i], "user=", 5)) {
1749 uid_t uid;
1750 if (parse_user(pamh, argv[i] + 5, &uid) < 0) {
1751 return -1;
1752 }
1753 params->fixed_uid = 1;
1754 params->uid = uid;
1755 } else if (!strncmp(argv[i], "allowed_perm=", 13)) {
1756 char *remainder = NULL;
1757 const int perm = (int)strtol(argv[i] + 13, &remainder, 8);
1758 if (perm == 0 || strlen(remainder) != 0) {
1759 log_message(LOG_ERR, pamh,
1760 "Invalid permissions in setting \"%s\"."
1761 " allowed_perm setting must be a positive octal integer.",
1762 argv[i]);
1763 return -1;
1764 }
1765 params->allowed_perm = perm;
1766 } else if (!strcmp(argv[i], "no_strict_owner")) {
1767 params->no_strict_owner = 1;
1768 } else if (!strcmp(argv[i], "debug")) {
1769 params->debug = 1;
1770 } else if (!strcmp(argv[i], "try_first_pass")) {
1771 params->pass_mode = TRY_FIRST_PASS;
1772 } else if (!strcmp(argv[i], "use_first_pass")) {
1773 params->pass_mode = USE_FIRST_PASS;
1774 } else if (!strcmp(argv[i], "forward_pass")) {
1775 params->forward_pass = 1;
1776 } else if (!strcmp(argv[i], "noskewadj")) {
1777 params->noskewadj = 1;
1778 } else if (!strcmp(argv[i], "no_increment_hotp")) {
1779 params->no_increment_hotp = 1;
1780 } else if (!strcmp(argv[i], "nullok")) {
1781 params->nullok = NULLOK;
1782 } else if (!strcmp(argv[i], "allow_readonly")) {
1783 params->allow_readonly = 1;
1784 } else if (!strcmp(argv[i], "echo-verification-code") ||
1785 !strcmp(argv[i], "echo_verification_code")) {
1786 params->echocode = PAM_PROMPT_ECHO_ON;
1787 } else if (!strncmp(argv[i], "grace_period=", 13)) {
1788 char *remainder = NULL;
1789 const time_t grace = (time_t)strtol(argv[i] + 13, &remainder, 10);
1790 if (grace < 0 || *remainder) {
1791 log_message(LOG_ERR, pamh,
1792 "Invalid value in setting \"%s\"."
1793 "grace_period must be a positive number of seconds.",
1794 argv[i]);
1795 return -1;
1796 }
1797 params->grace_period = grace;
1798 } else {
1799 log_message(LOG_ERR, pamh, "Unrecognized option \"%s\"", argv[i]);
1800 return -1;
1801 }
1802 }
1803 return 0;
1804 }
1805
google_authenticator(pam_handle_t * pamh,int argc,const char ** argv)1806 static int google_authenticator(pam_handle_t *pamh,
1807 int argc, const char **argv) {
1808 int rc = PAM_AUTH_ERR;
1809 uid_t uid = -1;
1810 int old_uid = -1, old_gid = -1, fd = -1;
1811 char *buf = NULL;
1812 struct stat orig_stat = { 0 };
1813 uint8_t *secret = NULL;
1814 int secretLen = 0;
1815
1816 // Handle optional arguments that configure our PAM module
1817 Params params = { 0 };
1818 params.allowed_perm = 0600;
1819 if (parse_args(pamh, argc, argv, ¶ms) < 0) {
1820 return rc;
1821 }
1822
1823 const char *prompt = params.authtok_prompt
1824 ? params.authtok_prompt
1825 : (params.forward_pass ? PWCODE_PROMPT : CODE_PROMPT);
1826
1827 // Read and process status file, then ask the user for the verification code.
1828 int early_updated = 0, updated = 0;
1829
1830 const char* const username = get_user_name(pamh, ¶ms);
1831 char* const secret_filename = get_secret_filename(pamh, ¶ms,
1832 username, &uid);
1833 int stopped_by_rate_limit = 0;
1834
1835 // Drop privileges.
1836 {
1837 const char* drop_username = username;
1838
1839 // If user doesn't exist, use 'nobody'.
1840 if (uid == -1) {
1841 drop_username = nobody;
1842 if (parse_user(pamh, drop_username, &uid)) {
1843 // If 'nobody' doesn't exist, bail. We need to drop privs to *someone*.
1844 goto out;
1845 }
1846 }
1847
1848 if (drop_privileges(pamh, drop_username, uid, &old_uid, &old_gid)) {
1849 // Don't allow to continue without dropping privs.
1850 goto out;
1851 }
1852 }
1853
1854 if (secret_filename) {
1855 fd = open_secret_file(pamh, secret_filename, ¶ms, username, uid, &orig_stat);
1856 if (fd >= 0) {
1857 buf = read_file_contents(pamh, ¶ms, secret_filename, &fd, orig_stat.st_size);
1858 }
1859
1860 if (buf) {
1861 if (rate_limit(pamh, secret_filename, &early_updated, &buf) >= 0) {
1862 secret = get_shared_secret(pamh, ¶ms, secret_filename, buf, &secretLen);
1863 } else {
1864 stopped_by_rate_limit=1;
1865 }
1866 }
1867 }
1868
1869 const long hotp_counter = get_hotp_counter(pamh, buf);
1870
1871 /*
1872 * Check to see if a successful login from the same host happened
1873 * within the grace period. If it did, then allow login without
1874 * an additional code.
1875 */
1876 if (buf && within_grace_period(pamh, ¶ms, buf)) {
1877 rc = PAM_SUCCESS;
1878 log_message(LOG_INFO, pamh,
1879 "within grace period: \"%s\"", username);
1880 goto out;
1881 }
1882
1883 // Only if nullok and we do not have a code will we NOT ask for a code.
1884 // In all other cases (i.e "have code" and "no nullok and no code") we DO ask for a code.
1885 if (!stopped_by_rate_limit &&
1886 ( secret || params.nullok != SECRETNOTFOUND )
1887 ) {
1888
1889 if (!secret) {
1890 log_message(LOG_WARNING , pamh, "No secret configured for user %s, asking for code anyway.", username);
1891 }
1892
1893 int must_advance_counter = 0;
1894 char *pw = NULL, *saved_pw = NULL;
1895 for (int mode = 0; mode < 4; ++mode) {
1896 // In the case of TRY_FIRST_PASS, we don't actually know whether we
1897 // get the verification code from the system password or from prompting
1898 // the user. We need to attempt both.
1899 // This only works correctly, if all failed attempts leave the global
1900 // state unchanged.
1901 if (updated || pw) {
1902 // Oops. There is something wrong with the internal logic of our
1903 // code. This error should never trigger. The unittest checks for
1904 // this.
1905 if (pw) {
1906 explicit_bzero(pw, strlen(pw));
1907 free(pw);
1908 pw = NULL;
1909 }
1910 rc = PAM_AUTH_ERR;
1911 break;
1912 }
1913 switch (mode) {
1914 case 0: // Extract possible verification code
1915 case 1: // Extract possible scratch code
1916 if (params.pass_mode == USE_FIRST_PASS ||
1917 params.pass_mode == TRY_FIRST_PASS) {
1918 pw = get_first_pass(pamh);
1919 }
1920 break;
1921 default:
1922 if (mode != 2 && // Prompt for pw and possible verification code
1923 mode != 3) { // Prompt for pw and possible scratch code
1924 rc = PAM_AUTH_ERR;
1925 continue;
1926 }
1927 if (params.pass_mode == PROMPT ||
1928 params.pass_mode == TRY_FIRST_PASS) {
1929 if (!saved_pw) {
1930 // If forwarding the password to the next stacked PAM module,
1931 // we cannot tell the difference between an eight digit scratch
1932 // code or a two digit password immediately followed by a six
1933 // digit verification code. We have to loop and try both
1934 // options.
1935 saved_pw = request_pass(pamh, params.echocode, prompt);
1936 }
1937 if (saved_pw) {
1938 pw = strdup(saved_pw);
1939 }
1940 }
1941 break;
1942 }
1943 if (!pw) {
1944 continue;
1945 }
1946
1947 // We are often dealing with a combined password and verification
1948 // code. Separate them now.
1949 const int pw_len = strlen(pw);
1950 const int expected_len = mode & 1 ? 8 : 6;
1951 char ch;
1952
1953 // Full OpenSSH "bad password" is "\b\n\r\177INCORRECT", capped
1954 // to original password length.
1955 if (pw_len > 0 && pw[0] == '\b') {
1956 log_message(LOG_INFO, pamh,
1957 "Dummy password supplied by PAM."
1958 " Did OpenSSH 'PermitRootLogin <anything but yes>' or some"
1959 " other config block this login?");
1960 }
1961
1962 if (pw_len < expected_len ||
1963 // Verification are six digits starting with '0'..'9',
1964 // scratch codes are eight digits starting with '1'..'9'
1965 (ch = pw[pw_len - expected_len]) > '9' ||
1966 ch < (expected_len == 8 ? '1' : '0')) {
1967 invalid:
1968 explicit_bzero(pw, pw_len);
1969 free(pw);
1970 pw = NULL;
1971 continue;
1972 }
1973 char *endptr;
1974 errno = 0;
1975 const long l = strtol(pw + pw_len - expected_len, &endptr, 10);
1976 if (errno || l < 0 || *endptr) {
1977 goto invalid;
1978 }
1979 const int code = (int)l;
1980 memset(pw + pw_len - expected_len, 0, expected_len);
1981
1982 if ((mode == 2 || mode == 3) && !params.forward_pass) {
1983 // We are explicitly configured so that we don't try to share
1984 // the password with any other stacked PAM module. We must
1985 // therefore verify that the user entered just the verification
1986 // code, but no password.
1987 if (*pw) {
1988 goto invalid;
1989 }
1990 }
1991
1992 // Only if we actually have a secret will we try to verify the code
1993 // In all other cases will we just remain at PAM_AUTH_ERR
1994 if (secret) {
1995 // Check all possible types of verification codes.
1996 switch (check_scratch_codes(pamh, ¶ms, secret_filename, &updated, buf, code)) {
1997 case 1:
1998 if (hotp_counter > 0) {
1999 switch (check_counterbased_code(pamh, secret_filename, &updated,
2000 &buf, secret, secretLen, code,
2001 hotp_counter,
2002 &must_advance_counter)) {
2003 case 0:
2004 rc = PAM_SUCCESS;
2005 break;
2006 case 1:
2007 goto invalid;
2008 default:
2009 break;
2010 }
2011 } else {
2012 switch (check_timebased_code(pamh, secret_filename, &updated, &buf,
2013 secret, secretLen, code, ¶ms)) {
2014 case 0:
2015 rc = PAM_SUCCESS;
2016 break;
2017 case 1:
2018 goto invalid;
2019 default:
2020 break;
2021 }
2022 }
2023 break;
2024 case 0:
2025 rc = PAM_SUCCESS;
2026 break;
2027 default:
2028 break;
2029 }
2030
2031 break;
2032 }
2033 }
2034
2035 // Update the system password, if we were asked to forward
2036 // the system password. We already removed the verification
2037 // code from the end of the password.
2038 if (rc == PAM_SUCCESS && params.forward_pass) {
2039 if (!pw || pam_set_item(pamh, PAM_AUTHTOK, pw) != PAM_SUCCESS) {
2040 rc = PAM_AUTH_ERR;
2041 }
2042 }
2043
2044 // Clear out password and deallocate memory
2045 if (pw) {
2046 explicit_bzero(pw,strlen(pw));
2047 free(pw);
2048 }
2049 if (saved_pw) {
2050 explicit_bzero(saved_pw, strlen(saved_pw));
2051 free(saved_pw);
2052 }
2053
2054 // If an hotp login attempt has been made, the counter must always be
2055 // advanced by at least one, unless this has been disabled.
2056 if (!params.no_increment_hotp && must_advance_counter) {
2057 char counter_str[40];
2058 snprintf(counter_str, sizeof counter_str, "%ld", hotp_counter + 1);
2059 if (set_cfg_value(pamh, "HOTP_COUNTER", counter_str, &buf) < 0) {
2060 rc = PAM_AUTH_ERR;
2061 }
2062 updated = 1;
2063 }
2064
2065 // Display a success or error message
2066 if (rc == PAM_SUCCESS) {
2067 log_message(LOG_INFO , pamh, "Accepted google_authenticator for %s", username);
2068 if (params.grace_period != 0) {
2069 if (update_logindetails(pamh, ¶ms, &buf)) {
2070 log_message(LOG_ERR, pamh, "Failed to store grace_period timestamp in config");
2071 }
2072 }
2073 } else {
2074 log_message(LOG_ERR, pamh, "Invalid verification code for %s", username);
2075 }
2076 }
2077
2078 // If the user has not created a state file with a shared secret, and if
2079 // the administrator set the "nullok" option, this PAM module completes
2080 // without saying success or failure, without ever prompting the user.
2081 // It's not a failure since "nullok" was specified, and it's not a success
2082 // because it must be distinguishable from "good credentials given" in
2083 // case the PAM config considers this module "sufficient".
2084 // (or more complex equivalents)
2085 if (params.nullok == SECRETNOTFOUND) {
2086 rc = PAM_IGNORE;
2087 }
2088
2089 // Persist the new state.
2090 if (early_updated || updated) {
2091 int err;
2092 if ((err = write_file_contents(pamh, ¶ms, secret_filename, &orig_stat, buf))) {
2093 // Inform user of error if the error is clearly a system error
2094 // and not an auth error.
2095 char s[1024];
2096 switch (err) {
2097 case EPERM:
2098 case ENOSPC:
2099 case EROFS:
2100 case EIO:
2101 case EDQUOT:
2102 snprintf(s, sizeof(s), "Error \"%s\" while writing config", strerror(err));
2103 conv_error(pamh, s);
2104 }
2105
2106 // If allow_readonly parameter is defined than ignore write errors and
2107 // allow user to login.
2108 if (!params.allow_readonly) {
2109 // Could not persist new state. Deny access.
2110 rc = PAM_AUTH_ERR;
2111 }
2112 }
2113 }
2114
2115 out:
2116 if (params.debug) {
2117 log_message(LOG_INFO, pamh,
2118 "debug: end of google_authenticator for \"%s\". Result: %s",
2119 username, pam_strerror(pamh, rc));
2120 }
2121 if (fd >= 0) {
2122 close(fd);
2123 }
2124 if (old_gid >= 0) {
2125 if (setgroup(old_gid) >= 0 && setgroup(old_gid) == old_gid) {
2126 old_gid = -1;
2127 }
2128 }
2129 if (old_uid >= 0) {
2130 if (setuser(old_uid) < 0 || setuser(old_uid) != old_uid) {
2131 log_message(LOG_EMERG, pamh, "We switched users from %d to %d, "
2132 "but can't switch back", old_uid, uid);
2133 }
2134 }
2135 free(secret_filename);
2136
2137 // Clean up
2138 if (buf) {
2139 explicit_bzero(buf, strlen(buf));
2140 free(buf);
2141 }
2142 if (secret) {
2143 explicit_bzero(secret, secretLen);
2144 free(secret);
2145 }
2146 return rc;
2147 }
2148
2149 #ifndef UNUSED_ATTR
2150 # if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
2151 # define UNUSED_ATTR __attribute__((__unused__))
2152 # else
2153 # define UNUSED_ATTR
2154 # endif
2155 #endif
2156
pam_sm_authenticate(pam_handle_t * pamh,int flags UNUSED_ATTR,int argc,const char ** argv)2157 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED_ATTR,
2158 int argc, const char **argv) {
2159 return google_authenticator(pamh, argc, argv);
2160 }
2161
2162 PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh UNUSED_ATTR,int flags UNUSED_ATTR,int argc UNUSED_ATTR,const char ** argv UNUSED_ATTR)2163 pam_sm_setcred (pam_handle_t *pamh UNUSED_ATTR,
2164 int flags UNUSED_ATTR,
2165 int argc UNUSED_ATTR,
2166 const char **argv UNUSED_ATTR) {
2167 return PAM_SUCCESS;
2168 }
2169
2170 #ifdef PAM_STATIC
2171 struct pam_module _pam_listfile_modstruct = {
2172 MODULE_NAME,
2173 pam_sm_authenticate,
2174 pam_sm_setcred,
2175 NULL,
2176 NULL,
2177 NULL,
2178 NULL
2179 };
2180 #endif
2181 /* ---- Emacs Variables ----
2182 * Local Variables:
2183 * c-basic-offset: 2
2184 * indent-tabs-mode: nil
2185 * End:
2186 */
2187