source: trunk/third/kpasswd/kadm_cli_wrap.c @ 11571

Revision 11571, 18.0 KB checked in by ghudson, 26 years ago (diff)
Deal properly with real v4 headers.
Line 
1/*
2 * kadm_cli_wrap.c
3 *
4 * Copyright 1988 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 * Kerberos administration server client-side routines
10 * The client side wrapping of the calls to the admin server.
11 */
12
13#include <mit-copyright.h>
14
15#include <string.h>
16
17#define DEFINE_SOCKADDR         /* Ask krb.h for struct sockaddr, netdb, etc */
18#include "krb.h"
19
20#include <kadm.h>
21#include <kadm_err.h>
22#include <krb_err.h>
23#include <krbports.h>
24
25#ifndef NULL
26#define NULL 0
27#endif
28
29#ifndef KRB_INT32
30#define KRB_INT32 KRB4_32
31#endif
32
33Kadm_Client client_parm;
34int default_client_port = 1;
35
36/* Macros for use in returning data... used in kadm_cli_send */
37#define RET_N_FREE(r) {clear_secrets(); free((char *)act_st); free((char *)priv_pak); return r;}
38
39/* Keys for use in the transactions */
40static des_cblock sess_key;            /* to be filled in by kadm_cli_keyd */
41static Key_schedule sess_sched;
42
43static void
44clear_secrets()
45{
46        memset((char *)sess_key, 0, sizeof(sess_key));
47        memset((char *)sess_sched, 0, sizeof(sess_sched));
48        return;
49}
50
51/*
52 * kadm_init_link
53 *      receives    : name, inst, realm
54 *
55 * initializes client parm, the Kadm_Client structure which holds the
56 * data about the connection between the server and client, the services
57 * used, the locations and other fun things
58 */
59int INTERFACE
60kadm_init_link(n, i, r)
61char n[];
62char i[];
63char r[];
64{
65        struct servent *sep;           /* service we will talk to */
66        u_short sep_port;
67        struct hostent *hop;           /* host we will talk to */
68        char adm_hostname[MAXHOSTNAMELEN];
69        char *scol = 0;
70
71#ifdef GLOBAL_ERROR_HANDLING
72        (void) init_kadm_err_tbl();
73        (void) init_krb_err_tbl();
74#endif
75
76        (void) strcpy(client_parm.sname, n);
77        (void) strcpy(client_parm.sinst, i);
78        (void) strcpy(client_parm.krbrlm, r);
79        client_parm.admin_fd = -1;
80
81        /* set up the admin_addr - fetch name of admin host */
82        if (krb_get_admhst(adm_hostname, client_parm.krbrlm, 1) != KSUCCESS)
83                return KADM_NO_HOST;
84        scol = strchr(adm_hostname,':');
85        if (scol) *scol = 0;
86        if ((hop = gethostbyname(adm_hostname)) == NULL)
87                return KADM_UNK_HOST;  /* couldnt find the admin servers
88                                        * address */
89        if (scol) {
90                sep_port = htons(atoi(scol+1)+1);
91                default_client_port = 0;
92        }
93        else if (sep = getservbyname(KADM_SNAME, "tcp"))
94                sep_port = sep->s_port;
95        else
96                sep_port = htons(KADM_PORT); /* KADM_SNAME = kerberos_master/tcp */
97        memset((char *) &client_parm.admin_addr, 0,
98              sizeof(client_parm.admin_addr));
99        client_parm.admin_addr.sin_family = hop->h_addrtype;
100        memcpy((char *) &client_parm.admin_addr.sin_addr, (char *) hop->h_addr,
101               hop->h_length);
102        client_parm.admin_addr.sin_port = sep_port;
103
104        return KADM_SUCCESS;
105}                                      /* procedure kadm_init_link */
106
107/*
108 * kadm_change_pw
109 * receives    : key
110 *
111 * Replaces the password (i.e. des key) of the caller with that specified in
112 * key. Returns no actual data from the master server, since this is called
113 * by a user
114 */
115int INTERFACE
116kadm_change_pw(newkey)
117des_cblock newkey;                     /* The DES form of the users key */
118{
119        u_char  *ret_st;
120        int     retval;
121
122        retval = kadm_change_pw2(newkey, (char *)0, &ret_st);
123        if (ret_st)
124                free(ret_st);
125        return(retval);
126}
127
128/*
129 * kadm_change_pw2
130 * recieves    : key, pw_string, ret_string
131 *
132 * Replaces the password (i.e. des key) of the caller with that specified in
133 * key. Returns no actual data from the master server, since this is called
134 * by a user
135 */
136int INTERFACE
137kadm_change_pw2(newkey, pwstring, retstring)
138des_cblock newkey;                     /* The DES form of the users key */
139char    *pwstring;
140u_char  **retstring;
141{
142        int stsize, retc;              /* stream size and return code */
143        u_char *send_st;               /* send stream */
144        u_char *ret_st;
145        int ret_sz;
146        unsigned KRB_INT32 keytmp;
147        extern char *malloc();
148
149        *retstring = (u_char *) 0;
150
151        if ((retc = kadm_cli_conn()) != KADM_SUCCESS)
152            return(retc);
153        /* possible problem with vts_long on a non-multiple of four boundary */
154
155        stsize = 0;                    /* start of our output packet */
156        send_st = (u_char *) malloc(1);/* to make it reallocable */
157        send_st[stsize++] = (u_char) CHANGE_PW;
158
159        /* change key to stream */
160
161        memcpy((char *) &keytmp, (char *) (((KRB_INT32 *) newkey) + 1), sizeof(KRB_INT32));
162        keytmp = htonl(keytmp);
163        stsize += vts_long(keytmp, &send_st, stsize);
164
165        memcpy((char *) &keytmp, (char *) newkey, sizeof(KRB_INT32));
166        keytmp = htonl(keytmp);
167        stsize += vts_long(keytmp, &send_st, stsize);
168
169        if (pwstring) {
170                stsize += vts_string(pwstring, &send_st, stsize);
171        }
172       
173        retc = kadm_cli_send(send_st, stsize, &ret_st, &ret_sz);
174        free((char *)send_st);
175        if (ret_sz)
176                *retstring = ret_st;
177        else {
178                *retstring = 0;
179                free(ret_st);
180        }
181        kadm_cli_disconn();
182        return(retc);
183}
184
185/*
186 * kadm_add
187 *      receives    : vals
188 *      returns     : vals
189 *
190 * Adds an entry containing values to the database returns the values of the
191 * entry, so if you leave certain fields blank you will be able to determine
192 * the default values they are set to
193 */
194kadm_add(vals)
195Kadm_vals *vals;
196{
197        u_char *st, *st2;              /* st will hold the stream of values */
198        int st_len;                    /* st2 the final stream with opcode */
199        int retc;                      /* return code from call */
200        u_char *ret_st;
201        int ret_sz;
202        extern char *malloc();
203
204        if ((retc = kadm_cli_conn()) != KADM_SUCCESS)
205            return(retc);
206        st_len = vals_to_stream(vals, &st);
207        st2 = (u_char *) malloc((unsigned)(1 + st_len));
208        *st2 = (u_char) ADD_ENT;       /* here's the opcode */
209        memcpy((char *) st2 + 1, (char *) st, st_len);  /* append st on */
210        retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz);
211        free((char *)st);
212        free((char *)st2);
213        if (retc == KADM_SUCCESS) {
214            /* ret_st has vals */
215            if (stream_to_vals(ret_st, vals, ret_sz) < 0)
216                retc = KADM_LENGTH_ERROR;
217            free((char *)ret_st);
218        }
219        kadm_cli_disconn();
220        return(retc);
221}
222
223/*
224 * kadm_delete
225 *      receives    : vals
226 *      returns     : vals
227 *
228 * Deletes an entry containing values from the database.
229 */
230kadm_delete(vals)
231Kadm_vals *vals;
232{
233        u_char *st, *st2;              /* st will hold the stream of values */
234        int st_len;                    /* st2 the final stream with opcode */
235        int retc;                      /* return code from call */
236        u_char *ret_st;
237        int ret_sz;
238        extern char *malloc();
239
240        if ((retc = kadm_cli_conn()) != KADM_SUCCESS)
241            return(retc);
242        st_len = vals_to_stream(vals, &st);
243        st2 = (u_char *) malloc((unsigned)(1 + st_len));
244        *st2 = (u_char) DEL_ENT;       /* here's the opcode */
245        memcpy((char *) st2 + 1, (char *) st, st_len);  /* append st on */
246        retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz);
247        free((char *)st);
248        free((char *)st2);
249        if (retc == KADM_SUCCESS) {
250            /* ret_st has vals */
251            if (stream_to_vals(ret_st, vals, ret_sz) < 0)
252                retc = KADM_LENGTH_ERROR;
253            free((char *)ret_st);
254        }
255        kadm_cli_disconn();
256        return(retc);
257}
258/*
259 * kadm_mod
260 *      receives    : KTEXT, {values, values}
261 *      returns     : CKSUM,  RETCODE, {values}
262 *      acl         : su, sms (as register or dealloc)
263 *
264 * Modifies all entries corresponding to the first values so they match the
265 * second values. returns the values for the changed entries in vals2
266 */
267int kadm_mod(vals1, vals2)
268Kadm_vals *vals1;
269Kadm_vals *vals2;
270{
271        u_char *st, *st2;              /* st will hold the stream of values */
272        int st_len, nlen;              /* st2 the final stream with opcode */
273        u_char *ret_st;
274        int ret_sz;
275        extern char *malloc();
276        extern char *realloc();
277
278        /* nlen is the length of second vals */
279        int retc;                      /* return code from call */
280
281        if ((retc = kadm_cli_conn()) != KADM_SUCCESS)
282            return(retc);
283
284        st_len = vals_to_stream(vals1, &st);
285        st2 = (u_char *) malloc((unsigned)(1 + st_len));
286        *st2 = (u_char) MOD_ENT;       /* here's the opcode */
287        memcpy((char *) st2 + 1, (char *) st, st_len++); /* append st on */
288        free((char *)st);
289        nlen = vals_to_stream(vals2, &st);
290        st2 = (u_char *) realloc((char *) st2, (unsigned)(st_len + nlen));
291        memcpy((char *) st2 + st_len, (char *) st, nlen); /* append st on */
292        retc = kadm_cli_send(st2, st_len + nlen, &ret_st, &ret_sz);
293        free((char *)st);
294        free((char *)st2);
295        if (retc == KADM_SUCCESS) {
296            /* ret_st has vals */
297            if (stream_to_vals(ret_st, vals2, ret_sz) < 0)
298                retc = KADM_LENGTH_ERROR;
299            free((char *)ret_st);
300        }
301        kadm_cli_disconn();
302        return(retc);
303}
304
305/*
306 * kadm_get
307 *      receives   : KTEXT, {values, flags}
308 *      returns    : CKSUM, RETCODE, {count, values, values, values}
309 *      acl        : su
310 *
311 * gets the fields requested by flags from all entries matching values returns
312 * this data for each matching recipient, after a count of how many such
313 * matches there were
314 */
315int kadm_get(vals, fl)
316Kadm_vals *vals;
317u_char fl[4];
318{
319        int loop;                      /* for copying the fields data */
320        u_char *st, *st2;              /* st will hold the stream of values */
321        int st_len;                    /* st2 the final stream with opcode */
322        int retc;                      /* return code from call */
323        u_char *ret_st;
324        int ret_sz;
325        extern char *malloc();
326
327        if ((retc = kadm_cli_conn()) != KADM_SUCCESS)
328            return(retc);
329        st_len = vals_to_stream(vals, &st);
330        st2 = (u_char *) malloc((unsigned)(1 + st_len + FLDSZ));
331        *st2 = (u_char) GET_ENT;       /* here's the opcode */
332        memcpy((char *) st2 + 1, (char *) st, st_len);  /* append st on */
333        for (loop = FLDSZ - 1; loop >= 0; loop--)
334                *(st2 + st_len + FLDSZ - loop) = fl[loop]; /* append the flags */
335        retc = kadm_cli_send(st2, st_len + 1 + FLDSZ,  &ret_st, &ret_sz);
336        free((char *)st);
337        free((char *)st2);
338        if (retc == KADM_SUCCESS) {
339            /* ret_st has vals */
340            if (stream_to_vals(ret_st, vals, ret_sz) < 0)
341                retc = KADM_LENGTH_ERROR;
342            free((char *)ret_st);
343        }
344        kadm_cli_disconn();
345        return(retc);
346}
347
348/*
349 * kadm_check_pw
350 * recieves    : key, pw_string, ret_string
351 *
352 * Sends the password to the server and asks it if the password is a
353 * "secure" password or not.  Returns the error KADM_INSECURE_PW and
354 * optionally returns a message if the password is not considered secure.
355 */
356int kadm_check_pw(newkey, pwstring, retstring)
357des_cblock newkey;                     /* The DES form of the users key */
358char    *pwstring;
359u_char  **retstring;
360{
361        int stsize, retc;              /* stream size and return code */
362        u_char *send_st;               /* send stream */
363        u_char *ret_st;
364        int ret_sz;
365        unsigned KRB_INT32 keytmp;
366        extern char *malloc();
367
368        if ((retc = kadm_cli_conn()) != KADM_SUCCESS)
369            return(retc);
370        /* possible problem with vts_long on a non-multiple of four boundary */
371
372        stsize = 0;                    /* start of our output packet */
373        send_st = (u_char *) malloc(1);/* to make it reallocable */
374        send_st[stsize++] = (u_char) CHECK_PW;
375
376        /* change key to stream */
377
378        memcpy((char *) &keytmp, (char *) (((KRB_INT32 *) newkey) + 1), sizeof(KRB_INT32));
379        keytmp = htonl(keytmp);
380        stsize += vts_long(keytmp, &send_st, stsize);
381
382        memcpy((char *) &keytmp, (char *) newkey, sizeof(KRB_INT32));
383        keytmp = htonl(keytmp);
384        stsize += vts_long(keytmp, &send_st, stsize);
385       
386        if (pwstring) {
387                stsize += vts_string(pwstring, &send_st, stsize);
388        }
389       
390        retc = kadm_cli_send(send_st, stsize, &ret_st, &ret_sz);
391        free((char *)send_st);
392        if (ret_sz)
393                *retstring = ret_st;
394        else {
395                *retstring = 0;
396                free(ret_st);
397        }
398        kadm_cli_disconn();
399        return(retc);
400}
401
402/*
403 * kadm_change_srvtab
404 * receives    : name, instance
405 * returns     : values
406 *
407 * Asks the admin server to change the srvtab key for the specified
408 * name, instance pair.  The name, instance pair must be a valid
409 * server principal.
410 */
411int kadm_change_srvtab(name, instance, values)
412        char    *name, *instance;
413        Kadm_vals       *values;
414{
415        u_char *st, *st2;              /* st will hold the stream of values */
416        int st_len;                    /* st2 the final stream with opcode */
417        int retc;                      /* return code from call */
418        u_char *ret_st;
419        int ret_sz;
420        Kadm_vals       vals;
421        extern char *malloc();
422
423        memset((char *) &vals, 0, sizeof(vals));
424        strncpy(vals.name, name, sizeof(vals.name));
425        strncpy(vals.instance, instance, sizeof(vals.instance));
426        SET_FIELD(KADM_NAME,vals.fields);
427        SET_FIELD(KADM_INST,vals.fields);
428
429        if ((retc = kadm_cli_conn()) != KADM_SUCCESS)
430            return(retc);
431        st_len = vals_to_stream(&vals, &st);
432        st2 = (u_char *) malloc((unsigned)(1 + st_len));
433        *st2 = (u_char) CHG_STAB;       /* here's the opcode */
434        memcpy((char *) st2 + 1, (char *) st, st_len);  /* append st on */
435        retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz);
436        free((char *)st);
437        free((char *)st2);
438        if (retc == KADM_SUCCESS) {
439            /* ret_st has vals */
440            if (stream_to_vals(ret_st, values, ret_sz) < 0)
441                retc = KADM_LENGTH_ERROR;
442            free((char *)ret_st);
443        }
444        kadm_cli_disconn();
445        return(retc);
446}
447
448/*
449 * kadm_cli_send
450 *      recieves   : opcode, packet, packet length, serv_name, serv_inst
451 *      returns    : return code from the packet build, the server, or
452 *                       something else
453 *
454 * It assembles a packet as follows:
455 *       8 bytes    : VERSION STRING
456 *       4 bytes    : LENGTH OF MESSAGE DATA and OPCODE
457 *                  : KTEXT
458 *                  : OPCODE       \
459 *                  : DATA          > Encrypted (with make priv)
460 *                  : ......       /
461 *
462 * If it builds the packet and it is small enough, then it attempts to open the
463 * connection to the admin server.  If the connection is succesfully open
464 * then it sends the data and waits for a reply.
465 */
466int kadm_cli_send(st_dat, st_siz, ret_dat, ret_siz)
467u_char *st_dat;                         /* the actual data */
468int st_siz;                             /* length of said data */
469u_char **ret_dat;                       /* to give return info */
470int *ret_siz;                           /* length of returned info */
471{
472        int act_len;                   /* current offset into packet, return */
473        KRB_INT32 retdat;              /* data */
474        KTEXT_ST authent;              /* the authenticator we will build */
475        u_char *act_st;                /* the pointer to the complete packet */
476        u_char *priv_pak;              /* private version of the packet */
477        int priv_len;                  /* length of private packet */
478        u_long cksum;                  /* checksum of the packet */
479        MSG_DAT mdat;
480        u_char *return_dat;
481        extern char *malloc();
482        extern char *realloc();
483
484        act_st = (u_char *) malloc(KADM_VERSIZE); /* verstr stored first */
485        (void) strncpy((char *)act_st, KADM_VERSTR, KADM_VERSIZE);
486        act_len = KADM_VERSIZE;
487
488        if ((retdat = kadm_cli_keyd(sess_key, sess_sched)) != KADM_SUCCESS) {
489                free((char *)act_st);
490                return retdat;         /* couldnt get key working */
491        }
492        priv_pak = (u_char *) malloc((unsigned)(st_siz + 200));
493        /* 200 bytes for extra info case */
494        if ((priv_len = krb_mk_priv(st_dat, priv_pak, (u_long)st_siz,
495                                    sess_sched, &sess_key, &client_parm.my_addr,
496                                    &client_parm.admin_addr)) < 0)
497                RET_N_FREE(KADM_NO_ENCRYPT);    /* whoops... we got a lose
498                                                 * here */
499        /* here is the length of priv data.  receiver calcs
500         size of authenticator by subtracting vno size, priv size, and
501         sizeof(u_long) (for the size indication) from total size */
502
503        act_len += vts_long((unsigned KRB_INT32) priv_len, &act_st, act_len);
504#ifdef NOENCRYPTION
505        cksum = 0;
506#else
507        cksum = quad_cksum(priv_pak, (unsigned KRB_INT32 *)0, (long)priv_len,
508                           0, &sess_key);
509#endif
510        if (retdat = krb_mk_req(&authent, client_parm.sname, client_parm.sinst,
511                                client_parm.krbrlm, (long)cksum)) {
512            /* authenticator? */
513            RET_N_FREE(retdat + krb_err_base);
514        }
515
516        act_st = (u_char *) realloc((char *) act_st,
517                                    (unsigned) (act_len + authent.length
518                                                + priv_len));
519        if (!act_st) {
520            clear_secrets();
521            free((char *)priv_pak);
522            return(KADM_NOMEM);
523        }
524        memcpy((char *)act_st + act_len, (char *)authent.dat, authent.length);
525        memcpy((char *)act_st + act_len + authent.length, (char *)priv_pak,
526               priv_len);
527        free((char *)priv_pak);
528        if ((retdat = kadm_cli_out(act_st,
529                                   act_len + authent.length + priv_len,
530                                   ret_dat, ret_siz)) != KADM_SUCCESS)
531            RET_N_FREE(retdat);
532        free((char *)act_st);
533#define RET_N_FREE2(r) {free((char *)*ret_dat); *ret_dat = 0; *ret_siz = 0; clear_secrets(); return(r);}
534
535        /* first see if it's a YOULOUSE */
536        if ((*ret_siz >= KADM_VERSIZE) &&
537            !strncmp(KADM_ULOSE, (char *)*ret_dat, KADM_VERSIZE))
538          {
539            unsigned KRB_INT32 errcode;
540            /* it's a youlose packet */
541            if (*ret_siz < KADM_VERSIZE + sizeof(unsigned KRB_INT32))
542                RET_N_FREE2(KADM_BAD_VER);
543            memcpy((char *)&errcode, (char *)(*ret_dat) + KADM_VERSIZE,
544                   sizeof(unsigned KRB_INT32));
545            retdat = (int) ntohl(errcode);
546            RET_N_FREE2(retdat);
547          }
548        /* need to decode the ret_dat */
549        if (retdat = krb_rd_priv(*ret_dat, (u_long)*ret_siz, sess_sched,
550                                 &sess_key, &client_parm.admin_addr,
551                                 &client_parm.my_addr, &mdat))
552            RET_N_FREE2(retdat+krb_err_base);
553        if (mdat.app_length < KADM_VERSIZE + 4)
554            /* too short! */
555            RET_N_FREE2(KADM_BAD_VER);
556        if (strncmp((char *)mdat.app_data, KADM_VERSTR, KADM_VERSIZE))
557            /* bad version */
558            RET_N_FREE2(KADM_BAD_VER);
559        memcpy((char *)&retdat, (char *)mdat.app_data+KADM_VERSIZE,
560               sizeof(unsigned KRB_INT32));
561        retdat = ntohl((u_long)retdat);
562        if ((mdat.app_length - KADM_VERSIZE - sizeof(unsigned KRB_INT32)) != 0) {
563          if (!(return_dat = (u_char *)
564                malloc((unsigned)(mdat.app_length - KADM_VERSIZE -
565                                  sizeof(unsigned KRB_INT32)))))
566            RET_N_FREE2(KADM_NOMEM);
567          memcpy((char *)return_dat,
568                 (char *) mdat.app_data + KADM_VERSIZE + sizeof(unsigned KRB_INT32),
569                 (int)mdat.app_length - KADM_VERSIZE - sizeof(unsigned KRB_INT32));
570        } else {
571          /* If it's zero length, still need to malloc a 1 byte string; */
572          /* malloc's of zero will return NULL on AIX & A/UX */
573          if (!(return_dat = (u_char *) malloc((unsigned) 1)))
574            RET_N_FREE2(KADM_NOMEM);
575          *return_dat = '\0';
576        }
577        free((char *)*ret_dat);
578        clear_secrets();
579        *ret_dat = return_dat;
580        *ret_siz = mdat.app_length - KADM_VERSIZE - sizeof(unsigned KRB_INT32);
581        return retdat;
582}
583
584/* takes in the sess_key and key_schedule and sets them appropriately */
585int kadm_cli_keyd(s_k, s_s)
586des_cblock s_k;                        /* session key */
587des_key_schedule s_s;                  /* session key schedule */
588{
589        CREDENTIALS cred;              /* to get key data */
590        int stat;
591
592        /* want .sname and .sinst here.... */
593        if (stat = krb_get_cred(client_parm.sname, client_parm.sinst,
594                                client_parm.krbrlm, &cred))
595                return stat + krb_err_base;
596        memcpy((char *) s_k, (char *) cred.session, sizeof(des_cblock));
597        memset((char *) cred.session, 0, sizeof(des_cblock));
598#ifdef NOENCRYPTION
599        memset(s_s, 0, sizeof(des_key_schedule));
600#else
601        if (stat = key_sched(s_k, s_s))
602                return stat + krb_err_base;
603#endif
604        return KADM_SUCCESS;
605}                                      /* This code "works" */
606
607/* Networking-specific routines have been moved out to kadm_net.c.  */
Note: See TracBrowser for help on using the repository browser.