OpenDNSSEC-libhsm  1.4.1
pin.c
Go to the documentation of this file.
1 /* $Id: pin.c 6704 2012-09-20 10:43:19Z rb $ */
2 
3 /*
4  * Copyright (c) 2011 .SE (The Internet Infrastructure Foundation).
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/shm.h>
34 #include <sys/sem.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <termios.h>
40 #include <errno.h>
41 
42 #include "libhsm.h"
43 
45 extern hsm_ctx_t *_hsm_ctx;
46 
47 /* Function from libhsm.c */
48 void
49 hsm_ctx_set_error(hsm_ctx_t *ctx, int error, const char *action,
50  const char *message, ...);
51 
52 /* Constants */
53 #define SHM_KEY (key_t)0x0d50d5ec
54 #define SEM_KEY (key_t)0x0d50d5ec
55 #define SHM_PERM S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
56 #define SEM_PERM S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
57 
58 #ifndef HAVE_UNION_SEMUN
59 /* From man page for semctl */
60 union semun {
61  int val; /* Value for SETVAL */
62  struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
63  unsigned short *array; /* Array for GETALL, SETALL */
64 };
65 #endif
66 
67 /* Remember PIN that we can save */
68 static char pin[HSM_MAX_PIN_LENGTH+1];
69 
70 char *
71 prompt_pass(char *prompt)
72 {
73  int c, i = 0;
74  static char pass[HSM_MAX_PIN_LENGTH+1];
75  struct termios oldt, newt;
76 
77  if (prompt == NULL) return NULL;
78 
79  printf("%s", prompt);
80 
81  /* Turn echoing off */
82  if (isatty(fileno(stdin))) {
83  if (tcgetattr(fileno(stdin), &oldt) != 0) return NULL;
84  newt = oldt;
85  newt.c_lflag &= ~ECHO;
86  if (tcsetattr(fileno(stdin), TCSAFLUSH, &newt) != 0) return NULL;
87  }
88 
89  /* Get the password */
90  do {
91  c = fgetc(stdin);
92  pass[i] = c;
93  i++;
94  } while (c != EOF && c != '\n' && c != '\r' && i < HSM_MAX_PIN_LENGTH+1);
95  pass[i-1] = '\0';
96 
97  /* Restore echoing */
98  if (isatty(fileno(stdin))) {
99  tcsetattr(fileno(stdin), TCSAFLUSH, &oldt);
100  }
101  printf("\n");
102 
103  return pass;
104 }
105 
106 int
108 {
109  int semid;
110  struct semid_ds buf;
111  union semun arg;
112 
113  /* Create/get the semaphore */
114  semid = semget(SEM_KEY, 1, IPC_CREAT|IPC_EXCL|SEM_PERM);
115  if (semid == -1) {
116  semid = semget(SEM_KEY, 1, IPC_CREAT|SEM_PERM);
117  if (semid == -1) {
118  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
119  "Could not access the semaphore: %s", strerror(errno));
120  return -1;
121  }
122  } else {
123  /* Set value to 1 if we created it */
124  arg.val = 1;
125  if (semctl(semid, 0, SETVAL, arg) == -1) {
126  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
127  "Could not set value on the semaphore: %s", strerror(errno));
128  return -1;
129  }
130  }
131 
132  /* Get information about the semaphore */
133  arg.buf = &buf;
134  if (semctl(semid, 0, IPC_STAT, arg) != 0) {
135  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
136  "Could not stat the semaphore: %s", strerror(errno));
137  return -1;
138  }
139 
140  /* Check permission to avoid an attack */
141  if ((buf.sem_perm.mode & (SEM_PERM)) != (SEM_PERM) ||
142  buf.sem_perm.gid != getegid())
143  {
144  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_open()",
145  "Bad permissions on the semaphore, please read Getting Help/Troubleshooting on OpenDNSSEC Wiki about this.");
146  return -1;
147  }
148 
149  return semid;
150 }
151 
152 int
153 hsm_sem_wait(int semid)
154 {
155  struct sembuf sb = { 0, -1, 0 };
156 
157  if (semop(semid, &sb, 1) == -1) {
158  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_wait()",
159  "Could not lock the semaphore: %s", strerror(errno));
160  return -1;
161  }
162 
163  return 0;
164 }
165 
166 int
167 hsm_sem_post(int semid)
168 {
169  struct sembuf sb = { 0, 1, 0 };
170 
171  if (semop(semid, &sb, 1) == -1) {
172  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_sem_post()",
173  "Could not unlock the semaphore: %s", strerror(errno));
174  return -1;
175  }
176 
177  return 0;
178 }
179 
180 int
182 {
183  int shmid;
184  size_t shmsize;
185  struct shmid_ds buf;
186 
187  /* Create/get the shared memory */
188  shmsize = sizeof(char)*HSM_MAX_SESSIONS*(HSM_MAX_PIN_LENGTH+1);
189  shmid = shmget(SHM_KEY, shmsize, IPC_CREAT|IPC_EXCL|SHM_PERM);
190  if (shmid == -1) {
191  shmid = shmget(SHM_KEY, shmsize, IPC_CREAT|SHM_PERM);
192  if (shmid == -1) {
193  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
194  "Could not access the shared memory: %s", strerror(errno));
195  return -1;
196  }
197  } else {
198  /* Zeroize if we created the memory area */
199 
200  /* The data should be set to zero according to man page */
201  }
202 
203  /* Get information about the shared memory */
204  if (shmctl(shmid, IPC_STAT, &buf) != 0) {
205  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
206  "Could not stat the semaphore: %s", strerror(errno));
207  return -1;
208  }
209 
210  /* Check the size of the memory segment */
211  if (buf.shm_segsz != shmsize) {
212  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
213  "Bad memory size, please read Getting Help/Troubleshooting on OpenDNSSEC Wiki about this.");
214  return -1;
215  }
216 
217  /* Check permission to avoid an attack */
218  if ((buf.shm_perm.mode & (SHM_PERM)) != (SHM_PERM) ||
219  buf.shm_perm.gid != getegid())
220  {
221  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_shm_open()",
222  "Bad permissions on the shared memory, please read Getting Help/Troubleshooting on OpenDNSSEC Wiki about this.");
223  return -1;
224  }
225 
226  return shmid;
227 }
228 
229 char *
230 hsm_prompt_pin(unsigned int id, const char *repository, unsigned int mode)
231 {
232  /* Shared memory */
233  int shmid;
234  int semid;
235  char *pins = NULL;
236  int index = id * (HSM_MAX_PIN_LENGTH + 1);
237 
238  /* PIN from getpass */
239  char prompt[64];
240  char *prompt_pin = NULL;
241  unsigned int size = 0;
242 
243  /* Check input data */
244  if (id >= HSM_MAX_SESSIONS) return NULL;
245  if (repository == NULL) return NULL;
246  if (mode != HSM_PIN_FIRST && mode != HSM_PIN_RETRY && mode != HSM_PIN_SAVE) return NULL;
247 
248  /* Create/get the semaphore */
249  semid = hsm_sem_open();
250  if (semid == -1) return NULL;
251 
252  /* Lock the semaphore */
253  if (hsm_sem_wait(semid) != 0) return NULL;
254 
255  /* Create/get the shared memory */
256  shmid = hsm_shm_open();
257  if (shmid == -1) {
258  hsm_sem_post(semid);
259  return NULL;
260  }
261 
262  /* Attach to the shared memory */
263  pins = (char *)shmat(shmid, NULL, 0);
264  if (pins == (char *)-1) {
265  pins = NULL;
266  hsm_sem_post(semid);
267  return NULL;
268  }
269 
270  /* Get the PIN */
271  if (mode != HSM_PIN_SAVE) {
272  /* Do we have a PIN in the shared memory? */
273  if (mode == HSM_PIN_FIRST && pins[index] != '\0') {
274  size = strlen(&pins[index]);
275  if (size > HSM_MAX_PIN_LENGTH) size = HSM_MAX_PIN_LENGTH;
276  memcpy(pin, &pins[index], size);
277  pin[size] = '\0';
278  } else {
279  /* Zeroize bad PIN in shared memory */
280  if (mode == HSM_PIN_RETRY && pins[index] != '\0') {
281  memset(&pins[index], '\0', HSM_MAX_PIN_LENGTH+1);
282  }
283 
284  /* Unlock the semaphore if someone would do Ctrl+C */
285  hsm_sem_post(semid);
286 
287  /* Get PIN */
288  snprintf(prompt, 64, "Enter PIN for token %s: ", repository);
289  prompt_pin = prompt_pass(prompt);
290  if (prompt_pin == NULL) {
291  shmdt(pins);
292  pins = NULL;
293  return NULL;
294  }
295 
296  /* Lock the semaphore */
297  hsm_sem_wait(semid);
298 
299  /* Remember PIN */
300  size = strlen(prompt_pin);
301  if (size > HSM_MAX_PIN_LENGTH) size = HSM_MAX_PIN_LENGTH;
302  memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
303  memcpy(pin, prompt_pin, size);
304 
305  /* Zeroize the prompt_pass PIN */
306  memset(prompt_pin, '\0', strlen(prompt_pin));
307  }
308  } else {
309  /* Save the PIN */
310  memcpy(&pins[index], pin, HSM_MAX_PIN_LENGTH+1);
311 
312  /* Zeroize the PIN */
313  memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
314  }
315 
316  /* Detach from the shared memory */
317  shmdt(pins);
318  pins = NULL;
319 
320  /* Unlock the semaphore */
321  hsm_sem_post(semid);
322 
323  return pin;
324 }
325 
326 char *
327 hsm_check_pin(unsigned int id, const char *repository, unsigned int mode)
328 {
329  /* Shared memory */
330  int shmid;
331  int semid;
332  char *pins = NULL;
333  int index = id * (HSM_MAX_PIN_LENGTH + 1);
334 
335  unsigned int size = 0;
336 
337  /* Check input data */
338  if (id >= HSM_MAX_SESSIONS) return NULL;
339  if (repository == NULL) return NULL;
340  if (mode != HSM_PIN_FIRST && mode != HSM_PIN_RETRY && mode != HSM_PIN_SAVE) return NULL;
341  if (mode == HSM_PIN_SAVE) {
342  /* Nothing to save */
343 
344  /* Zeroize the PIN */
345  memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
346 
347  return pin;
348  }
349 
350  /* Create/get the semaphore */
351  semid = hsm_sem_open();
352  if (semid == -1) return NULL;
353 
354  /* Lock the semaphore */
355  if (hsm_sem_wait(semid) != 0) return NULL;
356 
357  /* Create/get the shared memory */
358  shmid = hsm_shm_open();
359  if (shmid == -1) {
360  hsm_sem_post(semid);
361  return NULL;
362  }
363 
364  /* Attach to the shared memory */
365  pins = (char *)shmat(shmid, NULL, 0);
366  if (pins == (char *)-1) {
367  pins = NULL;
368  hsm_sem_post(semid);
369  return NULL;
370  }
371 
372  /* Zeroize PIN buffer */
373  memset(pin, '\0', HSM_MAX_PIN_LENGTH+1);
374 
375  /* Check if there is no PIN */
376  if (pins[index] == '\0') {
377  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_check_pin()",
378  "No PIN in shared memory. "
379  "Please login with \"ods-hsmutil login\"");
380  shmdt(pins);
381  pins = NULL;
382  hsm_sem_post(semid);
383  return NULL;
384  }
385 
386  /* Zeroize bad PIN in shared memory */
387  if (mode == HSM_PIN_RETRY) {
388  memset(&pins[index], '\0', HSM_MAX_PIN_LENGTH+1);
389  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_check_pin()",
390  "Removed bad PIN in shared memory. "
391  "Please login again with \"ods-hsmutil login\"");
392  shmdt(pins);
393  pins = NULL;
394  hsm_sem_post(semid);
395  return NULL;
396  }
397 
398  /* Get the PIN */
399  size = strlen(&pins[index]);
400  if (size > HSM_MAX_PIN_LENGTH) size = HSM_MAX_PIN_LENGTH;
401  memcpy(pin, &pins[index], size);
402  pin[size] = '\0';
403 
404  /* Detach from the shared memory */
405  shmdt(pins);
406  pins = NULL;
407 
408  /* Unlock the semaphore */
409  hsm_sem_post(semid);
410 
411  return pin;
412 }
413 
414 int
416 {
417  int semid;
418  int shmid;
419  union semun arg;
420  struct shmid_ds buf;
421 
422  /* Get the semaphore */
423  semid = semget(SEM_KEY, 1, 0);
424  if (semid == -1) {
425  if (errno != ENOENT) {
426  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
427  "Could not access the semaphore: %s", strerror(errno));
428  return HSM_ERROR;
429  }
430  } else {
431  /* Remove the semaphore */
432  if (semctl(semid, 0, IPC_RMID, arg) != 0) {
433  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
434  "Could not delete the semaphore: %s", strerror(errno));
435  return HSM_ERROR;
436  }
437  }
438 
439  /* Get the shared memory */
440  shmid = shmget(SHM_KEY, 0, 0);
441  if (shmid == -1) {
442  if (errno != ENOENT) {
443  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
444  "Could not access the shared memory: %s", strerror(errno));
445  return HSM_ERROR;
446  }
447  } else {
448  /* Remove the shared memory */
449  if (shmctl(shmid, IPC_RMID, &buf) != 0) {
450  hsm_ctx_set_error(_hsm_ctx, HSM_ERROR, "hsm_logout_pin()",
451  "Could not stat the semaphore: %s", strerror(errno));
452  return HSM_ERROR;
453  }
454  }
455 
456  return HSM_OK;
457 }
458