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