]> andersk Git - moira.git/blame - reg_svr/admin_call.c
Changed names of kerberos calls to new names from old ones.
[moira.git] / reg_svr / admin_call.c
CommitLineData
718bc25c 1/*
2 * $Source$
3 * $Author$
4 * $Header$
5 *
6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 *
8 * Utility functions for communication with the Kerberos admin_server
9 *
10 * Original version written by Jeffery I. Schiller, January 1987
11 * Completely gutted and rewritten by Bill Sommerfeld, August 1987
12 *
13 * $Log$
e5fdb505 14 * Revision 1.5 1988-08-01 00:42:54 qjb
15 * Changed names of kerberos calls to new names from old ones.
718bc25c 16 *
e5fdb505 17 * Revision 1.4 87/09/09 14:59:06 wesommer
18 * Allocate a new socket each time rather than keeping one around,
19 * due to protocol problems.
20 *
3004ebdb 21 * Revision 1.3 87/09/04 22:30:34 wesommer
22 * Un-crock the KDC host (oops -- this one got distributed!!).
23 *
56d50401 24 * Revision 1.2 87/08/22 17:13:59 wesommer
25 * Make admin_errmsg external rather than static.
26 * Crock up KDC host.
27 *
074685e3 28 * Revision 1.1 87/08/07 13:50:37 wesommer
29 * Initial revision
30 *
718bc25c 31 */
32
33#ifndef lint
34static char *rcsid_admin_call_c = "$Header$";
35#endif lint
36
37#include <sys/errno.h>
38#include <sys/types.h>
39#include <sys/time.h>
40#include <sys/ioctl.h>
41#include <sys/socket.h>
42#include <netinet/in.h>
43
44#include <netdb.h>
45#include <strings.h>
46#include <stdio.h>
47
48#include "admin_err.h"
49#include "admin_server.h"
50#include "prot.h"
51#include "krb.h"
52
53extern int krb_err_base; /* Offset between com_err and kerberos codes */
54extern int errno; /* System call error numbers */
55
56extern long gethostid();
57
58static u_char *strapp(); /* string append function */
59
60static int inited = 0; /* are we initialized? */
61static int admin_fd = -1; /* socket to talk to admin_server. */
62
63static struct sockaddr_in admin_addr; /* address of admin server. */
64static struct sockaddr_in my_addr; /* address bound to admin_fd. */
65static int my_addr_len; /* size of above address. */
66
67static char krbrlm[REALM_SZ]; /* Local kerberos realm */
074685e3 68char admin_errmsg[BUFSIZ]; /* Server error message */
718bc25c 69
70/*
71 * Initialize socket, etc. to use to talk to admin_server.
72 */
73
74int admin_call_init()
75{
76 register int status = 0;
77
78 if (!inited) {
79 struct hostent *hp; /* host to talk to */
80 struct servent *sp; /* service to talk to */
3004ebdb 81
718bc25c 82 init_kadm_err_tbl();
83 if (status = get_krbrlm(krbrlm, 1)) {
84 status += krb_err_base;
85 goto punt;
86 }
87
88 /*
89 * Locate server.
90 */
91
92 hp = gethostbyname(KERB_HOST);
93 if (!hp) {
94 status = ADMIN_UNKNOWN_HOST;
95 goto punt;
96 }
97 sp = getservbyname("atest3", "udp");
98 if (!sp) {
99 status = ADMIN_UNKNOWN_SERVICE;
100 goto punt;
101 }
102 bzero((char *)&admin_addr, sizeof(admin_addr));
103 admin_addr.sin_family = hp->h_addrtype;
104 bcopy((char *)hp->h_addr, (char *)&admin_addr.sin_addr, hp->h_length);
105 admin_addr.sin_port = sp->s_port;
106
718bc25c 107 inited = 1;
108 }
109 return 0;
110
111punt:
112 (void) close(admin_fd);
113 admin_fd = -1;
114 return status;
115}
116
117/*
118 * Build and transmit request to admin_server, and wait for
119 * response from server. Returns a standard error code.
120 */
121
122int
123admin_call(opcode, pname, old_passwd, new_passwd, crypt_passwd)
124 int opcode;
125 char *pname;
126 char *old_passwd;
127 char *new_passwd;
128 char *crypt_passwd;
129{
130 int status;
131 register u_char *bp; /* Pointer into buffer. */
132 u_char *ep; /* End of buffer pointer. */
133
134 u_char pvt_buf[BUFSIZ]; /* private message plaintext */
135 int pvt_len; /* length of valid data in pvt_buf */
136
137 u_char sealed_buf[BUFSIZ]; /* sealed version of private message */
138 int sealed_len; /* length of valid data in sealed_buf */
139
140 u_long checksum; /* quad_cksum of sealed request. */
141
142 C_Block sess_key; /* Session key. */
143 Key_schedule sess_sched; /* Key schedule for above. */
144
145 CREDENTIALS cred; /* Kerberos credentials. */
146 KTEXT_ST authent; /* Authenticator */
147 KTEXT_ST reply; /* Reply from admin_server */
148 MSG_DAT msg_data; /* Decrypted message */
149 int attempts; /* Number of retransmits so far */
150
151 struct sockaddr rec_addr; /* Address we got reply from */
152 int rec_addr_len; /* Length of that address */
3004ebdb 153 int on = 1; /* ioctl argument */
154
718bc25c 155
156 if (!inited) {
157 status = admin_call_init();
158 if (status) goto bad;
159 }
160
161 /*
162 * assemble packet:
163 *
164 * sealed message consists of:
165 * version number (one byte).
166 * request code (one byte).
167 * principal name (null terminated).
168 * new password (in the clear, null terminated).
169 * old password or instance (null terminated)
170 * crypt(new password, seed) (null terminated).
171 * an extra null.
172 * a '\001' character.
173 * This is all sealed inside a private_message, with an
174 * authenticator tacked on in front.
175 */
176
177 bp = pvt_buf;
178 ep = pvt_buf + sizeof(pvt_buf);
179
180 *bp++ = PW_SRV_VERSION;
181 *bp++ = opcode;
182 if ((bp = strapp(bp, (u_char *)pname, ep)) &&
183 (bp = strapp(bp, (u_char *)new_passwd, ep)) &&
184 (bp = strapp(bp, (u_char *)old_passwd, ep)) &&
185 (bp = strapp(bp, (u_char *)crypt_passwd, ep))) {
186 *bp++ = '\0';
187 *bp++ = '\1';
188 pvt_len = bp - pvt_buf;
189 } else {
190 status = ADMIN_TOO_LONG;
191 goto bad;
192 }
193
194 /*
195 * find our session key.
196 */
197
e5fdb505 198 if (status = krb_get_cred("changepw", "kerberos", krbrlm, &cred)) {
718bc25c 199 status += krb_err_base;
200 goto bad;
201 }
202
203 bcopy((char *)cred.session, (char *)sess_key, sizeof(sess_key));
204 bzero((char *)cred.session, sizeof(sess_key)); /* lest we remember */
205
206 if(key_sched(sess_key, sess_sched)) {
207 status = ADMIN_BAD_KEY;
208 goto bad;
209 }
210
3004ebdb 211 /*
212 * Set up socket.
213 */
214
215 admin_fd = socket(admin_addr.sin_family, SOCK_DGRAM, 0);
216 if (admin_fd < 0) {
217 status = errno;
218 goto bad;
219 }
220
221 bzero((char *)&my_addr, sizeof(my_addr));
222
223 my_addr.sin_family = admin_addr.sin_family;
224 my_addr.sin_addr.s_addr = gethostid();
225
226 if (bind(admin_fd, &my_addr, sizeof(my_addr)) < 0) {
227 status = errno;
228 goto bad;
229 }
230
231 my_addr_len = sizeof(my_addr);
232
233 if (getsockname(admin_fd, (struct sockaddr *)&my_addr,
234 &my_addr_len) < 0) {
235 status = errno;
236 goto bad;
237 }
238
239 if (ioctl(admin_fd, FIONBIO, (char *)&on) < 0) {
240 status = errno;
241 goto bad;
242 }
243
718bc25c 244 /*
245 * Encrypt the message using the session key.
246 * Since this contains passwords, it must be kept from prying eyes.
247 */
248
e5fdb505 249 sealed_len = krb_mk_priv(pvt_buf, sealed_buf, pvt_len,
718bc25c 250 sess_sched, sess_key, &my_addr,
251 &admin_addr);
252 if (sealed_len < 0) {
253 status = ADMIN_CANT_ENCRYPT;
254 goto bad;
255 }
256
257 /*
258 * Checksum the cypher text, to guard against tampering in flight.
259 */
260
261 checksum = quad_cksum(sealed_buf, NULL, sealed_len, 0, sess_key);
262
263 /*
264 * Make an authenticator, so the server can learn the session key
265 * and know who we are.
266 */
267
e5fdb505 268 if (status = krb_mk_req(&authent, "changepw", "kerberos", krbrlm,
718bc25c 269 checksum)) {
270 status += krb_err_base;
271 goto bad;
272 }
273
274 /*
275 * Add the sealed message to the end of the authenticator.
276 */
277
278 if ((authent.length + sealed_len) > MAX_KTXT_LEN) {
279 status = ADMIN_TOO_LONG;
280 goto bad;
281 }
282
283 bcopy(sealed_buf, authent.dat + authent.length, sealed_len);
284 authent.length += sealed_len;
285
286 /*
287 * send it off, and wait for a reply.
288 */
289
290 attempts = 0;
291
292 while (attempts++ < RETRY_LIMIT) {
293 int active; /* number of active fds (from select). */
294 fd_set set; /* interesting fd's. */
295 struct timeval timeout; /* timeout on select. */
296
297 if (sendto(admin_fd, (char *)authent.dat, authent.length,
298 0, &admin_addr, sizeof(admin_addr)) != authent.length) {
299 status = errno;
300 goto bad;
301 }
302
303 FD_ZERO(&set);
304 FD_SET(admin_fd, &set);
305
306 timeout.tv_sec = USER_TIMEOUT;
307 timeout.tv_usec = 0;
308
309 active = select(admin_fd+1, &set, (fd_set *)0, (fd_set *)0, &timeout);
310 if (active < 0) {
311 status = errno;
312 goto bad;
313 } else if (active == 0) continue;
314 else {
315 reply.length = recvfrom(admin_fd, (char *)reply.dat,
316 sizeof(reply.dat), 0,
317 &rec_addr, &rec_addr_len);
318 if (reply.length < 0) continue;
319#ifdef notdef
320 if (!bcmp(&rec_addr, &admin_addr, sizeof(admin_addr)))
321 /* the spoofers are out in force.. */
322 continue;
323#endif notdef
324 break; /* got one.. */
325 }
326 }
327
328 if (attempts > RETRY_LIMIT) {
329 status = ETIMEDOUT;
330 goto bad;
331 }
332
333 if (pkt_version((&reply)) != KRB_PROT_VERSION) {
334 status = ADMIN_BAD_VERSION;
335 goto bad;
336 }
337
338 if ((pkt_msg_type((&reply)) & ~1) != AUTH_MSG_PRIVATE) {
339 bp = reply.dat;
340 if (*bp++ != KRB_PROT_VERSION) {
341 status = ADMIN_BAD_VERSION;
342 goto bad;
343 }
344 if (*bp++ != AUTH_MSG_ERR_REPLY) {
345 status = ADMIN_UNKNOWN_CODE;
346 goto bad;
347 }
348 bp += strlen((char *)bp) + 1; /* Skip name */
349 bp += strlen((char *)bp) + 1; /* Skip instance */
350 bp += strlen((char *)bp) + 1; /* Skip realm */
351
352 /* null-terminate error string */
353 reply.dat[reply.length] = '\0';
354
355 if (*bp++ == 126) {
356 status = ADMIN_SERVER_ERROR;
357 strcpy(admin_errmsg, bp);
358 goto bad;
359 } else {
360 status = ADMIN_UNKNOWN_CODE;
361 goto bad;
362 }
363 }
e5fdb505 364 status = krb_rd_priv(reply.dat, reply.length,
718bc25c 365 sess_sched, sess_key,
366 &admin_addr, &my_addr,
367 &msg_data);
368 if (status) {
369 status += krb_err_base;
370 goto bad;
371 }
372 bp = msg_data.app_data;
373
374 if (*bp++ != PW_SRV_VERSION) {
375 status = ADMIN_BAD_VERSION;
376 goto bad;
377 }
378 if (*bp++ != INSTALL_REPLY) {
379 status = ADMIN_UNKNOWN_CODE;
380 goto bad;
381 }
382
383 status = 0;
384 /* fall through into cleanup */
385
386bad:
387 /*
388 * Paranoia: shred all the incriminating evidence.
389 * We'll let the caller shred the arguments.
390 */
391 bzero((char *)sess_key, sizeof(sess_key));
392 bzero((char *)sess_sched, sizeof(sess_sched));
393 bzero(pvt_buf, sizeof(pvt_buf));
3004ebdb 394
395 if (admin_fd >= 0) {
396 (void) close(admin_fd);
397 admin_fd = -1;
398 }
399
718bc25c 400 return status;
401}
402
403/*
404 * Copies characters from source to dest, returning a pointer to the
405 * point in dest after the last character copied from source.
406 * If this would be greater than end, no characters are copied, and NULL
407 * is returned instead.
408 */
409
410static u_char *strapp(dest, source, end)
411 register u_char *dest, *source, *end;
412{
413 register int length = strlen(source) + 1;
414 if (dest+length > end) return NULL;
415 else {
416 bcopy(source, dest, length);
417 return dest + length;
418 }
419}
420
421/*
422 * Local Variables:
423 * mode: c
424 * c-indent-level: 4
425 * c-continued-statement-offset: 4
426 * c-brace-offset: -4
427 * c-argdecl-indent: 4
428 * c-label-offset: -4
429 * End:
430 */
This page took 0.156712 seconds and 5 git commands to generate.