[8bd77b5] | 1 | /** |
---|
| 2 | ** abac_util.c |
---|
| 3 | **/ |
---|
[7f25a67f] | 4 | #include <err.h> |
---|
| 5 | #include <stdlib.h> |
---|
| 6 | #include <string.h> |
---|
[7727f26] | 7 | #include <stdio.h> |
---|
[8bd77b5] | 8 | #include <assert.h> |
---|
[2efdff5] | 9 | #include <stdarg.h> |
---|
| 10 | #include <sys/stat.h> |
---|
[ba6027a] | 11 | #include <termios.h> |
---|
| 12 | #include <unistd.h> |
---|
[2e9455f] | 13 | #include <sys/types.h> |
---|
| 14 | |
---|
| 15 | #include <credentials/certificates/certificate.h> |
---|
| 16 | #include <credentials/certificates/x509.h> |
---|
| 17 | #include <credentials/keys/private_key.h> |
---|
[8bd77b5] | 18 | |
---|
| 19 | #include "abac_util.h" |
---|
[7727f26] | 20 | |
---|
| 21 | static int debug=0; |
---|
[7f25a67f] | 22 | |
---|
[ba6027a] | 23 | /* Callback configuration */ |
---|
| 24 | struct cb_opts { |
---|
[2e9455f] | 25 | int use_prompt; /* Print a prompt to stderr */ |
---|
| 26 | int use_echo; /* If true, turn off input echo on stdin */ |
---|
| 27 | unsigned int tries; /* Number of attempts allowed */ |
---|
| 28 | char prompt[20]; /* The prompt to display if use_echo is true */ |
---|
[ba6027a] | 29 | }; |
---|
| 30 | |
---|
[2e9455f] | 31 | /** potato pw length */ |
---|
| 32 | #define PWLEN 128 |
---|
[ba6027a] | 33 | |
---|
[2e9455f] | 34 | /** SHA string length */ |
---|
[8bd77b5] | 35 | #define SHA1_LENGTH 40 |
---|
| 36 | |
---|
[2e9455f] | 37 | /****************************************************************/ |
---|
[2efdff5] | 38 | char *abac_version() |
---|
| 39 | { |
---|
[2e9455f] | 40 | DEBUG_PRINTF("abac_version is %s\n", ABAC_VERSION); |
---|
[373bf68] | 41 | return ABAC_VERSION; |
---|
[2efdff5] | 42 | } |
---|
| 43 | |
---|
[2e9455f] | 44 | char *prologIt(char *str) |
---|
| 45 | { |
---|
| 46 | char *tmp=NULL; |
---|
| 47 | asprintf(&tmp,"p%s",str); |
---|
| 48 | return tmp; |
---|
| 49 | } |
---|
| 50 | |
---|
[ba6027a] | 51 | void abac_clean_string(char *string) |
---|
| 52 | { |
---|
| 53 | int len=strlen(string); |
---|
| 54 | int i; |
---|
| 55 | for(i=0;i<len;i++) |
---|
| 56 | string[i]=0; |
---|
| 57 | } |
---|
| 58 | |
---|
[2efdff5] | 59 | void abac_errx(int eval, const char *msg) |
---|
| 60 | { |
---|
| 61 | errx(eval,"%s",msg); |
---|
| 62 | } |
---|
[8bd77b5] | 63 | |
---|
[7f25a67f] | 64 | /** |
---|
| 65 | * Malloc, fatal on error. |
---|
| 66 | */ |
---|
[3c251d0] | 67 | void *abac_xmalloc(size_t size) { |
---|
[7f25a67f] | 68 | void *ret; |
---|
| 69 | |
---|
| 70 | ret = malloc(size); |
---|
| 71 | if (ret == NULL) |
---|
| 72 | err(1, "malloc"); |
---|
| 73 | |
---|
| 74 | return ret; |
---|
| 75 | } |
---|
| 76 | |
---|
[8bd77b5] | 77 | void *abac_xrealloc(void *ptr, size_t size) { |
---|
| 78 | void *ret = realloc(ptr, size); |
---|
| 79 | if (ret == NULL) |
---|
| 80 | err(1, "couldn't realloc %d bytes\n", size); |
---|
| 81 | return ret; |
---|
| 82 | } |
---|
| 83 | |
---|
| 84 | |
---|
[7f25a67f] | 85 | /** |
---|
| 86 | * strdup fatal on error |
---|
| 87 | */ |
---|
[3c251d0] | 88 | char *abac_xstrdup(char *source) { |
---|
[7f25a67f] | 89 | char *ret; |
---|
| 90 | |
---|
[7727f26] | 91 | if (source == NULL) { |
---|
[ff3d104] | 92 | return NULL; |
---|
[7727f26] | 93 | } |
---|
[ff3d104] | 94 | |
---|
[7f25a67f] | 95 | ret = strdup(source); |
---|
| 96 | if (ret == NULL) |
---|
| 97 | err(1, "strdup"); |
---|
| 98 | |
---|
| 99 | return ret; |
---|
| 100 | } |
---|
[9a411d7] | 101 | |
---|
[c586a3c] | 102 | /* make a brand new string with or without being trimmed */ |
---|
| 103 | char *abac_trim_quotes(char *string) { |
---|
| 104 | char *tmp=abac_xstrdup(string); |
---|
| 105 | int len=strlen(tmp); |
---|
| 106 | if( (tmp[len-1] == '\'' || tmp[len-1] == '"') && |
---|
| 107 | (tmp[0] == '\'' || tmp[0] == '"')) { |
---|
| 108 | tmp[len-1]='\0'; |
---|
| 109 | char *ntmp=abac_xstrdup(&tmp[1]); |
---|
| 110 | free(tmp); |
---|
| 111 | return ntmp; |
---|
| 112 | } |
---|
| 113 | return tmp; |
---|
| 114 | } |
---|
| 115 | |
---|
[9a411d7] | 116 | /** |
---|
| 117 | * Split a string based on the given delimiter. |
---|
| 118 | */ |
---|
| 119 | void abac_split(char *string, char *delim, char **ret, int *num) { |
---|
| 120 | int len = strlen(delim); |
---|
| 121 | char *start = string; |
---|
| 122 | int count = 0; |
---|
| 123 | |
---|
| 124 | // split the string by the delim |
---|
| 125 | while ((start = strstr(string, delim)) != NULL) { |
---|
| 126 | *start = 0; |
---|
| 127 | ret[count++] = string; |
---|
| 128 | string = start + len; |
---|
| 129 | } |
---|
| 130 | ret[count++] = string; |
---|
| 131 | |
---|
| 132 | *num = count; |
---|
| 133 | } |
---|
[8bd77b5] | 134 | |
---|
| 135 | int abac_validate_clean_name(char *string) { |
---|
| 136 | int i; |
---|
| 137 | |
---|
| 138 | assert(string != NULL); |
---|
| 139 | |
---|
| 140 | // must start with a letter/number |
---|
| 141 | if (!isalnum(string[0])) return 0; |
---|
| 142 | |
---|
| 143 | // Name must be alphanumeric or - |
---|
| 144 | for (i = 1; string[i] != '\0'; ++i) |
---|
| 145 | if (!isalnum(string[i]) && string[i] != '-') |
---|
| 146 | return 0; |
---|
| 147 | |
---|
| 148 | return 1; |
---|
| 149 | } |
---|
| 150 | |
---|
| 151 | /* check up to first ( if its there.. |
---|
| 152 | a.role(this) |
---|
| 153 | a.role(?,?Year:[100..200],?Value:[one,two,three]) |
---|
| 154 | a.role(isi) |
---|
| 155 | */ |
---|
| 156 | int abac_validate_clean_aspect_name(char *string) { |
---|
| 157 | int i; |
---|
| 158 | |
---|
| 159 | assert(string != NULL); |
---|
| 160 | |
---|
| 161 | // must start with a letter/number |
---|
| 162 | if (!isalnum(string[0])) return 0; |
---|
| 163 | |
---|
| 164 | // Name must be alphanumeric or - or _ up to the ( if there is one |
---|
| 165 | for (i = 1; string[i] != '\0' && string[i] != '(' ; ++i) |
---|
| 166 | if (!isalnum(string[i]) && string[i] != '-' && |
---|
| 167 | string[i] != '_' ) |
---|
| 168 | return 0; |
---|
| 169 | return 1; |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | chunk_t abac_generate_serial() { |
---|
| 173 | chunk_t serial = chunk_empty; |
---|
| 174 | |
---|
| 175 | // create a serial (stolen from strongswan pki) |
---|
| 176 | rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); |
---|
| 177 | if (!rng) |
---|
| 178 | errx(1, "no random number generator"); |
---|
| 179 | |
---|
| 180 | rng->allocate_bytes(rng, 8, &serial); |
---|
[137b55f] | 181 | while (serial.ptr[0] == 0) { |
---|
[8bd77b5] | 182 | // don't get leading 0's |
---|
| 183 | rng->get_bytes(rng, 1, serial.ptr); |
---|
[137b55f] | 184 | } |
---|
[8bd77b5] | 185 | rng->destroy(rng); |
---|
| 186 | |
---|
[2e9455f] | 187 | DEBUG_PRINTF("abac_generate_serial, serial generated is %#B\n", &serial); |
---|
[8bd77b5] | 188 | return serial; |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | // validate a princpal's name |
---|
| 192 | // makes sure it's a valid SHA1 identifier |
---|
| 193 | // return values: |
---|
| 194 | // success: malloc'd copy with all hex digits lowercase |
---|
| 195 | // fail: NULL |
---|
| 196 | char *abac_validate_principal(char *keyid) { |
---|
| 197 | int i; |
---|
| 198 | char *copy = NULL; |
---|
| 199 | |
---|
| 200 | if (strlen(keyid) != SHA1_LENGTH) |
---|
| 201 | return NULL; |
---|
| 202 | |
---|
| 203 | int len = strlen(keyid) + 1; |
---|
| 204 | copy = abac_xmalloc(len); |
---|
| 205 | sprintf(copy, "%s", keyid); |
---|
| 206 | |
---|
| 207 | i=0; |
---|
| 208 | for (; i < SHA1_LENGTH; ++i) { |
---|
| 209 | copy[i] = tolower(copy[i]); |
---|
| 210 | if (!isxdigit(copy[i])) |
---|
| 211 | goto error; |
---|
| 212 | } |
---|
| 213 | return copy; |
---|
| 214 | error: |
---|
| 215 | free(copy); |
---|
| 216 | return NULL; |
---|
| 217 | } |
---|
| 218 | |
---|
| 219 | // parse&validate the validity |
---|
| 220 | int abac_validate_validity_string(char *validity_str) |
---|
| 221 | { |
---|
| 222 | int validity=0; |
---|
| 223 | if (validity_str != NULL) { |
---|
| 224 | char suffix = 'd'; // default suffix is days |
---|
| 225 | int multiplier; |
---|
| 226 | |
---|
| 227 | int len = strlen(validity_str); |
---|
| 228 | assert(len > 0); |
---|
| 229 | |
---|
| 230 | // get the suffix char if it's alphabetical |
---|
| 231 | if (isalpha(validity_str[len - 1])) { |
---|
| 232 | suffix = validity_str[len - 1]; |
---|
| 233 | |
---|
| 234 | // truncate |
---|
| 235 | validity_str[len - 1] = '\0'; |
---|
| 236 | --len; |
---|
| 237 | |
---|
| 238 | // make sure it's not only a suffix |
---|
| 239 | if (len == 0) { |
---|
| 240 | errx(1,"Invalid validity\n"); |
---|
| 241 | } |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | // convert the suffix to a multiplier |
---|
| 245 | switch(suffix) { |
---|
| 246 | case 's': multiplier = 1; break; |
---|
| 247 | case 'm': multiplier = 60; break; |
---|
| 248 | case 'h': multiplier = 3600; break; |
---|
| 249 | case 'd': multiplier = 86400; break; |
---|
| 250 | case 'y': multiplier = 31536000; break; |
---|
| 251 | default: |
---|
| 252 | errx(1,"Invalid suffix, must be s m h d y\n"); |
---|
| 253 | } |
---|
| 254 | |
---|
| 255 | // ascii to int |
---|
| 256 | char *end; |
---|
| 257 | validity = strtol(validity_str, &end, 10); |
---|
| 258 | if (end - validity_str < len) { |
---|
| 259 | errx(1,"Invalid validity\n"); |
---|
| 260 | } |
---|
| 261 | |
---|
| 262 | if (validity <= 0) { |
---|
| 263 | errx(1,"Invalid validity: must be > 0\n"); |
---|
| 264 | } |
---|
| 265 | |
---|
| 266 | // multiply! |
---|
| 267 | validity *= multiplier; |
---|
| 268 | } |
---|
| 269 | return validity; |
---|
| 270 | } |
---|
| 271 | |
---|
| 272 | |
---|
[2efdff5] | 273 | int file_exist(char *filename) |
---|
[8bd77b5] | 274 | { |
---|
[2efdff5] | 275 | struct stat stbuf; |
---|
| 276 | if(stat(filename,&stbuf) == -1) |
---|
| 277 | return 0; |
---|
| 278 | return 1; |
---|
[8bd77b5] | 279 | } |
---|
| 280 | |
---|
[2efdff5] | 281 | |
---|
[ba6027a] | 282 | chunk_t abac_get_potato_file(char *filename) |
---|
| 283 | { |
---|
| 284 | chunk_t pp=chunk_empty; |
---|
| 285 | if(file_exist(filename)) { |
---|
[2e9455f] | 286 | DEBUG_PRINTF("trying to open %s\n", filename); |
---|
[ba6027a] | 287 | FILE *fp=fopen(filename,"r"); |
---|
| 288 | char str[PWLEN]; |
---|
| 289 | int rc=fscanf(fp,"%s",str); |
---|
| 290 | if(rc) { |
---|
| 291 | pp.ptr=abac_xstrdup(str); |
---|
| 292 | pp.len=strlen(pp.ptr); |
---|
| 293 | if(str[pp.len-1]=='\n') |
---|
| 294 | pp.len--; |
---|
| 295 | } |
---|
| 296 | abac_clean_string(str); |
---|
| 297 | fclose(fp); |
---|
| 298 | } |
---|
| 299 | return pp; |
---|
| 300 | } |
---|
| 301 | |
---|
| 302 | /*** |
---|
| 303 | ***/ |
---|
| 304 | chunk_t abac_get_potato_cb(int try, char *name) { |
---|
| 305 | /* Get a password from stdin and return it as a chunk_t. If too many tries |
---|
| 306 | * have occurred or there is any other problem, return an empty chunk_t, |
---|
| 307 | * which libstrongswan takes as giving up. The chunk is alloated here |
---|
| 308 | * (inside getline), and presumably freed by libstrongswan. User points to |
---|
| 309 | * a cb_opts struct, which affects this routine in the obvious ways. |
---|
| 310 | */ |
---|
| 311 | /* Configuration options */ |
---|
| 312 | |
---|
| 313 | if(name!=NULL) { |
---|
| 314 | char *n=(char *)memrchr(name,'/',strlen(name)); |
---|
| 315 | if(n==NULL) |
---|
| 316 | printf("[%s] ", name); |
---|
| 317 | else printf("[%s] ",n); |
---|
| 318 | } |
---|
| 319 | struct cb_opts c_opts = { 1, 0, 3, "Key passphrase:" }; |
---|
| 320 | struct cb_opts *opts = &c_opts; |
---|
| 321 | chunk_t rv = chunk_empty; /* Return value, starts empty */ |
---|
| 322 | |
---|
| 323 | if (try -1 < opts->tries ) { |
---|
| 324 | struct termios t; /* Terminal settings */ |
---|
| 325 | size_t len = 0; /* Length of string from getline */ |
---|
| 326 | tcflag_t orig = 0; /* Holds the original local flags (echo in here) */ |
---|
| 327 | |
---|
| 328 | if (!opts->use_echo) { |
---|
| 329 | /* Use tc{get,set}attr to turn echo off and restore the intial |
---|
| 330 | * echo settings */ |
---|
| 331 | if (!tcgetattr(0, &t)) { |
---|
| 332 | orig = t.c_lflag; |
---|
| 333 | |
---|
| 334 | t.c_lflag &= ~ECHO; |
---|
| 335 | if ( tcsetattr(0, TCSANOW, &t) ) { |
---|
| 336 | perror("Cannot turn off echo"); |
---|
| 337 | return rv; |
---|
| 338 | } |
---|
| 339 | } |
---|
| 340 | else { |
---|
| 341 | perror("Cannot turn get attributes to off echo"); |
---|
| 342 | return rv; |
---|
| 343 | } |
---|
| 344 | } |
---|
| 345 | if (opts->use_prompt) printf("%s", opts->prompt); |
---|
| 346 | |
---|
| 347 | /* Because rv.ptr starts as NULL, getline allocates memory. The size |
---|
| 348 | * of the allocation returns in rv.len and the size of the string |
---|
| 349 | * (including newline and NUL) is in len. */ |
---|
| 350 | if ((rv.ptr = (u_char *) malloc(rv.len = PWLEN))) { |
---|
| 351 | if ( fgets(rv.ptr, rv.len, stdin) ) { |
---|
| 352 | /* Readjust the chunk_t's len field to the size of the string |
---|
| 353 | * w/o the newline or NUL */ |
---|
| 354 | /* would prefer strnlen, but no such luck in FBSD7 or earlier*/ |
---|
| 355 | size_t len = strlen(rv.ptr); |
---|
| 356 | |
---|
| 357 | /* \n\0, \n or \0 */ |
---|
| 358 | if (rv.ptr[len-2] == '\n') rv.len = len-2; |
---|
| 359 | else if (rv.ptr[len-1] == '\n') rv.len = len-1; |
---|
| 360 | else rv.len = len -1; |
---|
| 361 | } else { |
---|
| 362 | /* Read failed. Deallocate and clear rv */ |
---|
| 363 | free(rv.ptr); |
---|
| 364 | rv = chunk_empty; |
---|
| 365 | } |
---|
| 366 | } |
---|
| 367 | else { |
---|
| 368 | /* Failed malloc. Restore rv to empty and return it */ |
---|
| 369 | perror("malloc"); |
---|
| 370 | rv = chunk_empty; |
---|
| 371 | return rv; |
---|
| 372 | } |
---|
| 373 | |
---|
| 374 | if (!opts->use_echo ) { |
---|
| 375 | /* Pop echo beck to its original setting. */ |
---|
| 376 | t.c_lflag = orig; |
---|
| 377 | |
---|
| 378 | if ( tcsetattr(0, TCSANOW, &t) ) |
---|
| 379 | perror("Cannot restore echo setting?"); |
---|
| 380 | |
---|
| 381 | if (opts->use_prompt) printf("\n"); |
---|
| 382 | } |
---|
| 383 | } |
---|
| 384 | else fprintf(stderr, "Too many tries (%d)", try-1); |
---|
| 385 | return rv; |
---|
| 386 | } |
---|
| 387 | |
---|
| 388 | chunk_t extract_potato(char *filename, char *pfile) |
---|
| 389 | { |
---|
| 390 | chunk_t pp; |
---|
| 391 | if(pfile==NULL || strlen(pfile)==0 ) { |
---|
| 392 | pp=abac_get_potato_cb(2,filename); |
---|
| 393 | } else { |
---|
| 394 | pp=abac_get_potato_file(pfile); |
---|
| 395 | } |
---|
| 396 | return pp; |
---|
| 397 | } |
---|