File: pam-tmpdir-helper.c

package info (click to toggle)
pam-tmpdir 0.11
  • links: PTS
  • area: main
  • in suites: sid, trixie
  • size: 128 kB
  • sloc: ansic: 445; sh: 171; makefile: 28
file content (143 lines) | stat: -rw-r--r-- 4,020 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* pam_tmpdir module, based on pam_env which in turn was based on
   pam_mail */

/*
 * $Id: pam_env.c,v 1.3 1999/11/08 05:46:53 morgan Exp $
 * 
 * Written by Tollef Fog Heen <tfheen@err.no> 2001-02-03
 *
 * Based on pam_env
 * Written by Dave Kinchlea <kinch@kinch.ark.com> 1997/01/31
 * Inspired by Andrew Morgan <morgan@parc.power.net, who also supplied the 
 * template for this file (via pam_mail)
 */

#define _GNU_SOURCE

#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <libgen.h>
#include "util.h"

static int make_tmp_directory() {
  int ret;

  char *user_tmpdir;
  struct stat statbuf;
  mode_t old_umask;
  char *tmpdir = get_tmp_dir();

  if (tmpdir == NULL) {
    return 1;
  }
  
  /* We want 100% control of permissions */
  old_umask = umask(0000);

  /* Create $tmpdir */
  ret = mkdir(tmpdir,0711);

  /* Check whether the mkdir succeeded */
  if (ret == -1 && errno != EEXIST) {
    _log_err(LOG_NOTICE, "mkdir %s failed: %s\n", tmpdir, strerror(errno));
    free(tmpdir);
    return 1;
  } else if (ret != -1) {
    if (chown(tmpdir, 0, 0) == -1) {
      _log_err(LOG_NOTICE, "chown 0:0 %s failed: %s\n", tmpdir, strerror(errno));
      free(tmpdir);
      return 1;
    }
  }

  umask(old_umask);

  /* $tmpdir should now exist.  Make sure it is
     Check that $tmpdir is acceptable */

  ret = lstat(tmpdir,&statbuf);
  if (ret == -1) {
    _log_err(LOG_NOTICE, "%s", "lstat %s failed: %s\n", tmpdir, strerror(errno));
    return 1;
  } else if (statbuf.st_uid != 0) {
    /* Somebody else than root has grabbed /tmp/user.  Bad, bad, bad. */
    _log_err(LOG_ERR, "%s is owned by uid %d instead of root " 
	    "(uid 0). Failed to create safe $TMPDIR\n", tmpdir, 
             statbuf.st_uid);
    free(tmpdir);
    return 1;
  } else if (!S_ISDIR(statbuf.st_mode)) {
    _log_err(LOG_NOTICE, "%s is not a directory. Failed to create safe "
             "$TMPDIR\n", tmpdir);
    free(tmpdir);
    return 1;
  } else if ((statbuf.st_mode & S_IWGRP) || (statbuf.st_mode & S_IWOTH)) {
    _log_err(LOG_NOTICE, "%s is group or world writable. "
	     "Failed to create safe $TMPDIR\n", tmpdir);
    free(tmpdir);
    return 1;
  } else if (!(statbuf.st_mode & S_IXOTH)) {
    _log_err(LOG_NOTICE,"%s is not world searchable. "
	     "Failed to create safe $TMPDIR\n", tmpdir); 
    free(tmpdir);
    return 1;
  }

  if (asprintf(&user_tmpdir, "%s/%d",tmpdir,getuid()) == -1) {
    return 1;
  }

  /* Create user tmp dir */
  ret = mkdir(user_tmpdir,0700);

  if (ret == -1 && errno != EEXIST) {
    _log_err(LOG_NOTICE, "mkdir %s failed: %s\n", user_tmpdir, strerror(errno));
    return 1;
  } else if (ret != -1) {
    if (chown(user_tmpdir, getuid(), getgid()) == -1) {
      _log_err(LOG_NOTICE, "chown %d:%d %s failed: %s\n", getuid(), getgid(), 
               user_tmpdir, strerror(errno));
      return 1;
    }
  }

  ret = lstat(user_tmpdir,&statbuf);
  if (ret == -1) {
    _log_err(LOG_NOTICE, "lstat %s failed: %s\n", user_tmpdir, strerror(errno));
    return 1;
  } else if (statbuf.st_uid != getuid()) {
    _log_err(LOG_NOTICE, "%s owned by uid %d instead of uid %d. "
	     "Failed to create safe $TMPDIR\n", user_tmpdir, statbuf.st_uid, 
             getuid());
    return 1;
  } else if (!S_ISDIR(statbuf.st_mode)) {
    _log_err(LOG_NOTICE, "%s is not a directory. Failed to create safe $TMPDIR\n",
             user_tmpdir);
    return 1;
  }
  if ((statbuf.st_mode & S_IWGRP) || (statbuf.st_mode & S_IWOTH)) {
    _log_err(LOG_NOTICE, "Warning: %s is group or world writable. "
	     "Changing permissions to 0700\n", user_tmpdir);
    if (chmod(user_tmpdir, 0700) == -1) {
      _log_err(LOG_NOTICE, "chmod 0700 %s failed: %s\n", user_tmpdir, 
               strerror(errno));
      return 1;
    }
  }
  return 0;
}

int main(int argc, char **argv) {
  (void)argc;
  (void)argv;

  return make_tmp_directory();
}