/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: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/*
3
 
 * Splashy - 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
 
          if(errno == ENOENT){
124
 
            free(exe_link);
125
 
            continue;
126
 
          }
127
 
          perror("lstat");
128
 
          free(exe_link);
129
 
          free(prompt);
130
 
          closedir(proc_dir);
131
 
          return EXIT_FAILURE;
132
 
        }
133
 
        if(not S_ISLNK(exe_stat.st_mode)
134
 
           or exe_stat.st_uid != 0
135
 
           or exe_stat.st_gid != 0){
136
 
          free(exe_link);
137
 
          continue;
138
 
        }
139
 
        
140
 
        sret = readlink(exe_link, exe_target, sizeof(exe_target));
141
 
        free(exe_link);
142
 
      }
143
 
      if((sret == ((ssize_t)sizeof(exe_target)-1))
144
 
         and (memcmp(splashy_name, exe_target,
145
 
                     sizeof(exe_target)-1) == 0)){
146
 
        splashy_pid = pid;
147
 
        break;
148
 
      }
149
 
    }
150
 
    closedir(proc_dir);
151
 
  }
152
 
  if(splashy_pid == 0){
153
 
    free(prompt);
154
 
    return EXIT_FAILURE;
155
 
  }
156
 
  
157
 
  /* Set up the signal handler */
158
 
  {
159
 
    struct sigaction old_action,
160
 
      new_action = { .sa_handler = termination_handler,
161
 
                     .sa_flags = 0 };
162
 
    sigemptyset(&new_action.sa_mask);
163
 
    sigaddset(&new_action.sa_mask, SIGINT);
164
 
    sigaddset(&new_action.sa_mask, SIGHUP);
165
 
    sigaddset(&new_action.sa_mask, SIGTERM);
166
 
    ret = sigaction(SIGINT, NULL, &old_action);
167
 
    if(ret == -1){
168
 
      perror("sigaction");
169
 
      free(prompt);
170
 
      return EXIT_FAILURE;
171
 
    }
172
 
    if(old_action.sa_handler != SIG_IGN){
173
 
      ret = sigaction(SIGINT, &new_action, NULL);
174
 
      if(ret == -1){
175
 
        perror("sigaction");
176
 
        free(prompt);
177
 
        return EXIT_FAILURE;
178
 
      }
179
 
    }
180
 
    ret = sigaction(SIGHUP, NULL, &old_action);
181
 
    if(ret == -1){
182
 
      perror("sigaction");
183
 
      free(prompt);
184
 
      return EXIT_FAILURE;
185
 
    }
186
 
    if(old_action.sa_handler != SIG_IGN){
187
 
      ret = sigaction(SIGHUP, &new_action, NULL);
188
 
      if(ret == -1){
189
 
        perror("sigaction");
190
 
        free(prompt);
191
 
        return EXIT_FAILURE;
192
 
      }
193
 
    }
194
 
    ret = sigaction(SIGTERM, NULL, &old_action);
195
 
    if(ret == -1){
196
 
      perror("sigaction");
197
 
      free(prompt);
198
 
      return EXIT_FAILURE;
199
 
    }
200
 
    if(old_action.sa_handler != SIG_IGN){
201
 
      ret = sigaction(SIGTERM, &new_action, NULL);
202
 
      if(ret == -1){
203
 
        perror("sigaction");
204
 
        free(prompt);
205
 
        return EXIT_FAILURE;
206
 
      }
207
 
    }
208
 
  }
209
 
  
210
 
  /* Fork off the splashy command to prompt for password */
211
 
  pid_t splashy_command_pid = 0;
212
 
  if(not interrupted_by_signal){
213
 
    splashy_command_pid = fork();
214
 
    if(splashy_command_pid == -1){
215
 
      if(not interrupted_by_signal){
216
 
        perror("fork");
217
 
      }
218
 
      return EXIT_FAILURE;
219
 
    }
220
 
    /* Child */
221
 
    if(splashy_command_pid == 0){
222
 
      const char splashy_command[] = "/sbin/splashy_update";
223
 
      ret = execl(splashy_command, splashy_command, prompt,
224
 
                  (char *)NULL);
225
 
      if(not interrupted_by_signal){
226
 
        perror("execl");
227
 
      }
228
 
      free(prompt);
229
 
      _exit(EXIT_FAILURE);
230
 
    }
231
 
  }
232
 
  
233
 
  /* Parent */
234
 
  free(prompt);
235
 
  
236
 
  /* Wait for command to complete */
237
 
  if(not interrupted_by_signal and splashy_command_pid != 0){
238
 
    int status;
239
 
    ret = waitpid(splashy_command_pid, &status, 0);
240
 
    if(ret == -1){
241
 
      if(errno != EINTR){
242
 
        perror("waitpid");
243
 
      }
244
 
      if(errno == ECHILD){
245
 
        splashy_command_pid = 0;
246
 
      }
247
 
    } else {
248
 
      /* The child process has exited */
249
 
      splashy_command_pid = 0;
250
 
      if(not interrupted_by_signal and WIFEXITED(status)
251
 
         and WEXITSTATUS(status)==0){
252
 
        return EXIT_SUCCESS;
253
 
      }
254
 
    }
255
 
  }
256
 
  kill(splashy_pid, SIGTERM);
257
 
  if(interrupted_by_signal and splashy_command_pid != 0){
258
 
    kill(splashy_command_pid, SIGTERM);
259
 
  }
260
 
  sleep(2);
261
 
  while(kill(splashy_pid, 0) == 0){
262
 
    kill(splashy_pid, SIGKILL);
263
 
    sleep(1);
264
 
  }
265
 
  pid_t new_splashy_pid = fork();
266
 
  if(new_splashy_pid == 0){
267
 
    /* Child; will become new splashy process */
268
 
    
269
 
    /* Make the effective user ID (root) the only user ID instead of
270
 
       the real user ID (mandos) */
271
 
    ret = setuid(geteuid());
272
 
    if(ret == -1){
273
 
      perror("setuid");
274
 
    }
275
 
    
276
 
    setsid();
277
 
    ret = chdir("/");
278
 
/*     if(fork() != 0){ */
279
 
/*       _exit(EXIT_SUCCESS); */
280
 
/*     } */
281
 
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
282
 
    if(ret == -1){
283
 
      perror("dup2");
284
 
      _exit(EXIT_FAILURE);
285
 
    }
286
 
    
287
 
    execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
288
 
    if(not interrupted_by_signal){
289
 
      perror("execl");
290
 
    }
291
 
    _exit(EXIT_FAILURE);
292
 
  }
293
 
  
294
 
  return EXIT_FAILURE;
295
 
}