2 Copyright (C) 1989 by the Massachusetts Institute of Technology
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.
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
23 * Kerberos administration server client-side routines
27 * kadm_cli_wrap.c the client side wrapping of the calls to the admin server
30 #include "kadm_locl.h"
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 $");
36 static Kadm_Client client_parm;
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;}
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;
48 memset(sess_key, 0, sizeof(sess_key));
49 memset(sess_sched, 0, sizeof(sess_sched));
52 static RETSIGTYPE (*opipe)();
55 kadm_cli_disconn(void)
57 close(client_parm.admin_fd);
58 signal(SIGPIPE, opipe);
63 * receives : name, inst, realm
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
71 kadm_init_link(char *n, char *i, char *r)
73 struct hostent *hop; /* host we will talk to */
74 char adm_hostname[MaxHostNameLen];
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;
83 /* set up the admin_addr - fetch name of admin host */
84 if (krb_get_admhst(adm_hostname, client_parm.krbrlm, 1) != KSUCCESS)
86 if ((hop = gethostbyname(adm_hostname)) == NULL)
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));
100 { /* this connects and sets my_addr */
101 client_parm.admin_fd =
102 socket(client_parm.admin_addr.sin_family, SOCK_STREAM, 0);
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 */
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 */
123 #if defined(SO_KEEPALIVE) && defined(HAVE_SETSOCKOPT)
127 if (setsockopt(client_parm.admin_fd, SOL_SOCKET, SO_KEEPALIVE,
130 close(client_parm.admin_fd);
131 client_parm.admin_fd = -1;
132 signal(SIGPIPE, opipe);
133 return KADM_NO_CONN; /* XXX */
140 /* takes in the sess_key and key_schedule and sets them appropriately */
142 kadm_cli_keyd(des_cblock (*s_k), /* session key */
143 des_key_schedule s_s) /* session key schedule */
145 CREDENTIALS cred; /* to get key data */
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));
155 memset(s_s, 0, sizeof(des_key_schedule));
157 if ((stat = des_key_sched(s_k,s_s)))
158 return stat+krb_err_base;
161 } /* This code "works" */
164 kadm_cli_out(u_char *dat, int dat_len, u_char **ret_dat, int *ret_siz)
172 dlen = (u_int16_t) dat_len;
174 if (dat_len != (int)dlen)
175 return (KADM_NO_ROOM);
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 */
182 if (krb_net_write(client_parm.admin_fd, dat, dat_len) < 0)
183 return (errno); /* XXX */
186 if ((retval = krb_net_read(client_parm.admin_fd, tmp, 2)) != 2){
188 return(errno); /* XXX */
190 return(EPIPE); /* short read ! */
192 dlen = (tmp[0] << 8) | tmp[1];
194 *ret_dat = malloc(dlen);
195 if (*ret_dat == NULL)
198 if ((retval = krb_net_read(client_parm.admin_fd, *ret_dat,
203 return(errno); /* XXX */
205 return(EPIPE); /* short read ! */
207 *ret_siz = (int) dlen;
213 * recieves : opcode, packet, packet length, serv_name, serv_inst
214 * returns : return code from the packet build, the server, or
217 * It assembles a packet as follows:
218 * 8 bytes : VERSION STRING
219 * 4 bytes : LENGTH OF MESSAGE DATA and OPCODE
222 * : DATA > Encrypted (with make priv)
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.
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 */
235 int act_len, retdat; /* current offset into packet, return
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 */
250 act_st = malloc(KADM_VERSIZE); /* verstr stored first */
251 if (act_st == NULL) {
255 memcpy(act_st, KADM_VERSTR, KADM_VERSIZE);
256 act_len = KADM_VERSIZE;
258 if ((retdat = kadm_cli_keyd(&sess_key, sess_sched)) != KADM_SUCCESS) {
261 return retdat; /* couldnt get key working */
263 priv_pak = malloc(st_siz + 200);
264 /* 200 bytes for extra info case */
265 if (priv_pak == NULL) {
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);
275 RET_N_FREE(KADM_NO_ENCRYPT); /* whoops... we got a lose
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 */
281 tmp = vts_long(priv_len, &act_st, act_len);
283 RET_N_FREE(KADM_NOMEM);
288 cksum = des_quad_cksum((des_cblock *)priv_pak,
289 (des_cblock *)0, priv_len, 0,
293 retdat = krb_mk_req(&authent, client_parm.sname, client_parm.sinst,
294 client_parm.krbrlm, cksum);
298 RET_N_FREE(retdat + krb_err_base);
301 tmp_ptr = realloc(act_st,
302 act_len + authent.length + priv_len);
303 if (tmp_ptr == NULL) {
310 memcpy(act_st + act_len, authent.dat, authent.length);
311 memcpy(act_st + act_len + authent.length, priv_pak, priv_len);
313 retdat = kadm_cli_out(act_st,
314 act_len + authent.length + priv_len,
317 if (retdat != KADM_SUCCESS) {
321 #define RET_N_FREE2(r) {free(*ret_dat); *ret_dat = NULL; clear_secrets(); return(r);}
323 /* first see if it's a YOULOUSE */
324 if ((*ret_siz >= KADM_VERSIZE) &&
325 !strncmp(KADM_ULOSE, (char *)*ret_dat, KADM_VERSIZE)) {
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];
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);
339 RET_N_FREE2(retdat+krb_err_base);
340 if (mdat.app_length < KADM_VERSIZE + 4)
342 RET_N_FREE2(KADM_BAD_VER);
343 if (strncmp((char *)mdat.app_data, KADM_VERSTR, KADM_VERSIZE))
345 RET_N_FREE2(KADM_BAD_VER);
347 unsigned char *p = mdat.app_data+KADM_VERSIZE;
348 retdat = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
351 int s = mdat.app_length - KADM_VERSIZE - 4;
355 return_dat = malloc(s);
356 if (return_dat == NULL)
357 RET_N_FREE2(KADM_NOMEM);
360 (char *) mdat.app_data + KADM_VERSIZE + 4,
361 mdat.app_length - KADM_VERSIZE - 4);
364 *ret_dat = return_dat;
365 *ret_siz = mdat.app_length - KADM_VERSIZE - 4;
372 * kadm_change_pw_plain
377 int kadm_change_pw_plain(unsigned char *newkey, char *password, char **pw_msg)
379 int stsize, retc; /* stream size and return code */
380 u_char *send_st; /* send stream */
384 static char msg[128];
386 /* possible problem with vts_long on a non-multiple of four boundary */
388 stsize = 0; /* start of our output packet */
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);
397 /* change key to stream */
399 if(password && *password) {
400 int tmp = vts_string(password, &send_st, stsize);
409 if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
413 retc = kadm_cli_send(send_st, stsize, &ret_st, &ret_sz);
416 if(retc != KADM_SUCCESS){
417 status = stv_string(ret_st, msg, 0, sizeof(msg), ret_sz);
429 * This function is here for compatibility with CNS
432 int kadm_change_pw2(unsigned char *newkey, char *password, char **pw_msg)
434 return kadm_change_pw_plain (newkey, password, pw_msg);
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
447 int kadm_change_pw(unsigned char *newkey)
450 return kadm_change_pw_plain(newkey, "", &pw_msg);
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
463 kadm_add(Kadm_vals *vals)
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 */
471 st_len = vals_to_stream(vals, &st);
472 st2 = malloc(1 + st_len);
477 *st2 = (u_char) ADD_ENT; /* here's the opcode */
478 memcpy((char *) st2 + 1, st, st_len); /* append st on */
481 if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
485 retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz);
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;
499 * receives : KTEXT, {values, values}
500 * returns : CKSUM, RETCODE, {values}
501 * acl : su, sms (as register or dealloc)
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
507 kadm_mod(Kadm_vals *vals1, Kadm_vals *vals2)
509 u_char *st, *st2; /* st will hold the stream of values */
510 int st_len, nlen; /* st2 the final stream with opcode */
515 /* nlen is the length of second vals */
516 int retc; /* return code from call */
518 st_len = vals_to_stream(vals1, &st);
519 st2 = malloc(1 + st_len);
524 *st2 = (u_char) MOD_ENT; /* here's the opcode */
525 memcpy((char *)st2 + 1, st, st_len++); /* append st on */
527 nlen = vals_to_stream(vals2, &st);
528 tmp_ptr = realloc(st2, st_len + nlen);
529 if (tmp_ptr == NULL) {
535 memcpy((char *) st2 + st_len, st, nlen); /* append st on */
538 if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
543 retc = kadm_cli_send(st2, st_len + nlen, &ret_st, &ret_sz);
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;
557 kadm_del(Kadm_vals *vals)
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 */
565 st_len = vals_to_stream(vals, &st);
566 st2 = malloc(st_len + 1);
571 *st2 = DEL_ENT; /* here's the opcode */
572 memcpy(st2 + 1, st, st_len); /* append st on */
575 if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
579 retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz);
589 * receives : KTEXT, {values, flags}
590 * returns : CKSUM, RETCODE, {count, values, values, values}
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
598 kadm_get(Kadm_vals *vals, u_char *fl)
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 */
607 st_len = vals_to_stream(vals, &st);
608 st2 = malloc(1 + st_len + FLDSZ);
613 *st2 = (u_char) GET_ENT; /* here's the opcode */
614 memcpy((char *)st2 + 1, st, st_len); /* append st on */
616 for (loop = FLDSZ - 1; loop >= 0; loop--)
617 *(st2 + st_len + FLDSZ - loop) = fl[loop]; /* append the flags */
619 if ((retc = kadm_cli_conn()) != KADM_SUCCESS) {
623 retc = kadm_cli_send(st2, st_len + 1 + FLDSZ, &ret_st, &ret_sz);
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;