From http://www.jwz.org/xscreensaver/xscreensaver-5.27.tar.gz
[xscreensaver] / driver / passwd-helper.c
1 /* passwd-helper.c --- verifying typed passwords with external helper program
2  * written by Olaf Kirch <okir@suse.de>
3  * xscreensaver, Copyright (c) 1993-2005 Jamie Zawinski <jwz@jwz.org>
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation.  No representations are made about the suitability of this
10  * software for any purpose.  It is provided "as is" without express or 
11  * implied warranty.
12  */
13
14 /* The idea here is to be able to run xscreensaver without any setuid bits.
15  * Password verification happens through an external program that you feed
16  * your password to on stdin.  The external command is invoked with a user
17  * name argument.
18  *
19  * The external helper does whatever authentication is necessary.  Currently,
20  * SuSE uses "unix2_chkpwd", which is a variation of "unix_chkpwd" from the
21  * PAM distribution.
22  *
23  * Normally, the password helper should just authenticate the calling user
24  * (i.e. based on the caller's real uid).  This is in order to prevent
25  * brute-forcing passwords in a shadow environment.  A less restrictive
26  * approach would be to allow verifying other passwords as well, but always
27  * with a 2 second delay or so.  (Not sure what SuSE's "unix2_chkpwd"
28  * currently does.)
29  *                         -- Olaf Kirch <okir@suse.de>, 16-Dec-2003
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #ifndef NO_LOCKING  /* whole file */
37
38 #include <X11/Xlib.h>           /* not used for much... */
39
40 /* This file doesn't need the Xt headers, so stub these types out... */
41 #undef XtPointer
42 #define XtAppContext void*
43 #define XrmDatabase  void*
44 #define XtIntervalId void*
45 #define XtPointer    void*
46 #define Widget       void*
47
48 #include "xscreensaver.h"
49
50 #include <stdlib.h>
51 #ifdef HAVE_UNISTD_H
52 # include <unistd.h>
53 #endif
54
55 #include <stdio.h>
56 #include <string.h>
57 #include <sys/types.h>
58 #include <pwd.h>
59 #include <errno.h>
60
61 #include <sys/wait.h>
62
63 static int
64 ext_run (const char *user, const char *typed_passwd, int verbose_p)
65 {
66   int pfd[2], status;
67   pid_t pid;
68
69   if (pipe(pfd) < 0)
70     return 0;
71
72   if (verbose_p)
73     fprintf (stderr, "%s: ext_run (%s, %s)\n",
74              blurb(), PASSWD_HELPER_PROGRAM, user);
75
76   block_sigchld();
77
78   if ((pid = fork()) < 0) {
79     close(pfd[0]);
80     close(pfd[1]);
81     return 0;
82   }
83
84   if (pid == 0) {
85     close(pfd[1]);
86     if (pfd[0] != 0)
87       dup2(pfd[0], 0);
88
89     /* Helper is invoked as helper service-name [user] */
90     execlp(PASSWD_HELPER_PROGRAM, PASSWD_HELPER_PROGRAM, "xscreensaver", user, NULL);
91     if (verbose_p)
92       fprintf(stderr, "%s: %s\n", PASSWD_HELPER_PROGRAM,
93                 strerror(errno));
94     exit(1);
95   }
96
97   close(pfd[0]);
98
99   /* Write out password to helper process */
100   if (!typed_passwd)
101     typed_passwd = "";
102   write(pfd[1], typed_passwd, strlen(typed_passwd));
103   close(pfd[1]);
104
105   while (waitpid(pid, &status, 0) < 0) {
106     if (errno == EINTR)
107       continue;
108     if (verbose_p)
109       fprintf(stderr, "%s: ext_run: waitpid failed: %s\n",
110                 blurb(), strerror(errno));
111     unblock_sigchld();
112     return 0;
113   }
114
115   unblock_sigchld();
116
117   if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
118     return 0;
119   return 1;
120 }
121
122
123
124 /* This can be called at any time, and says whether the typed password
125    belongs to either the logged in user (real uid, not effective); or
126    to root.
127  */
128 int
129 ext_passwd_valid_p (const char *typed_passwd, int verbose_p)
130 {
131   struct passwd *pw;
132   int res = 0;
133
134   if ((pw = getpwuid(getuid())) != NULL)
135     res = ext_run (pw->pw_name, typed_passwd, verbose_p);
136   endpwent();
137
138 #ifdef ALLOW_ROOT_PASSWD
139   if (!res)
140     res = ext_run ("root", typed_passwd, verbose_p);
141 #endif /* ALLOW_ROOT_PASSWD */
142
143   return res;
144 }
145
146
147 int 
148 ext_priv_init (int argc, char **argv, int verbose_p)
149 {
150   /* Make sure the passwd helper exists */
151   if (access(PASSWD_HELPER_PROGRAM, X_OK) < 0) {
152     fprintf(stderr,
153                 "%s: warning: %s does not exist.\n"
154                 "%s: password authentication via "
155                         "external helper will not work.\n",
156                 blurb(), PASSWD_HELPER_PROGRAM, blurb());
157     return 0;
158   }
159   return 1;
160 }
161
162 #endif /* NO_LOCKING -- whole file */