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