Print this page
onc plus-be-gone


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /* ONC_PLUS EXTRACT START */
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * University Copyright- Copyright (c) 1982, 1986, 1988
  33  * The Regents of the University of California
  34  * All Rights Reserved
  35  *
  36  * University Acknowledgment- Portions of this document are derived from
  37  * software developed by the University of California, Berkeley, and its
  38  * contributors.
  39  */
  40 
  41 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  42 /*        All Rights Reserved   */
  43 
  44 /* ONC_PLUS EXTRACT END */
  45 
  46 /*
  47  * For a complete reference to login(1), see the manual page.  However,
  48  * login has accreted some intentionally undocumented options, which are
  49  * explained here:
  50  *
  51  * -a: This legacy flag appears to be unused.
  52  *
  53  * -f <username>: This flag was introduced by PSARC 1995/039 in support
  54  *    of Kerberos.  But it's not used by Sun's Kerberos implementation.
  55  *    It is however employed by zlogin(1), since it allows one to tell
  56  *    login: "This user is authenticated."  In the case of zlogin that's
  57  *    true because the zone always trusts the global zone.
  58  *
  59  * -z <zonename>: This flag is passed to login when zlogin(1) executes a
  60  *    zone login.  This tells login(1) to skip it's normal CONSOLE check
  61  *    (i.e. that the root login must be on /dev/console) and tells us the
  62  *    name of the zone from which the login is occurring.
  63  */
  64 
  65 #include <sys/types.h>


 149 #define ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
 150         (void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
 151 
 152 /*
 153  * Other macros
 154  */
 155 #define NMAX    sizeof (((struct utmpx *)0)->ut_name)
 156 #define HMAX    sizeof (((struct utmpx *)0)->ut_host)
 157 #define min(a, b)       (((a) < (b)) ? (a) : (b))
 158 
 159 /*
 160  * Various useful files and string constants
 161  */
 162 #define SHELL           "/usr/bin/sh"
 163 #define SHELL2          "/sbin/sh"
 164 #define SUBLOGIN        "<!sublogin>"
 165 #define LASTLOG         "/var/adm/lastlog"
 166 #define PROG_NAME       "login"
 167 #define HUSHLOGIN       ".hushlogin"
 168 
 169 /* ONC_PLUS EXTRACT START */
 170 /*
 171  * Array and Buffer sizes
 172  */
 173 #define PBUFSIZE 8      /* max significant characters in a password */
 174 /* ONC_PLUS EXTRACT END */
 175 #define MAXARGS 63      /* change value below if changing this */
 176 #define MAXARGSWIDTH 2  /* log10(MAXARGS) */
 177 #define MAXENV 1024
 178 #define MAXLINE 2048
 179 
 180 /*
 181  * Miscellaneous constants
 182  */
 183 #define ROOTUID         0
 184 #define ERROR           1
 185 #define OK              0
 186 #define LOG_ERROR       1
 187 #define DONT_LOG_ERROR  0
 188 #define TRUE            1
 189 #define FALSE           0
 190 
 191 /*
 192  * Counters for counting the number of failed login attempts
 193  */
 194 static int trys = 0;
 195 static int count = 1;
 196 
 197 /*
 198  * error value for login_exit() audit output (0 == no audit record)
 199  */
 200 static int      audit_error = 0;
 201 
 202 /*
 203  * Externs a plenty
 204  */
 205 /* ONC_PLUS EXTRACT START */
 206 extern  int     getsecretkey();
 207 /* ONC_PLUS EXTRACT START */
 208 
 209 /*
 210  * The current user name
 211  */
 212 static  char    user_name[NMAX];
 213 static  char    minusnam[16] = "-";
 214 
 215 /*
 216  * login_pid, used to find utmpx entry to update.
 217  */
 218 static pid_t    login_pid;
 219 
 220 /*
 221  * locale environments to be passed to shells.
 222  */
 223 static char *localeenv[] = {
 224         "LANG",
 225         "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
 226         "LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
 227 static int locale_envmatch(char *, char *);


 247 #endif
 248 extern char **environ;
 249 static  char inputline[MAXLINE];
 250 
 251 #define MAX_ID_LEN 256
 252 #define MAX_REPOSITORY_LEN 256
 253 #define MAX_PAMSERVICE_LEN 256
 254 
 255 static char identity[MAX_ID_LEN];
 256 static char repository[MAX_REPOSITORY_LEN];
 257 static char progname[MAX_PAMSERVICE_LEN];
 258 
 259 
 260 /*
 261  * Strings used to prompt the user.
 262  */
 263 static  char    loginmsg[] = "login: ";
 264 static  char    passwdmsg[] = "Password:";
 265 static  char    incorrectmsg[] = "Login incorrect\n";
 266 
 267 /* ONC_PLUS EXTRACT START */
 268 /*
 269  * Password file support
 270  */
 271 static  struct  passwd *pwd = NULL;
 272 static  char    remote_host[HMAX];
 273 static  char    zone_name[ZONENAME_MAX];
 274 
 275 /*
 276  * Illegal passwd entries.
 277  */
 278 static  struct  passwd nouser = { "", "no:password", (uid_t)-1 };
 279 /* ONC_PLUS EXTRACT END */
 280 
 281 /*
 282  * Log file support
 283  */
 284 static  char    *log_entry[LOGTRYS];
 285 static  int     writelog = 0;
 286 static  int     lastlogok = 0;
 287 static  struct lastlog ll;
 288 static  int     dosyslog = 0;
 289 static  int     flogin = MAXTRYS;       /* flag for SYSLOG_FAILED_LOGINS */
 290 
 291 /*
 292  * Default file toggles
 293  */
 294 static  char    *Pndefault      = "/etc/default/login";
 295 static  char    *Altshell       = NULL;
 296 static  char    *Console        = NULL;
 297 static  int     Passreqflag     = 0;
 298 
 299 #define DEFUMASK        022


 326 /*
 327  * Pass inherited environment.  Used by telnetd in support of the telnet
 328  * ENVIRON option.
 329  */
 330 static  boolean_t pflag = B_FALSE;
 331 static  boolean_t uflag = B_FALSE;
 332 static  boolean_t Rflag = B_FALSE;
 333 static  boolean_t sflag = B_FALSE;
 334 static  boolean_t Uflag = B_FALSE;
 335 static  boolean_t tflag = B_FALSE;
 336 static  boolean_t hflag = B_FALSE;
 337 static  boolean_t rflag = B_FALSE;
 338 static  boolean_t zflag = B_FALSE;
 339 
 340 /*
 341  * Remote login support
 342  */
 343 static  char    rusername[NMAX+1], lusername[NMAX+1];
 344 static  char    terminal[MAXPATHLEN];
 345 
 346 /* ONC_PLUS EXTRACT START */
 347 /*
 348  * Pre-authentication flag support
 349  */
 350 static  int     fflag;
 351 
 352 static char ** getargs(char *);
 353 
 354 static int login_conv(int, struct pam_message **,
 355     struct pam_response **, void *);
 356 
 357 static struct pam_conv pam_conv = {login_conv, NULL};
 358 static pam_handle_t *pamh;      /* Authentication handle */
 359 /* ONC_PLUS EXTRACT END */
 360 
 361 /*
 362  * Function declarations
 363  */
 364 static  void    turn_on_logging(void);
 365 static  void    defaults(void);
 366 static  void    usage(void);
 367 static  void    process_rlogin(void);
 368 /* ONC_PLUS EXTRACT START */
 369 static  void    login_authenticate();
 370 static  void    setup_credentials(void);
 371 /* ONC_PLUS EXTRACT END */
 372 static  void    adjust_nice(void);
 373 static  void    update_utmpx_entry(int);
 374 static  void    establish_user_environment(char **);
 375 static  void    print_banner(void);
 376 static  void    display_last_login_time(void);
 377 static  void    exec_the_shell(void);
 378 static  int     process_chroot_logins(void);
 379 static  void    chdir_to_dir_user(void);
 380 static  void    check_log(void);
 381 static  void    validate_account(void);
 382 static  void    doremoteterm(char *);
 383 static  int     get_options(int, char **);
 384 static  void    getstr(char *, int, char *);
 385 static  int     legalenvvar(char *);
 386 static  void    check_for_console(void);
 387 static  void    check_for_dueling_unix(char *);
 388 static  void    get_user_name(void);
 389 static  uint_t  get_audit_id(void);
 390 static  void    login_exit(int)__NORETURN;
 391 static  int     logins_disabled(char *);
 392 static  void    log_bad_attempts(void);
 393 static  int     is_number(char *);
 394 
 395 /* ONC_PLUS EXTRACT START */
 396 /*
 397  *                      *** main ***
 398  *
 399  *      The primary flow of control is directed in this routine.
 400  *      Control moves in line from top to bottom calling subfunctions
 401  *      which perform the bulk of the work.  Many of these calls exit
 402  *      when a fatal error is encountered and do not return to main.
 403  *
 404  *
 405  */
 406 
 407 int
 408 main(int argc, char *argv[], char **renvp)
 409 {
 410 /* ONC_PLUS EXTRACT END */
 411         int sublogin;
 412         int pam_rc;
 413 
 414         login_pid = getpid();
 415 
 416         /*
 417          * Set up Defaults and flags
 418          */
 419         defaults();
 420         SCPYL(progname, PROG_NAME);
 421 
 422         /*
 423          * Set up default umask
 424          */
 425         if (Umask > ((mode_t)0777))
 426                 Umask = DEFUMASK;
 427         (void) umask(Umask);
 428 
 429         /*
 430          * Set up default timeouts and delays


 452                 sublogin = 1;
 453 
 454         /*
 455          * Parse Arguments
 456          */
 457         if (get_options(argc, argv) == -1) {
 458                 usage();
 459                 audit_error = ADT_FAIL_VALUE_BAD_CMD;
 460                 login_exit(1);
 461         }
 462 
 463         /*
 464          * if devicename is not passed as argument, call ttyname(0)
 465          */
 466         if (ttyn == NULL) {
 467                 ttyn = ttyname(0);
 468                 if (ttyn == NULL)
 469                         ttyn = "/dev/???";
 470         }
 471 
 472 /* ONC_PLUS EXTRACT START */
 473         /*
 474          * Call pam_start to initiate a PAM authentication operation
 475          */
 476 
 477         if ((pam_rc = pam_start(progname, user_name, &pam_conv, &pamh))
 478             != PAM_SUCCESS) {
 479                 audit_error = ADT_FAIL_PAM + pam_rc;
 480                 login_exit(1);
 481         }
 482         if ((pam_rc = pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
 483                 audit_error = ADT_FAIL_PAM + pam_rc;
 484                 login_exit(1);
 485         }
 486         if ((pam_rc = pam_set_item(pamh, PAM_RHOST, remote_host)) !=
 487             PAM_SUCCESS) {
 488                 audit_error = ADT_FAIL_PAM + pam_rc;
 489                 login_exit(1);
 490         }
 491 
 492         /*
 493          * We currently only support special handling of the KRB5 PAM repository
 494          */
 495         if ((Rflag && strlen(repository)) &&
 496             strcmp(repository, KRB5_REPOSITORY_NAME) == 0 &&
 497             (uflag && strlen(identity))) {
 498                 krb5_repository_data_t krb5_data;
 499                 pam_repository_t pam_rep_data;
 500 
 501                 krb5_data.principal = identity;
 502                 krb5_data.flags = SUNW_PAM_KRB5_ALREADY_AUTHENTICATED;
 503 
 504                 pam_rep_data.type = repository;
 505                 pam_rep_data.scope = (void *)&krb5_data;
 506                 pam_rep_data.scope_len = sizeof (krb5_data);
 507 
 508                 (void) pam_set_item(pamh, PAM_REPOSITORY,
 509                     (void *)&pam_rep_data);
 510         }
 511 /* ONC_PLUS EXTRACT END */
 512 
 513         /*
 514          * Open the log file which contains a record of successful and failed
 515          * login attempts
 516          */
 517         turn_on_logging();
 518 
 519         /*
 520          * say "hi" to syslogd ..
 521          */
 522         openlog("login", 0, LOG_AUTH);
 523 
 524         /*
 525          * Do special processing for -r (rlogin) flag
 526          */
 527         if (rflag)
 528                 process_rlogin();
 529 
 530 /* ONC_PLUS EXTRACT START */
 531         /*
 532          * validate user
 533          */
 534         /* we are already authenticated. fill in what we must, then continue */
 535         if (fflag) {
 536 /* ONC_PLUS EXTRACT END */
 537                 if ((pwd = getpwnam(user_name)) == NULL) {
 538                         audit_error = ADT_FAIL_VALUE_USERNAME;
 539 
 540                         log_bad_attempts();
 541                         (void) printf("Login failed: unknown user '%s'.\n",
 542                             user_name);
 543                         login_exit(1);
 544                 }
 545 /* ONC_PLUS EXTRACT START */
 546         } else {
 547                 /*
 548                  * Perform the primary login authentication activity.
 549                  */
 550                 login_authenticate();
 551         }
 552 /* ONC_PLUS EXTRACT END */
 553 
 554         /* change root login, then we exec another login and try again */
 555         if (process_chroot_logins() != OK)
 556                 login_exit(1);
 557 
 558         /*
 559          * If root login and not on system console then call exit(2)
 560          */
 561         check_for_console();
 562 
 563         /*
 564          * Check to see if a shutdown is in progress, if it is and
 565          * we are not root then throw the user off the system
 566          */
 567         if (logins_disabled(user_name) == TRUE) {
 568                 audit_error = ADT_FAIL_VALUE_LOGIN_DISABLED;
 569                 login_exit(1);
 570         }
 571 
 572         if (pwd->pw_uid == 0) {


 585          * We only get here if we've been authenticated.
 586          */
 587 
 588         /*
 589          * Now we set up the environment for the new user, which includes
 590          * the users ulimit, nice value, ownership of this tty, uid, gid,
 591          * and environment variables.
 592          */
 593         if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
 594                 (void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
 595 
 596         /* di_devperm_login() sends detailed errors to syslog */
 597         if (di_devperm_login((const char *)ttyn, pwd->pw_uid, pwd->pw_gid,
 598             NULL) == -1) {
 599                 (void) fprintf(stderr, "error processing /etc/logindevperm,"
 600                     " see syslog for more details\n");
 601         }
 602 
 603         adjust_nice();          /* passwd file can specify nice value */
 604 
 605 /* ONC_PLUS EXTRACT START */
 606         setup_credentials();    /* Set user credentials  - exits on failure */
 607 
 608         /*
 609          * NOTE: telnetd and rlogind rely upon this updating of utmpx
 610          * to indicate that the authentication completed  successfully,
 611          * pam_open_session was called and therefore they are required to
 612          * call pam_close_session.
 613          */
 614         update_utmpx_entry(sublogin);
 615 
 616         /* set the real (and effective) UID */
 617         if (setuid(pwd->pw_uid) == -1) {
 618                 login_exit(1);
 619         }
 620 
 621         /*
 622          * Set up the basic environment for the exec.  This includes
 623          * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
 624          */
 625         chdir_to_dir_user();
 626 
 627         establish_user_environment(renvp);
 628 
 629         (void) pam_end(pamh, PAM_SUCCESS);      /* Done using PAM */
 630         pamh = NULL;
 631 /* ONC_PLUS EXTRACT END */
 632 
 633         if (pwd->pw_uid == 0) {
 634                 if (dosyslog) {
 635                         if (remote_host[0]) {
 636                                 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
 637                                     ttyn, HMAX, remote_host);
 638                         } else
 639                                 syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
 640                 }
 641         }
 642         closelog();
 643 
 644         (void) signal(SIGQUIT, SIG_DFL);
 645         (void) signal(SIGINT, SIG_DFL);
 646 
 647         /*
 648          * Display some useful information to the new user like the banner
 649          * and last login time if not a quiet login.
 650          */
 651 


 665 
 666         /*
 667          * Now fire off the shell of choice
 668          */
 669         exec_the_shell();
 670 
 671         /*
 672          * All done
 673          */
 674         login_exit(1);
 675         return (0);
 676 }
 677 
 678 
 679 /*
 680  *                      *** Utility functions ***
 681  */
 682 
 683 
 684 
 685 /* ONC_PLUS EXTRACT START */
 686 /*
 687  * donothing & catch        - Signal catching functions
 688  */
 689 
 690 /*ARGSUSED*/
 691 static void
 692 donothing(int sig)
 693 {
 694         if (pamh)
 695                 (void) pam_end(pamh, PAM_ABORT);
 696 }
 697 /* ONC_PLUS EXTRACT END */
 698 
 699 #ifdef notdef
 700 static  int     intrupt;
 701 
 702 /*ARGSUSED*/
 703 static void
 704 catch(int sig)
 705 {
 706         ++intrupt;
 707 }
 708 #endif
 709 
 710 /*
 711  *                      *** Bad login logging support ***
 712  */
 713 
 714 /*
 715  * badlogin()           - log to the log file 'trys'
 716  *                        unsuccessful attempts
 717  */


 798 
 799 static void
 800 turn_on_logging(void)
 801 {
 802         struct stat dbuf;
 803         int i;
 804 
 805         if (stat(LOGINLOG, &dbuf) == 0) {
 806                 writelog = 1;
 807                 for (i = 0; i < LOGTRYS; i++) {
 808                         if (!(log_entry[i] = malloc((size_t)ENT_SIZE))) {
 809                                 writelog = 0;
 810                                 break;
 811                         }
 812                         *log_entry[i] = '\0';
 813                 }
 814         }
 815 }
 816 
 817 
 818 /* ONC_PLUS EXTRACT START */
 819 /*
 820  * login_conv():
 821  *      This is the conv (conversation) function called from
 822  *      a PAM authentication module to print error messages
 823  *      or garner information from the user.
 824  */
 825 /*ARGSUSED*/
 826 static int
 827 login_conv(int num_msg, struct pam_message **msg,
 828     struct pam_response **response, void *appdata_ptr)
 829 {
 830         struct pam_message      *m;
 831         struct pam_response     *r;
 832         char                    *temp;
 833         int                     k, i;
 834 
 835         if (num_msg <= 0)
 836                 return (PAM_CONV_ERR);
 837 
 838         *response = calloc(num_msg, sizeof (struct pam_response));


 964          * PAM authenticates the user for us.
 965          */
 966         error = pam_authenticate(pamh, flag);
 967 
 968         /* get the user_name from the pam handle */
 969         (void) pam_get_item(pamh, PAM_USER, (void**)&user);
 970 
 971         if (user == NULL || *user == '\0')
 972                 return (PAM_SYSTEM_ERR);
 973 
 974         SCPYL(user_name, user);
 975         check_for_dueling_unix(user_name);
 976 
 977         if (((pwd = getpwnam(user_name)) == NULL) &&
 978             (error != PAM_USER_UNKNOWN)) {
 979                 return (PAM_SYSTEM_ERR);
 980         }
 981 
 982         return (error);
 983 }
 984 /* ONC_PLUS EXTRACT END */
 985 
 986 /*
 987  * quotec               - Called by getargs
 988  */
 989 
 990 static int
 991 quotec(void)
 992 {
 993         int c, i, num;
 994 
 995         switch (c = getc(stdin)) {
 996 
 997                 case 'n':
 998                         c = '\n';
 999                         break;
1000 
1001                 case 'r':
1002                         c = '\r';
1003                         break;
1004 


1771                                             "LOGIN FAILURES ON %s FROM %.*s ",
1772                                             " %.*s", ttyn, HMAX,
1773                                             remote_host, NMAX, pwd->pw_name);
1774                                 } else {
1775                                         syslog(LOG_CRIT,
1776                                             "LOGIN FAILURES ON %s, %.*s",
1777                                             ttyn, NMAX, pwd->pw_name);
1778                                 }
1779                         }
1780                         closelog();
1781                         (void) sleep(Disabletime);
1782                         exit(1);
1783                 } else {
1784                         (void) printf("No directory! Logging in with home=/\n");
1785                         pwd->pw_dir = "/";
1786                 }
1787         }
1788 }
1789 
1790 
1791 /* ONC_PLUS EXTRACT START */
1792 /*
1793  * login_authenticate   - Performs the main authentication work
1794  *                        1. Prints the login prompt
1795  *                        2. Requests and verifys the password
1796  *                        3. Checks the port password
1797  */
1798 
1799 static void
1800 login_authenticate(void)
1801 {
1802         char *user;
1803         int err;
1804         int login_successful = 0;
1805 
1806         do {
1807                 /* if scheme broken, then nothing to do but quit */
1808                 if (pam_get_item(pamh, PAM_USER, (void **)&user) != PAM_SUCCESS)
1809                         exit(1);
1810 
1811                 /*


1950         if ((user_name[0] == '\0') ||
1951             (initgroups(user_name, pwd->pw_gid) == -1)) {
1952                 audit_error = ADT_FAIL_VALUE_PROGRAM;
1953                 login_exit(1);
1954         }
1955 
1956         if ((error = pam_setcred(pamh, zflag ? PAM_REINITIALIZE_CRED :
1957             PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
1958                 audit_error = ADT_FAIL_PAM + error;
1959                 login_exit(error);
1960         }
1961 
1962         /*
1963          * Record successful login and fork process that records logout.
1964          * We have to do this after setting credentials because pam_setcred()
1965          * loads key audit info into the cred, but before setuid() so audit
1966          * system calls will work.
1967          */
1968         audit_success(get_audit_id(), pwd, zone_name);
1969 }
1970 /* ONC_PLUS EXTRACT END */
1971 
1972 static uint_t
1973 get_audit_id(void)
1974 {
1975         if (rflag)
1976                 return (ADT_rlogin);
1977         else if (hflag)
1978                 return (ADT_telnet);
1979         else if (zflag)
1980                 return (ADT_zlogin);
1981 
1982         return (ADT_login);
1983 }
1984 
1985 /*
1986  *
1987  *              *** Routines to get a new user set up and running ***
1988  *
1989  *                      Things to do when starting up a new user:
1990  *                              adjust_nice


2010         if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
2011                 pri = 0;
2012                 mflg = 0;
2013                 i = 4;
2014 
2015                 if (pwd->pw_gecos[i] == '-') {
2016                         mflg++;
2017                         i++;
2018                 }
2019 
2020                 while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
2021                         pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
2022 
2023                 if (mflg)
2024                         pri = -pri;
2025 
2026                 (void) nice(pri);
2027         }
2028 }
2029 
2030 /* ONC_PLUS EXTRACT START */
2031 /*
2032  * update_utmpx_entry   - Searchs for the correct utmpx entry, making an
2033  *                        entry there if it finds one, otherwise exits.
2034  */
2035 
2036 static void
2037 update_utmpx_entry(int sublogin)
2038 {
2039         int     err;
2040         char    *user;
2041         static char     *errmsg = "No utmpx entry. "
2042             "You must exec \"login\" from the lowest level \"shell\".";
2043         int     tmplen;
2044         struct utmpx  *u = (struct utmpx *)0;
2045         struct utmpx  utmpx;
2046         char    *ttyntail;
2047 
2048         /*
2049          * If we're not a sublogin then
2050          * we'll get an error back if our PID doesn't match the PID of the
2051          * entry we are updating, otherwise if its a sublogin the flags
2052          * field is set to 0, which means we just write a matching entry
2053          * (without checking the pid), or a new entry if an entry doesn't
2054          * exist.
2055          */
2056 
2057         if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
2058                 audit_error = ADT_FAIL_PAM + err;
2059                 login_exit(1);
2060         }
2061 
2062         if ((err = pam_get_item(pamh, PAM_USER, (void **) &user)) !=
2063             PAM_SUCCESS) {
2064                 audit_error = ADT_FAIL_PAM + err;
2065                 login_exit(1);
2066         }
2067 /* ONC_PLUS EXTRACT END */
2068 
2069         (void) memset((void *)&utmpx, 0, sizeof (utmpx));
2070         (void) time(&utmpx.ut_tv.tv_sec);
2071         utmpx.ut_pid = getpid();
2072 
2073         if (rflag || hflag) {
2074                 SCPYN(utmpx.ut_host, remote_host);
2075                 tmplen = strlen(remote_host) + 1;
2076                 if (tmplen < sizeof (utmpx.ut_host))
2077                         utmpx.ut_syslen = tmplen;
2078                 else
2079                         utmpx.ut_syslen = sizeof (utmpx.ut_host);
2080         } else if (zflag) {
2081                 /*
2082                  * If this is a login from another zone, put the
2083                  * zone:<zonename> string in the utmpx entry.
2084                  */
2085                 SCPYN(utmpx.ut_host, zone_name);
2086                 tmplen = strlen(zone_name) + 1;
2087                 if (tmplen < sizeof (utmpx.ut_host))


2115         }
2116         endutxent();
2117 
2118         if (u == (struct utmpx *)NULL) {
2119                 if (!sublogin) {
2120                         /*
2121                          * no utmpx entry already setup
2122                          * (init or rlogind/telnetd)
2123                          */
2124                         (void) puts(errmsg);
2125 
2126                         audit_error = ADT_FAIL_VALUE_PROGRAM;
2127                         login_exit(1);
2128                 }
2129         } else {
2130                 /* Now attempt to write out this entry to the wtmp file if */
2131                 /* we were successful in getting it from the utmpx file and */
2132                 /* the wtmp file exists.                                   */
2133                 updwtmpx(WTMPX_FILE, &utmpx);
2134         }
2135 /* ONC_PLUS EXTRACT START */
2136 }
2137 
2138 
2139 
2140 /*
2141  * process_chroot_logins        - Chroots to the specified subdirectory and
2142  *                                re executes login.
2143  */
2144 
2145 static int
2146 process_chroot_logins(void)
2147 {
2148         /*
2149          * If the shell field starts with a '*', do a chroot to the home
2150          * directory and perform a new login.
2151          */
2152 
2153         if (*pwd->pw_shell == '*') {
2154                 (void) pam_end(pamh, PAM_SUCCESS);      /* Done using PAM */
2155                 pamh = NULL;                            /* really done */
2156                 if (chroot(pwd->pw_dir) < 0) {
2157                         (void) printf("No Root Directory\n");
2158 
2159                         audit_failure(get_audit_id(),
2160                             ADT_FAIL_VALUE_CHDIR_FAILED,
2161                             pwd, remote_host, ttyn, zone_name);
2162 
2163                         return (ERROR);
2164                 }
2165                 /*
2166                  * Set the environment flag <!sublogin> so that the next login
2167                  * knows that it is a sublogin.
2168                  */
2169 /* ONC_PLUS EXTRACT END */
2170                 envinit[0] = SUBLOGIN;
2171                 envinit[1] = (char *)NULL;
2172                 (void) printf("Subsystem root: %s\n", pwd->pw_dir);
2173                 (void) execle("/usr/bin/login", "login", (char *)0,
2174                     &envinit[0]);
2175                 (void) execle("/etc/login", "login", (char *)0, &envinit[0]);
2176                 (void) printf("No /usr/bin/login or /etc/login on root\n");
2177 
2178                 audit_error = ADT_FAIL_VALUE_PROGRAM;
2179 
2180                 login_exit(1);
2181         }
2182         return (OK);
2183 /* ONC_PLUS EXTRACT START */
2184 }
2185 
2186 /*
2187  * establish_user_environment   - Set up the new users enviornment
2188  */
2189 
2190 static void
2191 establish_user_environment(char **renvp)
2192 {
2193         int i, j, k, l_index, length, idx = 0;
2194         char *endptr;
2195         char **lenvp;
2196         char **pam_env;
2197 
2198         lenvp = environ;
2199         while (*lenvp++)
2200                 ;
2201 
2202         /* count the number of PAM environment variables set by modules */
2203         if ((pam_env = pam_getenvlist(pamh)) != 0) {


2211                 (void) printf("Calloc failed - out of swap space.\n");
2212                 login_exit(8);
2213         }
2214 
2215         /*
2216          * add PAM environment variables first so they
2217          * can be overwritten at login's discretion.
2218          * check for illegal environment variables.
2219          */
2220         idx = 0;        basicenv = 0;
2221         if (pam_env != 0) {
2222                 while (pam_env[idx] != 0) {
2223                         if (legalenvvar(pam_env[idx])) {
2224                                 envinit[basicenv] = pam_env[idx];
2225                                 basicenv++;
2226                         }
2227                         idx++;
2228                 }
2229         }
2230         (void) memcpy(&envinit[basicenv], newenv, sizeof (newenv));
2231 /* ONC_PLUS EXTRACT END */
2232 
2233         /* Set up environment */
2234         if (rflag) {
2235                 ENVSTRNCAT(term, terminal);
2236         } else if (hflag) {
2237                 if (strlen(terminal)) {
2238                         ENVSTRNCAT(term, terminal);
2239                 }
2240         } else {
2241                 char *tp = getenv("TERM");
2242 
2243                 if ((tp != NULL) && (*tp != '\0'))
2244                         ENVSTRNCAT(term, tp);
2245         }
2246 
2247         ENVSTRNCAT(logname, pwd->pw_name);
2248 
2249         /*
2250          * There are three places to get timezone info.  init.c sets
2251          * TZ if the file /etc/TIMEZONE contains a value for TZ.




   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 

  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  * University Copyright- Copyright (c) 1982, 1986, 1988
  32  * The Regents of the University of California
  33  * All Rights Reserved
  34  *
  35  * University Acknowledgment- Portions of this document are derived from
  36  * software developed by the University of California, Berkeley, and its
  37  * contributors.
  38  */
  39 
  40 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  41 /*        All Rights Reserved   */
  42 


  43 /*
  44  * For a complete reference to login(1), see the manual page.  However,
  45  * login has accreted some intentionally undocumented options, which are
  46  * explained here:
  47  *
  48  * -a: This legacy flag appears to be unused.
  49  *
  50  * -f <username>: This flag was introduced by PSARC 1995/039 in support
  51  *    of Kerberos.  But it's not used by Sun's Kerberos implementation.
  52  *    It is however employed by zlogin(1), since it allows one to tell
  53  *    login: "This user is authenticated."  In the case of zlogin that's
  54  *    true because the zone always trusts the global zone.
  55  *
  56  * -z <zonename>: This flag is passed to login when zlogin(1) executes a
  57  *    zone login.  This tells login(1) to skip it's normal CONSOLE check
  58  *    (i.e. that the root login must be on /dev/console) and tells us the
  59  *    name of the zone from which the login is occurring.
  60  */
  61 
  62 #include <sys/types.h>


 146 #define ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
 147         (void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
 148 
 149 /*
 150  * Other macros
 151  */
 152 #define NMAX    sizeof (((struct utmpx *)0)->ut_name)
 153 #define HMAX    sizeof (((struct utmpx *)0)->ut_host)
 154 #define min(a, b)       (((a) < (b)) ? (a) : (b))
 155 
 156 /*
 157  * Various useful files and string constants
 158  */
 159 #define SHELL           "/usr/bin/sh"
 160 #define SHELL2          "/sbin/sh"
 161 #define SUBLOGIN        "<!sublogin>"
 162 #define LASTLOG         "/var/adm/lastlog"
 163 #define PROG_NAME       "login"
 164 #define HUSHLOGIN       ".hushlogin"
 165 

 166 /*
 167  * Array and Buffer sizes
 168  */
 169 #define PBUFSIZE 8      /* max significant characters in a password */

 170 #define MAXARGS 63      /* change value below if changing this */
 171 #define MAXARGSWIDTH 2  /* log10(MAXARGS) */
 172 #define MAXENV 1024
 173 #define MAXLINE 2048
 174 
 175 /*
 176  * Miscellaneous constants
 177  */
 178 #define ROOTUID         0
 179 #define ERROR           1
 180 #define OK              0
 181 #define LOG_ERROR       1
 182 #define DONT_LOG_ERROR  0
 183 #define TRUE            1
 184 #define FALSE           0
 185 
 186 /*
 187  * Counters for counting the number of failed login attempts
 188  */
 189 static int trys = 0;
 190 static int count = 1;
 191 
 192 /*
 193  * error value for login_exit() audit output (0 == no audit record)
 194  */
 195 static int      audit_error = 0;
 196 
 197 /*
 198  * Externs a plenty
 199  */

 200 extern  int     getsecretkey();

 201 
 202 /*
 203  * The current user name
 204  */
 205 static  char    user_name[NMAX];
 206 static  char    minusnam[16] = "-";
 207 
 208 /*
 209  * login_pid, used to find utmpx entry to update.
 210  */
 211 static pid_t    login_pid;
 212 
 213 /*
 214  * locale environments to be passed to shells.
 215  */
 216 static char *localeenv[] = {
 217         "LANG",
 218         "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
 219         "LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
 220 static int locale_envmatch(char *, char *);


 240 #endif
 241 extern char **environ;
 242 static  char inputline[MAXLINE];
 243 
 244 #define MAX_ID_LEN 256
 245 #define MAX_REPOSITORY_LEN 256
 246 #define MAX_PAMSERVICE_LEN 256
 247 
 248 static char identity[MAX_ID_LEN];
 249 static char repository[MAX_REPOSITORY_LEN];
 250 static char progname[MAX_PAMSERVICE_LEN];
 251 
 252 
 253 /*
 254  * Strings used to prompt the user.
 255  */
 256 static  char    loginmsg[] = "login: ";
 257 static  char    passwdmsg[] = "Password:";
 258 static  char    incorrectmsg[] = "Login incorrect\n";
 259 

 260 /*
 261  * Password file support
 262  */
 263 static  struct  passwd *pwd = NULL;
 264 static  char    remote_host[HMAX];
 265 static  char    zone_name[ZONENAME_MAX];
 266 
 267 /*
 268  * Illegal passwd entries.
 269  */
 270 static  struct  passwd nouser = { "", "no:password", (uid_t)-1 };

 271 
 272 /*
 273  * Log file support
 274  */
 275 static  char    *log_entry[LOGTRYS];
 276 static  int     writelog = 0;
 277 static  int     lastlogok = 0;
 278 static  struct lastlog ll;
 279 static  int     dosyslog = 0;
 280 static  int     flogin = MAXTRYS;       /* flag for SYSLOG_FAILED_LOGINS */
 281 
 282 /*
 283  * Default file toggles
 284  */
 285 static  char    *Pndefault      = "/etc/default/login";
 286 static  char    *Altshell       = NULL;
 287 static  char    *Console        = NULL;
 288 static  int     Passreqflag     = 0;
 289 
 290 #define DEFUMASK        022


 317 /*
 318  * Pass inherited environment.  Used by telnetd in support of the telnet
 319  * ENVIRON option.
 320  */
 321 static  boolean_t pflag = B_FALSE;
 322 static  boolean_t uflag = B_FALSE;
 323 static  boolean_t Rflag = B_FALSE;
 324 static  boolean_t sflag = B_FALSE;
 325 static  boolean_t Uflag = B_FALSE;
 326 static  boolean_t tflag = B_FALSE;
 327 static  boolean_t hflag = B_FALSE;
 328 static  boolean_t rflag = B_FALSE;
 329 static  boolean_t zflag = B_FALSE;
 330 
 331 /*
 332  * Remote login support
 333  */
 334 static  char    rusername[NMAX+1], lusername[NMAX+1];
 335 static  char    terminal[MAXPATHLEN];
 336 

 337 /*
 338  * Pre-authentication flag support
 339  */
 340 static  int     fflag;
 341 
 342 static char ** getargs(char *);
 343 
 344 static int login_conv(int, struct pam_message **,
 345     struct pam_response **, void *);
 346 
 347 static struct pam_conv pam_conv = {login_conv, NULL};
 348 static pam_handle_t *pamh;      /* Authentication handle */

 349 
 350 /*
 351  * Function declarations
 352  */
 353 static  void    turn_on_logging(void);
 354 static  void    defaults(void);
 355 static  void    usage(void);
 356 static  void    process_rlogin(void);

 357 static  void    login_authenticate();
 358 static  void    setup_credentials(void);

 359 static  void    adjust_nice(void);
 360 static  void    update_utmpx_entry(int);
 361 static  void    establish_user_environment(char **);
 362 static  void    print_banner(void);
 363 static  void    display_last_login_time(void);
 364 static  void    exec_the_shell(void);
 365 static  int     process_chroot_logins(void);
 366 static  void    chdir_to_dir_user(void);
 367 static  void    check_log(void);
 368 static  void    validate_account(void);
 369 static  void    doremoteterm(char *);
 370 static  int     get_options(int, char **);
 371 static  void    getstr(char *, int, char *);
 372 static  int     legalenvvar(char *);
 373 static  void    check_for_console(void);
 374 static  void    check_for_dueling_unix(char *);
 375 static  void    get_user_name(void);
 376 static  uint_t  get_audit_id(void);
 377 static  void    login_exit(int)__NORETURN;
 378 static  int     logins_disabled(char *);
 379 static  void    log_bad_attempts(void);
 380 static  int     is_number(char *);
 381 

 382 /*
 383  *                      *** main ***
 384  *
 385  *      The primary flow of control is directed in this routine.
 386  *      Control moves in line from top to bottom calling subfunctions
 387  *      which perform the bulk of the work.  Many of these calls exit
 388  *      when a fatal error is encountered and do not return to main.
 389  *
 390  *
 391  */
 392 
 393 int
 394 main(int argc, char *argv[], char **renvp)
 395 {

 396         int sublogin;
 397         int pam_rc;
 398 
 399         login_pid = getpid();
 400 
 401         /*
 402          * Set up Defaults and flags
 403          */
 404         defaults();
 405         SCPYL(progname, PROG_NAME);
 406 
 407         /*
 408          * Set up default umask
 409          */
 410         if (Umask > ((mode_t)0777))
 411                 Umask = DEFUMASK;
 412         (void) umask(Umask);
 413 
 414         /*
 415          * Set up default timeouts and delays


 437                 sublogin = 1;
 438 
 439         /*
 440          * Parse Arguments
 441          */
 442         if (get_options(argc, argv) == -1) {
 443                 usage();
 444                 audit_error = ADT_FAIL_VALUE_BAD_CMD;
 445                 login_exit(1);
 446         }
 447 
 448         /*
 449          * if devicename is not passed as argument, call ttyname(0)
 450          */
 451         if (ttyn == NULL) {
 452                 ttyn = ttyname(0);
 453                 if (ttyn == NULL)
 454                         ttyn = "/dev/???";
 455         }
 456 

 457         /*
 458          * Call pam_start to initiate a PAM authentication operation
 459          */
 460 
 461         if ((pam_rc = pam_start(progname, user_name, &pam_conv, &pamh))
 462             != PAM_SUCCESS) {
 463                 audit_error = ADT_FAIL_PAM + pam_rc;
 464                 login_exit(1);
 465         }
 466         if ((pam_rc = pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
 467                 audit_error = ADT_FAIL_PAM + pam_rc;
 468                 login_exit(1);
 469         }
 470         if ((pam_rc = pam_set_item(pamh, PAM_RHOST, remote_host)) !=
 471             PAM_SUCCESS) {
 472                 audit_error = ADT_FAIL_PAM + pam_rc;
 473                 login_exit(1);
 474         }
 475 
 476         /*
 477          * We currently only support special handling of the KRB5 PAM repository
 478          */
 479         if ((Rflag && strlen(repository)) &&
 480             strcmp(repository, KRB5_REPOSITORY_NAME) == 0 &&
 481             (uflag && strlen(identity))) {
 482                 krb5_repository_data_t krb5_data;
 483                 pam_repository_t pam_rep_data;
 484 
 485                 krb5_data.principal = identity;
 486                 krb5_data.flags = SUNW_PAM_KRB5_ALREADY_AUTHENTICATED;
 487 
 488                 pam_rep_data.type = repository;
 489                 pam_rep_data.scope = (void *)&krb5_data;
 490                 pam_rep_data.scope_len = sizeof (krb5_data);
 491 
 492                 (void) pam_set_item(pamh, PAM_REPOSITORY,
 493                     (void *)&pam_rep_data);
 494         }

 495 
 496         /*
 497          * Open the log file which contains a record of successful and failed
 498          * login attempts
 499          */
 500         turn_on_logging();
 501 
 502         /*
 503          * say "hi" to syslogd ..
 504          */
 505         openlog("login", 0, LOG_AUTH);
 506 
 507         /*
 508          * Do special processing for -r (rlogin) flag
 509          */
 510         if (rflag)
 511                 process_rlogin();
 512 

 513         /*
 514          * validate user
 515          */
 516         /* we are already authenticated. fill in what we must, then continue */
 517         if (fflag) {

 518                 if ((pwd = getpwnam(user_name)) == NULL) {
 519                         audit_error = ADT_FAIL_VALUE_USERNAME;
 520 
 521                         log_bad_attempts();
 522                         (void) printf("Login failed: unknown user '%s'.\n",
 523                             user_name);
 524                         login_exit(1);
 525                 }

 526         } else {
 527                 /*
 528                  * Perform the primary login authentication activity.
 529                  */
 530                 login_authenticate();
 531         }

 532 
 533         /* change root login, then we exec another login and try again */
 534         if (process_chroot_logins() != OK)
 535                 login_exit(1);
 536 
 537         /*
 538          * If root login and not on system console then call exit(2)
 539          */
 540         check_for_console();
 541 
 542         /*
 543          * Check to see if a shutdown is in progress, if it is and
 544          * we are not root then throw the user off the system
 545          */
 546         if (logins_disabled(user_name) == TRUE) {
 547                 audit_error = ADT_FAIL_VALUE_LOGIN_DISABLED;
 548                 login_exit(1);
 549         }
 550 
 551         if (pwd->pw_uid == 0) {


 564          * We only get here if we've been authenticated.
 565          */
 566 
 567         /*
 568          * Now we set up the environment for the new user, which includes
 569          * the users ulimit, nice value, ownership of this tty, uid, gid,
 570          * and environment variables.
 571          */
 572         if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
 573                 (void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
 574 
 575         /* di_devperm_login() sends detailed errors to syslog */
 576         if (di_devperm_login((const char *)ttyn, pwd->pw_uid, pwd->pw_gid,
 577             NULL) == -1) {
 578                 (void) fprintf(stderr, "error processing /etc/logindevperm,"
 579                     " see syslog for more details\n");
 580         }
 581 
 582         adjust_nice();          /* passwd file can specify nice value */
 583 

 584         setup_credentials();    /* Set user credentials  - exits on failure */
 585 
 586         /*
 587          * NOTE: telnetd and rlogind rely upon this updating of utmpx
 588          * to indicate that the authentication completed  successfully,
 589          * pam_open_session was called and therefore they are required to
 590          * call pam_close_session.
 591          */
 592         update_utmpx_entry(sublogin);
 593 
 594         /* set the real (and effective) UID */
 595         if (setuid(pwd->pw_uid) == -1) {
 596                 login_exit(1);
 597         }
 598 
 599         /*
 600          * Set up the basic environment for the exec.  This includes
 601          * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
 602          */
 603         chdir_to_dir_user();
 604 
 605         establish_user_environment(renvp);
 606 
 607         (void) pam_end(pamh, PAM_SUCCESS);      /* Done using PAM */
 608         pamh = NULL;

 609 
 610         if (pwd->pw_uid == 0) {
 611                 if (dosyslog) {
 612                         if (remote_host[0]) {
 613                                 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
 614                                     ttyn, HMAX, remote_host);
 615                         } else
 616                                 syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
 617                 }
 618         }
 619         closelog();
 620 
 621         (void) signal(SIGQUIT, SIG_DFL);
 622         (void) signal(SIGINT, SIG_DFL);
 623 
 624         /*
 625          * Display some useful information to the new user like the banner
 626          * and last login time if not a quiet login.
 627          */
 628 


 642 
 643         /*
 644          * Now fire off the shell of choice
 645          */
 646         exec_the_shell();
 647 
 648         /*
 649          * All done
 650          */
 651         login_exit(1);
 652         return (0);
 653 }
 654 
 655 
 656 /*
 657  *                      *** Utility functions ***
 658  */
 659 
 660 
 661 

 662 /*
 663  * donothing & catch        - Signal catching functions
 664  */
 665 
 666 /*ARGSUSED*/
 667 static void
 668 donothing(int sig)
 669 {
 670         if (pamh)
 671                 (void) pam_end(pamh, PAM_ABORT);
 672 }

 673 
 674 #ifdef notdef
 675 static  int     intrupt;
 676 
 677 /*ARGSUSED*/
 678 static void
 679 catch(int sig)
 680 {
 681         ++intrupt;
 682 }
 683 #endif
 684 
 685 /*
 686  *                      *** Bad login logging support ***
 687  */
 688 
 689 /*
 690  * badlogin()           - log to the log file 'trys'
 691  *                        unsuccessful attempts
 692  */


 773 
 774 static void
 775 turn_on_logging(void)
 776 {
 777         struct stat dbuf;
 778         int i;
 779 
 780         if (stat(LOGINLOG, &dbuf) == 0) {
 781                 writelog = 1;
 782                 for (i = 0; i < LOGTRYS; i++) {
 783                         if (!(log_entry[i] = malloc((size_t)ENT_SIZE))) {
 784                                 writelog = 0;
 785                                 break;
 786                         }
 787                         *log_entry[i] = '\0';
 788                 }
 789         }
 790 }
 791 
 792 

 793 /*
 794  * login_conv():
 795  *      This is the conv (conversation) function called from
 796  *      a PAM authentication module to print error messages
 797  *      or garner information from the user.
 798  */
 799 /*ARGSUSED*/
 800 static int
 801 login_conv(int num_msg, struct pam_message **msg,
 802     struct pam_response **response, void *appdata_ptr)
 803 {
 804         struct pam_message      *m;
 805         struct pam_response     *r;
 806         char                    *temp;
 807         int                     k, i;
 808 
 809         if (num_msg <= 0)
 810                 return (PAM_CONV_ERR);
 811 
 812         *response = calloc(num_msg, sizeof (struct pam_response));


 938          * PAM authenticates the user for us.
 939          */
 940         error = pam_authenticate(pamh, flag);
 941 
 942         /* get the user_name from the pam handle */
 943         (void) pam_get_item(pamh, PAM_USER, (void**)&user);
 944 
 945         if (user == NULL || *user == '\0')
 946                 return (PAM_SYSTEM_ERR);
 947 
 948         SCPYL(user_name, user);
 949         check_for_dueling_unix(user_name);
 950 
 951         if (((pwd = getpwnam(user_name)) == NULL) &&
 952             (error != PAM_USER_UNKNOWN)) {
 953                 return (PAM_SYSTEM_ERR);
 954         }
 955 
 956         return (error);
 957 }

 958 
 959 /*
 960  * quotec               - Called by getargs
 961  */
 962 
 963 static int
 964 quotec(void)
 965 {
 966         int c, i, num;
 967 
 968         switch (c = getc(stdin)) {
 969 
 970                 case 'n':
 971                         c = '\n';
 972                         break;
 973 
 974                 case 'r':
 975                         c = '\r';
 976                         break;
 977 


1744                                             "LOGIN FAILURES ON %s FROM %.*s ",
1745                                             " %.*s", ttyn, HMAX,
1746                                             remote_host, NMAX, pwd->pw_name);
1747                                 } else {
1748                                         syslog(LOG_CRIT,
1749                                             "LOGIN FAILURES ON %s, %.*s",
1750                                             ttyn, NMAX, pwd->pw_name);
1751                                 }
1752                         }
1753                         closelog();
1754                         (void) sleep(Disabletime);
1755                         exit(1);
1756                 } else {
1757                         (void) printf("No directory! Logging in with home=/\n");
1758                         pwd->pw_dir = "/";
1759                 }
1760         }
1761 }
1762 
1763 

1764 /*
1765  * login_authenticate   - Performs the main authentication work
1766  *                        1. Prints the login prompt
1767  *                        2. Requests and verifys the password
1768  *                        3. Checks the port password
1769  */
1770 
1771 static void
1772 login_authenticate(void)
1773 {
1774         char *user;
1775         int err;
1776         int login_successful = 0;
1777 
1778         do {
1779                 /* if scheme broken, then nothing to do but quit */
1780                 if (pam_get_item(pamh, PAM_USER, (void **)&user) != PAM_SUCCESS)
1781                         exit(1);
1782 
1783                 /*


1922         if ((user_name[0] == '\0') ||
1923             (initgroups(user_name, pwd->pw_gid) == -1)) {
1924                 audit_error = ADT_FAIL_VALUE_PROGRAM;
1925                 login_exit(1);
1926         }
1927 
1928         if ((error = pam_setcred(pamh, zflag ? PAM_REINITIALIZE_CRED :
1929             PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
1930                 audit_error = ADT_FAIL_PAM + error;
1931                 login_exit(error);
1932         }
1933 
1934         /*
1935          * Record successful login and fork process that records logout.
1936          * We have to do this after setting credentials because pam_setcred()
1937          * loads key audit info into the cred, but before setuid() so audit
1938          * system calls will work.
1939          */
1940         audit_success(get_audit_id(), pwd, zone_name);
1941 }

1942 
1943 static uint_t
1944 get_audit_id(void)
1945 {
1946         if (rflag)
1947                 return (ADT_rlogin);
1948         else if (hflag)
1949                 return (ADT_telnet);
1950         else if (zflag)
1951                 return (ADT_zlogin);
1952 
1953         return (ADT_login);
1954 }
1955 
1956 /*
1957  *
1958  *              *** Routines to get a new user set up and running ***
1959  *
1960  *                      Things to do when starting up a new user:
1961  *                              adjust_nice


1981         if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
1982                 pri = 0;
1983                 mflg = 0;
1984                 i = 4;
1985 
1986                 if (pwd->pw_gecos[i] == '-') {
1987                         mflg++;
1988                         i++;
1989                 }
1990 
1991                 while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
1992                         pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
1993 
1994                 if (mflg)
1995                         pri = -pri;
1996 
1997                 (void) nice(pri);
1998         }
1999 }
2000 

2001 /*
2002  * update_utmpx_entry   - Searchs for the correct utmpx entry, making an
2003  *                        entry there if it finds one, otherwise exits.
2004  */
2005 
2006 static void
2007 update_utmpx_entry(int sublogin)
2008 {
2009         int     err;
2010         char    *user;
2011         static char     *errmsg = "No utmpx entry. "
2012             "You must exec \"login\" from the lowest level \"shell\".";
2013         int     tmplen;
2014         struct utmpx  *u = (struct utmpx *)0;
2015         struct utmpx  utmpx;
2016         char    *ttyntail;
2017 
2018         /*
2019          * If we're not a sublogin then
2020          * we'll get an error back if our PID doesn't match the PID of the
2021          * entry we are updating, otherwise if its a sublogin the flags
2022          * field is set to 0, which means we just write a matching entry
2023          * (without checking the pid), or a new entry if an entry doesn't
2024          * exist.
2025          */
2026 
2027         if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
2028                 audit_error = ADT_FAIL_PAM + err;
2029                 login_exit(1);
2030         }
2031 
2032         if ((err = pam_get_item(pamh, PAM_USER, (void **) &user)) !=
2033             PAM_SUCCESS) {
2034                 audit_error = ADT_FAIL_PAM + err;
2035                 login_exit(1);
2036         }

2037 
2038         (void) memset((void *)&utmpx, 0, sizeof (utmpx));
2039         (void) time(&utmpx.ut_tv.tv_sec);
2040         utmpx.ut_pid = getpid();
2041 
2042         if (rflag || hflag) {
2043                 SCPYN(utmpx.ut_host, remote_host);
2044                 tmplen = strlen(remote_host) + 1;
2045                 if (tmplen < sizeof (utmpx.ut_host))
2046                         utmpx.ut_syslen = tmplen;
2047                 else
2048                         utmpx.ut_syslen = sizeof (utmpx.ut_host);
2049         } else if (zflag) {
2050                 /*
2051                  * If this is a login from another zone, put the
2052                  * zone:<zonename> string in the utmpx entry.
2053                  */
2054                 SCPYN(utmpx.ut_host, zone_name);
2055                 tmplen = strlen(zone_name) + 1;
2056                 if (tmplen < sizeof (utmpx.ut_host))


2084         }
2085         endutxent();
2086 
2087         if (u == (struct utmpx *)NULL) {
2088                 if (!sublogin) {
2089                         /*
2090                          * no utmpx entry already setup
2091                          * (init or rlogind/telnetd)
2092                          */
2093                         (void) puts(errmsg);
2094 
2095                         audit_error = ADT_FAIL_VALUE_PROGRAM;
2096                         login_exit(1);
2097                 }
2098         } else {
2099                 /* Now attempt to write out this entry to the wtmp file if */
2100                 /* we were successful in getting it from the utmpx file and */
2101                 /* the wtmp file exists.                                   */
2102                 updwtmpx(WTMPX_FILE, &utmpx);
2103         }

2104 }
2105 
2106 
2107 
2108 /*
2109  * process_chroot_logins        - Chroots to the specified subdirectory and
2110  *                                re executes login.
2111  */
2112 
2113 static int
2114 process_chroot_logins(void)
2115 {
2116         /*
2117          * If the shell field starts with a '*', do a chroot to the home
2118          * directory and perform a new login.
2119          */
2120 
2121         if (*pwd->pw_shell == '*') {
2122                 (void) pam_end(pamh, PAM_SUCCESS);      /* Done using PAM */
2123                 pamh = NULL;                            /* really done */
2124                 if (chroot(pwd->pw_dir) < 0) {
2125                         (void) printf("No Root Directory\n");
2126 
2127                         audit_failure(get_audit_id(),
2128                             ADT_FAIL_VALUE_CHDIR_FAILED,
2129                             pwd, remote_host, ttyn, zone_name);
2130 
2131                         return (ERROR);
2132                 }
2133                 /*
2134                  * Set the environment flag <!sublogin> so that the next login
2135                  * knows that it is a sublogin.
2136                  */

2137                 envinit[0] = SUBLOGIN;
2138                 envinit[1] = (char *)NULL;
2139                 (void) printf("Subsystem root: %s\n", pwd->pw_dir);
2140                 (void) execle("/usr/bin/login", "login", (char *)0,
2141                     &envinit[0]);
2142                 (void) execle("/etc/login", "login", (char *)0, &envinit[0]);
2143                 (void) printf("No /usr/bin/login or /etc/login on root\n");
2144 
2145                 audit_error = ADT_FAIL_VALUE_PROGRAM;
2146 
2147                 login_exit(1);
2148         }
2149         return (OK);

2150 }
2151 
2152 /*
2153  * establish_user_environment   - Set up the new users enviornment
2154  */
2155 
2156 static void
2157 establish_user_environment(char **renvp)
2158 {
2159         int i, j, k, l_index, length, idx = 0;
2160         char *endptr;
2161         char **lenvp;
2162         char **pam_env;
2163 
2164         lenvp = environ;
2165         while (*lenvp++)
2166                 ;
2167 
2168         /* count the number of PAM environment variables set by modules */
2169         if ((pam_env = pam_getenvlist(pamh)) != 0) {


2177                 (void) printf("Calloc failed - out of swap space.\n");
2178                 login_exit(8);
2179         }
2180 
2181         /*
2182          * add PAM environment variables first so they
2183          * can be overwritten at login's discretion.
2184          * check for illegal environment variables.
2185          */
2186         idx = 0;        basicenv = 0;
2187         if (pam_env != 0) {
2188                 while (pam_env[idx] != 0) {
2189                         if (legalenvvar(pam_env[idx])) {
2190                                 envinit[basicenv] = pam_env[idx];
2191                                 basicenv++;
2192                         }
2193                         idx++;
2194                 }
2195         }
2196         (void) memcpy(&envinit[basicenv], newenv, sizeof (newenv));

2197 
2198         /* Set up environment */
2199         if (rflag) {
2200                 ENVSTRNCAT(term, terminal);
2201         } else if (hflag) {
2202                 if (strlen(terminal)) {
2203                         ENVSTRNCAT(term, terminal);
2204                 }
2205         } else {
2206                 char *tp = getenv("TERM");
2207 
2208                 if ((tp != NULL) && (*tp != '\0'))
2209                         ENVSTRNCAT(term, tp);
2210         }
2211 
2212         ENVSTRNCAT(logname, pwd->pw_name);
2213 
2214         /*
2215          * There are three places to get timezone info.  init.c sets
2216          * TZ if the file /etc/TIMEZONE contains a value for TZ.