~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/kadmin/server/ovsec_kadmd.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2009-05-07 16:16:34 UTC
  • mfrom: (13.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090507161634-xqyk0s9na0le4flj
Tags: 1.7dfsg~beta1-4
When  decrypting the TGS response fails with the subkey, try with the
session key to work around Heimdal bug, Closes: #527353 

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
#include    "kdb_kt.h"  /* for krb5_ktkdb_set_context */
54
54
#include    <string.h>
55
55
#include    "kadm5/server_internal.h" /* XXX for kadm5_server_handle_t */
 
56
#include    <kdb_log.h>
56
57
 
57
58
#include    "misc.h"
58
59
 
71
72
 
72
73
volatile int    signal_request_exit = 0;
73
74
volatile int    signal_request_hup = 0;
74
 
void    setup_signal_handlers(void);
 
75
void    setup_signal_handlers(iprop_role iproprole);
75
76
void    request_exit(int);
76
77
void    request_hup(int);
77
78
void    reset_db(void);
78
79
void    sig_pipe(int);
79
 
void    kadm_svc_run(kadm5_config_params *params);
80
80
 
81
81
#ifdef POSIX_SIGNALS
82
82
static struct sigaction s_action;
98
98
#define OVSEC_KADM_CHANGEPW_SERVICE     "ovsec_adm/changepw"
99
99
 
100
100
extern krb5_keyblock master_keyblock;
 
101
extern krb5_keylist_node  *master_keylist;
101
102
 
102
103
char *build_princ_name(char *name, char *realm);
103
104
void log_badauth(OM_uint32 major, OM_uint32 minor,
114
115
int schpw;
115
116
void do_schpw(int s, kadm5_config_params *params);
116
117
 
 
118
#ifndef DISABLE_IPROP
 
119
int ipropfd;
 
120
#endif
 
121
 
117
122
#ifdef USE_PASSWORD_SERVER
118
123
void kadm5_set_use_password_server (void);
119
124
#endif
199
204
 
200
205
static krb5_context hctx;
201
206
 
 
207
int nofork = 0;
 
208
 
202
209
int main(int argc, char *argv[])
203
210
{
204
 
     register   SVCXPRT *transp;
205
211
     extern     char *optarg;
206
212
     extern     int optind, opterr;
207
 
     int ret, nofork, oldnames = 0;
 
213
     int ret, oldnames = 0;
208
214
     OM_uint32 OMret, major_status, minor_status;
209
215
     char *whoami;
210
216
     gss_buffer_desc in_buf;
211
 
     struct sockaddr_in addr;
212
 
     int s;
213
217
     auth_gssapi_name names[4];
214
218
     gss_buffer_desc gssbuf;
215
219
     gss_OID nt_krb5_name_oid;
217
221
     char **db_args      = NULL;
218
222
     int    db_args_size = 0;
219
223
     char *errmsg;
 
224
     int i;
 
225
 
 
226
     kdb_log_context *log_ctx;
220
227
 
221
228
     setvbuf(stderr, NULL, _IONBF, 0);
222
229
 
316
323
          exit(1);
317
324
     }
318
325
 
319
 
     if( db_args )
320
 
     {
321
 
         free(db_args), db_args=NULL;
322
 
     }
323
 
     
324
326
     if ((ret = kadm5_get_config_params(context, 1, &params,
325
327
                                        &params))) {
326
328
          const char *e_txt = krb5_get_error_message (context, ret);
337
339
 
338
340
     if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
339
341
          krb5_klog_syslog(LOG_ERR, "%s: Missing required configuration values "
340
 
                           "while initializing, aborting", whoami,
 
342
                           "(%lx) while initializing, aborting", whoami,
341
343
                           (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
342
344
          fprintf(stderr, "%s: Missing required configuration values "
343
345
                  "(%lx) while initializing, aborting\n", whoami,
347
349
          exit(1);
348
350
     }
349
351
 
350
 
     memset(&addr, 0, sizeof(addr));
351
 
     addr.sin_family = AF_INET;
352
 
     addr.sin_addr.s_addr = INADDR_ANY;
353
 
     addr.sin_port = htons(params.kadmind_port);
354
 
 
355
 
     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
 
352
     if ((ret = setup_network(global_server_handle, whoami))) {
356
353
          const char *e_txt = krb5_get_error_message (context, ret);
357
 
          krb5_klog_syslog(LOG_ERR, "Cannot create TCP socket: %s",
358
 
                           e_txt);
359
 
          fprintf(stderr, "Cannot create TCP socket: %s",
360
 
                  e_txt);
361
 
          kadm5_destroy(global_server_handle);
362
 
          krb5_klog_close(context);       
363
 
          exit(1);
364
 
     }
365
 
 
366
 
     if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
367
 
         const char *e_txt = krb5_get_error_message (context, ret);
368
 
         krb5_klog_syslog(LOG_ERR,
369
 
                          "cannot create simple chpw socket: %s",
370
 
                          e_txt);
371
 
         fprintf(stderr, "Cannot create simple chpw socket: %s",
372
 
                 e_txt);
373
 
         kadm5_destroy(global_server_handle);
374
 
         krb5_klog_close(context);
375
 
         exit(1);
376
 
     }
377
 
 
378
 
#ifdef SO_REUSEADDR
379
 
     /* the old admin server turned on SO_REUSEADDR for non-default
380
 
        port numbers.  this was necessary, on solaris, for the tests
381
 
        to work.  jhawk argues that the debug and production modes
382
 
        should be the same.  I think I agree, so I'm always going to set
383
 
        SO_REUSEADDR.  The other option is to have the unit tests wait
384
 
        until the port is useable, or use a different port each time.  
385
 
        --marc */
386
 
 
387
 
     {
388
 
         int    allowed;
389
 
 
390
 
         allowed = 1;
391
 
         if (setsockopt(s,
392
 
                        SOL_SOCKET,
393
 
                        SO_REUSEADDR,
394
 
                        (char *) &allowed,
395
 
                        sizeof(allowed)) < 0) {
396
 
             const char *e_txt = krb5_get_error_message (context, ret);
397
 
             krb5_klog_syslog(LOG_ERR, "Cannot set SO_REUSEADDR: %s",
398
 
                              e_txt);
399
 
             fprintf(stderr, "Cannot set SO_REUSEADDR: %s", e_txt);
400
 
             kadm5_destroy(global_server_handle);
401
 
             krb5_klog_close(context);    
402
 
             exit(1);
403
 
         }
404
 
         if (setsockopt(schpw, SOL_SOCKET, SO_REUSEADDR,
405
 
                        (char *) &allowed, sizeof(allowed)) < 0) {
406
 
             const char *e_txt = krb5_get_error_message (context, ret);
407
 
             krb5_klog_syslog(LOG_ERR, "main",
408
 
                              "cannot set SO_REUSEADDR on simple chpw socket: %s", 
409
 
                              e_txt);
410
 
             fprintf(stderr,
411
 
                     "Cannot set SO_REUSEADDR on simple chpw socket: %s",
412
 
                     e_txt);
413
 
             kadm5_destroy(global_server_handle);
414
 
             krb5_klog_close(context);
415
 
         }
416
 
 
417
 
     }
418
 
#endif /* SO_REUSEADDR */
419
 
     memset(&addr, 0, sizeof(addr));
420
 
     addr.sin_family = AF_INET;
421
 
     addr.sin_addr.s_addr = INADDR_ANY;
422
 
     addr.sin_port = htons(params.kadmind_port);
423
 
 
424
 
     if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
425
 
          int oerrno = errno;
426
 
          const char *e_txt = krb5_get_error_message (context, errno);
427
 
          fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
428
 
          fprintf(stderr, "bind: %s\n", e_txt);
429
 
          errno = oerrno;
430
 
          krb5_klog_syslog(LOG_ERR, "Cannot bind socket: %s", e_txt);
431
 
          if(oerrno == EADDRINUSE) {
432
 
               char *w = strrchr(whoami, '/');
433
 
               if (w) {
434
 
                    w++;
435
 
               }
436
 
               else {
437
 
                    w = whoami;
438
 
               }
439
 
               fprintf(stderr,
440
 
"This probably means that another %s process is already\n"
441
 
"running, or that another program is using the server port (number %d)\n"
442
 
"after being assigned it by the RPC portmap daemon.  If another\n"
443
 
"%s is already running, you should kill it before\n"
444
 
"restarting the server.  If, on the other hand, another program is\n"
445
 
"using the server port, you should kill it before running\n"
446
 
"%s, and ensure that the conflict does not occur in the\n"
447
 
"future by making sure that %s is started on reboot\n"
448
 
                       "before portmap.\n", w, ntohs(addr.sin_port), w, w, w);
449
 
               krb5_klog_syslog(LOG_ERR, "Check for already-running %s or for "
450
 
                      "another process using port %d", w,
451
 
                      htons(addr.sin_port));
452
 
          }
 
354
          krb5_klog_syslog(LOG_ERR, "%s: %s while initializing network, aborting",
 
355
                           whoami, e_txt);
 
356
          fprintf(stderr, "%s: %s while initializing network, aborting\n",
 
357
                  whoami, e_txt);
453
358
          kadm5_destroy(global_server_handle);
454
359
          krb5_klog_close(context);
455
360
          exit(1);
456
361
     }
457
 
     memset(&addr, 0, sizeof(addr));
458
 
     addr.sin_family = AF_INET;
459
 
     addr.sin_addr.s_addr = INADDR_ANY;
460
 
     /* XXX */
461
 
     addr.sin_port = htons(params.kpasswd_port);
462
 
 
463
 
     if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
464
 
          char portbuf[32];
465
 
          int oerrno = errno;
466
 
          const char *e_txt = krb5_get_error_message (context, errno);
467
 
          fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
468
 
          fprintf(stderr, "bind: %s\n", e_txt);
469
 
          errno = oerrno;
470
 
          sprintf(portbuf, "%d", ntohs(addr.sin_port));
471
 
          krb5_klog_syslog(LOG_ERR, "cannot bind simple chpw socket: %s",
472
 
                           e_txt);
473
 
          if(oerrno == EADDRINUSE) {
474
 
               char *w = strrchr(whoami, '/');
475
 
               if (w) {
476
 
                    w++;
477
 
               }
478
 
               else {
479
 
                    w = whoami;
480
 
               }
481
 
               fprintf(stderr,
482
 
"This probably means that another %s process is already\n"
483
 
"running, or that another program is using the server port (number %d).\n"
484
 
"If another %s is already running, you should kill it before\n"
485
 
"restarting the server.\n",
486
 
                       w, ntohs(addr.sin_port), w);
487
 
          }
488
 
          kadm5_destroy(global_server_handle);
489
 
          krb5_klog_close(context);
490
 
          exit(1);
491
 
     }
492
 
     
493
 
     transp = svctcp_create(s, 0, 0);
494
 
     if(transp == NULL) {
495
 
          fprintf(stderr, "%s: Cannot create RPC service.\n", whoami);
496
 
          krb5_klog_syslog(LOG_ERR, "Cannot create RPC service: %m");
497
 
          kadm5_destroy(global_server_handle);
498
 
          krb5_klog_close(context);       
499
 
          exit(1);
500
 
     }
501
 
     if(!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) {
502
 
          fprintf(stderr, "%s: Cannot register RPC service.\n", whoami);
503
 
          krb5_klog_syslog(LOG_ERR, "Cannot register RPC service, failing.");
504
 
          kadm5_destroy(global_server_handle);
505
 
          krb5_klog_close(context);       
506
 
          exit(1);
507
 
     }
508
362
 
509
363
     names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
510
364
     names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
542
396
          krb5_klog_syslog(LOG_ERR, "Can't set master key for kdb keytab.");
543
397
          goto kterr;
544
398
     }
 
399
     ret = krb5_db_set_mkey_list(hctx, master_keylist);
 
400
     if (ret) {
 
401
          krb5_klog_syslog(LOG_ERR, "Can't set master key list for kdb keytab.");
 
402
          goto kterr;
 
403
     }
545
404
     ret = krb5_kt_register(context, &krb5_kt_kdb_ops);
546
405
     if (ret) {
547
406
          krb5_klog_syslog(LOG_ERR, "Can't register kdb keytab.");
641
500
          exit(1);
642
501
     }
643
502
          
644
 
     setup_signal_handlers();
645
 
     krb5_klog_syslog(LOG_INFO, "starting");
646
 
     kadm_svc_run(&params);
 
503
    if (params.iprop_enabled == TRUE)
 
504
        ulog_set_role(hctx, IPROP_MASTER);
 
505
    else
 
506
        ulog_set_role(hctx, IPROP_NULL);
 
507
 
 
508
    log_ctx = hctx->kdblog_context;
 
509
 
 
510
    if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
 
511
        /*
 
512
         * IProp is enabled, so let's map in the update log
 
513
         * and setup the service.
 
514
         */
 
515
        if ((ret = ulog_map(hctx, params.iprop_logfile,
 
516
                            params.iprop_ulogsize, FKADMIND, db_args)) != 0) {
 
517
            fprintf(stderr,
 
518
                    _("%s: %s while mapping update log (`%s.ulog')\n"),
 
519
                    whoami, error_message(ret), params.dbname);
 
520
            krb5_klog_syslog(LOG_ERR,
 
521
                             _("%s while mapping update log (`%s.ulog')"),
 
522
                             error_message(ret), params.dbname);
 
523
            krb5_klog_close(context);
 
524
            exit(1);
 
525
        }
 
526
 
 
527
 
 
528
        if (nofork)
 
529
            fprintf(stderr,
 
530
                    "%s: create IPROP svc (PROG=%d, VERS=%d)\n",
 
531
                    whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
 
532
 
 
533
#if 0
 
534
        if (!svc_create(krb5_iprop_prog_1,
 
535
                        KRB5_IPROP_PROG, KRB5_IPROP_VERS,
 
536
                        "circuit_v")) {
 
537
            fprintf(stderr,
 
538
                    _("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"),
 
539
                    whoami,
 
540
                    KRB5_IPROP_PROG, KRB5_IPROP_VERS);
 
541
            krb5_klog_syslog(LOG_ERR,
 
542
                             _("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."),
 
543
                             KRB5_IPROP_PROG, KRB5_IPROP_VERS);
 
544
            krb5_klog_close(context);
 
545
            exit(1);
 
546
        }
 
547
#endif
 
548
 
 
549
#if 0 /* authgss only? */
 
550
        if ((ret = kiprop_get_adm_host_srv_name(context,
 
551
                                                params.realm,
 
552
                                                &kiprop_name)) != 0) {
 
553
            krb5_klog_syslog(LOG_ERR,
 
554
                             _("%s while getting IProp svc name, failing"),
 
555
                             error_message(ret));
 
556
            fprintf(stderr,
 
557
                    _("%s: %s while getting IProp svc name, failing\n"),
 
558
                    whoami, error_message(ret));
 
559
            krb5_klog_close(context);
 
560
            exit(1);
 
561
        }
 
562
 
 
563
        auth_gssapi_name iprop_name;
 
564
        iprop_name.name = build_princ_name(foo, bar);
 
565
        if (iprop_name.name == NULL) {
 
566
            foo error;
 
567
        }
 
568
        iprop_name.type = nt_krb5_name_oid;
 
569
        if (svcauth_gssapi_set_names(&iprop_name, 1) == FALSE) {
 
570
            foo error;
 
571
        }
 
572
        if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0,
 
573
                                  KRB5_IPROP_PROG, KRB5_IPROP_VERS)) {
 
574
            rpc_gss_error_t err;
 
575
            (void) rpc_gss_get_error(&err);
 
576
 
 
577
            krb5_klog_syslog(LOG_ERR,
 
578
                             _("Unable to set RPCSEC_GSS service name (`%s'), failing."),
 
579
                             kiprop_name ? kiprop_name : "<null>");
 
580
 
 
581
            fprintf(stderr,
 
582
                    _("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"),
 
583
                    whoami,
 
584
                    kiprop_name ? kiprop_name : "<null>");
 
585
 
 
586
            if (nofork) {
 
587
                fprintf(stderr,
 
588
                        "%s: set svc name (rpcsec err=%d, sys err=%d)\n",
 
589
                        whoami,
 
590
                        err.rpc_gss_error,
 
591
                        err.system_error);
 
592
            }
 
593
 
 
594
            exit(1);
 
595
        }
 
596
        free(kiprop_name);
 
597
#endif
 
598
    }
 
599
 
 
600
    setup_signal_handlers(log_ctx->iproprole);
 
601
    krb5_klog_syslog(LOG_INFO, _("starting"));
 
602
    if (nofork)
 
603
        fprintf(stderr, "%s: starting...\n", whoami);
 
604
 
 
605
     listen_and_process(global_server_handle, whoami);
647
606
     krb5_klog_syslog(LOG_INFO, "finished, exiting");
648
607
 
649
608
     /* Clean up memory, etc */
650
609
     svcauth_gssapi_unset_names();
651
610
     kadm5_destroy(global_server_handle);
652
 
     close(s);
 
611
     closedown_network(global_server_handle, whoami);
653
612
     kadm5int_acl_finish(context, 0);
654
613
     if(gss_changepw_name) {
655
614
          (void) gss_release_name(&OMret, &gss_changepw_name);
657
616
     if(gss_oldchangepw_name) {
658
617
          (void) gss_release_name(&OMret, &gss_oldchangepw_name);
659
618
     }
660
 
     for(s = 0 ; s < 4; s++) {
661
 
          if (names[s].name) {
662
 
                free(names[s].name);
 
619
     for(i = 0 ; i < 4; i++) {
 
620
          if (names[i].name) {
 
621
                free(names[i].name);
663
622
          }
664
623
     }
665
624
 
675
634
 * if possible, otherwise with System V's signal().
676
635
 */
677
636
 
678
 
void setup_signal_handlers(void) {
 
637
void setup_signal_handlers(iprop_role iproprole) {
679
638
#ifdef POSIX_SIGNALS
680
639
     (void) sigemptyset(&s_action.sa_mask);
681
640
     s_action.sa_handler = request_exit;
692
651
     s_action.sa_handler = request_pure_clear;
693
652
     (void) sigaction(SIGUSR2, &s_action, (struct sigaction *) NULL);
694
653
#endif /* PURIFY */
 
654
 
 
655
     /*
 
656
      * IProp will fork for a full-resync, we don't want to
 
657
      * wait on it and we don't want the living dead procs either.
 
658
      */
 
659
     if (iproprole == IPROP_MASTER) {
 
660
         s_action.sa_handler = SIG_IGN;
 
661
         (void) sigaction(SIGCHLD, &s_action, (struct sigaction *) NULL);
 
662
     }
695
663
#else /* POSIX_SIGNALS */
696
664
     signal(SIGINT, request_exit);
697
665
     signal(SIGTERM, request_exit);
702
670
     signal(SIGUSR1, request_pure_report);
703
671
     signal(SIGUSR2, request_pure_clear);
704
672
#endif /* PURIFY */
 
673
 
 
674
     /*
 
675
      * IProp will fork for a full-resync, we don't want to
 
676
      * wait on it and we don't want the living dead procs either.
 
677
      */
 
678
     if (iproprole == IPROP_MASTER)
 
679
         (void) signal(SIGCHLD, SIG_IGN);
705
680
#endif /* POSIX_SIGNALS */
706
681
}
707
682
 
708
 
/*
709
 
 * Function: kadm_svc_run
710
 
 * 
711
 
 * Purpose: modified version of sunrpc svc_run.
712
 
 *          which closes the database every TIMEOUT seconds.
713
 
 *
714
 
 * Arguments:
715
 
 * Requires:
716
 
 * Effects:
717
 
 * Modifies:
718
 
 */
719
 
 
720
 
void kadm_svc_run(params)
721
 
kadm5_config_params *params;
722
 
{
723
 
     fd_set     rfd;
724
 
     struct     timeval     timeout;
725
 
     
726
 
     while(signal_request_exit == 0) {
727
 
          if (signal_request_hup) {
728
 
              reset_db();
729
 
              krb5_klog_reopen(context);
730
 
              signal_request_hup = 0;
731
 
          }
732
 
#ifdef PURIFY
733
 
          if (signal_pure_report)       /* check to see if a report */
734
 
                                        /* should be dumped... */
735
 
            {
736
 
              purify_new_reports();
737
 
              signal_pure_report = 0;
738
 
            }
739
 
          if (signal_pure_clear)        /* ...before checking whether */
740
 
                                        /* the info should be cleared. */
741
 
            {
742
 
              purify_clear_new_reports();
743
 
              signal_pure_clear = 0;
744
 
            }
745
 
#endif /* PURIFY */
746
 
          timeout.tv_sec = TIMEOUT;
747
 
          timeout.tv_usec = 0;
748
 
          rfd = svc_fdset;
749
 
          FD_SET(schpw, &rfd);
750
 
#define max(a, b) (((a) > (b)) ? (a) : (b))
751
 
          switch(select(max(schpw, svc_maxfd) + 1,
752
 
                        (fd_set *) &rfd, NULL, NULL, &timeout)) {
753
 
          case -1:
754
 
               if(errno == EINTR)
755
 
                    continue;
756
 
               perror("select");
757
 
               return;
758
 
          case 0:
759
 
               reset_db();
760
 
               break;
761
 
          default:
762
 
              if (FD_ISSET(schpw, &rfd))
763
 
                  do_schpw(schpw, params);
764
 
              else
765
 
                  svc_getreqset(&rfd);
766
 
          }
767
 
     }
768
 
}
769
 
 
770
683
#ifdef PURIFY
771
684
/*
772
685
 * Function: request_pure_report
924
837
{
925
838
     char *fullname;
926
839
 
927
 
     fullname = (char *) malloc(strlen(name) + 1 +
928
 
                                (realm ? strlen(realm) + 1 : 0));
929
 
     if (fullname == NULL)
930
 
          return NULL;
931
 
     if (realm)
932
 
          sprintf(fullname, "%s@%s", name, realm);
933
 
     else
934
 
          strcpy(fullname, name);
 
840
     if (realm) {
 
841
         if (asprintf(&fullname, "%s@%s", name, realm) < 0)
 
842
             fullname = NULL;
 
843
     } else
 
844
         fullname = strdup(name);
 
845
 
935
846
     return fullname;
936
847
}
937
848
 
1029
940
     if (procname != NULL)
1030
941
          krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %s, "
1031
942
                           "claimed client = %.*s%s, server = %.*s%s, addr = %s",
1032
 
                           procname, clen, client.value, cdots,
1033
 
                           slen, server.value, sdots, a);
 
943
                           procname, (int) clen, (char *) client.value, cdots,
 
944
                           (int) slen, (char *) server.value, sdots, a);
1034
945
     else
1035
946
          krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %d, "
1036
947
                           "claimed client = %.*s%s, server = %.*s%s, addr = %s",
1037
 
                           proc, clen, client.value, cdots,
1038
 
                           slen, server.value, sdots, a);
 
948
                           proc, (int) clen, (char *) client.value, cdots,
 
949
                           (int) slen, (char *) server.value, sdots, a);
1039
950
 
1040
951
     (void) gss_release_buffer(&minor, &client);
1041
952
     (void) gss_release_buffer(&minor, &server);
1125
1036
                    log_badauth_display_status_1(m, minor_stat,
1126
1037
                                                 GSS_C_MECH_CODE, 1);
1127
1038
               } else
1128
 
                    krb5_klog_syslog(LOG_ERR, "GSS-API authentication error %s: "
1129
 
                           "recursive failure!", msg);
 
1039
                    krb5_klog_syslog(LOG_ERR, "GSS-API authentication error %.*s: "
 
1040
                                     "recursive failure!", (int) msg.length,
 
1041
                                     (char *) msg.value);
1130
1042
               return;
1131
1043
          }
1132
1044
 
1133
 
          krb5_klog_syslog(LOG_NOTICE, "%s %s", m, (char *)msg.value); 
 
1045
          krb5_klog_syslog(LOG_NOTICE, "%s %.*s", m, (int)msg.length,
 
1046
                           (char *)msg.value);
1134
1047
          (void) gss_release_buffer(&minor_stat, &msg);
1135
1048
          
1136
1049
          if (!msg_ctx)
1138
1051
     }
1139
1052
}
1140
1053
 
1141
 
void do_schpw(int s1, kadm5_config_params *params)
1142
 
{
1143
 
    krb5_error_code ret;
1144
 
    /* XXX buffer = ethernet mtu */
1145
 
    char req[1500];
1146
 
    int len;
1147
 
    struct sockaddr_in from;
1148
 
    socklen_t fromlen;
1149
 
    krb5_keytab kt;
1150
 
    krb5_data reqdata, repdata;
1151
 
    int s2;
1152
 
 
1153
 
    fromlen = sizeof(from);
1154
 
    if ((len = recvfrom(s1, req, sizeof(req), 0, (struct sockaddr *)&from,
1155
 
                        &fromlen)) < 0) {
1156
 
        krb5_klog_syslog(LOG_ERR, "chpw: Couldn't receive request: %s",
1157
 
                         krb5_get_error_message (context, errno));
1158
 
        return;
1159
 
    }
1160
 
 
1161
 
    if ((ret = krb5_kt_resolve(context, "KDB:", &kt))) {
1162
 
        krb5_klog_syslog(LOG_ERR, "chpw: Couldn't open admin keytab %s",
1163
 
                         krb5_get_error_message (context, ret));
1164
 
        return;
1165
 
    }
1166
 
 
1167
 
    reqdata.length = len;
1168
 
    reqdata.data = req;
1169
 
 
1170
 
    /* this is really obscure.  s1 is used for all communications.  it
1171
 
       is left unconnected in case the server is multihomed and routes
1172
 
       are asymmetric.  s2 is connected to resolve routes and get
1173
 
       addresses.  this is the *only* way to get proper addresses for
1174
 
       multihomed hosts if routing is asymmetric.  
1175
 
 
1176
 
       A related problem in the server, but not the client, is that
1177
 
       many os's have no way to disconnect a connected udp socket, so
1178
 
       the s2 socket needs to be closed and recreated for each
1179
 
       request.  The s1 socket must not be closed, or else queued
1180
 
       requests will be lost.
1181
 
 
1182
 
       A "naive" client implementation (one socket, no connect,
1183
 
       hostname resolution to get the local ip addr) will work and
1184
 
       interoperate if the client is single-homed. */
1185
 
 
1186
 
    if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1187
 
        const char *errmsg = krb5_get_error_message (context, errno);
1188
 
        krb5_klog_syslog(LOG_ERR, "cannot create connecting socket: %s",
1189
 
                         errmsg);
1190
 
        fprintf(stderr, "Cannot create connecting socket: %s",
1191
 
                errmsg);
1192
 
        svcauth_gssapi_unset_names();
1193
 
        kadm5_destroy(global_server_handle);
1194
 
        krb5_klog_close(context);         
1195
 
        exit(1);
1196
 
    }
1197
 
 
1198
 
    if (connect(s2, (struct sockaddr *) &from, sizeof(from)) < 0) {
1199
 
        krb5_klog_syslog(LOG_ERR, "chpw: Couldn't connect to client: %s",
1200
 
                         krb5_get_error_message (context, errno));
1201
 
        goto cleanup;
1202
 
    }
1203
 
 
1204
 
    if ((ret = process_chpw_request(context, global_server_handle,
1205
 
                                    params->realm, s2, kt, &from,
1206
 
                                    &reqdata, &repdata))) {
1207
 
        krb5_klog_syslog(LOG_ERR, "chpw: Error processing request: %s", 
1208
 
                         krb5_get_error_message (context, ret));
1209
 
    }
1210
 
 
1211
 
    close(s2);
1212
 
 
1213
 
    if (repdata.length == 0) {
1214
 
        /* just return.  This means something really bad happened */
1215
 
        goto cleanup;
1216
 
    }
1217
 
 
1218
 
    len = sendto(s1, repdata.data, (int) repdata.length, 0,
1219
 
                 (struct sockaddr *) &from, sizeof(from));
1220
 
 
1221
 
    if (len < (int) repdata.length) {
1222
 
        krb5_xfree(repdata.data);
1223
 
 
1224
 
        krb5_klog_syslog(LOG_ERR, "chpw: Error sending reply: %s", 
1225
 
                         krb5_get_error_message (context, errno));
1226
 
        goto cleanup;
1227
 
    }
1228
 
 
1229
 
    krb5_xfree(repdata.data);
1230
 
 
1231
 
cleanup:
1232
 
    krb5_kt_close(context, kt);
1233
 
 
1234
 
    return;
1235
 
}