source: trunk/athena/etc/xdm/xlogin/verify.c @ 12350

Revision 12350, 26.0 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/* $Id: verify.c,v 1.99 1999-01-22 23:16:25 ghudson Exp $ */
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <pwd.h>
6#include <unistd.h>
7#include <signal.h>
8#include <fcntl.h>
9#ifdef SYSV
10#include <shadow.h>
11#include <limits.h>
12#include <utmpx.h>
13#include <sys/sysmacros.h>
14#endif
15#include <grp.h>
16#include <string.h>
17#include <sys/types.h>
18#include <sys/file.h>
19#include <sys/param.h>
20#include <utime.h>
21#include <dirent.h>
22#include <sys/stat.h>
23#include <sys/time.h>
24#include <utmp.h>
25#include <netdb.h>
26#ifdef sgi
27#include <sys/statfs.h>
28#endif
29#include <errno.h>
30#include <syslog.h>
31
32#include <krb.h>
33#include <hesiod.h>
34#include <al.h>
35#include <larv.h>
36
37#ifdef KRB5
38#include <krb5.h>
39#endif
40
41#ifdef XDM
42#include "dm.h"
43#endif
44
45#include "environment.h"
46
47#ifndef TRUE
48#define FALSE 0
49#define TRUE (!FALSE)
50#endif
51
52#define LOGIN_TKT_DEFAULT_LIFETIME 120 /* Ten hours */
53#define PASSWORD_LEN 14
54#define MAXENVIRON 32
55
56#define MOTD "/etc/motd"
57#ifndef SYSV
58#if defined(UTMP_FILE)
59#define UTMP UTMP_FILE
60#define WTMP WTMP_FILE
61#elif defined(_PATH_UTMP)
62#define UTMP _PATH_UTMP
63#define WTMP _PATH_WTMP
64#else
65#define UTMP "/var/adm/utmp"
66#define WTMP "/var/adm/wtmp"
67#endif
68#endif /* SYSV */
69#ifdef SOLARIS
70char *defaultpath = "/srvd/patch:/usr/athena/bin:/bin/athena:/usr/openwin/bin:/bin:/usr/ucb:/usr/sbin:/usr/andrew/bin:.";
71#else
72#ifdef sgi
73char *defaultpath = "/srvd/patch:/usr/athena/bin:/bin/athena:/usr/sbin:/usr/bsd:/usr/bin:/bin:/etc:/usr/etc:/usr/bin/X11:/usr/andrew/bin:.";
74#else
75char *defaultpath = "/srvd/patch:/usr/athena/bin:/bin/athena:/usr/bin/X11:/usr/new:/usr/ucb:/bin:/usr/bin:/usr/ibm:/usr/andrew/bin:.";
76#endif
77#endif
78
79#ifdef sgi
80extern FILE *xdmstream;
81#endif
82
83pid_t fork_and_store(pid_t *var);
84extern char *crypt(), *lose(), *getenv();
85extern char *krb_get_phost(); /* should be in <krb.h> */
86char *get_tickets(), *strsave();
87int abort_verify();
88extern pid_t attach_pid, attachhelp_pid, quota_pid;
89extern int attach_state, attachhelp_state, errno;
90extern sigset_t sig_zero;
91
92#ifdef SOLARIS
93struct passwd *get_pwnam(usr)
94     char *usr;
95{
96  struct passwd *pwd;
97  struct spwd *sp;
98
99  pwd = getpwnam(usr);
100  sp = getspnam(usr);
101  if ((sp != NULL) && (pwd != NULL))
102    pwd->pw_passwd = sp->sp_pwdp;
103  return pwd;
104}
105#else
106#define get_pwnam(x) getpwnam(x)
107#endif
108
109#ifdef XDM
110char *dologin(user, passwd, option, script, tty, session, display, verify)
111     struct verify_info *verify;
112#else /* XDM */
113char *dologin(user, passwd, option, script, tty, session, display)
114#endif /* XDM */
115     char *user;
116     char *passwd;
117     int option;
118     char *script;
119     char *tty;
120     char *session;
121     char *display;
122{
123  static char errbuf[5120];
124  char tkt_file[128], *msg, wgfile[16];
125#ifdef KRB5
126  char tkt5_file[128];
127#endif
128  struct passwd *pwd;
129  struct group *gr;
130  struct utimbuf times;
131  long salt;
132  char saltc[2], c;
133  char encrypt[PASSWORD_LEN + 1];
134  char **environment;
135  char fixed_tty[16], *p;
136#ifdef sgi
137  char *newargv[4];
138#endif
139  int i;
140  /* state variables: */
141  int local_passwd = FALSE;     /* user is in local passwd file */
142  int local_ok = FALSE;         /* verified from local password file */
143  int local_acct;               /* user's account is supposed to be local */
144  char *altext = NULL, *alerrmem;
145  int status, *warnings, *warning;
146  int tmp_homedir = 0;
147  int pid;
148
149  /* 4.2 vs 4.3 style syslog */
150#ifndef  LOG_ODELAY
151  openlog("xlogin", LOG_NOTICE);
152#else
153  openlog("xlogin", LOG_ODELAY, LOG_AUTH);
154#endif
155
156  /* Check to make sure a username was entered. */
157  if (!strcmp(user, ""))
158    return "No username entered.  Please enter a username and "
159           "password to try again.";
160
161  /* Check that the user is allowed to log in. */
162  status = al_login_allowed(user, 0, &local_acct, &altext);
163  if (status != AL_SUCCESS)
164    {
165      memset(passwd, 0, strlen(passwd));        /* zap ASAP */
166      switch(status)
167        {
168        case AL_ENOUSER:
169          sprintf(errbuf,
170                  "Unknown user name entered (no hesiod information "
171                  "for \"%s\")", user);
172          break;
173        case AL_ENOLOGIN:
174          strcpy(errbuf,
175                 "Logins are currently disabled on this workstation.  ");
176          break;
177        case AL_ENOCREATE:
178          strcpy(errbuf,
179                 "You are not allowed to log into this workstation.  "
180                 "Contact the workstation's administrator or a consultant "
181                 "for further information.  ");
182          break;
183        case AL_EBADHES:
184          strcpy(errbuf, "This account conflicts with a locally defined "
185                 "account... aborting.");
186          break;
187        case AL_ENOMEM:
188          strcpy(errbuf, "Out of memory.");
189          break;
190        default:
191          strcpy(errbuf, al_strerror(status, &alerrmem));
192          al_free_errmem(alerrmem);
193          break;
194        }
195
196      if (altext)
197        {
198          strncat(errbuf, altext, sizeof(errbuf) - strlen(errbuf) - 1);
199          free(altext);
200        }
201
202      syslog(LOG_INFO, "Unauthorized login attempt for username %s: %s", user,
203             al_strerror(status, &alerrmem));
204      al_free_errmem(alerrmem);
205
206      return errbuf;
207    }
208
209  /* Test to see if the user can be authenticated locally. If not,
210   * grab their password information from Hesiod, since the uid is
211   * potentially needed for mail-check login and the ticket file
212   * name, before we want to call al_acct_create().
213   */
214  pwd = get_pwnam(user);
215  if (pwd != NULL)
216    {
217      local_passwd = TRUE;
218      if (strcmp(crypt(passwd, pwd->pw_passwd), pwd->pw_passwd) == 0)
219        local_ok = TRUE;
220      else if (local_acct)
221        return "Incorrect password";
222    }
223  else
224    {
225      pwd = hes_getpwnam(user);
226      if (pwd == NULL) /* "can't" happen */
227        return "Strange failure in Hesiod lookup.";
228    }
229
230  /* Only do Kerberos-related things if the account is not local. */
231  if (!local_acct)
232      {
233        /* Terminal names may be something like pts/0; we don't want any /'s
234         * in the path name; replace them with _'s.
235         */
236        if (tty != NULL)
237          {
238            strcpy(fixed_tty, tty);
239            while (p = strchr(fixed_tty, '/'))
240              *p = '_';
241          }
242        else
243          sprintf(fixed_tty, "%d", pwd->pw_uid);
244        sprintf(tkt_file, "/tmp/tkt_%s", fixed_tty);
245        psetenv("KRBTKFILE", tkt_file, 1);
246
247        /* We set the ticket file here because a previous dest_tkt() might
248         * have cached the wrong ticket file.
249         */
250        krb_set_tkt_string(tkt_file);
251
252#ifdef KRB5
253        sprintf(tkt5_file, "/tmp/krb5cc_%s", fixed_tty);
254        psetenv("KRB5CCNAME", tkt5_file, 1);
255#endif
256
257        /* Save encrypted password to put in local password file. We do
258         * this ahead of time so that we can be sure of zeroing the
259         * password below.
260         */
261        salt = 9 * getpid();
262        saltc[0] = salt & 077;
263        saltc[1] = (salt>>6) & 077;
264        for (i = 0; i < 2 ; i++)
265          {
266            c = saltc[i] + '.';
267            if (c > '9')
268              c += 7;
269            if (c > 'Z')
270              c += 6;
271            saltc[i] = c;
272          }
273        strcpy(encrypt, crypt(passwd, saltc)); 
274
275        msg = get_tickets(user, passwd);
276        memset(passwd, 0, strlen(passwd));
277
278        if (msg)
279          {
280            if (!local_ok)
281              return msg;
282            else
283              {
284                prompt_user("Unable to get full authentication, you will "
285                            "have local access only during this login "
286                            "session (failed to get kerberos tickets).  "
287                            "Continue anyway?", abort_verify, NULL);
288              }
289          }
290
291        chown(tkt_file, pwd->pw_uid, pwd->pw_gid);
292#ifdef KRB5
293        chown(tkt5_file, pwd->pw_uid, pwd->pw_gid);
294#endif
295      }
296
297  /* Code for verifying a secure tty used to be here. */
298
299  /* If a mail-check login has been selected, do that now. */
300  if (option == 4)
301    {
302      attach_state = -1;
303      switch(fork_and_store(&attach_pid))
304        {
305        case -1:
306          fprintf(stderr, "Unable to fork to check your mail.\n");
307          break;
308        case 0:
309          if (setuid(pwd->pw_uid) != 0)
310            {
311              fprintf(stderr, "Unable to set user ID to check your mail.\n");
312              _exit(-1);
313            }
314          printf("Electronic mail status:\n");
315          execlp("from", "from", "-r", user, NULL);
316          fprintf(stderr, "Unable to run mailcheck program.\n");
317          _exit(-1);
318        default:
319          while (attach_state == -1)
320            sigsuspend(&sig_zero);
321          printf("\n");
322          prompt_user("A summary of your waiting email is displayed in "
323                      "the console window.  Continue with full login "
324                      "session or logout now?", abort_verify, NULL);
325        }
326    }
327#if defined(SETPAG) && !defined(sgi) /* not appropriate for SGI system */
328  setpag();
329#endif
330
331#ifdef sgi
332  if (nanny_getNannyPid(&pid))
333    return lose("failed to get pid from nanny");
334#else
335  pid = getpid();
336#endif
337
338  if (!local_acct)
339    {
340      status = al_acct_create(user, encrypt, pid, !msg, 1, &warnings);
341      if (status != AL_SUCCESS)
342        {
343          switch(status)
344            {
345            case AL_EPASSWD:
346              strcpy(errbuf, "An unexpected error occured while entering you "
347                     "in the local password file.");
348              return errbuf;
349              break;
350            case AL_WARNINGS:
351              warning = warnings;
352              while (*warning != AL_SUCCESS)
353                {
354                  switch(*warning)
355                    {
356                    case AL_WGROUP:
357                      prompt_user("Unable to set your group access list.  "
358                                  "You may have insufficient permission to "
359                                  "access some files.  Continue with this "
360                                  "login session anyway?", abort_verify, user);
361                      break;
362                    case AL_WXTMPDIR:
363                      tmp_homedir = 1;
364                      prompt_user("You are currently logged in with a "
365                                  "temporary home directory, so this login "
366                                  "session will use that directory. Continue "
367                                  "with this login session anyway?",
368                                  abort_verify, user);
369                      break;
370                    case AL_WTMPDIR:
371                      tmp_homedir = 1;
372                      prompt_user("Your home directory is unavailable.  A "
373                                  "temporary directory will be created for "
374                                  "you.  However, it will be DELETED when you "
375                                  "logout.  Any mail that you incorporate "
376                                  "during this session WILL BE LOST when you "
377                                  "logout.  Continue with this login session "
378                                  "anyway?", abort_verify, user);
379                      break;
380                    case AL_WNOHOMEDIR:
381                      prompt_user("No home directory is available.  Continue "
382                                  "with this login session anyway?",
383                                  abort_verify, user);
384                      break;
385                    case AL_WNOATTACH:
386                      prompt_user("This workstation is configured not to "
387                                  "attach remote filesystems.  Continue with "
388                                  "your local home directory?", abort_verify,
389                                  user);
390                      break;
391                    case AL_WBADSESSION:
392                    default:
393                      break;
394                    }
395                  warning++;
396                }
397              free(warnings);
398              break;
399            default:
400              strcpy(errbuf, al_strerror(status, &alerrmem));
401              al_free_errmem(alerrmem);
402              return errbuf;
403              break;
404            }
405        }
406    }
407
408  /* Get the password entry again. We need a new copy because it
409   * may have been edited by al_acct_create().
410   */
411  pwd = get_pwnam(user);
412  if (pwd == NULL) /* "can't" happen */
413    return lose("Unable to get your password entry.\n");
414
415  switch(fork_and_store(&quota_pid))
416    {
417    case -1:
418      fprintf(stderr, "Unable to fork to check your filesystem quota.\n");
419      break;
420    case 0:
421      if (setuid(pwd->pw_uid) != 0)
422        {
423          fprintf(stderr,
424                  "Unable to set user ID to check your filesystem quota.\n");
425          _exit(-1);
426        }
427      execlp("quota", "quota", NULL);
428      fprintf(stderr, "Unable to run quota command %s\n", "quota");
429      _exit(-1);
430    default:
431      ;
432    }
433
434  /* Show the message of the day. */
435  sprintf(errbuf, "%s/.hushlogin", pwd->pw_dir);
436  if (!file_exists(errbuf))
437    {
438      int f, count;
439
440      f = open(MOTD, O_RDONLY, 0);
441      if (f >= 0)
442        {
443          count = read(f, errbuf, sizeof(errbuf) - 1);
444          write(1, errbuf, count);
445          close(f);
446        }
447    }
448
449  /*
450   * Set up the user's environment.
451   *
452   *   By default, none of xlogin's environment is passed to
453   *   users who log in.
454   *
455   *   The PASSENV macro is defined to make it trivial to pass
456   *   an element of xlogin's environment on to the user.
457   *
458   *   Note that the environment for pre-login options is set
459   *   up in xlogin.c: it is NOT RELATED to this environment
460   *   setup. If you add a new environment variable here,
461   *   consider whether or not it also needs to be added there.
462   *   Note that variables that need to be PASSENVed here do not
463   *   need similar treatment in the pre-login area, since there
464   *   all variables as passed by default.
465   */
466#define PASSENV(envvar)                                 \
467  msg = getenv(envvar);                                 \
468  if (msg)                                              \
469    {                                                   \
470      sprintf(errbuf, "%s=%s", envvar, msg);            \
471      environment[i++] = strsave(errbuf);               \
472    }
473
474  environment = (char **) malloc(MAXENVIRON * sizeof(char *));
475  if (environment == NULL)
476    return "Out of memory while trying to initialize user environment "
477           "variables.";
478
479  i = 0;
480  sprintf(errbuf, "HOME=%s", pwd->pw_dir);
481  environment[i++] = strsave(errbuf);
482  sprintf(errbuf, "PATH=%s", defaultpath);
483  environment[i++] = strsave(errbuf);
484  sprintf(errbuf, "USER=%s", pwd->pw_name);
485  environment[i++] = strsave(errbuf);
486  sprintf(errbuf, "SHELL=%s", pwd->pw_shell);
487  environment[i++] = strsave(errbuf);
488  sprintf(errbuf, "DISPLAY=%s", display);
489  environment[i++] = strsave(errbuf);
490  if (!local_acct)
491    {
492      sprintf(errbuf, "KRBTKFILE=%s", tkt_file);
493      environment[i++] = strsave(errbuf);
494#ifdef KRB5
495      sprintf(errbuf, "KRB5CCNAME=%s", tkt5_file);
496      environment[i++] = strsave(errbuf);
497#endif
498    }
499#ifdef HOSTTYPE
500  sprintf(errbuf, "hosttype=%s", HOSTTYPE); /* environment.h */
501  environment[i++] = strsave(errbuf);
502#endif
503
504#ifdef SOLARIS
505#ifdef XDM
506  sprintf(errbuf, "LD_LIBRARY_PATH=%s", "/usr/openwin/lib");
507  environment[i++] = strsave(errbuf);
508  sprintf(errbuf, "OPENWINHOME=%s", "/usr/openwin");
509  environment[i++] = strsave(errbuf);
510#else
511  PASSENV("LD_LIBRARY_PATH");
512  PASSENV("OPENWINHOME");
513#endif
514#endif
515
516  if (tmp_homedir)
517    environment[i++] = "TMPHOME=1";
518  strcpy(wgfile, "/tmp/wg.XXXXXX");
519  mktemp(wgfile);
520  sprintf(errbuf, "WGFILE=%s", wgfile);
521  environment[i++] = strsave(errbuf);
522  PASSENV("TZ");
523
524#ifdef sgi
525  PASSENV("XAUTHORITY");
526#endif
527
528  environment[i++] = NULL;
529
530#ifndef sgi /* nanny handles this on SGI */
531  add_utmp(user, tty, display);
532#endif
533  if (pwd->pw_uid == ROOT)
534    syslog(LOG_CRIT, "ROOT LOGIN on tty %s", tty ? tty : "X");
535  else
536    syslog(LOG_INFO, "%s LOGIN on tty %s", user, tty ? tty : "X");
537
538#ifndef sgi /* nanny/xdm does all this on SGI too... */
539  /* Set the owner and modtime on the tty. */
540  sprintf(errbuf, "/dev/%s", tty);
541  gr = getgrnam("tty");
542  chown(errbuf, pwd->pw_uid, gr ? gr->gr_gid : pwd->pw_gid);
543  chmod(errbuf, 0620);
544
545  times.actime = times.modtime = time(NULL);
546  utime(errbuf, &times);
547
548#ifdef XDM
549  {
550    static char *newargv[4];
551
552    verify->uid = pwd->pw_uid;
553    getGroups(pwd->pw_name, verify, pwd->pw_gid);
554    verify->userEnviron = environment;
555    newargv[0] = script;
556    sprintf(errbuf, "%d", option);
557    newargv[1] = errbuf;
558    newargv[2] = session;
559    newargv[3] = NULL;
560    verify->argv = newargv;
561    return NULL;
562  }
563#endif /* XDM */
564
565  i = setgid(pwd->pw_gid);
566  if (i)
567    return lose("Unable to set your primary GID.\n");
568       
569  if (initgroups(user, pwd->pw_gid) < 0)
570    prompt_user("Unable to set your group access list.  You may have "
571                "insufficient permission to access some files.  "
572                "Continue with this login session anyway?",
573                abort_verify, user);
574
575#ifdef SOLARIS_MAE
576  /* If the login fails, lose() is called, setting a global flag
577   * to indicate that xlogin will exit as soon as the user has
578   * been notified of the error. xlogin will then restart, and
579   * at the beginning of xlogin we chown netdev back to root.
580   */
581  if (netspy)
582    chown(NETDEV, pwd->pw_uid, SYS);
583#endif
584
585  i = setuid(pwd->pw_uid);
586  if (i)
587    return lose("Unable to set your user ID.\n");
588#endif /* not sgi */
589
590  if (chdir(pwd->pw_dir))
591    fprintf(stderr, "Unable to connect to your home directory.\n");
592
593  /* Stuff first arg for xsession into a string. */
594  sprintf(errbuf, "%d", option);
595
596#ifdef sgi
597  /* Output username and environment information and let xdm log us in. */
598  fprintf(xdmstream, "%s", pwd->pw_name);
599  fputc(0, xdmstream);
600
601  newargv[0] = errbuf;
602  newargv[1] = script;
603  newargv[2] = NULL;
604  if (nanny_setupUser(pwd->pw_name, environment, newargv))
605    return lose("failed to setup for login");
606
607  exit(0);
608#else
609  execle(session, "sh", errbuf, script, NULL, environment);
610#endif /* sgi */
611
612  return lose("Failed to start session.");
613}
614
615char *get_tickets(username, password)
616     char *username;
617     char *password;
618{
619  char inst[INST_SZ], realm[REALM_SZ];
620  char hostname[MAXHOSTNAMELEN], phost[INST_SZ];
621  char key[8], *rcmd;
622  static char errbuf[1024];
623  int error;
624  struct hostent *hp;
625  KTEXT_ST ticket;
626  AUTH_DAT authdata;
627  unsigned long addr;
628
629  rcmd = "rcmd";
630
631  /* inst has to be a buffer instead of the constant "" because
632   * krb_get_pw_in_tkt() will write a zero at inst[INST_SZ] to
633   * truncate it.
634   */
635  inst[0] = 0;
636  dest_tkt();
637#ifdef KRB5
638  do_v5_kdestroy(0);
639#endif
640
641  if (krb_get_lrealm(realm, 1) != KSUCCESS)
642    strcpy(realm, KRB_REALM);
643
644  error = krb_get_pw_in_tkt(username, inst, realm, "krbtgt", realm,
645                            LOGIN_TKT_DEFAULT_LIFETIME, password);
646  switch(error)
647    {
648    case KSUCCESS:
649      break;
650    case INTK_BADPW:
651      return "Incorrect password entered.";
652    case KDC_PR_UNKNOWN:
653      return "Unknown username entered.";
654    default:
655      sprintf(errbuf, "Unable to authenticate you, kerberos failure "
656              "%d: %s.  Try again here or on another workstation.",
657              error, krb_err_txt[error]);
658      return errbuf;
659    }
660
661#ifdef KRB5
662  {
663    krb5_error_code krb5_ret;
664    char *etext;
665
666    krb5_ret = do_v5_kinit(username, inst, realm,
667                           LOGIN_TKT_DEFAULT_LIFETIME, password,
668                           0, &etext);
669    if (krb5_ret && krb5_ret != KRB5KRB_AP_ERR_BAD_INTEGRITY)
670      com_err("xlogin", krb5_ret, etext);
671  }
672#endif
673
674  if (gethostname(hostname, sizeof(hostname)) == -1)
675    {
676      fprintf(stderr, "Warning: cannot retrieve local hostname\n");
677      return NULL;
678    }
679  strncpy(phost, krb_get_phost(hostname), sizeof(phost));
680  phost[sizeof(phost) - 1] = '\0';
681
682  /* Without a srvtab, we cannot verify tickets. */
683  if (read_service_key(rcmd, phost, realm, 0, KEYFILE, key) == KFAILURE)
684    return NULL;
685
686  hp = gethostbyname(hostname);
687  if (!hp)
688    {
689      fprintf(stderr, "Warning: cannot get address for host %s\n", hostname);
690      return NULL;
691    }
692  memmove(&addr, hp->h_addr, sizeof(addr));
693
694  error = krb_mk_req(&ticket, rcmd, phost, realm, 0);
695  if (error == KDC_PR_UNKNOWN)
696    return NULL;
697  if (error != KSUCCESS)
698    {
699      sprintf(errbuf, "Unable to authenticate you, kerberos failure %d: %s",
700              error, krb_err_txt[error]);
701      return errbuf;
702    }
703
704  error = krb_rd_req(&ticket, rcmd, phost, addr, &authdata, "");
705  if (error != KSUCCESS)
706    {
707      memset(&ticket, 0, sizeof(ticket));
708      sprintf(errbuf, "Unable to authenticate you, kerberos failure %d: %s",
709              error, krb_err_txt[error]);
710      return errbuf;
711    }
712  memset(&ticket, 0, sizeof(ticket));
713  memset(&authdata, 0, sizeof(authdata));
714  return NULL;
715}
716
717/* Destroy kerberos tickets and let al_acct_revert clean up the rest. */
718cleanup(user)
719     char *user;
720{
721  dest_tkt();
722#ifdef KRB5
723  do_v5_kdestroy(0);
724#endif
725
726  if (user)
727    al_acct_revert(user, getpid());
728
729  /* Set real uid to zero.  If this is impossible, exit.  The
730   * current implementation of lose() will not print a message
731   * so xlogin will just exit silently.  This call "can't fail",
732   * so this is not a serious problem.
733   */
734  if (setuid(0) == -1)
735    lose("Unable to reset real uid to root");
736}
737
738abort_verify(user)
739     char *user;
740{
741  cleanup(user);
742  _exit(1);
743}
744
745char *strsave(s)
746     char *s;
747{
748  char *ret = malloc(strlen(s) + 1);
749
750  strcpy(ret, s);
751  return ret;
752}
753
754add_utmp(user, tty, display)
755     char *user;
756     char *tty;
757     char *display;
758{
759  struct utmp ut_entry;
760#ifndef SYSV
761  struct utmp ut_tmp;
762#else
763  struct utmp *ut_tmp;
764  struct utmpx utx_entry;
765  struct utmpx *utx_tmp;
766#endif /* SYSV */
767  int f;
768
769#ifdef SYSV
770  memset(&utx_entry, 0, sizeof(utx_entry));
771
772  strncpy(utx_entry.ut_line, tty, sizeof(utx_entry.ut_line));
773  strncpy(utx_entry.ut_name, user, sizeof(utx_entry.ut_name));
774
775  /* Be sure the host string is null terminated. */
776  strncpy(utx_entry.ut_host, display, sizeof(utx_entry.ut_host));
777  utx_entry.ut_host[sizeof(utx_entry.ut_host) - 1] = '\0';
778
779  gettimeofday(&utx_entry.ut_tv, NULL);
780  utx_entry.ut_pid = getppid();
781  utx_entry.ut_type = USER_PROCESS;
782  strncpy(utx_entry.ut_id, "XLOG", sizeof(utx_entry.ut_id));
783
784  getutmp(&utx_entry, &ut_entry);
785
786  setutent();
787  while (ut_tmp = getutline(&ut_entry))
788    if (!strncmp(ut_tmp->ut_id, "XLOG", sizeof(ut_tmp->ut_id)))
789      break;
790  pututline(&ut_entry);
791
792  setutxent();
793  while (utx_tmp = getutxline(&utx_entry))
794    if (!strncmp(utx_tmp->ut_id, "XLOG", sizeof(utx_tmp->ut_id)))
795      break;
796  pututxline(&utx_entry);
797
798  f = open(WTMP_FILE, O_WRONLY | O_APPEND);
799  if (f >= 0)
800    {
801      write(f, (char *)&ut_entry, sizeof(ut_entry));
802      close(f);
803    }
804
805  f = open(WTMPX_FILE, O_WRONLY | O_APPEND);
806  if (f >= 0)
807    {
808      write(f, (char *)&utx_entry, sizeof(utx_entry));
809      close(f);
810    }
811#else /* !SYSV */
812  memset(&ut_entry, 0, sizeof(ut_entry));
813
814  strncpy(ut_entry.ut_line, tty, sizeof(ut_entry.ut_line));
815  strncpy(ut_entry.ut_name, user, sizeof(ut_entry.ut_name));
816
817  /* Be sure the host string is null terminated. */
818  strncpy(ut_entry.ut_host, display, sizeof(ut_entry.ut_host));
819  ut_entry.ut_host[sizeof(ut_entry.ut_host) - 1] = '\0';
820
821  time(&(ut_entry.ut_time));
822#ifdef USER_PROCESS
823  ut_entry.ut_pid = getppid();
824  ut_entry.ut_type = USER_PROCESS;
825#endif
826
827  f = open(UTMP, O_RDWR);
828  if (f >= 0)
829    {
830      while (read(f, (char *)&ut_tmp, sizeof(ut_tmp)) == sizeof(ut_tmp))
831        if (ut_tmp.ut_pid == ut_entry.ut_pid)
832          {
833            strncpy(ut_entry.ut_id, ut_tmp.ut_id, sizeof(ut_tmp.ut_id));
834            lseek(f, (long) -sizeof(ut_tmp), 1);
835            break;
836          }
837      write(f, (char *)&ut_entry, sizeof(ut_entry));
838      close(f);
839    }
840
841  f = open(WTMP, O_WRONLY | O_APPEND);
842  if (f >= 0)
843    {
844      write(f, (char *)&ut_entry, sizeof(ut_entry));
845      close(f);
846    }
847#endif /* SYSV */
848}
849
850#define MAXGNAMELENGTH  32
851
852/* Fork, storing the pid in a variable var and returning the pid.
853 * Make sure that the pid is stored before any SIGCHLD can be
854 * delivered.
855 */
856pid_t fork_and_store(pid_t *var)
857{
858  pid_t pid;
859  sigset_t mask, omask;
860
861  sigemptyset(&mask);
862  sigaddset(&mask, SIGCHLD);
863  sigprocmask(SIG_BLOCK, &mask, &omask);
864  pid = fork();
865  *var = pid;
866  sigprocmask(SIG_SETMASK, &omask, NULL);
867  return pid;
868}
869
870/* Emulate setenv() with the more portable (these days) putenv(). */
871int psetenv(const char *name, const char *value, int overwrite)
872{
873  char *var;
874
875  if (!overwrite && getenv(name) != NULL)
876    return 0;
877  var = malloc(strlen(name) + strlen(value) + 2);
878  if (!var)
879    {
880      errno = ENOMEM;
881      return -1;
882    }
883  sprintf(var, "%s=%s", name, value);
884  putenv(var);
885  return 0;
886}
887
888/* Emulate unsetenv() by fiddling with the environment. */
889int punsetenv(const char *name)
890{
891  extern char **environ;
892  char **p, **q;
893  int len = strlen(name);
894
895  q = environ;
896  for (p = environ; *p; p++)
897    {
898      if (strncmp(*p, name, len) != 0 || (*p)[len] != '=')
899        *q++ = *p;
900    }
901  *q = NULL;
902  return 0;
903}
904
905#ifdef KRB5
906/* This routine takes v4 kinit parameters and performs a V5 kinit.
907 *
908 * name, instance, realm is the v4 principal information
909 *
910 * lifetime is the v4 lifetime (i.e., in units of 5 minutes)
911 *
912 * password is the password
913 *
914 * ret_cache_name is an optional output argument in case the caller
915 * wants to know the name of the actual V5 credentials cache (to put
916 * into the KRB5_ENV_CCNAME environment variable)
917 *
918 * etext is a mandatory output variable which is filled in with
919 * additional explanatory text in case of an error.
920 */
921krb5_error_code do_v5_kinit(name, instance, realm, lifetime, password,
922                            ret_cache_name, etext)
923     char       *name;
924     char       *instance;
925     char       *realm;
926     int        lifetime;
927     char       *password;
928     char       **ret_cache_name;
929     char       **etext;
930{
931  krb5_context context;
932  krb5_error_code retval;
933  krb5_principal me = 0, server = 0;
934  krb5_ccache ccache = NULL;
935  krb5_creds my_creds;
936  krb5_timestamp now;
937  krb5_flags options = KDC_OPT_FORWARDABLE | KDC_OPT_PROXIABLE;
938
939  char *cache_name;
940
941  *etext = 0;
942  if (ret_cache_name)
943    *ret_cache_name = 0;
944  memset(&my_creds, 0, sizeof(my_creds));
945
946  retval = krb5_init_context(&context);
947  if (retval)
948    return retval;
949
950  cache_name = krb5_cc_default_name(context);
951  krb5_init_ets(context);
952
953  retval = krb5_425_conv_principal(context, name, instance, realm, &me);
954  if (retval)
955    {
956      *etext = "while converting V4 principal";
957      goto cleanup;
958    }
959
960  retval = krb5_cc_resolve(context, cache_name, &ccache);
961  if (retval)
962    {
963      *etext = "while resolving ccache";
964      goto cleanup;
965    }
966
967  retval = krb5_cc_initialize(context, ccache, me);
968  if (retval)
969    {
970      *etext = "while initializing cache";
971      goto cleanup;
972    }
973
974  retval = krb5_build_principal_ext(context, &server,
975                                    krb5_princ_realm(context,
976                                                     me)->length,
977                                    krb5_princ_realm(context, me)->data,
978                                    KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
979                                    krb5_princ_realm(context,
980                                                     me)->length,
981                                    krb5_princ_realm(context, me)->data,
982                                    0);
983  if (retval)
984    {
985      *etext = "while building server name";
986      goto cleanup;
987    }
988
989  retval = krb5_timeofday(context, &now);
990  if (retval)
991    {
992      *etext = "while getting time of day";
993      goto cleanup;
994    }
995
996  my_creds.client = me;
997  my_creds.server = server;
998  my_creds.times.starttime = 0;
999  my_creds.times.endtime = now + lifetime * 5 * 60;
1000  my_creds.times.renew_till = 0;
1001
1002  retval = krb5_get_in_tkt_with_password(context, options, NULL, NULL,
1003                                         NULL, password, ccache,
1004                                         &my_creds, NULL);
1005  if (retval)
1006    {
1007      *etext = "while calling krb5_get_in_tkt_with_password";
1008      goto cleanup;
1009    }
1010
1011  if (ret_cache_name)
1012    {
1013      *ret_cache_name = malloc(strlen(cache_name) + 1);
1014      if (!*ret_cache_name)
1015        {
1016          retval = ENOMEM;
1017          goto cleanup;
1018        }
1019      strcpy(*ret_cache_name, cache_name);
1020    }
1021
1022cleanup:
1023  if (me)
1024    krb5_free_principal(context, me);
1025  if (server)
1026    krb5_free_principal(context, server);
1027  if (ccache)
1028    krb5_cc_close(context, ccache);
1029  my_creds.client = 0;
1030  my_creds.server = 0;
1031  krb5_free_cred_contents(context, &my_creds);
1032  krb5_free_context(context);
1033  return retval;
1034}
1035
1036krb5_error_code do_v5_kdestroy(cachename)
1037     char       *cachename;
1038{
1039  krb5_context context;
1040  krb5_error_code retval;
1041  krb5_ccache cache;
1042
1043  retval = krb5_init_context(&context);
1044  if (retval)
1045    return retval;
1046
1047  if (!cachename)
1048    cachename = krb5_cc_default_name(context);
1049
1050  krb5_init_ets(context);
1051
1052  retval = krb5_cc_resolve(context, cachename, &cache);
1053  if (retval)
1054    {
1055      krb5_free_context(context);
1056      return retval;
1057    }
1058
1059  retval = krb5_cc_destroy(context, cache);
1060
1061  krb5_free_context(context);
1062  return retval;
1063}
1064#endif /* KRB5 */
Note: See TracBrowser for help on using the repository browser.