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