Change __signed to signed.
[dragonfly.git] / crypto / kerberosIV / lib / kadm / kadm_cli_wrap.c
1 /* 
2   Copyright (C) 1989 by the Massachusetts Institute of Technology
3
4    Export of this software from the United States of America is assumed
5    to require a specific license from the United States Government.
6    It is the responsibility of any person or organization contemplating
7    export to obtain such a license before exporting.
8
9 WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10 distribute this software and its documentation for any purpose and
11 without fee is hereby granted, provided that the above copyright
12 notice appear in all copies and that both that copyright notice and
13 this permission notice appear in supporting documentation, and that
14 the name of M.I.T. not be used in advertising or publicity pertaining
15 to distribution of the software without specific, written prior
16 permission.  M.I.T. makes no representations about the suitability of
17 this software for any purpose.  It is provided "as is" without express
18 or implied warranty.
19
20   */
21
22 /*
23  * Kerberos administration server client-side routines
24  */
25
26 /*
27  * kadm_cli_wrap.c the client side wrapping of the calls to the admin server 
28  */
29
30 #include "kadm_locl.h"
31
32 /* RCSID("$Id: kadm_cli_wrap.c,v 1.27 1999/09/16 20:41:46 assar Exp $");*/
33 RCSID("$FreeBSD: src/crypto/kerberosIV/lib/kadm/kadm_cli_wrap.c,v 1.1.1.3.2.2 2003/02/13 21:34:35 nectar Exp $");
34 RCSID("$DragonFly: src/crypto/kerberosIV/lib/kadm/Attic/kadm_cli_wrap.c,v 1.2 2003/06/17 04:24:36 dillon Exp $");
35
36 static Kadm_Client client_parm;
37
38 /* Macros for use in returning data... used in kadm_cli_send */
39 #define RET_N_FREE(r) {clear_secrets(); free(act_st); free(priv_pak); return r;}
40
41 /* Keys for use in the transactions */
42 static des_cblock sess_key;            /* to be filled in by kadm_cli_keyd */
43 static des_key_schedule sess_sched;
44
45 static void
46 clear_secrets(void)
47 {
48         memset(sess_key, 0, sizeof(sess_key));
49         memset(sess_sched, 0, sizeof(sess_sched));
50 }
51
52 static RETSIGTYPE (*opipe)();
53
54 static void
55 kadm_cli_disconn(void)
56 {
57     close(client_parm.admin_fd);
58     signal(SIGPIPE, opipe);
59 }
60
61 /*
62  * kadm_init_link
63  *      receives    : name, inst, realm
64  *
65  * initializes client parm, the Kadm_Client structure which holds the 
66  * data about the connection between the server and client, the services 
67  * used, the locations and other fun things 
68  */
69
70 int
71 kadm_init_link(char *n, char *i, char *r)
72 {
73         struct hostent *hop;           /* host we will talk to */
74         char adm_hostname[MaxHostNameLen];
75
76         init_kadm_err_tbl();
77         init_krb_err_tbl();
78         strlcpy(client_parm.sname, n, ANAME_SZ);
79         strlcpy(client_parm.sinst, i, INST_SZ);
80         strlcpy(client_parm.krbrlm, r, REALM_SZ);
81         client_parm.admin_fd = -1;
82
83         /* set up the admin_addr - fetch name of admin host */
84         if (krb_get_admhst(adm_hostname, client_parm.krbrlm, 1) != KSUCCESS)
85                 return KADM_NO_HOST;
86         if ((hop = gethostbyname(adm_hostname)) == NULL)
87                 return KADM_UNK_HOST;
88         memset(&client_parm.admin_addr, 0, sizeof(client_parm.admin_addr));
89         client_parm.admin_addr.sin_port = 
90           k_getportbyname(KADM_SNAME, "tcp", htons(KADM_PORT));
91         client_parm.admin_addr.sin_family = hop->h_addrtype;
92         memcpy(&client_parm.admin_addr.sin_addr, hop->h_addr,
93                sizeof(client_parm.admin_addr.sin_addr));
94
95         return KADM_SUCCESS;
96 }
97
98 static int
99 kadm_cli_conn(void)
100 {                                       /* this connects and sets my_addr */
101     client_parm.admin_fd =
102         socket(client_parm.admin_addr.sin_family, SOCK_STREAM, 0);
103
104     if (client_parm.admin_fd < 0)
105         return KADM_NO_SOCK;            /* couldn't create the socket */
106     if (connect(client_parm.admin_fd,
107                 (struct sockaddr *) & client_parm.admin_addr,
108                 sizeof(client_parm.admin_addr))) {
109         close(client_parm.admin_fd);
110         client_parm.admin_fd = -1;
111         return KADM_NO_CONN;            /* couldn't get the connect */
112     }
113     opipe = signal(SIGPIPE, SIG_IGN);
114     client_parm.my_addr_len = sizeof(client_parm.my_addr);
115     if (getsockname(client_parm.admin_fd,
116                     (struct sockaddr *) & client_parm.my_addr,
117                     &client_parm.my_addr_len) < 0) {
118         close(client_parm.admin_fd);
119         client_parm.admin_fd = -1;
120         signal(SIGPIPE, opipe);
121         return KADM_NO_HERE;            /* couldn't find out who we are */
122     }
123 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
124     {
125         int on = 1;
126
127         if (setsockopt(client_parm.admin_fd, SOL_SOCKET, SO_KEEPALIVE,
128                        (void *)&on,
129                        sizeof(on)) < 0) {
130             close(client_parm.admin_fd);
131             client_parm.admin_fd = -1;
132             signal(SIGPIPE, opipe);
133             return KADM_NO_CONN;                /* XXX */
134         }
135     }
136 #endif
137     return KADM_SUCCESS;
138 }
139
140 /* takes in the sess_key and key_schedule and sets them appropriately */
141 static int
142 kadm_cli_keyd(des_cblock (*s_k), /* session key */
143               des_key_schedule s_s) /* session key schedule */
144 {
145         CREDENTIALS cred;              /* to get key data */
146         int stat;
147
148         /* want .sname and .sinst here.... */
149         if ((stat = krb_get_cred(client_parm.sname, client_parm.sinst,
150                                  client_parm.krbrlm, &cred)))
151                 return stat + krb_err_base;
152         memcpy(s_k, cred.session, sizeof(des_cblock));
153         memset(cred.session, 0, sizeof(des_cblock));
154 #ifdef NOENCRYPTION
155         memset(s_s, 0, sizeof(des_key_schedule));
156 #else
157         if ((stat = des_key_sched(s_k,s_s)))
158                 return stat+krb_err_base;
159 #endif
160         return KADM_SUCCESS;
161 }                                      /* This code "works" */
162
163 static int
164 kadm_cli_out(u_char *dat, int dat_len, u_char **ret_dat, int *ret_siz)
165 {
166         u_int16_t dlen;
167         int retval;
168         char tmp[4];
169
170         *ret_dat = NULL;
171         *ret_siz = 0;
172         dlen = (u_int16_t) dat_len;
173
174         if (dat_len != (int)dlen)
175                 return (KADM_NO_ROOM);
176
177         tmp[0] = (dlen >> 8) & 0xff;
178         tmp[1] = dlen & 0xff;
179         if (krb_net_write(client_parm.admin_fd, tmp, 2) != 2)
180             return (errno);            /* XXX */
181
182         if (krb_net_write(client_parm.admin_fd, dat, dat_len) < 0)
183                 return (errno);        /* XXX */
184
185         
186         if ((retval = krb_net_read(client_parm.admin_fd, tmp, 2)) != 2){
187             if (retval < 0)
188                 return(errno);          /* XXX */
189             else
190                 return(EPIPE);          /* short read ! */
191         }
192         dlen = (tmp[0] << 8) | tmp[1];
193
194         *ret_dat = malloc(dlen);
195         if (*ret_dat == NULL)
196             return(KADM_NOMEM);
197
198         if ((retval = krb_net_read(client_parm.admin_fd,  *ret_dat,
199                                    dlen) != dlen)) {
200             free(*ret_dat);
201             *ret_dat = NULL;
202             if (retval < 0)
203                 return(errno);          /* XXX */
204             else
205                 return(EPIPE);          /* short read ! */
206         }
207         *ret_siz = (int) dlen;
208         return KADM_SUCCESS;
209 }
210
211 /*
212  * kadm_cli_send
213  *      recieves   : opcode, packet, packet length, serv_name, serv_inst
214  *      returns    : return code from the packet build, the server, or
215  *                       something else 
216  *
217  * It assembles a packet as follows:
218  *       8 bytes    : VERSION STRING
219  *       4 bytes    : LENGTH OF MESSAGE DATA and OPCODE
220  *                  : KTEXT
221  *                  : OPCODE       \
222  *                  : DATA          > Encrypted (with make priv)
223  *                  : ......       / 
224  *
225  * If it builds the packet and it is small enough, then it attempts to open the
226  * connection to the admin server.  If the connection is succesfully open
227  * then it sends the data and waits for a reply. 
228  */
229 static int
230 kadm_cli_send(u_char *st_dat,   /* the actual data */
231               int st_siz,       /* length of said data */
232               u_char **ret_dat, /* to give return info */
233               int *ret_siz)     /* length of returned info */
234 {
235         int act_len, retdat;    /* current offset into packet, return
236                                  * data */
237         KTEXT_ST authent;       /* the authenticator we will build */
238         u_char *act_st;         /* the pointer to the complete packet */
239         u_char *priv_pak;       /* private version of the packet */
240         int priv_len;           /* length of private packet */
241         u_int32_t cksum;        /* checksum of the packet */
242         MSG_DAT mdat;
243         u_char *return_dat;
244         int tmp;
245         void *tmp_ptr;
246
247         *ret_dat = NULL;
248         *ret_siz = 0;
249
250         act_st = malloc(KADM_VERSIZE); /* verstr stored first */
251         if (act_st == NULL) {
252             clear_secrets ();
253             return KADM_NOMEM;
254         }
255         memcpy(act_st, KADM_VERSTR, KADM_VERSIZE);
256         act_len = KADM_VERSIZE;
257
258         if ((retdat = kadm_cli_keyd(&sess_key, sess_sched)) != KADM_SUCCESS) {
259                 free(act_st);
260                 clear_secrets();
261                 return retdat;         /* couldnt get key working */
262         }
263         priv_pak = malloc(st_siz + 200);
264         /* 200 bytes for extra info case */
265         if (priv_pak == NULL) {
266             free(act_st);
267             clear_secrets ();
268             return KADM_NOMEM;
269         }
270         priv_len = krb_mk_priv(st_dat, priv_pak, st_siz,
271                                sess_sched, &sess_key, &client_parm.my_addr,
272                                &client_parm.admin_addr);
273
274         if (priv_len < 0)
275                 RET_N_FREE(KADM_NO_ENCRYPT);    /* whoops... we got a lose
276                                                  * here */
277         /* here is the length of priv data.  receiver calcs
278          size of authenticator by subtracting vno size, priv size, and
279          sizeof(u_int32_t) (for the size indication) from total size */
280
281         tmp = vts_long(priv_len, &act_st, act_len);
282         if (tmp < 0)
283             RET_N_FREE(KADM_NOMEM);
284         act_len += tmp;
285 #ifdef NOENCRYPTION
286         cksum = 0;
287 #else
288         cksum = des_quad_cksum((des_cblock *)priv_pak,
289                                (des_cblock *)0, priv_len, 0,
290                                &sess_key);
291 #endif
292         
293         retdat = krb_mk_req(&authent, client_parm.sname, client_parm.sinst,
294                             client_parm.krbrlm, cksum);
295
296         if (retdat) {
297             /* authenticator? */
298             RET_N_FREE(retdat + krb_err_base);
299         }
300
301         tmp_ptr = realloc(act_st,
302                           act_len + authent.length + priv_len);
303         if (tmp_ptr == NULL) {
304             clear_secrets();
305             free (priv_pak);
306             free (act_st);
307             return KADM_NOMEM;
308         }
309         act_st = tmp_ptr;
310         memcpy(act_st + act_len, authent.dat, authent.length);
311         memcpy(act_st + act_len + authent.length, priv_pak, priv_len);
312         free(priv_pak);
313         retdat = kadm_cli_out(act_st,
314                               act_len + authent.length + priv_len,
315                               ret_dat, ret_siz);
316         free(act_st);
317         if (retdat != KADM_SUCCESS) {
318             clear_secrets();
319             return retdat;
320         }
321 #define RET_N_FREE2(r) {free(*ret_dat); *ret_dat = NULL; clear_secrets(); return(r);}
322
323         /* first see if it's a YOULOUSE */
324         if ((*ret_siz >= KADM_VERSIZE) &&
325             !strncmp(KADM_ULOSE, (char *)*ret_dat, KADM_VERSIZE)) {
326             unsigned char *p;
327             /* it's a youlose packet */
328             if (*ret_siz < KADM_VERSIZE + 4)
329                 RET_N_FREE2(KADM_BAD_VER);
330             p = (*ret_dat)+KADM_VERSIZE;
331             retdat = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
332             RET_N_FREE2(retdat);
333         }
334         /* need to decode the ret_dat */
335         retdat = krb_rd_priv(*ret_dat, (u_int32_t)*ret_siz, sess_sched,
336                              &sess_key, &client_parm.admin_addr,
337                              &client_parm.my_addr, &mdat);
338         if (retdat)
339             RET_N_FREE2(retdat+krb_err_base);
340         if (mdat.app_length < KADM_VERSIZE + 4)
341             /* too short! */
342             RET_N_FREE2(KADM_BAD_VER);
343         if (strncmp((char *)mdat.app_data, KADM_VERSTR, KADM_VERSIZE))
344             /* bad version */
345             RET_N_FREE2(KADM_BAD_VER);
346         {
347             unsigned char *p = mdat.app_data+KADM_VERSIZE;
348             retdat = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
349         }
350         {
351           int s = mdat.app_length - KADM_VERSIZE - 4;
352
353           if(s <= 0)
354               s=1;
355           return_dat = malloc(s);
356           if (return_dat == NULL)
357               RET_N_FREE2(KADM_NOMEM);
358         }
359         memcpy(return_dat,
360                (char *) mdat.app_data + KADM_VERSIZE + 4,
361                mdat.app_length - KADM_VERSIZE - 4);
362         free(*ret_dat);
363         clear_secrets();
364         *ret_dat = return_dat;
365         *ret_siz = mdat.app_length - KADM_VERSIZE - 4;
366         return retdat;
367 }
368
369
370
371 /* 
372  * kadm_change_pw_plain
373  *
374  * see kadm_change_pw
375  *
376  */
377 int kadm_change_pw_plain(unsigned char *newkey, char *password, char **pw_msg)
378 {
379         int stsize, retc;              /* stream size and return code */
380         u_char *send_st;               /* send stream */
381         u_char *ret_st;
382         int ret_sz;
383         int status;
384         static char msg[128];
385
386         /* possible problem with vts_long on a non-multiple of four boundary */
387
388         stsize = 0;                    /* start of our output packet */
389         send_st = malloc(9);
390         if (send_st == NULL)
391             return KADM_NOMEM;
392         send_st[stsize++] = (u_char) CHANGE_PW;
393         memcpy(send_st + stsize + 4, newkey, 4); /* yes, this is backwards */
394         memcpy(send_st + stsize, newkey + 4, 4);
395         stsize += 8;
396
397         /* change key to stream */
398
399         if(password && *password) {
400             int tmp = vts_string(password, &send_st, stsize);
401
402             if (tmp < 0) {
403                 free(send_st);
404                 return KADM_NOMEM;
405             }
406             stsize += tmp;
407         }
408
409         if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
410             free(send_st);
411             return(retc);
412         }
413         retc = kadm_cli_send(send_st, stsize, &ret_st, &ret_sz);
414         free(send_st);
415         
416         if(retc != KADM_SUCCESS){
417           status = stv_string(ret_st, msg, 0, sizeof(msg), ret_sz);
418           if(status<0)
419             msg[0]=0;
420           *pw_msg=msg;
421         }
422         free(ret_st);
423         
424         kadm_cli_disconn();
425         return(retc);
426 }
427
428 /*
429  * This function is here for compatibility with CNS
430  */
431
432 int kadm_change_pw2(unsigned char *newkey, char *password, char **pw_msg)
433 {
434     return kadm_change_pw_plain (newkey, password, pw_msg);
435 }
436
437
438 /*
439  * kadm_change_pw
440  * recieves    : key 
441  *
442  * Replaces the password (i.e. des key) of the caller with that specified in
443  * key. Returns no actual data from the master server, since this is called
444  * by a user 
445  */
446
447 int kadm_change_pw(unsigned char *newkey)
448 {
449   char *pw_msg;
450   return kadm_change_pw_plain(newkey, "", &pw_msg);
451 }
452
453 /*
454  * kadm_add
455  *      receives    : vals
456  *      returns     : vals 
457  *
458  * Adds and entry containing values to the database returns the values of the
459  * entry, so if you leave certain fields blank you will be able to determine
460  * the default values they are set to 
461  */
462 int
463 kadm_add(Kadm_vals *vals)
464 {
465         u_char *st, *st2;              /* st will hold the stream of values */
466         int st_len;                    /* st2 the final stream with opcode */
467         int retc;                      /* return code from call */
468         u_char *ret_st;
469         int ret_sz;
470
471         st_len = vals_to_stream(vals, &st);
472         st2 = malloc(1 + st_len);
473         if (st2 == NULL) {
474             free(st);
475             return KADM_NOMEM;
476         }
477         *st2 = (u_char) ADD_ENT;       /* here's the opcode */
478         memcpy((char *) st2 + 1, st, st_len);   /* append st on */
479         free(st);
480
481         if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
482             free(st2);
483             return(retc);
484         }
485         retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz);
486         free(st2);
487         if (retc == KADM_SUCCESS) {
488             /* ret_st has vals */
489             if (stream_to_vals(ret_st, vals, ret_sz) < 0)
490                 retc = KADM_LENGTH_ERROR;
491         }
492         free(ret_st);
493         kadm_cli_disconn();
494         return(retc);
495 }
496
497 /*
498  * kadm_mod
499  *      receives    : KTEXT, {values, values}
500  *      returns     : CKSUM,  RETCODE, {values} 
501  *      acl         : su, sms (as register or dealloc) 
502  *
503  * Modifies all entries corresponding to the first values so they match the
504  * second values. returns the values for the changed entries in vals2
505  */
506 int
507 kadm_mod(Kadm_vals *vals1, Kadm_vals *vals2)
508 {
509         u_char *st, *st2;              /* st will hold the stream of values */
510         int st_len, nlen;              /* st2 the final stream with opcode */
511         u_char *ret_st;
512         int ret_sz;
513         void *tmp_ptr;
514
515         /* nlen is the length of second vals */
516         int retc;                      /* return code from call */
517
518         st_len = vals_to_stream(vals1, &st);
519         st2 = malloc(1 + st_len);
520         if (st2 == NULL) {
521             free(st);
522             return KADM_NOMEM;
523         }
524         *st2 = (u_char) MOD_ENT;       /* here's the opcode */
525         memcpy((char *)st2 + 1, st, st_len++); /* append st on */
526         free(st);
527         nlen = vals_to_stream(vals2, &st);
528         tmp_ptr = realloc(st2, st_len + nlen);
529         if (tmp_ptr == NULL) {
530             free(st);
531             free(st2);
532             return KADM_NOMEM;
533         }
534         st2 = tmp_ptr;
535         memcpy((char *) st2 + st_len, st, nlen); /* append st on */
536         free(st);
537
538         if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
539             free(st2);
540             return(retc);
541         }
542
543         retc = kadm_cli_send(st2, st_len + nlen, &ret_st, &ret_sz);
544         free(st2);
545         if (retc == KADM_SUCCESS) {
546             /* ret_st has vals */
547             if (stream_to_vals(ret_st, vals2, ret_sz) < 0)
548                 retc = KADM_LENGTH_ERROR;
549         }
550         free(ret_st);
551         kadm_cli_disconn();
552         return(retc);
553 }
554
555
556 int
557 kadm_del(Kadm_vals *vals)
558 {
559     unsigned char *st, *st2;           /* st will hold the stream of values */
560     int st_len;                /* st2 the final stream with opcode */
561     int retc;                  /* return code from call */
562     u_char *ret_st;
563     int ret_sz;
564     
565     st_len = vals_to_stream(vals, &st);
566     st2 = malloc(st_len + 1);
567     if (st2 == NULL) {
568         free(st);
569         return KADM_NOMEM;
570     }
571     *st2 = DEL_ENT;       /* here's the opcode */
572     memcpy(st2 + 1, st, st_len);        /* append st on */
573     free (st);
574
575     if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
576         free(st2);
577         return(retc);
578     }
579     retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz);
580     free(st2);
581     free(ret_st);
582     kadm_cli_disconn();
583     return(retc);
584 }
585
586
587 /*
588  * kadm_get
589  *      receives   : KTEXT, {values, flags} 
590  *      returns    : CKSUM, RETCODE, {count, values, values, values}
591  *      acl        : su 
592  *
593  * gets the fields requested by flags from all entries matching values returns
594  * this data for each matching recipient, after a count of how many such
595  * matches there were 
596  */
597 int
598 kadm_get(Kadm_vals *vals, u_char *fl)
599 {
600         int loop;                      /* for copying the fields data */
601         u_char *st, *st2;              /* st will hold the stream of values */
602         int st_len;                    /* st2 the final stream with opcode */
603         int retc;                      /* return code from call */
604         u_char *ret_st;
605         int ret_sz;
606
607         st_len = vals_to_stream(vals, &st);
608         st2 = malloc(1 + st_len + FLDSZ);
609         if (st2 == NULL) {
610             free(st);
611             return KADM_NOMEM;
612         }
613         *st2 = (u_char) GET_ENT;       /* here's the opcode */
614         memcpy((char *)st2 + 1, st, st_len); /* append st on */
615         free(st);
616         for (loop = FLDSZ - 1; loop >= 0; loop--)
617                 *(st2 + st_len + FLDSZ - loop) = fl[loop]; /* append the flags */
618
619         if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
620             free(st2);
621             return(retc);
622         }
623         retc = kadm_cli_send(st2, st_len + 1 + FLDSZ,  &ret_st, &ret_sz);
624         free(st2);
625         if (retc == KADM_SUCCESS) {
626             /* ret_st has vals */
627             if (stream_to_vals(ret_st, vals, ret_sz) < 0)
628                 retc = KADM_LENGTH_ERROR;
629         }
630         free(ret_st);
631         kadm_cli_disconn();
632         return(retc);
633 }