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