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