ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.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 #ifndef HAVE_PAM
199   /* We only issue this warning if not compiled with support for PAM.
200      If we're using PAM, it's not unheard of that normal pwent passwords
201      would be unavailable. */
202
203   if (!result)
204     fprintf (stderr, "%s: couldn't get password of \"%s\"\n",
205              blurb(), (user ? user : "(null)"));
206 #endif /* !HAVE_PAM */
207
208   return result;
209 }
210
211
212
213 /* This has to be called before we've changed our effective user ID,
214    because it might need privileges to get at the encrypted passwords.
215    Returns false if we weren't able to get any passwords, and therefore,
216    locking isn't possible.  (It will also have written to stderr.)
217  */
218
219 #ifndef VMS
220
221 Bool
222 pwent_priv_init (int argc, char **argv, Bool verbose_p)
223 {
224   char *u;
225
226 #ifdef HAVE_ENHANCED_PASSWD
227   set_auth_parameters(argc, argv);
228   check_auth_parameters();
229 #endif /* HAVE_DEC_ENHANCED */
230
231   u = user_name();
232   encrypted_user_passwd = get_encrypted_passwd(u);
233   encrypted_root_passwd = get_encrypted_passwd(ROOT);
234   if (u) free (u);
235
236   if (encrypted_user_passwd)
237     return True;
238   else
239     return False;
240 }
241
242
243 Bool
244 pwent_lock_init (int argc, char **argv, Bool verbose_p)
245 {
246   if (encrypted_user_passwd)
247     return True;
248   else
249     return False;
250 }
251
252
253
254 static Bool
255 passwds_match_p (const char *cleartext, const char *ciphertext)
256 {
257   char *s = 0;  /* note that on some systems, crypt() may return null */
258
259   s = (char *) crypt (cleartext, ciphertext);
260   if (s && !strcmp (s, ciphertext))
261     return True;
262
263 #ifdef HAVE_BIGCRYPT
264   /* There seems to be no way to tell at runtime if an HP machine is in
265      "trusted" mode, and thereby, which of crypt() or bigcrypt() we should
266      be calling to compare passwords.  So call them both, and see which
267      one works. */
268
269   s = (char *) bigcrypt (cleartext, ciphertext);
270   if (s && !strcmp (s, ciphertext))
271     return True;
272
273 #endif /* HAVE_BIGCRYPT */
274   
275   return False;
276 }
277
278
279
280 /* This can be called at any time, and says whether the typed password
281    belongs to either the logged in user (real uid, not effective); or
282    to root.
283  */
284 Bool
285 pwent_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
286 {
287   if (encrypted_user_passwd &&
288       passwds_match_p (typed_passwd, encrypted_user_passwd))
289     return True;
290
291   /* do not allow root to have a null password. */
292   else if (typed_passwd[0] &&
293            encrypted_root_passwd &&
294            passwds_match_p (typed_passwd, encrypted_root_passwd))
295     return True;
296
297   else
298     return False;
299 }
300
301 #else  /* VMS */
302 Bool pwent_lock_init (int argc, char **argv, Bool verbose_p) { return True; }
303 #endif /* VMS */
304
305 #endif /* NO_LOCKING -- whole file */