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