http://ftp.x.org/contrib/applications/xscreensaver-3.10.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
108
109 #ifndef VMS
110
111 static char *
112 user_name (void)
113 {
114   /* I think that just checking $USER here is not the best idea. */
115
116   const char *u = 0;
117
118   /* It has been reported that getlogin() returns the wrong user id on some
119      very old SGI systems...  And I've seen it return the string "rlogin"
120      sometimes!  Screw it, using getpwuid() should be enough...
121    */
122 /* u = (char *) getlogin ();
123  */
124
125   /* getlogin() fails if not attached to a terminal; in that case, use
126      getpwuid().  (Note that in this case, we're not doing shadow stuff, since
127      all we're interested in is the name, not the password.  So that should
128      still work.  Right?) */
129   if (!u || !*u)
130     {
131       struct passwd *p = getpwuid (getuid ());
132       u = (p ? p->pw_name : 0);
133     }
134
135   return (u ? strdup(u) : 0);
136 }
137
138 #else  /* VMS */
139
140 static char *
141 user_name (void)
142 {
143   char *u = getenv("USER");
144   return (u ? strdup(u) : 0);
145 }
146
147 #endif /* VMS */
148
149
150 static Bool
151 passwd_known_p (const char *pw)
152 {
153   return (pw &&
154           pw[0] != '*' &&       /* This would be sensible...         */
155           strlen(pw) > 4);      /* ...but this is what Solaris does. */
156 }
157
158
159 static char *
160 get_encrypted_passwd(const char *user)
161 {
162   char *result = 0;
163
164 #ifdef PWTYPE
165   if (user && *user && !result)
166     {                                   /* First check the shadow passwords. */
167       PWTYPE p = GETPW((char *) user);
168       if (p && passwd_known_p (p->PWPSLOT))
169         result = strdup(p->PWPSLOT);
170     }
171 #endif /* PWTYPE */
172
173   if (user && *user && !result)
174     {                                   /* Check non-shadow passwords too. */
175       struct passwd *p = getpwnam(user);
176       if (p && passwd_known_p (p->pw_passwd))
177         result = strdup(p->pw_passwd);
178     }
179
180   /* The manual for passwd(4) on HPUX 10.10 says:
181
182           Password aging is put in effect for a particular user if his
183           encrypted password in the password file is followed by a comma and
184           a nonnull string of characters from the above alphabet.  This
185           string defines the "age" needed to implement password aging.
186
187      So this means that passwd->pw_passwd isn't simply a string of cyphertext,
188      it might have trailing junk.  So, if there is a comma in the string, and
189      that comma is beyond position 13, terminate the string before the comma.
190    */
191   if (result && strlen(result) > 13)
192     {
193       char *s = strchr (result+13, ',');
194       if (s)
195         *s = 0;
196     }
197
198   if (!result)
199     fprintf (stderr, "%s: couldn't get password of \"%s\"\n",
200              blurb(), (user ? user : "(null)"));
201
202   return result;
203 }
204
205
206
207 /* This has to be called before we've changed our effective user ID,
208    because it might need privileges to get at the encrypted passwords.
209    Returns false if we weren't able to get any passwords, and therefore,
210    locking isn't possible.  (It will also have written to stderr.)
211  */
212
213 #ifndef VMS
214
215 Bool
216 pwent_priv_init (int argc, char **argv, Bool verbose_p)
217 {
218   char *u;
219
220 #ifdef HAVE_ENHANCED_PASSWD
221   set_auth_parameters(argc, argv);
222   check_auth_parameters();
223 #endif /* HAVE_DEC_ENHANCED */
224
225   u = user_name();
226   encrypted_user_passwd = get_encrypted_passwd(u);
227   encrypted_root_passwd = get_encrypted_passwd(ROOT);
228   if (u) free (u);
229
230   if (encrypted_user_passwd)
231     return True;
232   else
233     return False;
234 }
235
236
237 Bool
238 pwent_lock_init (int argc, char **argv, Bool verbose_p)
239 {
240   if (encrypted_user_passwd)
241     return True;
242   else
243     return False;
244 }
245
246
247
248 static Bool
249 passwds_match_p (const char *cleartext, const char *ciphertext)
250 {
251   char *s = 0;  /* note that on some systems, crypt() may return null */
252
253   s = (char *) crypt (cleartext, ciphertext);
254   if (s && !strcmp (s, ciphertext))
255     return True;
256
257 #ifdef HAVE_BIGCRYPT
258   /* There seems to be no way to tell at runtime if an HP machine is in
259      "trusted" mode, and thereby, which of crypt() or bigcrypt() we should
260      be calling to compare passwords.  So call them both, and see which
261      one works. */
262
263   s = (char *) bigcrypt (cleartext, ciphertext);
264   if (s && !strcmp (s, ciphertext))
265     return True;
266
267 #endif /* HAVE_BIGCRYPT */
268   
269   return False;
270 }
271
272
273
274 /* This can be called at any time, and says whether the typed password
275    belongs to either the logged in user (real uid, not effective); or
276    to root.
277  */
278 Bool
279 pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
280 {
281   if (encrypted_user_passwd &&
282       passwds_match_p (typed_passwd, encrypted_user_passwd))
283     return True;
284
285   /* do not allow root to have a null password. */
286   else if (typed_passwd[0] &&
287            encrypted_root_passwd &&
288            passwds_match_p (typed_passwd, encrypted_root_passwd))
289     return True;
290
291   else
292     return False;
293 }
294
295 #else  /* VMS */
296 Bool pwent_lock_init (int argc, char **argv, Bool verbose_p) { return True; }
297 #endif /* VMS */
298
299 #endif /* NO_LOCKING -- whole file */