This commit was manufactured by cvs2svn to create tag
[krb5.git] / src / slave / kprop.c
index 5755a32bb564b5483a042e562a8688114c54e52a..fa32f11a8432b6492e4c9e2aca78c695a7c5f30a 100644 (file)
  * this permission notice appear in supporting documentation, and that
  * the name of M.I.T. not be used in advertising or publicity pertaining
  * to distribution of the software without specific, written prior
- * permission.  M.I.T. makes no representations about the suitability of
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
  * this software for any purpose.  It is provided "as is" without express
  * or implied warranty.
  * 
 #include <netinet/in.h>
 #include <sys/param.h>
 #include <netdb.h>
+#include <fcntl.h>
 
 #include "k5-int.h"
 #include "com_err.h"
-
-#ifdef NEED_SYS_FCNTL_H
-#include <sys/fcntl.h>
-#endif
-
 #include "kprop.h"
 
 static char *kprop_version = KPROP_PROT_VERSION;
 
 char   *progname = 0;
 int     debug = 0;
+char   *srvtab = 0;
 char   *slave_host;
 char   *realm = 0;
 char   *file = KPROP_DEFAULT_FILE;
+short  port = 0;
 
 krb5_principal my_principal;           /* The Kerberos principal we'll be */
                                /* running under, initialized in */
@@ -61,27 +62,27 @@ krb5_principal      my_principal;           /* The Kerberos principal we'll be */
 krb5_ccache    ccache;         /* Credentials cache which we'll be using */
 /* krb5_creds  my_creds;       /* My credentials */
 krb5_creds     creds;
-krb5_int32     my_seq_num;     /* Sequence number to use for connection */
-krb5_int32     his_seq_num;    /* Remote sequence number */
 krb5_address   sender_addr;
 krb5_address   receiver_addr;
 
 void   PRS
-       PROTOTYPE((krb5_context, char **));
+       PROTOTYPE((int, char **));
 void   get_tickets
        PROTOTYPE((krb5_context));
 static void usage 
        PROTOTYPE((void));
 krb5_error_code open_connection 
-       PROTOTYPE((char *, int *, char *));
+       PROTOTYPE((char *, int *, char *, int));
 void   kerberos_authenticate 
-       PROTOTYPE((krb5_context, int, krb5_principal, krb5_creds **));
+       PROTOTYPE((krb5_context, krb5_auth_context *, 
+                  int, krb5_principal, krb5_creds **));
 int    open_database 
        PROTOTYPE((krb5_context, char *, int *));
 void   close_database 
        PROTOTYPE((krb5_context, int));
 void   xmit_database 
-       PROTOTYPE((krb5_context, krb5_creds *, int, int, int));
+       PROTOTYPE((krb5_context, krb5_auth_context, krb5_creds *, 
+                  int, int, int));
 void   send_error 
        PROTOTYPE((krb5_context, krb5_creds *, int, char *, krb5_error_code));
 void   update_last_prop_file 
@@ -89,12 +90,12 @@ void        update_last_prop_file
 
 static void usage()
 {
-       fprintf(stderr, "\nUsage: %s [-r realm] [-f file] [-d] slave_host\n\n",
+       fprintf(stderr, "\nUsage: %s [-r realm] [-f file] [-d] [-P port] [-s srvtab] slave_host\n\n",
                progname);
        exit(1);
 }
 
-void
+int
 main(argc, argv)
        int     argc;
        char    **argv;
@@ -102,14 +103,20 @@ main(argc, argv)
        int     fd, database_fd, database_size;
        krb5_error_code retval;
        krb5_context context;
-       krb5_creds my_creds;
+       krb5_creds *my_creds;
+       krb5_auth_context auth_context;
        char    Errmsg[256];
        
-       PRS(context, argv);
+       retval = krb5_init_context(&context);
+       if (retval) {
+               com_err(argv[0], retval, "while initializing krb5");
+               exit(1);
+       }
+       PRS(argc, argv);
        get_tickets(context);
 
        database_fd = open_database(context, file, &database_size);
-       if (retval = open_connection(slave_host, &fd, Errmsg)) {
+       if (retval = open_connection(slave_host, &fd, Errmsg, sizeof(Errmsg))) {
                com_err(progname, retval, "%s while opening connection to %s",
                        Errmsg, slave_host);
                exit(1);
@@ -119,29 +126,25 @@ main(argc, argv)
                        progname, Errmsg, slave_host);
                exit(1);
        }
-       kerberos_authenticate(context, fd, my_principal, &my_creds);
-       if (debug) {
-               printf("My sequence number: %d\n", my_seq_num);
-               printf("His sequence number: %d\n", his_seq_num);
-       }
-       xmit_database(context, & my_creds, fd, database_fd, database_size);
+       kerberos_authenticate(context, &auth_context, fd, my_principal, 
+                             &my_creds);
+       xmit_database(context, auth_context, my_creds, fd, database_fd, 
+                     database_size);
        update_last_prop_file(slave_host, file);
        printf("Database propagation to %s: SUCCEEDED\n", slave_host);
-       krb5_free_cred_contents(context, &my_creds);
+       krb5_free_cred_contents(context, my_creds);
        close_database(context, database_fd);
        exit(0);
 }
 
-void PRS(context, argv)
-       krb5_context context;
+void PRS(argc, argv)
+       int     argc;
        char    **argv;
 {
        register char   *word, ch;
        
-       krb5_init_context(&context);
-       krb5_init_ets(context);
        progname = *argv++;
-       while (word = *argv++) {
+       while (--argc && (word = *argv++)) {
                if (*word == '-') {
                        word++;
                        while (word && (ch = *word++)) {
@@ -167,6 +170,24 @@ void PRS(context, argv)
                                case 'd':
                                        debug++;
                                        break;
+                               case 'P':
+                                       if (*word)
+                                               port = htons(atoi(word));
+                                       else
+                                               port = htons(atoi(*argv++));
+                                       if (!port)
+                                               usage();
+                                       word = 0;
+                                       break;
+                               case 's':
+                                       if (*word)
+                                               srvtab = word;
+                                       else
+                                               srvtab = *argv++;
+                                       if (!srvtab)
+                                               usage();
+                                       word = 0;
+                                       break;
                                default:
                                        usage();
                                }
@@ -192,30 +213,25 @@ void get_tickets(context)
        struct hostent *hp;
        krb5_error_code retval;
        static char tkstring[] = "/tmp/kproptktXXXXXX";
+       krb5_keytab keytab = NULL;
 
        /*
         * Figure out what tickets we'll be using to send stuff
         */
-       if (gethostname (my_host_name, sizeof(my_host_name)) != 0) { 
-               com_err(progname, errno, "while getting my hostname");
-               exit(1);
-       }
-       /* get canonicalized  service instance name */
-       if (!(hp = gethostbyname(my_host_name))) {
-               fprintf(stderr, "Couldn't get my cannonicalized host name!\n");
-               exit(1);
+       retval = krb5_sname_to_principal(context, NULL, NULL,
+                                        KRB5_NT_SRV_HST, &my_principal);
+       if (retval) {
+           com_err(progname, errno, "while setting client principal name");
+           exit(1);
        }
-       for (cp=hp->h_name; *cp; cp++)
-               if (isupper(*cp))
-                       *cp = tolower(*cp);
-       if (realm)
-               sprintf(buf, "host/%s@%s", hp->h_name, realm);
-       else
-               sprintf(buf, "host/%s", hp->h_name);
-       if (retval = krb5_parse_name(context, buf, &my_principal)) {
-               com_err (progname, retval, "when parsing name %s",buf);
-               exit(1);
+       if (realm) {
+           (void) krb5_xfree(krb5_princ_realm(context, my_principal)->data);
+           krb5_princ_set_realm_length(context, my_principal, strlen(realm));
+           krb5_princ_set_realm_data(context, my_principal, strdup(realm));
        }
+#if 0
+       krb5_princ_type(context, my_principal) = KRB5_NT_PRINCIPAL;
+#endif
 
        /*
         * Initialize cache file which we're going to be using
@@ -223,7 +239,7 @@ void get_tickets(context)
        (void) mktemp(tkstring);
        sprintf(buf, "FILE:%s", tkstring);
        if (retval = krb5_cc_resolve(context, buf, &ccache)) {
-               com_err(progname, retval, "while opening crednetials cache %s",
+               com_err(progname, retval, "while opening credential cache %s",
                        buf);
                exit(1);
        }
@@ -239,43 +255,47 @@ void get_tickets(context)
         * Construct the principal name for the slave host.
         */
        memset((char *)&creds, 0, sizeof(creds));
-       if (!(hp = gethostbyname(slave_host))) {
-               fprintf(stderr,
-                       "Couldn't get cannonicalized name for slave\n");
-               exit(1);
-       }
-       for (cp=hp->h_name; *cp; cp++)
-               if (isupper(*cp))
-                       *cp = tolower(*cp);
-       if (!(slave_host = malloc(strlen(hp->h_name) + 1))) {
-               com_err(progname, ENOMEM,
-                       "while allocate space for canonicalized slave host");
-               exit(1);
+       retval = krb5_sname_to_principal(context,
+                                        slave_host, KPROP_SERVICE_NAME,
+                                        KRB5_NT_SRV_HST, &creds.server);
+       if (retval) {
+           com_err(progname, errno, "while setting server principal name");
+           (void) krb5_cc_destroy(context, ccache);
+           exit(1);
        }
-       strcpy(slave_host, hp->h_name);
-       if (realm)
-               sprintf(buf, "%s/%s@%s", KPROP_SERVICE_NAME, slave_host,
-                       realm);
-       else
-               sprintf(buf, "%s/%s", KPROP_SERVICE_NAME, hp->h_name);
-       if (retval = krb5_parse_name(context, buf, &creds.server)) {
-               com_err(progname, retval,
-                       "while parsing slave principal name");
-               exit(1);
+       if (realm) {
+           (void) krb5_xfree(krb5_princ_realm(context, creds.server)->data);
+           krb5_princ_set_realm_length(context, creds.server, strlen(realm));
+           krb5_princ_set_realm_data(context, creds.server, strdup(realm));
        }
+
        /*
         * Now fill in the client....
         */
        if (retval = krb5_copy_principal(context, my_principal, &creds.client)) {
                com_err(progname, retval, "While copying client principal");
+               (void) krb5_cc_destroy(context, ccache);
                exit(1);
        }
+       if (srvtab) {
+               if (retval = krb5_kt_resolve(context, srvtab, &keytab)) {
+                       com_err(progname, retval, "while resolving keytab");
+                       (void) krb5_cc_destroy(context, ccache);
+                       exit(1);
+               }
+       }
+
        retval = krb5_get_in_tkt_with_keytab(context, 0, 0, NULL,
-                                            NULL, NULL, ccache, &creds, 0);
+                                            NULL, keytab, ccache, &creds, 0);
        if (retval) {
                com_err(progname, retval, "while getting initial ticket\n");
+               (void) krb5_cc_destroy(context, ccache);
                exit(1);
        }
+
+       if (keytab)
+           (void) krb5_kt_close(context, keytab);
+       
        /*
         * Now destroy the cache right away --- the credentials we
         * need will be in my_creds.
@@ -287,10 +307,11 @@ void get_tickets(context)
 }
 
 krb5_error_code
-open_connection(host, fd, Errmsg)
+open_connection(host, fd, Errmsg, ErrmsgSz)
        char    *host;
        int     *fd;
        char    *Errmsg;
+       int      ErrmsgSz;
 {
        int     s;
        krb5_error_code retval;
@@ -306,16 +327,20 @@ open_connection(host, fd, Errmsg)
                *fd = -1;
                return(0);
        }
-       sp = getservbyname(KPROP_SERVICE, "tcp");
-       if (sp == 0) {
-               (void) strcpy(Errmsg, KPROP_SERVICE);
-               (void) strcat(Errmsg, "/tcp: unknown service");
-               *fd = -1;
-               return(0);
-       }
        sin.sin_family = hp->h_addrtype;
-       memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
-       sin.sin_port = sp->s_port;
+       memcpy((char *)&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+       if(!port) {
+               sp = getservbyname(KPROP_SERVICE, "tcp");
+               if (sp == 0) {
+                       (void) strncpy(Errmsg, KPROP_SERVICE, ErrmsgSz - 1);
+                       Errmsg[ErrmsgSz - 1] = '\0';
+                       (void) strncat(Errmsg, "/tcp: unknown service", ErrmsgSz - 1 - strlen(Errmsg));
+                       *fd = -1;
+                       return(0);
+               }
+               sin.sin_port = sp->s_port;
+       } else
+               sin.sin_port = port;
        s = socket(AF_INET, SOCK_STREAM, 0);
        
        if (s < 0) {
@@ -356,8 +381,9 @@ open_connection(host, fd, Errmsg)
 }
 
 
-void kerberos_authenticate(context, fd, me, new_creds)
+void kerberos_authenticate(context, auth_context, fd, me, new_creds)
     krb5_context context;
+    krb5_auth_context *auth_context;
     int        fd;
     krb5_principal me;
     krb5_creds ** new_creds;
@@ -366,9 +392,21 @@ void kerberos_authenticate(context, fd, me, new_creds)
        krb5_error      *error = NULL;
        krb5_ap_rep_enc_part    *rep_result;
 
-       if (retval = krb5_sendauth(context, (void *)&fd, kprop_version, me,
-                                  creds.server, AP_OPTS_MUTUAL_REQUIRED,
-                                  NULL, &creds, NULL, &my_seq_num, NULL,
+    if (retval = krb5_auth_con_init(context, auth_context)) 
+       exit(1);
+
+    krb5_auth_con_setflags(context, *auth_context, 
+                          KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+    if (retval = krb5_auth_con_setaddrs(context, *auth_context, &sender_addr,
+                                       &receiver_addr)) {
+       com_err(progname, retval, "in krb5_auth_con_setaddrs");
+       exit(1);
+    }
+
+       if (retval = krb5_sendauth(context, auth_context, (void *)&fd, 
+                                  kprop_version, me, creds.server,
+                                  AP_OPTS_MUTUAL_REQUIRED, NULL, &creds, NULL,
                                   &error, &rep_result, new_creds)) {
                com_err(progname, retval, "while authenticating to server");
                if (error) {
@@ -390,11 +428,9 @@ void kerberos_authenticate(context, fd, me, new_creds)
                }
                exit(1);
        }
-       his_seq_num = rep_result->seq_number;
        krb5_free_ap_rep_enc_part(context, rep_result);
 }
 
-FILE * dbfp;
 char * dbpathname;
 /*
  * Open the Kerberos database dump file.  Takes care of locking it
@@ -422,13 +458,13 @@ open_database(context, data_fn, size)
                    data_fn);
            exit(1);
        }
-       if ((dbfp = fopen(dbpathname, "r")) == 0) {
+       if ((fd = open(dbpathname, O_RDONLY)) < 0) {
                com_err(progname, errno, "while trying to open %s",
                        dbpathname);
                exit(1);
        }
 
-       err = krb5_lock_file(context, dbfp, dbpathname,
+       err = krb5_lock_file(context, fd,
                             KRB5_LOCKMODE_SHARED|KRB5_LOCKMODE_DONTBLOCK);
        if (err == EAGAIN || err == EWOULDBLOCK || errno == EACCES) {
            com_err(progname, 0, "database locked");
@@ -437,7 +473,6 @@ open_database(context, data_fn, size)
            com_err(progname, err, "while trying to lock '%s'", dbpathname);
            exit(1);
        }           
-       fd = fileno(dbfp);
        if (fstat(fd, &stbuf)) {
                com_err(progname, errno, "while trying to stat %s",
                        data_fn);
@@ -448,7 +483,8 @@ open_database(context, data_fn, size)
                com_err(progname, ENOMEM, "while trying to malloc data_ok_fn");
                exit(1);
        }
-       strcat(strcpy(data_ok_fn, data_fn), ok);
+       strcpy(data_ok_fn, data_fn);
+       strcat(data_ok_fn, ok);
        if (stat(data_ok_fn, &stbuf_ok)) {
                com_err(progname, errno, "while trying to stat %s",
                        data_ok_fn);
@@ -471,15 +507,10 @@ close_database(context, fd)
     int fd;
 {
     int err;
-    if (fd != fileno(dbfp)) {
-       com_err(progname, 0, "bad fd passed to close_database");
-       exit(1);
-    }
-    err = krb5_lock_file(context, dbfp, dbpathname, KRB5_LOCKMODE_UNLOCK);
-    if (err)
+    if (err = krb5_lock_file(context, fd, KRB5_LOCKMODE_UNLOCK))
        com_err(progname, err, "while unlocking database '%s'", dbpathname);
     free(dbpathname);
-    (void) fclose(dbfp);
+    (void)close(fd);
     return;
 }
   
@@ -493,17 +524,17 @@ close_database(context, fd)
  * will abort the entire operation.
  */
 void
-xmit_database(context, my_creds, fd, database_fd, database_size)
+xmit_database(context, auth_context, my_creds, fd, database_fd, database_size)
     krb5_context context;
+    krb5_auth_context auth_context;
     krb5_creds *my_creds;
     int        fd;
     int        database_fd;
     int        database_size;
 {
-       int     send_size, sent_size, n, eblock_size;
+       krb5_int32      send_size, sent_size, n;
        krb5_data       inbuf, outbuf;
        char            buf[KPROP_BUFSIZ];
-       char            *i_vector;
        krb5_error_code retval;
        krb5_error      *error;
        
@@ -513,35 +544,28 @@ xmit_database(context, my_creds, fd, database_fd, database_size)
        send_size = htonl(database_size);
        inbuf.data = (char *) &send_size;
        inbuf.length = sizeof(send_size); /* must be 4, really */
-       if (retval = krb5_mk_safe(context, &inbuf, KPROP_CKSUMTYPE,
-                                 &my_creds->keyblock, 
-                                 &sender_addr, &receiver_addr,
-                                 my_seq_num++,
-                                 KRB5_PRIV_DOSEQUENCE|KRB5_SAFE_NOTIME,
-                                 0,    /* no rcache when NOTIME */
-                                 &outbuf)) {
+       /* KPROP_CKSUMTYPE */
+       if (retval = krb5_mk_safe(context, auth_context, &inbuf, 
+                                 &outbuf, NULL)) {
                com_err(progname, retval, "while encoding database size");
                send_error(context, my_creds, fd, "while encoding database size", retval);
                exit(1);
        }
        if (retval = krb5_write_message(context, (void *) &fd, &outbuf)) {
-               krb5_xfree(outbuf.data);
+               krb5_free_data_contents(context, &outbuf);
                com_err(progname, retval, "while sending database size");
                exit(1);
        }
-       krb5_xfree(outbuf.data);
-       /*
-        * Initialize the initial vector.
-        */
-       eblock_size = krb5_keytype_array[my_creds->keyblock.keytype]->
-               system->block_length;
-       if (!(i_vector=malloc(eblock_size))) {
-               com_err(progname, ENOMEM, "while allocating i_vector");
-               send_error(context, my_creds, fd, 
-                          "malloc failed while allocating i_vector", ENOMEM);
-               exit(1);
-       }
-       memset(i_vector, 0, eblock_size);
+       krb5_free_data_contents(context, &outbuf);
+    /*
+     * Initialize the initial vector.
+     */
+    if (retval = krb5_auth_con_initivector(context, auth_context)) {
+       send_error(context, my_creds, fd, 
+                  "failed while initializing i_vector", retval);
+       com_err(progname, retval, "while allocating i_vector");
+       exit(1);
+    }
        /*
         * Send over the file, block by block....
         */
@@ -549,15 +573,8 @@ xmit_database(context, my_creds, fd, database_fd, database_size)
        sent_size = 0;
        while (n = read(database_fd, buf, sizeof(buf))) {
                inbuf.length = n;
-               if (retval = krb5_mk_priv(context, &inbuf, ETYPE_DES_CBC_CRC,
-                                         &my_creds->keyblock,
-                                         &sender_addr,
-                                         &receiver_addr,
-                                         my_seq_num++,
-                                         KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
-                                         0, /* again, no rcache */
-                                         i_vector,
-                                         &outbuf)) {
+               if (retval = krb5_mk_priv(context, auth_context, &inbuf,
+                                         &outbuf, NULL)) {
                        sprintf(buf,
                                "while encoding database block starting at %d",
                                sent_size);
@@ -566,13 +583,13 @@ xmit_database(context, my_creds, fd, database_fd, database_size)
                        exit(1);
                }
                if (retval = krb5_write_message(context, (void *)&fd,&outbuf)) {
-                       krb5_xfree(outbuf.data);
+                       krb5_free_data_contents(context, &outbuf);
                        com_err(progname, retval,
                                "while sending database block starting at %d",
                                sent_size);
                        exit(1);
                }
-               krb5_xfree(outbuf.data);
+               krb5_free_data_contents(context, &outbuf);
                sent_size += n;
                if (debug)
                        printf("%d bytes sent.\n", sent_size);
@@ -618,10 +635,7 @@ xmit_database(context, my_creds, fd, database_fd, database_size)
                krb5_free_error(context, error);
                exit(1);
        }
-       if (retval = krb5_rd_safe(context, &inbuf, &my_creds->keyblock,         
-                                 &receiver_addr, &sender_addr, his_seq_num++,
-                                 KRB5_SAFE_DOSEQUENCE|KRB5_SAFE_NOTIME,
-                                 0, &outbuf)) {
+       if (retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL)) {
                com_err(progname, retval,
                        "while decoding final size packet from server");
                exit(1);
@@ -666,7 +680,7 @@ send_error(context, my_creds, fd, err_text, err_code)
                strcpy(error.text.data, text);
                if (!krb5_mk_error(context, &error, &outbuf)) {
                        (void) krb5_write_message(context, (void *)&fd,&outbuf);
-                       krb5_xfree(outbuf.data);
+                       krb5_free_data_contents(context, &outbuf);
                }
                free(error.text.data);
        }
@@ -692,13 +706,14 @@ void update_last_prop_file(hostname, file_name)
        strcat(file_last_prop, ".");
        strcat(file_last_prop, hostname);
        strcat(file_last_prop, last_prop);
-       if ((fd = open(file_last_prop, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+       if ((fd = THREEPARAMOPEN(file_last_prop, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
                com_err(progname, errno,
                        "while creating 'last_prop' file, '%s'",
                        file_last_prop);
                free(file_last_prop);
                return;
        }
+       write(fd, "", 1);
        free(file_last_prop);
        close(fd);
        return;