source: trunk/athena/lib/al/homedir.c @ 11787

Revision 11787, 7.5 KB checked in by ghudson, 26 years ago (diff)
From mwhitson: <sys/stat.h> should come after <sys/types.h>.
Line 
1/* Copyright 1997 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16/* This file is part of the Athena login library.  It implements
17 * functions to set up and revert user home directories.
18 */
19
20static const char rcsid[] = "$Id: homedir.c,v 1.8 1998-07-25 20:58:31 ghudson Exp $";
21
22#include <hesiod.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/wait.h>
29#include <unistd.h>
30#include <errno.h>
31#include <pwd.h>
32#include <dirent.h>
33#include "al.h"
34#include "al_private.h"
35
36int al__setup_homedir(const char *username, struct al_record *record,
37                      int havecred, int tmphomedir)
38{
39  struct passwd *local_pwd, *hes_pwd;
40  pid_t pid, rpid;
41  int status;
42  char *tmpdir, *tmpfile, *saved_homedir;
43  void *hescontext;
44  DIR *dir;
45  struct dirent *entry;
46
47  /* If there's an existing session using a tmp homedir, we'll use that. */
48  if (record->old_homedir)
49    return AL_WXTMPDIR;
50
51  /* Get local password entry. User should already have been added to
52   * passwd database, so if this fails, we've already lost, so punt. */
53  local_pwd = al__getpwnam(username);
54  if (!local_pwd)
55    return AL_WNOHOMEDIR;
56
57  /* Get hesiod password entry. If the user has no hesiod passwd
58   * entry or the listed homedir differs from the local passwd entry,
59   * return AL_SUCCESS (and use the local homedir). */
60  if (hesiod_init(&hescontext) != 0)
61    {
62      al__free_passwd(local_pwd);
63      return AL_WNOHOMEDIR;
64    }
65  hes_pwd = hesiod_getpwnam(hescontext, username);
66  if (!hes_pwd || strcmp(local_pwd->pw_dir, hes_pwd->pw_dir))
67    {
68      if (hes_pwd)
69        hesiod_free_passwd(hescontext, hes_pwd);
70      hesiod_end(hescontext);
71      al__free_passwd(local_pwd);
72      return AL_SUCCESS;
73    }
74  if (hes_pwd)
75    hesiod_free_passwd(hescontext, hes_pwd);
76  hesiod_end(hescontext);
77
78  /* We want to attach a remote home directory. Make sure this is OK. */
79  if (access(PATH_NOATTACH, F_OK) == 0)
80    {
81      al__free_passwd(local_pwd);
82      return AL_WNOATTACH;
83    }
84
85  pid = fork();
86  switch (pid)
87    {
88    case -1:
89      /* If we can't fork, we just lose. */
90      al__free_passwd(local_pwd);
91      return AL_WNOHOMEDIR;
92
93    case 0:
94      close(STDOUT_FILENO);
95      close(STDERR_FILENO);
96      if (havecred)
97        {
98          execl(PATH_ATTACH, "attach", "-user", username, "-quiet",
99                "-nozephyr", username, (char *) NULL);
100        }
101      else
102        {
103          execl(PATH_ATTACH, "attach", "-user", username, "-quiet",
104                "-nozephyr", "-nomap", username, (char *) NULL);
105        }
106      _exit(1);
107
108    default:
109      while ((rpid = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
110        ;
111
112      if (rpid == pid && WIFEXITED(status) && WEXITSTATUS(status) == 0 &&
113          access(local_pwd->pw_dir, F_OK) == 0)
114        {
115          record->attached = 1;
116          al__free_passwd(local_pwd);
117          return AL_SUCCESS;
118        }
119      break;
120    }
121
122  /* attach failed somehow. Try to make a local homedir now, unless
123   * the caller doesn't want that. */
124  if (!tmphomedir)
125    {
126      al__free_passwd(local_pwd);
127      return AL_WNOHOMEDIR;
128    }
129
130  /* Allocate space to hold directory names. */
131  tmpdir = malloc(strlen(PATH_TMPDIRS) * 2 + strlen(username) * 2 + 8);
132  if (!tmpdir)
133    {
134      al__free_passwd(local_pwd);
135      return AL_ENOMEM;
136    }
137
138  /* If the user's temporary directory does not exist, we need to create
139   * it.  PATH_TMPDIRS is not world-writable, so we don't have to be
140   * paranoid about the creation of the user home directory, but we do
141   * have to be careful about doing anything as root in a diretory which
142   * we've already chowned to the user. */
143  sprintf(tmpdir, "%s/%s", PATH_TMPDIRS, username);
144  if (access(tmpdir, F_OK) == -1)
145    {
146      /* First make sure PATH_TMPDIRS exists. */
147      if (access(PATH_TMPDIRS, F_OK) == -1)
148        mkdir(PATH_TMPDIRS, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
149
150      /* Create and chown tmpdir. */
151      if (mkdir(tmpdir, S_IRWXU) == -1
152          || chown(tmpdir, local_pwd->pw_uid, local_pwd->pw_gid) == -1)
153        {
154          rmdir(tmpdir);
155          free(tmpdir);
156          al__free_passwd(local_pwd);
157          return AL_WNOHOMEDIR;
158        }
159
160      /* Copy files from PATH_TMPPROTO to the ephemeral directory. */
161      dir = opendir(PATH_TMPPROTO);
162      if (!dir)
163        {
164          rmdir(tmpdir);
165          free(tmpdir);
166          al__free_passwd(local_pwd);
167          return AL_WNOHOMEDIR;
168        }
169
170      while ((entry = readdir(dir)) != NULL)
171        {
172          if (strcmp(entry->d_name, ".") == 0
173              || strcmp(entry->d_name, "..") == 0)
174            continue;
175
176          /* fork to copy the file into the tmpdir. */
177          pid = fork();
178          switch (pid)
179            {
180            case -1:
181              closedir(dir);
182              rmdir(tmpdir);
183              free(tmpdir);
184              al__free_passwd(local_pwd);
185              return AL_WNOHOMEDIR;
186
187            case 0:
188              close(STDOUT_FILENO);
189              close(STDERR_FILENO);
190              if (setgid(local_pwd->pw_gid) == -1
191                  || setuid(local_pwd->pw_uid) == -1)
192                _exit(1);
193              tmpfile = malloc(strlen(PATH_TMPPROTO) + strlen(entry->d_name)
194                               + 2);
195              if (!tmpfile)
196                _exit(1);
197              sprintf(tmpfile, "%s/%s", PATH_TMPPROTO, entry->d_name);
198              execlp("cp", "cp", tmpfile, tmpdir, (char *) NULL);
199              _exit(1);
200
201            default:
202              while ((rpid = waitpid(pid, &status, 0) < 0) && errno == EINTR)
203                ;
204              if (rpid == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
205                {
206                  closedir(dir);
207                  rmdir(tmpdir);
208                  free(tmpdir);
209                  al__free_passwd(local_pwd);
210                  return AL_WNOHOMEDIR;
211                }
212              break;
213            }
214        }
215      closedir(dir);
216    }
217
218  /* Update session records.  (malloc first so we will never have
219   * to back out after calling al__change_passwd_homedir). */
220  if (!record->passwd_added)
221    {
222      saved_homedir = malloc(strlen(local_pwd->pw_dir) + 1);
223      if (!saved_homedir)
224        {
225          free(tmpdir);
226          al__free_passwd(local_pwd);
227          return AL_ENOMEM;
228        }
229      strcpy(saved_homedir, local_pwd->pw_dir);
230    }
231  if (al__change_passwd_homedir(username, tmpdir) != AL_SUCCESS)
232    {
233      free(tmpdir);
234      al__free_passwd(local_pwd);
235      return AL_WNOHOMEDIR;
236    }
237  if (!record->passwd_added)
238    record->old_homedir = saved_homedir;
239
240  free(tmpdir);
241  al__free_passwd(local_pwd);
242  return AL_WTMPDIR;
243}
244
245int al__revert_homedir(const char *username, struct al_record *record)
246{
247  struct passwd *local_pwd;
248  pid_t pid;
249  int status;
250
251  local_pwd = al__getpwnam(username);
252  if (!local_pwd)
253    return AL_EPERM;
254
255  if (record->old_homedir && !record->passwd_added)
256    {
257      if (al__change_passwd_homedir(username,
258                                    record->old_homedir) != AL_SUCCESS)
259        {
260          al__free_passwd(local_pwd);
261          return AL_EPERM;
262        }
263    }
264
265  if (record->attached)
266    {
267      pid = fork();
268      switch (pid)
269        {
270        case -1:
271          al__free_passwd(local_pwd);
272          return AL_ENOMEM;
273
274        case 0:
275          close(STDOUT_FILENO);
276          close(STDERR_FILENO);
277          if (setgid(local_pwd->pw_gid) == -1
278              || setuid(local_pwd->pw_uid) == -1)
279            _exit(1);
280          execl(PATH_DETACH, "detach", "-quiet", "-nozephyr",
281                username, (char *) NULL);
282          _exit(1);
283
284        default:
285          while (waitpid(pid, &status, 0) < 0 && errno == EINTR)
286            ;
287          break;
288        }
289    }
290
291  al__free_passwd(local_pwd);
292  return AL_SUCCESS;
293}
Note: See TracBrowser for help on using the repository browser.