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