/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to plugins.d/splashy.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/*
3
 
 * Passprompt - Read a password from splashy and output it
4
 
 * 
5
 
 * Copyright © 2008,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 Björn Påhlsson
7
 
 * 
8
 
 * This program is free software: you can redistribute it and/or
9
 
 * modify it under the terms of the GNU General Public License as
10
 
 * published by the Free Software Foundation, either version 3 of the
11
 
 * License, or (at your option) any later version.
12
 
 * 
13
 
 * This program is distributed in the hope that it will be useful, but
14
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 
 * General Public License for more details.
17
 
 * 
18
 
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program.  If not, see
20
 
 * <http://www.gnu.org/licenses/>.
21
 
 * 
22
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
23
 
 * <https://www.fukt.bsnet.se/~teddy/>.
24
 
 */
25
 
 
26
 
#define _GNU_SOURCE             /* asprintf() */
27
 
#include <signal.h>             /* sig_atomic_t, struct sigaction,
28
 
                                   sigemptyset(), sigaddset(), SIGINT,
29
 
                                   SIGHUP, SIGTERM, sigaction,
30
 
                                   SIG_IGN, kill(), SIGKILL */
31
 
#include <stddef.h>             /* NULL */
32
 
#include <stdlib.h>             /* getenv() */
33
 
#include <stdio.h>              /* asprintf(), perror() */
34
 
#include <stdlib.h>             /* EXIT_FAILURE, free(), strtoul(),
35
 
                                   EXIT_SUCCESS */
36
 
#include <sys/types.h>          /* pid_t, DIR, struct dirent,
37
 
                                   ssize_t */
38
 
#include <dirent.h>             /* opendir(), readdir(), closedir() */
39
 
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
40
 
#include <iso646.h>             /* not, or, and */
41
 
#include <unistd.h>             /* readlink(), fork(), execl(),
42
 
                                   sleep(), dup2() STDERR_FILENO,
43
 
                                   STDOUT_FILENO, _exit() */
44
 
#include <string.h>             /* memcmp() */
45
 
#include <errno.h>              /* errno */
46
 
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
47
 
                                   WEXITSTATUS() */
48
 
 
49
 
sig_atomic_t interrupted_by_signal = 0;
50
 
 
51
 
static void termination_handler(__attribute__((unused))int signum){
52
 
  interrupted_by_signal = 1;
53
 
}
54
 
 
55
 
int main(__attribute__((unused))int argc,
56
 
         __attribute__((unused))char **argv){
57
 
  int ret = 0;
58
 
  
59
 
  /* Create prompt string */
60
 
  char *prompt = NULL;
61
 
  {
62
 
    const char *const cryptsource = getenv("cryptsource");
63
 
    const char *const crypttarget = getenv("crypttarget");
64
 
    const char *const prompt_start = "getpass "
65
 
      "Enter passphrase to unlock the disk";
66
 
    
67
 
    if(cryptsource == NULL){
68
 
      if(crypttarget == NULL){
69
 
        ret = asprintf(&prompt, "%s: ", prompt_start);
70
 
      } else {
71
 
        ret = asprintf(&prompt, "%s (%s): ", prompt_start,
72
 
                       crypttarget);
73
 
      }
74
 
    } else {
75
 
      if(crypttarget == NULL){
76
 
        ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
77
 
      } else {
78
 
        ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
79
 
                       cryptsource, crypttarget);
80
 
      }
81
 
    }
82
 
    if(ret == -1){
83
 
      return EXIT_FAILURE;
84
 
    }
85
 
  }
86
 
  
87
 
  /* Find splashy process */
88
 
  pid_t splashy_pid = 0;
89
 
  {
90
 
    const char splashy_name[] = "/sbin/splashy";
91
 
    DIR *proc_dir = opendir("/proc");
92
 
    if(proc_dir == NULL){
93
 
      free(prompt);
94
 
      perror("opendir");
95
 
      return EXIT_FAILURE;
96
 
    }
97
 
    for(struct dirent *proc_ent = readdir(proc_dir);
98
 
        proc_ent != NULL;
99
 
        proc_ent = readdir(proc_dir)){
100
 
      pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10);
101
 
      if(pid == 0){
102
 
        /* Not a process */
103
 
        continue;
104
 
      }
105
 
      /* Find the executable name by doing readlink() on the
106
 
         /proc/<pid>/exe link */
107
 
      char exe_target[sizeof(splashy_name)];
108
 
      ssize_t sret;
109
 
      {
110
 
        char *exe_link;
111
 
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
112
 
        if(ret == -1){
113
 
          perror("asprintf");
114
 
          free(prompt);
115
 
          closedir(proc_dir);
116
 
          return EXIT_FAILURE;
117
 
        }
118
 
        
119
 
        /* Check that it refers to a symlink owned by root:root */
120
 
        struct stat exe_stat;
121
 
        ret = lstat(exe_link, &exe_stat);
122
 
        if(ret == -1){
123
 
          perror("lstat");
124
 
          free(exe_link);
125
 
          free(prompt);
126
 
          closedir(proc_dir);
127
 
          return EXIT_FAILURE;
128
 
        }
129
 
        if(not S_ISLNK(exe_stat.st_mode)
130
 
           or exe_stat.st_uid != 0
131
 
           or exe_stat.st_gid != 0){
132
 
          free(exe_link);
133
 
          continue;
134
 
        }
135
 
        
136
 
        sret = readlink(exe_link, exe_target, sizeof(exe_target));
137
 
        free(exe_link);
138
 
      }
139
 
      if((sret == ((ssize_t)sizeof(exe_target)-1))
140
 
         and (memcmp(splashy_name, exe_target,
141
 
                     sizeof(exe_target)-1) == 0)){
142
 
        splashy_pid = pid;
143
 
        break;
144
 
      }
145
 
    }
146
 
    closedir(proc_dir);
147
 
  }
148
 
  if(splashy_pid == 0){
149
 
    free(prompt);
150
 
    return EXIT_FAILURE;
151
 
  }
152
 
  
153
 
  /* Set up the signal handler */
154
 
  {
155
 
    struct sigaction old_action,
156
 
      new_action = { .sa_handler = termination_handler,
157
 
                     .sa_flags = 0 };
158
 
    sigemptyset(&new_action.sa_mask);
159
 
    sigaddset(&new_action.sa_mask, SIGINT);
160
 
    sigaddset(&new_action.sa_mask, SIGHUP);
161
 
    sigaddset(&new_action.sa_mask, SIGTERM);
162
 
    ret = sigaction(SIGINT, NULL, &old_action);
163
 
    if(ret == -1){
164
 
      perror("sigaction");
165
 
      free(prompt);
166
 
      return EXIT_FAILURE;
167
 
    }
168
 
    if(old_action.sa_handler != SIG_IGN){
169
 
      ret = sigaction(SIGINT, &new_action, NULL);
170
 
      if(ret == -1){
171
 
        perror("sigaction");
172
 
        free(prompt);
173
 
        return EXIT_FAILURE;
174
 
      }
175
 
    }
176
 
    ret = sigaction(SIGHUP, NULL, &old_action);
177
 
    if(ret == -1){
178
 
      perror("sigaction");
179
 
      free(prompt);
180
 
      return EXIT_FAILURE;
181
 
    }
182
 
    if(old_action.sa_handler != SIG_IGN){
183
 
      ret = sigaction(SIGHUP, &new_action, NULL);
184
 
      if(ret == -1){
185
 
        perror("sigaction");
186
 
        free(prompt);
187
 
        return EXIT_FAILURE;
188
 
      }
189
 
    }
190
 
    ret = sigaction(SIGTERM, NULL, &old_action);
191
 
    if(ret == -1){
192
 
      perror("sigaction");
193
 
      free(prompt);
194
 
      return EXIT_FAILURE;
195
 
    }
196
 
    if(old_action.sa_handler != SIG_IGN){
197
 
      ret = sigaction(SIGTERM, &new_action, NULL);
198
 
      if(ret == -1){
199
 
        perror("sigaction");
200
 
        free(prompt);
201
 
        return EXIT_FAILURE;
202
 
      }
203
 
    }
204
 
  }
205
 
  
206
 
  /* Fork off the splashy command to prompt for password */
207
 
  pid_t splashy_command_pid = 0;
208
 
  if(not interrupted_by_signal){
209
 
    splashy_command_pid = fork();
210
 
    if(splashy_command_pid == -1){
211
 
      if(not interrupted_by_signal){
212
 
        perror("fork");
213
 
      }
214
 
      return EXIT_FAILURE;
215
 
    }
216
 
    /* Child */
217
 
    if(splashy_command_pid == 0){
218
 
      const char splashy_command[] = "/sbin/splashy_update";
219
 
      ret = execl(splashy_command, splashy_command, prompt,
220
 
                  (char *)NULL);
221
 
      if(not interrupted_by_signal){
222
 
        perror("execl");
223
 
      }
224
 
      free(prompt);
225
 
      _exit(EXIT_FAILURE);
226
 
    }
227
 
  }
228
 
  
229
 
  /* Parent */
230
 
  free(prompt);
231
 
  
232
 
  /* Wait for command to complete */
233
 
  if(not interrupted_by_signal and splashy_command_pid != 0){
234
 
    int status;
235
 
    ret = waitpid(splashy_command_pid, &status, 0);
236
 
    if(ret == -1){
237
 
      if(errno != EINTR){
238
 
        perror("waitpid");
239
 
      }
240
 
      if(errno == ECHILD){
241
 
        splashy_command_pid = 0;
242
 
      }
243
 
    } else {
244
 
      /* The child process has exited */
245
 
      splashy_command_pid = 0;
246
 
      if(not interrupted_by_signal and WIFEXITED(status)
247
 
         and WEXITSTATUS(status)==0){
248
 
        return EXIT_SUCCESS;
249
 
      }
250
 
    }
251
 
  }
252
 
  kill(splashy_pid, SIGTERM);
253
 
  if(interrupted_by_signal and splashy_command_pid != 0){
254
 
    kill(splashy_command_pid, SIGTERM);
255
 
  }
256
 
  sleep(2);
257
 
  while(kill(splashy_pid, 0) == 0){
258
 
    kill(splashy_pid, SIGKILL);
259
 
    sleep(1);
260
 
  }
261
 
  pid_t new_splashy_pid = fork();
262
 
  if(new_splashy_pid == 0){
263
 
    /* Child; will become new splashy process */
264
 
    
265
 
    /* Make the effective user ID (root) the only user ID instead of
266
 
       the real user ID (mandos) */
267
 
    ret = setuid(geteuid());
268
 
    if(ret == -1){
269
 
      perror("setuid");
270
 
    }
271
 
    
272
 
    setsid();
273
 
    ret = chdir("/");
274
 
/*     if(fork() != 0){ */
275
 
/*       _exit(EXIT_SUCCESS); */
276
 
/*     } */
277
 
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
278
 
    if(ret == -1){
279
 
      perror("dup2");
280
 
      _exit(EXIT_FAILURE);
281
 
    }
282
 
    
283
 
    execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
284
 
    if(not interrupted_by_signal){
285
 
      perror("execl");
286
 
    }
287
 
    _exit(EXIT_FAILURE);
288
 
  }
289
 
  
290
 
  return EXIT_FAILURE;
291
 
}