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