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