From http://www.jwz.org/xscreensaver/xscreensaver-5.27.tar.gz
[xscreensaver] / driver / passwd-pwent.c
1 /* passwd-pwent.c --- verifying typed passwords with the OS.
2  * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #ifndef NO_LOCKING  /* whole file */
18
19 #include <stdlib.h>
20 #ifdef HAVE_UNISTD_H
21 # include <unistd.h>
22 #endif
23
24 #ifdef HAVE_CRYPT_H
25 # include <crypt.h>
26 #endif
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifndef VMS
32 # include <pwd.h>
33 # include <grp.h>
34 #else /* VMS */
35 # include "vms-pwd.h"
36 #endif /* VMS */
37
38
39 #ifdef __bsdi__
40 # include <sys/param.h>
41 # if _BSDI_VERSION >= 199608
42 #  define BSD_AUTH
43 # endif
44 #endif /* __bsdi__ */
45
46
47 #if defined(HAVE_SHADOW_PASSWD)       /* passwds live in /etc/shadow */
48
49 #   include <shadow.h>
50 #   define PWTYPE   struct spwd *
51 #   define PWPSLOT  sp_pwdp
52 #   define GETPW    getspnam
53
54 #elif defined(HAVE_ENHANCED_PASSWD)      /* passwds live in /tcb/files/auth/ */
55                                       /* M.Matsumoto <matsu@yao.sharp.co.jp> */
56 #   include <sys/security.h>
57 #   include <prot.h>
58
59 #   define PWTYPE   struct pr_passwd *
60 #   define PWPSLOT  ufld.fd_encrypt
61 #   define GETPW    getprpwnam
62
63 #elif defined(HAVE_ADJUNCT_PASSWD)
64
65 #   include <sys/label.h>
66 #   include <sys/audit.h>
67 #   include <pwdadj.h>
68
69 #   define PWTYPE   struct passwd_adjunct *
70 #   define PWPSLOT  pwa_passwd
71 #   define GETPW    getpwanam
72
73 #elif defined(HAVE_HPUX_PASSWD)
74
75 #   include <hpsecurity.h>
76 #   include <prot.h>
77
78 #   define PWTYPE   struct s_passwd *
79 #   define PWPSLOT  pw_passwd
80 #   define GETPW    getspwnam
81
82 #   define HAVE_BIGCRYPT
83
84 #endif
85
86
87 /* blargh */
88 #undef  Bool
89 #undef  True
90 #undef  False
91 #define Bool  int
92 #define True  1
93 #define False 0
94
95
96 extern const char *blurb(void);
97
98 static char *encrypted_root_passwd = 0;
99 static char *encrypted_user_passwd = 0;
100
101 #ifdef VMS
102 # define ROOT "SYSTEM"
103 #else
104 # define ROOT "root"
105 #endif
106
107 #ifndef VMS
108 Bool pwent_priv_init (int argc, char **argv, Bool verbose_p);
109 Bool pwent_lock_init (int argc, char **argv, Bool verbose_p);
110 Bool pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
111 #endif
112
113
114 #ifndef VMS
115
116 static char *
117 user_name (void)
118 {
119   /* I think that just checking $USER here is not the best idea. */
120
121   const char *u = 0;
122
123   /* It has been reported that getlogin() returns the wrong user id on some
124      very old SGI systems...  And I've seen it return the string "rlogin"
125      sometimes!  Screw it, using getpwuid() should be enough...
126    */
127 /* u = (char *) getlogin ();
128  */
129
130   /* getlogin() fails if not attached to a terminal; in that case, use
131      getpwuid().  (Note that in this case, we're not doing shadow stuff, since
132      all we're interested in is the name, not the password.  So that should
133      still work.  Right?) */
134   if (!u || !*u)
135     {
136       struct passwd *p = getpwuid (getuid ());
137       u = (p ? p->pw_name : 0);
138     }
139
140   return (u ? strdup(u) : 0);
141 }
142
143 #else  /* VMS */
144
145 static char *
146 user_name (void)
147 {
148   char *u = getenv("USER");
149   return (u ? strdup(u) : 0);
150 }
151
152 #endif /* VMS */
153
154
155 static Bool
156 passwd_known_p (const char *pw)
157 {
158   return (pw &&
159           pw[0] != '*' &&       /* This would be sensible...         */
160           strlen(pw) > 4);      /* ...but this is what Solaris does. */
161 }
162
163
164 static char *
165 get_encrypted_passwd(const char *user)
166 {
167   char *result = 0;
168
169 #ifdef PWTYPE
170   if (user && *user && !result)
171     {                                   /* First check the shadow passwords. */
172       PWTYPE p = GETPW((char *) user);
173       if (p && passwd_known_p (p->PWPSLOT))
174         result = strdup(p->PWPSLOT);
175     }
176 #endif /* PWTYPE */
177
178   if (user && *user && !result)
179     {                                   /* Check non-shadow passwords too. */
180       struct passwd *p = getpwnam(user);
181       if (p && passwd_known_p (p->pw_passwd))
182         result = strdup(p->pw_passwd);
183     }
184
185   /* The manual for passwd(4) on HPUX 10.10 says:
186
187           Password aging is put in effect for a particular user if his
188           encrypted password in the password file is followed by a comma and
189           a nonnull string of characters from the above alphabet.  This
190           string defines the "age" needed to implement password aging.
191
192      So this means that passwd->pw_passwd isn't simply a string of cyphertext,
193      it might have trailing junk.  So, if there is a comma in the string, and
194      that comma is beyond position 13, terminate the string before the comma.
195    */
196   if (result && strlen(result) > 13)
197     {
198       char *s = strchr (result+13, ',');
199       if (s)
200         *s = 0;
201     }
202
203 #ifndef HAVE_PAM
204   /* We only issue this warning if not compiled with support for PAM.
205      If we're using PAM, it's not unheard of that normal pwent passwords
206      would be unavailable. */
207
208   if (!result)
209     fprintf (stderr, "%s: couldn't get password of \"%s\"\n",
210              blurb(), (user ? user : "(null)"));
211 #endif /* !HAVE_PAM */
212
213   return result;
214 }
215
216
217
218 /* This has to be called before we've changed our effective user ID,
219    because it might need privileges to get at the encrypted passwords.
220    Returns false if we weren't able to get any passwords, and therefore,
221    locking isn't possible.  (It will also have written to stderr.)
222  */
223
224 #ifndef VMS
225
226 Bool
227 pwent_priv_init (int argc, char **argv, Bool verbose_p)
228 {
229   char *u;
230
231 #ifdef HAVE_ENHANCED_PASSWD
232   set_auth_parameters(argc, argv);
233   check_auth_parameters();
234 #endif /* HAVE_DEC_ENHANCED */
235
236   u = user_name();
237   encrypted_user_passwd = get_encrypted_passwd(u);
238   encrypted_root_passwd = get_encrypted_passwd(ROOT);
239   if (u) free (u);
240
241   if (encrypted_user_passwd)
242     return True;
243   else
244     return False;
245 }
246
247
248 Bool
249 pwent_lock_init (int argc, char **argv, Bool verbose_p)
250 {
251   if (encrypted_user_passwd)
252     return True;
253   else
254     return False;
255 }
256
257
258
259 static Bool
260 passwds_match_p (const char *cleartext, const char *ciphertext)
261 {
262   char *s = 0;  /* note that on some systems, crypt() may return null */
263
264   s = (char *) crypt (cleartext, ciphertext);
265   if (s && !strcmp (s, ciphertext))
266     return True;
267
268 #ifdef HAVE_BIGCRYPT
269   /* There seems to be no way to tell at runtime if an HP machine is in
270      "trusted" mode, and thereby, which of crypt() or bigcrypt() we should
271      be calling to compare passwords.  So call them both, and see which
272      one works. */
273
274   s = (char *) bigcrypt (cleartext, ciphertext);
275   if (s && !strcmp (s, ciphertext))
276     return True;
277
278 #endif /* HAVE_BIGCRYPT */
279   
280   return False;
281 }
282
283
284
285 /* This can be called at any time, and says whether the typed password
286    belongs to either the logged in user (real uid, not effective); or
287    to root.
288  */
289 Bool
290 pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
291 {
292   if (encrypted_user_passwd &&
293       passwds_match_p (typed_passwd, encrypted_user_passwd))
294     return True;
295
296 #ifdef ALLOW_ROOT_PASSWD
297   /* do not allow root to have a null password. */
298   else if (typed_passwd[0] &&
299            encrypted_root_passwd &&
300            passwds_match_p (typed_passwd, encrypted_root_passwd))
301     return True;
302 #endif /* ALLOW_ROOT_PASSWD */
303
304   else
305     return False;
306 }
307
308 #else  /* VMS */
309 Bool pwent_lock_init (int argc, char **argv, Bool verbose_p) { return True; }
310 #endif /* VMS */
311
312 #endif /* NO_LOCKING -- whole file */