2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: validate.c /main/4 1995/10/27 16:19:47 rswiston $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: HP Visual User Environment (DT)
31 ** Description: Dtgreet BLS user authentication routines
33 ** These routines validate the user; checking name, password,
34 ** number of users on the system, password aging, etc.
37 ** (c) Copyright 1987, 1988, 1989 by Hewlett-Packard Company
40 ** Conditional compiles:
43 ** HP-UX 7.0/7.03 restricted license counting algorithms
44 ** are used. Otherwise HP-UX 8.0 and beyond is used
46 ** BLS HP BLS B1 simple authentication.
48 ** __hpux HP-UX OS only
50 ****************************************************************************
51 ************************************<+>*************************************/
55 /***************************************************************************
59 ***************************************************************************/
70 /***************************************************************************
72 * HP-UX BLS authentication routines
74 ***************************************************************************/
76 #include <sys/param.h> /* for MAXUID macro */
77 #include <sys/types.h>
78 #include <sys/utsname.h>
85 /* BLS only headers */
86 # include <sys/security.h>
91 #define how_to_count ut_exit.e_exit
94 static int num_users[] = { 2, 32767 };
95 # define MIN_VERSION 'A'
96 # define UNLIMITED 'B'
98 static int num_users[] = { 2, 16, 32, 64 , 8 };
99 # define MIN_VERSION 'A'
100 # define UNLIMITED 'U'
103 /* Maximum number of users allowed with restricted license */
104 #if OSMAJORVERSION < 8
105 # define MAX_STRICT_USERS 2
107 # define MAX_STRICT_USERS 8
110 #define NUM_VERSIONS (sizeof(num_users)/sizeof(num_users[0])) - 1
114 /***************************************************************************
116 * External declarations
118 ***************************************************************************/
120 extern Widget focusWidget; /* login or password text field */
122 extern long groups[NGROUPS];
125 /***************************************************************************
127 * Procedure declarations
129 ***************************************************************************/
131 static int CheckPassword( char *name, char *passwd );
132 static int CountUsers( int added_users) ;
133 static int CountUsersStrict( char *new_user) ;
134 static void WriteBtmp( char *name) ;
139 /***************************************************************************
143 ***************************************************************************/
146 struct pr_passwd *b1_pwd;
147 struct verify_info verify_data;
148 struct verify_info *verify = &verify_data;
149 struct greet_info greet_data;
150 struct greet_info *greet = &greet_data;
151 static int UserHasPassword = 1;
154 /***************************************************************************
158 * see if new user has exceeded the maximum.
159 ***************************************************************************/
164 CountUsers( int added_users )
166 int count[NCOUNT], nusers, i;
169 for (i=0; i<NCOUNT; i++)
172 count[added_users]++;
174 while ( (entry = getutent()) != NULL) {
175 if (entry->ut_type == USER_PROCESS) {
176 i = entry->how_to_count;
177 if (i < 0 || i >= NCOUNT)
178 i = 1; /* if out of range, then count */
179 /* as ordinary user */
187 * [0] does not count at all
188 * [1] counts as real user
189 * [2] logins via a pty which have not gone trough login. These
190 * collectively count as 1 user IF count[3] is 0, otherwise,
191 * they are not counted. Starting with HP-UX 8.0 they are
192 * no longer counted at all.
193 * [3] logins via a pty which have been logged through login (i.e.
194 * rlogin and telnet). these count as 1 "real" user per
196 * [4-15] may be used for groups of users which collectively
201 #if OSMAJORVERSION < 8
202 for (i=2; i<NCOUNT; i++)
204 for (i=3; i<NCOUNT; i++)
215 /***************************************************************************
219 * see if new user has exceeded the maximum.
220 ***************************************************************************/
223 CountUsersStrict( char *new_user )
225 char pty_users[MAX_STRICT_USERS][8];
226 int count[NCOUNT], nusers, i, cnt, pty_off = -1, uname_off;
230 * Initialize count array...
232 for (i = 0; i < NCOUNT; i++)
236 * Add in the new user (we know it's not a pty)...
240 while ( (entry = getutent()) != NULL ) {
241 if (entry->ut_type == USER_PROCESS) {
242 i = entry->how_to_count;
244 /* if out of range, then count as ordinary user logged in
246 if (i == 1 || (i < 0 || i >= NCOUNT))
248 /* See if it is a pty login granted by login program */
251 /* See if user is already logged in via login pty */
253 for (cnt = 0; cnt <= pty_off; cnt++)
254 if (strncmp(pty_users[cnt], entry->ut_user, 8) == 0)
257 if (uname_off == -1) { /* user is not logged in via pty yet */
259 if (pty_off >= MAX_STRICT_USERS) /* cannot add any
261 return(MAX_STRICT_USERS + 1);
262 /* add the user name to the array of pty users */
264 strncpy(pty_users[++pty_off], entry->ut_user, 8);
266 } /* end if (i == 3) */
269 } /* end if entry->ut_type == USER_PROCESS */
270 } /* end while (entry = getutent()) */
275 * [0] does not count at all
276 * [1] counts as "real" user
277 * [2] logins via a pty which have not gone trough login. These
278 * collectively count as 1 user IF count[3] is 0, otherwise,
279 * they are not counted. Starting with HP-UX 8.0 they are
280 * no longer counted at all.
281 * [3] logins via a pty which have been logged through login (i.e.
282 * rlogin and telnet). these count as 1 "real" user per
284 * [4-15] may be used for groups of users which collectively count
288 nusers = pty_off + 1 + count[1]; /* Current number of users is sum of
289 users logged in via tty + the
290 number of unique users logged in
291 via pty which have gone through
294 #if OSMAJORVERSION < 8
295 if ((count[3] == 0) && (count[2] != 0))
296 nusers++; /* Add 1 user for all pty logins IF
297 none of pty logins have been
298 granted by the login program */
301 * Don't count any hpterm logins (exit status of 2). We already
302 * counted all pty logins granted by the login program.
306 for (i = 4; i < NCOUNT; i++)
314 /***************************************************************************
318 * Check validity of user password.
320 ***************************************************************************/
323 CheckPassword( char *name, char *passwd )
331 * HP BLS B1 password authentication...
335 b1_pwd = getprpwnam(name);
337 if ( b1_pwd == NULL || strlen(name) == 0 ) {
338 Debug("unknown user '%s'\n", name);
339 audit_login((struct pr_passwd *)0, (struct passwd *)0,
340 dpyinfo.name, "No entry in protected password db",
346 * look up user's regular account information...
351 if ( p == NULL || strlen(name) == 0 ) {
352 Debug("unknown user '%s'\n", name);
353 audit_login((struct pr_passwd *)0, (struct passwd *)0,
354 dpyinfo.name, "No entry in password file",
359 /* verify_info has become a catchall for info needed later */
360 verify->user_name = name;
361 verify->prpwd = b1_pwd;
363 strncpy(verify->terminal, dpyinfo.name, 15);
364 verify->terminal[15]='\0';
368 Debug("Verify %s \n",name);
370 /* if the password doesn't exists, we can't check it, but
371 * the user will be forced to change it later */
372 if ( (UserHasPassword = password_exists(verify)) != 0 )
373 if ( strcmp(bigcrypt(passwd,b1_pwd->ufld.fd_encrypt),
374 b1_pwd->ufld.fd_encrypt) ) {
375 Debug("verify failed\n");
376 audit_login( b1_pwd, p ,dpyinfo.name,
377 "Password incorrect",
381 Debug ("username/password verify succeeded\n");
385 * all password checks failed...
395 /***************************************************************************
401 * return codes indicate authentication results.
402 ***************************************************************************/
404 #define MAXATTEMPTS 3
406 static struct passwd nouser = {"", "nope"}; /* invalid user password struct */
409 BLS_Verify( char *name, char *passwd )
412 static int login_attempts = 0; /* # failed authentications */
414 struct passwd *p; /* password structure */
415 struct pr_passwd *prpwd;
417 struct utsname utsnam;
422 * Desparate maneuvre to give dtgreet the privledges it needs
424 if ( login_attempts == 0 ) {
425 Debug("Setting luid for dtgreet\n");
426 if ( getluid() == -1 )
431 * validate password...
434 if ( CheckPassword(name, passwd) == FALSE) {
436 if ( focusWidget == passwd_text ) {
440 if ((++login_attempts % MAXATTEMPTS) == 0 ) {
442 if (p->pw_name == NULL )
445 audit_login( b1_pwd, p ,dpyinfo.name,
446 "Failed login(bailout)",
450 } else if ( !UserHasPassword ) {
452 * The user has not password -- this must be the initial login for this
453 * user. Treat it like an expired password. This should invoke the
454 * password program on behalf of the user.
457 return VF_PASSWD_AGED;
462 prpwd = verify->prpwd;
465 /* check that the uid of both passwd and pr_passwd struct's agree */
467 if (uid != prpwd->ufld.fd_uid) {
468 audit_login(prpwd, p, verify->terminal,
469 "User id's inconsistent across password database\n",
471 Debug("login failed - uid's do not match\n");
476 /* check if user's account is locked
477 * This can be by dead password (lifetime exceeded),
478 * fd_lock is set, or fd_max_tries is exceeded.
479 * locked_out is from libsec, but is poorly documented.
481 if (locked_out(prpwd)) {
482 Debug("Account locked\n");
483 audit_login(prpwd, p, verify->terminal,
484 "Account locked", ES_LOGIN_FAILED);
487 /* can user log in at this time?
488 * time_lock is in libsec, but poorly documented
490 if (time_lock(prpwd)) {
491 Debug("Account time-locked\n");
492 audit_login(prpwd, p, verify->terminal,
493 "Account time-locked", ES_LOGIN_FAILED);
497 /****************************************************
498 xdm checks the security level here using
500 We do it later from the dtgreet callback rountine
501 VerifySensitivityLevel()
502 ****************************************************/
506 * check restricted license...
508 * Note: This only applies to local displays. Foreign displays
509 * (i.e. X-terminals) apparently do not count.
512 /* Get the version info via uname. If it doesn't look right,
513 * assume the smallest user configuration
516 if (getenv(LOCATION) != NULL) {
517 if (uname(&utsnam) < 0)
518 utsnam.version[0] = MIN_VERSION;
530 if ((!strncmp(utsnam.machine, "9000/834", UTSLEN)) ||
531 (!strncmp(utsnam.machine, "9000/844", UTSLEN)) ||
532 (!strncmp(utsnam.machine, "9000/836", UTSLEN)) ||
533 (!strncmp(utsnam.machine, "9000/846", UTSLEN)) ||
534 (!strncmp(utsnam.machine, "9000/843", UTSLEN)) ||
535 (!strncmp(utsnam.machine, "9000/853", UTSLEN))) {
537 /* strict_count = 1;*/
538 if (CountUsersStrict(name) > MAX_STRICT_USERS) {
539 audit_login( b1_pwd, p ,dpyinfo.name,
540 "Attempted to login - too many users on the system",
542 return(VF_MAX_USERS);
546 if (utsnam.version[0] != UNLIMITED) {
547 if ((utsnam.version[0]-'A' < 0) ||
548 (utsnam.version[0]-'A' > NUM_VERSIONS))
549 utsnam.version[0] = MIN_VERSION;
551 n = (int) utsnam.version[0] - 'A';
552 if (CountUsers(1) > num_users[n]) {
553 audit_login( b1_pwd, p ,dpyinfo.name,
554 "Attempted to login - too many users on the system",
556 return(VF_MAX_USERS);
565 * check password aging...
568 if ( passwordExpired(verify)) {
569 audit_login( b1_pwd, p ,dpyinfo.name,
572 return(VF_PASSWD_AGED);
577 * verify home directory exists...
580 if(chdir(p->pw_dir) < 0) {
581 Debug("Attempted to login -- no home directory\n");
582 audit_login( b1_pwd, p ,dpyinfo.name,
583 " Attempted to login - no home directory",
589 * validate uid and gid...
592 getGroups(greet->name, verify, p->pw_gid);
594 verify->gid = pwd->pw_gid;
596 if ((p->pw_gid < 0) ||
597 (p->pw_gid > MAXUID) ||
598 (setgid(p->pw_gid) == -1)) {
600 Debug("Attempted to login -- bad group id");
601 audit_login( b1_pwd, p ,dpyinfo.name,
602 "Attempted to login - bad group id",
608 if ((p->pw_uid < 0) ||
609 (p->pw_uid > MAXUID) ||
610 (setresuid(p->pw_uid, p->pw_uid, 0) == -1)) {
612 Debug("Attempted to login -- bad user id\n");
613 audit_login( b1_pwd, p ,dpyinfo.name,
614 "Attempted to login - bad user id",
624 Debug ("Successful login\n");
625 audit_login( b1_pwd, p ,dpyinfo.name,
634 /***************************************************************************
638 * log bad login attempts
640 ***************************************************************************/
643 WriteBtmp( char *name )
646 struct utmp utmp, *u;
650 bzero(&utmp, sizeof(struct utmp));
652 utmp.ut_pid = getppid();
653 while ((u = getutent()) != NULL) {
654 if ( (u->ut_type == INIT_PROCESS ||
655 u->ut_type == LOGIN_PROCESS ||
656 u->ut_type == USER_PROCESS) &&
657 u->ut_pid == utmp.ut_pid ) {
666 * if no utmp entry, this may be an X-terminal. Construct a utmp
671 strncpy(utmp.ut_id, "??", sizeof(utmp.ut_id));
672 strncpy(utmp.ut_line, dpyinfo.name, sizeof(utmp.ut_line));
673 utmp.ut_type = LOGIN_PROCESS;
674 strncpy(utmp.ut_host, dpyinfo.name, sizeof(utmp.ut_host));
680 * If btmp exists, then record the bad attempt
682 if ( (fd = open(BTMP_FILE,O_WRONLY|O_APPEND)) >= 0) {
683 strncpy(u->ut_user, name, sizeof(u->ut_user));
684 (void) time(&u->ut_time);
685 write(fd, (char *)u, sizeof(utmp));
689 endutent(); /* Close utmp file */
693 /***************************************************************************
695 * VerifySensitivityLevel
697 * verify B1 Sensitivity Level
698 **************************************************************************/
699 extern char *sensitivityLevel;
702 VerifySensitivityLevel( void)
707 greet->b1security = sensitivityLevel =
708 (char *) XmTextFieldGetString(passwd_text);
710 /* new functions: (side effects: auditing, change verify) */
711 if (verify_user_seclevel(verify, sensitivityLevel)
712 && verify_sec_xterm(verify, sensitivityLevel)) {
714 Debug("verify_user_seclevel succeeded.\n");
718 Debug("verify_user_seclevel failed\n");
719 return (VF_BAD_SEN_LEVEL);
724 groupMember ( char *name, char **members )
727 if (!strcmp (name, *members))
734 getGroups ( char *name, struct verify_info *verify, int gid)
741 verify->groups[ngroups++] = gid;
743 while (g = getgrent()) {
745 * make the list unique
747 for (i = 0; i < ngroups; i++)
748 if (verify->groups[i] == g->gr_gid)
752 if (groupMember (name, g->gr_mem)) {
753 if (ngroups >= NGROUPS)
754 LogError ("%s belongs to more than %d groups, %s ignored\n",
755 name, NGROUPS, g->gr_name);
757 verify->groups[ngroups++] = g->gr_gid;
760 verify->ngroups = ngroups;
765 /* check whether the password has expired or not.
766 * return 1 means that the password has expired.
769 passwordExpired( struct verify_info *verify)
771 struct pr_passwd *pr;
774 time_t expiration_time;
777 struct pr_passwd save_data;
778 struct pr_default *df;
785 * If null password, do not check expiration.
788 if (!pr->uflg.fg_encrypt || (pr->ufld.fd_encrypt[0] == '\0'))
791 now = time((long *) 0);
793 if (pr->uflg.fg_schange)
794 last_change = pr->ufld.fd_schange;
796 last_change = (time_t) 0;
798 if (pr->uflg.fg_expire)
799 expiration = pr->ufld.fd_expire;
800 else if (pr->sflg.fg_expire)
801 expiration = pr->sfld.fd_expire;
803 expiration = (time_t) 0;
805 df = getprdfnam(AUTH_DEFAULT);
808 * A 0 or missing expiration field means there is no
811 expiration_time = expiration ? last_change + expiration : 0;
813 if (expiration_time && now > expiration_time ) {
815 * The password has expired
817 Debug("The password is expired\n");
821 Debug("The password is not expired\n");
826 /***************************************************************************
828 * end HP-UX authentication routines
830 ***************************************************************************/