/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/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2018-08-15 09:26:02 UTC
  • Revision ID: teddy@recompile.se-20180815092602-xoyb5s6gf8376i7u
mandos-client: Set system clock if necessary

* plugins.d/mandos-client.c (init_gpgme/import_key): If the system
  clock is not set, or set to january 1970, set the system clock to
  the more plausible value that is the mtime of the key file.  This is
  required by GnuPG to be able to import the keys.  (We can't pass the
  --ignore-time-conflict or the --ignore-valid-from options though
  GPGME.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008-2016 Teddy Hogeborn
13
 
 * Copyright © 2008-2016 Björn Påhlsson
14
 
 * 
15
 
 * This program is free software: you can redistribute it and/or
16
 
 * modify it under the terms of the GNU General Public License as
17
 
 * published by the Free Software Foundation, either version 3 of the
18
 
 * License, or (at your option) any later version.
19
 
 * 
20
 
 * This program is distributed in the hope that it will be useful, but
 
12
 * Copyright © 2008-2018 Teddy Hogeborn
 
13
 * Copyright © 2008-2018 Björn Påhlsson
 
14
 * 
 
15
 * This file is part of Mandos.
 
16
 * 
 
17
 * Mandos is free software: you can redistribute it and/or modify it
 
18
 * under the terms of the GNU General Public License as published by
 
19
 * the Free Software Foundation, either version 3 of the License, or
 
20
 * (at your option) any later version.
 
21
 * 
 
22
 * Mandos is distributed in the hope that it will be useful, but
21
23
 * WITHOUT ANY WARRANTY; without even the implied warranty of
22
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23
25
 * General Public License for more details.
24
26
 * 
25
27
 * You should have received a copy of the GNU General Public License
26
 
 * along with this program.  If not, see
27
 
 * <http://www.gnu.org/licenses/>.
 
28
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
28
29
 * 
29
30
 * Contact the authors at <mandos@recompile.se>.
30
31
 */
47
48
                                   strtof(), abort() */
48
49
#include <stdbool.h>            /* bool, false, true */
49
50
#include <string.h>             /* strcmp(), strlen(), strerror(),
50
 
                                   asprintf(), strncpy() */
 
51
                                   asprintf(), strncpy(), strsignal()
 
52
                                */
51
53
#include <sys/ioctl.h>          /* ioctl */
52
54
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
53
55
                                   sockaddr_in6, PF_INET6,
270
272
  return true;
271
273
}
272
274
 
 
275
/* Set effective uid to 0, return errno */
 
276
__attribute__((warn_unused_result))
 
277
int raise_privileges(void){
 
278
  int old_errno = errno;
 
279
  int ret = 0;
 
280
  if(seteuid(0) == -1){
 
281
    ret = errno;
 
282
  }
 
283
  errno = old_errno;
 
284
  return ret;
 
285
}
 
286
 
 
287
/* Set effective and real user ID to 0.  Return errno. */
 
288
__attribute__((warn_unused_result))
 
289
int raise_privileges_permanently(void){
 
290
  int old_errno = errno;
 
291
  int ret = raise_privileges();
 
292
  if(ret != 0){
 
293
    errno = old_errno;
 
294
    return ret;
 
295
  }
 
296
  if(setuid(0) == -1){
 
297
    ret = errno;
 
298
  }
 
299
  errno = old_errno;
 
300
  return ret;
 
301
}
 
302
 
 
303
/* Set effective user ID to unprivileged saved user ID */
 
304
__attribute__((warn_unused_result))
 
305
int lower_privileges(void){
 
306
  int old_errno = errno;
 
307
  int ret = 0;
 
308
  if(seteuid(uid) == -1){
 
309
    ret = errno;
 
310
  }
 
311
  errno = old_errno;
 
312
  return ret;
 
313
}
 
314
 
 
315
/* Lower privileges permanently */
 
316
__attribute__((warn_unused_result))
 
317
int lower_privileges_permanently(void){
 
318
  int old_errno = errno;
 
319
  int ret = 0;
 
320
  if(setuid(uid) == -1){
 
321
    ret = errno;
 
322
  }
 
323
  errno = old_errno;
 
324
  return ret;
 
325
}
 
326
 
273
327
/* 
274
328
 * Initialize GPGME.
275
329
 */
295
349
      return false;
296
350
    }
297
351
    
 
352
    /* Workaround for systems without a real-time clock; see also
 
353
       Debian bug #894495: <https://bugs.debian.org/894495> */
 
354
    do {
 
355
      {
 
356
        time_t currtime = time(NULL);
 
357
        if(currtime != (time_t)-1){
 
358
          struct tm tm;
 
359
          if(gmtime_r(&currtime, &tm) == NULL) {
 
360
            perror_plus("gmtime_r");
 
361
            break;
 
362
          }
 
363
          if(tm.tm_year != 70 or tm.tm_mon != 0){
 
364
            break;
 
365
          }
 
366
          if(debug){
 
367
            fprintf_plus(stderr, "System clock is January 1970");
 
368
          }
 
369
        } else {
 
370
          if(debug){
 
371
            fprintf_plus(stderr, "System clock is invalid");
 
372
          }
 
373
        }
 
374
      }
 
375
      struct stat keystat;
 
376
      ret = fstat(fd, &keystat);
 
377
      if(ret != 0){
 
378
        perror_plus("fstat");
 
379
        break;
 
380
      }
 
381
      ret = raise_privileges();
 
382
      if(ret != 0){
 
383
        errno = ret;
 
384
        perror_plus("Failed to raise privileges");
 
385
        break;
 
386
      }
 
387
      if(debug){
 
388
        fprintf_plus(stderr,
 
389
                     "Setting system clock to key file mtime");
 
390
      }
 
391
      time_t keytime = keystat.st_mtim.tv_sec;
 
392
      if(stime(&keytime) != 0){
 
393
        perror_plus("stime");
 
394
      }
 
395
      ret = lower_privileges();
 
396
      if(ret != 0){
 
397
        errno = ret;
 
398
        perror_plus("Failed to lower privileges");
 
399
      }
 
400
    } while(false);
 
401
 
298
402
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
299
403
    if(rc != GPG_ERR_NO_ERROR){
300
404
      fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
308
412
                   gpgme_strsource(rc), gpgme_strerror(rc));
309
413
      return false;
310
414
    }
 
415
    {
 
416
      gpgme_import_result_t import_result
 
417
        = gpgme_op_import_result(mc->ctx);
 
418
      if((import_result->imported < 1
 
419
          or import_result->not_imported > 0)
 
420
         and import_result->unchanged == 0){
 
421
        fprintf_plus(stderr, "bad gpgme_op_import_results:\n");
 
422
        fprintf_plus(stderr,
 
423
                     "The total number of considered keys: %d\n",
 
424
                     import_result->considered);
 
425
        fprintf_plus(stderr,
 
426
                     "The number of keys without user ID: %d\n",
 
427
                     import_result->no_user_id);
 
428
        fprintf_plus(stderr,
 
429
                     "The total number of imported keys: %d\n",
 
430
                     import_result->imported);
 
431
        fprintf_plus(stderr, "The number of imported RSA keys: %d\n",
 
432
                     import_result->imported_rsa);
 
433
        fprintf_plus(stderr, "The number of unchanged keys: %d\n",
 
434
                     import_result->unchanged);
 
435
        fprintf_plus(stderr, "The number of new user IDs: %d\n",
 
436
                     import_result->new_user_ids);
 
437
        fprintf_plus(stderr, "The number of new sub keys: %d\n",
 
438
                     import_result->new_sub_keys);
 
439
        fprintf_plus(stderr, "The number of new signatures: %d\n",
 
440
                     import_result->new_signatures);
 
441
        fprintf_plus(stderr, "The number of new revocations: %d\n",
 
442
                     import_result->new_revocations);
 
443
        fprintf_plus(stderr,
 
444
                     "The total number of secret keys read: %d\n",
 
445
                     import_result->secret_read);
 
446
        fprintf_plus(stderr,
 
447
                     "The number of imported secret keys: %d\n",
 
448
                     import_result->secret_imported);
 
449
        fprintf_plus(stderr,
 
450
                     "The number of unchanged secret keys: %d\n",
 
451
                     import_result->secret_unchanged);
 
452
        fprintf_plus(stderr, "The number of keys not imported: %d\n",
 
453
                     import_result->not_imported);
 
454
        for(gpgme_import_status_t import_status
 
455
              = import_result->imports;
 
456
            import_status != NULL;
 
457
            import_status = import_status->next){
 
458
          fprintf_plus(stderr, "Import status for key: %s\n",
 
459
                       import_status->fpr);
 
460
          if(import_status->result != GPG_ERR_NO_ERROR){
 
461
            fprintf_plus(stderr, "Import result: %s: %s\n",
 
462
                         gpgme_strsource(import_status->result),
 
463
                         gpgme_strerror(import_status->result));
 
464
          }
 
465
          fprintf_plus(stderr, "Key status:\n");
 
466
          fprintf_plus(stderr,
 
467
                       import_status->status & GPGME_IMPORT_NEW
 
468
                       ? "The key was new.\n"
 
469
                       : "The key was not new.\n");
 
470
          fprintf_plus(stderr,
 
471
                       import_status->status & GPGME_IMPORT_UID
 
472
                       ? "The key contained new user IDs.\n"
 
473
                       : "The key did not contain new user IDs.\n");
 
474
          fprintf_plus(stderr,
 
475
                       import_status->status & GPGME_IMPORT_SIG
 
476
                       ? "The key contained new signatures.\n"
 
477
                       : "The key did not contain new signatures.\n");
 
478
          fprintf_plus(stderr,
 
479
                       import_status->status & GPGME_IMPORT_SUBKEY
 
480
                       ? "The key contained new sub keys.\n"
 
481
                       : "The key did not contain new sub keys.\n");
 
482
          fprintf_plus(stderr,
 
483
                       import_status->status & GPGME_IMPORT_SECRET
 
484
                       ? "The key contained a secret key.\n"
 
485
                       : "The key did not contain a secret key.\n");
 
486
        }
 
487
        return false;
 
488
      }
 
489
    }
311
490
    
312
491
    ret = close(fd);
313
492
    if(ret == -1){
354
533
  /* Create new GPGME "context" */
355
534
  rc = gpgme_new(&(mc->ctx));
356
535
  if(rc != GPG_ERR_NO_ERROR){
357
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
358
 
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
359
 
                 gpgme_strerror(rc));
 
536
    fprintf_plus(stderr, "bad gpgme_new: %s: %s\n",
 
537
                 gpgme_strsource(rc), gpgme_strerror(rc));
360
538
    return false;
361
539
  }
362
540
  
398
576
  /* Create new empty GPGME data buffer for the plaintext */
399
577
  rc = gpgme_data_new(&dh_plain);
400
578
  if(rc != GPG_ERR_NO_ERROR){
401
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
402
 
                 "bad gpgme_data_new: %s: %s\n",
 
579
    fprintf_plus(stderr, "bad gpgme_data_new: %s: %s\n",
403
580
                 gpgme_strsource(rc), gpgme_strerror(rc));
404
581
    gpgme_data_release(dh_crypto);
405
582
    return -1;
418
595
      if(result == NULL){
419
596
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
420
597
      } else {
421
 
        fprintf_plus(stderr, "Unsupported algorithm: %s\n",
422
 
                     result->unsupported_algorithm);
423
 
        fprintf_plus(stderr, "Wrong key usage: %u\n",
424
 
                     result->wrong_key_usage);
 
598
        if(result->unsupported_algorithm != NULL) {
 
599
          fprintf_plus(stderr, "Unsupported algorithm: %s\n",
 
600
                       result->unsupported_algorithm);
 
601
        }
 
602
        fprintf_plus(stderr, "Wrong key usage: %s\n",
 
603
                     result->wrong_key_usage ? "Yes" : "No");
425
604
        if(result->file_name != NULL){
426
605
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
427
606
        }
428
 
        gpgme_recipient_t recipient;
429
 
        recipient = result->recipients;
430
 
        while(recipient != NULL){
 
607
 
 
608
        for(gpgme_recipient_t r = result->recipients; r != NULL;
 
609
            r = r->next){
431
610
          fprintf_plus(stderr, "Public key algorithm: %s\n",
432
 
                       gpgme_pubkey_algo_name
433
 
                       (recipient->pubkey_algo));
434
 
          fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
 
611
                       gpgme_pubkey_algo_name(r->pubkey_algo));
 
612
          fprintf_plus(stderr, "Key ID: %s\n", r->keyid);
435
613
          fprintf_plus(stderr, "Secret key available: %s\n",
436
 
                       recipient->status == GPG_ERR_NO_SECKEY
437
 
                       ? "No" : "Yes");
438
 
          recipient = recipient->next;
 
614
                       r->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
439
615
        }
440
616
      }
441
617
    }
611
787
        }
612
788
        params.size += (unsigned int)bytes_read;
613
789
      }
 
790
      ret = close(dhpfile);
 
791
      if(ret == -1){
 
792
        perror_plus("close");
 
793
      }
614
794
      if(params.data == NULL){
615
795
        dhparamsfilename = NULL;
616
796
      }
625
805
                     safer_gnutls_strerror(ret));
626
806
        dhparamsfilename = NULL;
627
807
      }
 
808
      free(params.data);
628
809
    } while(false);
629
810
  }
630
811
  if(dhparamsfilename == NULL){
815
996
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
816
997
                      __attribute__((unused)) const char *txt){}
817
998
 
818
 
/* Set effective uid to 0, return errno */
819
 
__attribute__((warn_unused_result))
820
 
error_t raise_privileges(void){
821
 
  error_t old_errno = errno;
822
 
  error_t ret_errno = 0;
823
 
  if(seteuid(0) == -1){
824
 
    ret_errno = errno;
825
 
  }
826
 
  errno = old_errno;
827
 
  return ret_errno;
828
 
}
829
 
 
830
 
/* Set effective and real user ID to 0.  Return errno. */
831
 
__attribute__((warn_unused_result))
832
 
error_t raise_privileges_permanently(void){
833
 
  error_t old_errno = errno;
834
 
  error_t ret_errno = raise_privileges();
835
 
  if(ret_errno != 0){
836
 
    errno = old_errno;
837
 
    return ret_errno;
838
 
  }
839
 
  if(setuid(0) == -1){
840
 
    ret_errno = errno;
841
 
  }
842
 
  errno = old_errno;
843
 
  return ret_errno;
844
 
}
845
 
 
846
 
/* Set effective user ID to unprivileged saved user ID */
847
 
__attribute__((warn_unused_result))
848
 
error_t lower_privileges(void){
849
 
  error_t old_errno = errno;
850
 
  error_t ret_errno = 0;
851
 
  if(seteuid(uid) == -1){
852
 
    ret_errno = errno;
853
 
  }
854
 
  errno = old_errno;
855
 
  return ret_errno;
856
 
}
857
 
 
858
 
/* Lower privileges permanently */
859
 
__attribute__((warn_unused_result))
860
 
error_t lower_privileges_permanently(void){
861
 
  error_t old_errno = errno;
862
 
  error_t ret_errno = 0;
863
 
  if(setuid(uid) == -1){
864
 
    ret_errno = errno;
865
 
  }
866
 
  errno = old_errno;
867
 
  return ret_errno;
868
 
}
869
 
 
870
999
/* Helper function to add_local_route() and delete_local_route() */
871
1000
__attribute__((nonnull, warn_unused_result))
872
1001
static bool add_delete_local_route(const bool add,
1077
1206
    bool match = false;
1078
1207
    {
1079
1208
      char *interface = NULL;
1080
 
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
1081
 
                                 interface))){
 
1209
      while((interface = argz_next(mc->interfaces,
 
1210
                                   mc->interfaces_size,
 
1211
                                   interface))){
1082
1212
        if(if_nametoindex(interface) == (unsigned int)if_index){
1083
1213
          match = true;
1084
1214
          break;
1237
1367
           with an explicit route added with the server's address.
1238
1368
           
1239
1369
           Avahi bug reference:
1240
 
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
 
1370
           https://lists.freedesktop.org/archives/avahi/2010-February/001833.html
1241
1371
           https://bugs.debian.org/587961
1242
1372
        */
1243
1373
        if(debug){
1423
1553
                                               &decrypted_buffer, mc);
1424
1554
    if(decrypted_buffer_size >= 0){
1425
1555
      
 
1556
      clearerr(stdout);
1426
1557
      written = 0;
1427
1558
      while(written < (size_t) decrypted_buffer_size){
1428
1559
        if(quit_now){
1444
1575
        }
1445
1576
        written += (size_t)ret;
1446
1577
      }
 
1578
      ret = fflush(stdout);
 
1579
      if(ret != 0){
 
1580
        int e = errno;
 
1581
        if(debug){
 
1582
          fprintf_plus(stderr, "Error writing encrypted data: %s\n",
 
1583
                       strerror(errno));
 
1584
        }
 
1585
        errno = e;
 
1586
        goto mandos_end;
 
1587
      }
1447
1588
      retval = 0;
1448
1589
    }
1449
1590
  }
1480
1621
  return retval;
1481
1622
}
1482
1623
 
1483
 
__attribute__((nonnull))
1484
1624
static void resolve_callback(AvahiSServiceResolver *r,
1485
1625
                             AvahiIfIndex interface,
1486
1626
                             AvahiProtocol proto,
1623
1763
__attribute__((nonnull, warn_unused_result))
1624
1764
bool get_flags(const char *ifname, struct ifreq *ifr){
1625
1765
  int ret;
1626
 
  error_t ret_errno;
 
1766
  int old_errno;
1627
1767
  
1628
1768
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1629
1769
  if(s < 0){
1630
 
    ret_errno = errno;
 
1770
    old_errno = errno;
1631
1771
    perror_plus("socket");
1632
 
    errno = ret_errno;
 
1772
    errno = old_errno;
1633
1773
    return false;
1634
1774
  }
1635
1775
  strncpy(ifr->ifr_name, ifname, IF_NAMESIZE);
1637
1777
  ret = ioctl(s, SIOCGIFFLAGS, ifr);
1638
1778
  if(ret == -1){
1639
1779
    if(debug){
1640
 
      ret_errno = errno;
 
1780
      old_errno = errno;
1641
1781
      perror_plus("ioctl SIOCGIFFLAGS");
1642
 
      errno = ret_errno;
 
1782
      errno = old_errno;
 
1783
    }
 
1784
    if((close(s) == -1) and debug){
 
1785
      old_errno = errno;
 
1786
      perror_plus("close");
 
1787
      errno = old_errno;
1643
1788
    }
1644
1789
    return false;
1645
1790
  }
 
1791
  if((close(s) == -1) and debug){
 
1792
    old_errno = errno;
 
1793
    perror_plus("close");
 
1794
    errno = old_errno;
 
1795
  }
1646
1796
  return true;
1647
1797
}
1648
1798
 
1909
2059
      return;
1910
2060
    }
1911
2061
  }
 
2062
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
2063
  if(devnull == -1){
 
2064
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
2065
    return;
 
2066
  }
1912
2067
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
1913
2068
                           runnable_hook, alphasort);
1914
2069
  if(numhooks == -1){
1915
2070
    perror_plus("scandir");
 
2071
    close(devnull);
1916
2072
    return;
1917
2073
  }
1918
2074
  struct dirent *direntry;
1919
2075
  int ret;
1920
 
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
1921
 
  if(devnull == -1){
1922
 
    perror_plus("open(\"/dev/null\", O_RDONLY)");
1923
 
    return;
1924
 
  }
1925
2076
  for(int i = 0; i < numhooks; i++){
1926
2077
    direntry = direntries[i];
1927
2078
    if(debug){
2071
2222
}
2072
2223
 
2073
2224
__attribute__((nonnull, warn_unused_result))
2074
 
error_t bring_up_interface(const char *const interface,
2075
 
                           const float delay){
2076
 
  error_t old_errno = errno;
 
2225
int bring_up_interface(const char *const interface,
 
2226
                       const float delay){
 
2227
  int old_errno = errno;
2077
2228
  int ret;
2078
2229
  struct ifreq network;
2079
2230
  unsigned int if_index = if_nametoindex(interface);
2089
2240
  }
2090
2241
  
2091
2242
  if(not interface_is_up(interface)){
2092
 
    error_t ret_errno = 0, ioctl_errno = 0;
 
2243
    int ret_errno = 0;
 
2244
    int ioctl_errno = 0;
2093
2245
    if(not get_flags(interface, &network)){
2094
2246
      ret_errno = errno;
2095
2247
      fprintf_plus(stderr, "Failed to get flags for interface "
2182
2334
  
2183
2335
  /* Sleep checking until interface is running.
2184
2336
     Check every 0.25s, up to total time of delay */
2185
 
  for(int i=0; i < delay * 4; i++){
 
2337
  for(int i = 0; i < delay * 4; i++){
2186
2338
    if(interface_is_running(interface)){
2187
2339
      break;
2188
2340
    }
2198
2350
}
2199
2351
 
2200
2352
__attribute__((nonnull, warn_unused_result))
2201
 
error_t take_down_interface(const char *const interface){
2202
 
  error_t old_errno = errno;
 
2353
int take_down_interface(const char *const interface){
 
2354
  int old_errno = errno;
2203
2355
  struct ifreq network;
2204
2356
  unsigned int if_index = if_nametoindex(interface);
2205
2357
  if(if_index == 0){
2208
2360
    return ENXIO;
2209
2361
  }
2210
2362
  if(interface_is_up(interface)){
2211
 
    error_t ret_errno = 0, ioctl_errno = 0;
 
2363
    int ret_errno = 0;
 
2364
    int ioctl_errno = 0;
2212
2365
    if(not get_flags(interface, &network) and debug){
2213
2366
      ret_errno = errno;
2214
2367
      fprintf_plus(stderr, "Failed to get flags for interface "
2464
2617
                         .args_doc = "",
2465
2618
                         .doc = "Mandos client -- Get and decrypt"
2466
2619
                         " passwords from a Mandos server" };
2467
 
    ret = argp_parse(&argp, argc, argv,
2468
 
                     ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
2469
 
    switch(ret){
 
2620
    ret_errno = argp_parse(&argp, argc, argv,
 
2621
                           ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
 
2622
    switch(ret_errno){
2470
2623
    case 0:
2471
2624
      break;
2472
2625
    case ENOMEM:
2473
2626
    default:
2474
 
      errno = ret;
 
2627
      errno = ret_errno;
2475
2628
      perror_plus("argp_parse");
2476
2629
      exitcode = EX_OSERR;
2477
2630
      goto end;
2483
2636
  
2484
2637
  {
2485
2638
    /* Work around Debian bug #633582:
2486
 
       <http://bugs.debian.org/633582> */
 
2639
       <https://bugs.debian.org/633582> */
2487
2640
    
2488
2641
    /* Re-raise privileges */
2489
 
    ret_errno = raise_privileges();
2490
 
    if(ret_errno != 0){
2491
 
      errno = ret_errno;
 
2642
    ret = raise_privileges();
 
2643
    if(ret != 0){
 
2644
      errno = ret;
2492
2645
      perror_plus("Failed to raise privileges");
2493
2646
    } else {
2494
2647
      struct stat st;
2558
2711
      }
2559
2712
      
2560
2713
      /* Lower privileges */
2561
 
      ret_errno = lower_privileges();
2562
 
      if(ret_errno != 0){
2563
 
        errno = ret_errno;
 
2714
      ret = lower_privileges();
 
2715
      if(ret != 0){
 
2716
        errno = ret;
2564
2717
        perror_plus("Failed to lower privileges");
2565
2718
      }
2566
2719
    }
2894
3047
    
2895
3048
    /* Allocate a new server */
2896
3049
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
2897
 
                                 &config, NULL, NULL, &ret_errno);
 
3050
                                 &config, NULL, NULL, &ret);
2898
3051
    
2899
3052
    /* Free the Avahi configuration data */
2900
3053
    avahi_server_config_free(&config);
2903
3056
  /* Check if creating the Avahi server object succeeded */
2904
3057
  if(mc.server == NULL){
2905
3058
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
2906
 
                 avahi_strerror(ret_errno));
 
3059
                 avahi_strerror(ret));
2907
3060
    exitcode = EX_UNAVAILABLE;
2908
3061
    goto end;
2909
3062
  }
2944
3097
 end:
2945
3098
  
2946
3099
  if(debug){
2947
 
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
 
3100
    if(signal_received){
 
3101
      fprintf_plus(stderr, "%s exiting due to signal %d: %s\n",
 
3102
                   argv[0], signal_received,
 
3103
                   strsignal(signal_received));
 
3104
    } else {
 
3105
      fprintf_plus(stderr, "%s exiting\n", argv[0]);
 
3106
    }
2948
3107
  }
2949
3108
  
2950
3109
  /* Cleanup things */
2989
3148
  
2990
3149
  /* Re-raise privileges */
2991
3150
  {
2992
 
    ret_errno = raise_privileges();
2993
 
    if(ret_errno != 0){
2994
 
      errno = ret_errno;
 
3151
    ret = raise_privileges();
 
3152
    if(ret != 0){
 
3153
      errno = ret;
2995
3154
      perror_plus("Failed to raise privileges");
2996
3155
    } else {
2997
3156
      
3002
3161
      /* Take down the network interfaces which were brought up */
3003
3162
      {
3004
3163
        char *interface = NULL;
3005
 
        while((interface=argz_next(interfaces_to_take_down,
3006
 
                                   interfaces_to_take_down_size,
3007
 
                                   interface))){
3008
 
          ret_errno = take_down_interface(interface);
3009
 
          if(ret_errno != 0){
3010
 
            errno = ret_errno;
 
3164
        while((interface = argz_next(interfaces_to_take_down,
 
3165
                                     interfaces_to_take_down_size,
 
3166
                                     interface))){
 
3167
          ret = take_down_interface(interface);
 
3168
          if(ret != 0){
 
3169
            errno = ret;
3011
3170
            perror_plus("Failed to take down interface");
3012
3171
          }
3013
3172
        }
3018
3177
      }
3019
3178
    }
3020
3179
    
3021
 
    ret_errno = lower_privileges_permanently();
3022
 
    if(ret_errno != 0){
3023
 
      errno = ret_errno;
 
3180
    ret = lower_privileges_permanently();
 
3181
    if(ret != 0){
 
3182
      errno = ret;
3024
3183
      perror_plus("Failed to lower privileges permanently");
3025
3184
    }
3026
3185
  }
3039
3198
                                                | O_PATH));
3040
3199
    if(dir_fd == -1){
3041
3200
      perror_plus("open");
 
3201
      return;
3042
3202
    }
3043
3203
    int numentries = scandirat(dir_fd, ".", &direntries,
3044
3204
                               notdotentries, alphasort);
3061
3221
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3062
3222
            dret = 0;
3063
3223
          }
3064
 
          if(dret == -1){
 
3224
          if((dret == -1) and (errno != ENOENT)){
3065
3225
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3066
3226
                         direntries[i]->d_name, strerror(errno));
3067
3227
          }
3071
3231
      
3072
3232
      /* need to clean even if 0 because man page doesn't specify */
3073
3233
      free(direntries);
3074
 
      if(numentries == -1){
3075
 
        perror_plus("scandirat");
3076
 
      }
3077
3234
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
3078
3235
      if(dret == -1 and errno != ENOENT){
3079
3236
        perror_plus("rmdir");