/mandos/release

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

« back to all changes in this revision

Viewing changes to plugins.d/splashy.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define _GNU_SOURCE             /* asprintf() */
2
 
#include <signal.h>             /* sig_atomic_t, struct sigaction,
3
 
                                   sigemptyset(), sigaddset(),
4
 
                                   sigaction, SIGINT, SIG_IGN, SIGHUP,
5
 
                                   SIGTERM, kill(), SIGKILL */
6
 
#include <stddef.h>             /* NULL */
7
 
#include <stdlib.h>             /* getenv() */
8
 
#include <stdio.h>              /* asprintf(), perror() */
9
 
#include <stdlib.h>             /* EXIT_FAILURE, EXIT_SUCCESS,
10
 
                                   strtoul(), free() */
11
 
#include <sys/types.h>          /* pid_t, DIR, struct dirent,
12
 
                                   ssize_t */
13
 
#include <dirent.h>             /* opendir(), readdir(), closedir() */
14
 
#include <unistd.h>             /* readlink(), fork(), execl(),
15
 
                                   _exit */
16
 
#include <string.h>             /* memcmp() */
17
 
#include <iso646.h>             /* and */
18
 
#include <errno.h>              /* errno */
19
 
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
20
 
                                   WEXITSTATUS() */
21
 
 
22
 
sig_atomic_t interrupted_by_signal = 0;
23
 
 
24
 
static void termination_handler(__attribute__((unused))int signum){
25
 
  interrupted_by_signal = 1;
26
 
}
27
 
 
28
 
int main(__attribute__((unused))int argc,
29
 
         __attribute__((unused))char **argv){
30
 
  int ret = 0;
31
 
  
32
 
  /* Create prompt string */
33
 
  char *prompt = NULL;
34
 
  {
35
 
    const char *const cryptsource = getenv("cryptsource");
36
 
    const char *const crypttarget = getenv("crypttarget");
37
 
    const char *const prompt_start = "getpass "
38
 
      "Enter passphrase to unlock the disk";
39
 
    
40
 
    if(cryptsource == NULL){
41
 
      if(crypttarget == NULL){
42
 
        ret = asprintf(&prompt, "%s: ", prompt_start);
43
 
      } else {
44
 
        ret = asprintf(&prompt, "%s (%s): ", prompt_start,
45
 
                       crypttarget);
46
 
      }
47
 
    } else {
48
 
      if(crypttarget == NULL){
49
 
        ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
50
 
      } else {
51
 
        ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
52
 
                       cryptsource, crypttarget);
53
 
      }
54
 
    }
55
 
    if(ret == -1){
56
 
      return EXIT_FAILURE;
57
 
    }
58
 
  }
59
 
  
60
 
  /* Find splashy process */
61
 
  pid_t splashy_pid = 0;
62
 
  {
63
 
    const char splashy_name[] = "/sbin/splashy";
64
 
    DIR *proc_dir = opendir("/proc");
65
 
    if(proc_dir == NULL){
66
 
      free(prompt);
67
 
      perror("opendir");
68
 
      return EXIT_FAILURE;
69
 
    }
70
 
    for(struct dirent *proc_ent = readdir(proc_dir);
71
 
        proc_ent != NULL;
72
 
        proc_ent = readdir(proc_dir)){
73
 
      pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10);
74
 
      if(pid == 0){
75
 
        /* Not a process */
76
 
        continue;
77
 
      }
78
 
      /* Find the executable name by doing readlink() on the
79
 
         /proc/<pid>/exe link */
80
 
      char exe_target[sizeof(splashy_name)];
81
 
      ssize_t sret;
82
 
      {
83
 
        char *exe_link;
84
 
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
85
 
        if(ret == -1){
86
 
          perror("asprintf");
87
 
          free(prompt);
88
 
          closedir(proc_dir);
89
 
          return EXIT_FAILURE;
90
 
        }
91
 
        sret = readlink(exe_link, exe_target, sizeof(exe_target));
92
 
        free(exe_link);
93
 
      }
94
 
      if((sret == ((ssize_t)sizeof(exe_target)-1))
95
 
         and (memcmp(splashy_name, exe_target,
96
 
                     sizeof(exe_target)-1) == 0)){
97
 
        splashy_pid = pid;
98
 
        break;
99
 
      }
100
 
    }
101
 
    closedir(proc_dir);
102
 
  }
103
 
  if(splashy_pid == 0){
104
 
    free(prompt);
105
 
    return EXIT_FAILURE;
106
 
  }
107
 
  
108
 
  /* Set up the signal handler */
109
 
  {
110
 
    struct sigaction old_action,
111
 
      new_action = { .sa_handler = termination_handler,
112
 
                     .sa_flags = 0 };
113
 
    sigemptyset(&new_action.sa_mask);
114
 
    sigaddset(&new_action.sa_mask, SIGINT);
115
 
    sigaddset(&new_action.sa_mask, SIGHUP);
116
 
    sigaddset(&new_action.sa_mask, SIGTERM);
117
 
    ret = sigaction(SIGINT, NULL, &old_action);
118
 
    if(ret == -1){
119
 
      perror("sigaction");
120
 
      free(prompt);
121
 
      return EXIT_FAILURE;
122
 
    }
123
 
    if (old_action.sa_handler != SIG_IGN){
124
 
      ret = sigaction(SIGINT, &new_action, NULL);
125
 
      if(ret == -1){
126
 
        perror("sigaction");
127
 
        free(prompt);
128
 
        return EXIT_FAILURE;
129
 
      }
130
 
    }
131
 
    ret = sigaction(SIGHUP, NULL, &old_action);
132
 
    if(ret == -1){
133
 
      perror("sigaction");
134
 
      free(prompt);
135
 
      return EXIT_FAILURE;
136
 
    }
137
 
    if (old_action.sa_handler != SIG_IGN){
138
 
      ret = sigaction(SIGHUP, &new_action, NULL);
139
 
      if(ret == -1){
140
 
        perror("sigaction");
141
 
        free(prompt);
142
 
        return EXIT_FAILURE;
143
 
      }
144
 
    }
145
 
    ret = sigaction(SIGTERM, NULL, &old_action);
146
 
    if(ret == -1){
147
 
      perror("sigaction");
148
 
      free(prompt);
149
 
      return EXIT_FAILURE;
150
 
    }
151
 
    if (old_action.sa_handler != SIG_IGN){
152
 
      ret = sigaction(SIGTERM, &new_action, NULL);
153
 
      if(ret == -1){
154
 
        perror("sigaction");
155
 
        free(prompt);
156
 
        return EXIT_FAILURE;
157
 
      }
158
 
    }
159
 
  }
160
 
  
161
 
  /* Fork off the splashy command to prompt for password */
162
 
  pid_t splashy_command_pid = 0;
163
 
  if(not interrupted_by_signal){
164
 
    splashy_command_pid = fork();
165
 
    if(splashy_command_pid == -1){
166
 
      if(not interrupted_by_signal){
167
 
        perror("fork");
168
 
      }
169
 
      return EXIT_FAILURE;
170
 
    }
171
 
    /* Child */
172
 
    if(splashy_command_pid == 0){
173
 
      const char splashy_command[] = "/sbin/splashy_update";
174
 
      ret = execl(splashy_command, splashy_command, prompt,
175
 
                  (char *)NULL);
176
 
      if(not interrupted_by_signal and errno != ENOENT){
177
 
        /* Don't report "File not found", since splashy might not be
178
 
           installed. */
179
 
        perror("execl");
180
 
      }
181
 
      free(prompt);
182
 
      return EXIT_FAILURE;
183
 
    }
184
 
  }
185
 
  
186
 
  /* Parent */
187
 
  free(prompt);
188
 
  
189
 
  /* Wait for command to complete */
190
 
  int status;
191
 
  while(not interrupted_by_signal){
192
 
    waitpid(splashy_command_pid, &status, 0);
193
 
    if(not interrupted_by_signal
194
 
       and WIFEXITED(status) and WEXITSTATUS(status)==0){
195
 
      return EXIT_SUCCESS;
196
 
    }
197
 
  }
198
 
  kill(splashy_pid, SIGTERM);
199
 
  if(interrupted_by_signal){
200
 
    kill(splashy_command_pid, SIGTERM);
201
 
  }
202
 
  
203
 
  pid_t new_splashy_pid = fork();
204
 
  if(new_splashy_pid == 0){
205
 
    /* Child; will become new splashy process */
206
 
    while(kill(splashy_pid, 0)){
207
 
      sleep(2);
208
 
      kill(splashy_pid, SIGKILL);
209
 
      sleep(1);
210
 
    }
211
 
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
212
 
    if(ret == -1){
213
 
      perror("dup2");
214
 
      _exit(EXIT_FAILURE);
215
 
    }
216
 
    execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
217
 
  }
218
 
  
219
 
  return EXIT_FAILURE;
220
 
}