]>
Commit | Line | Data |
---|---|---|
7ac48069 | 1 | /* $Id $ |
6e6374cb | 2 | * |
7ac48069 | 3 | * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology. |
4 | * For copying and distribution information, please see the file | |
5 | * <mit-copyright.h>. | |
6e6374cb | 6 | */ |
7 | ||
7189310c | 8 | #include <mit-copyright.h> |
7ac48069 | 9 | #include <moira.h> |
10 | #include <moira_site.h> | |
11 | #include "ureg_proto.h" | |
12 | ||
6e6374cb | 13 | #include <sys/types.h> |
6e6374cb | 14 | #include <sys/socket.h> |
7ac48069 | 15 | |
6e6374cb | 16 | #include <netdb.h> |
7ac48069 | 17 | #include <netinet/in.h> |
18 | ||
19 | #include <ctype.h> | |
6e6374cb | 20 | #include <errno.h> |
7ac48069 | 21 | #include <stdio.h> |
22 | #include <stdlib.h> | |
f071d8a7 | 23 | #include <string.h> |
7ac48069 | 24 | #include <unistd.h> |
25 | ||
26 | #include <des.h> | |
27 | #include <hesiod.h> | |
28 | #include <kadm_err.h> | |
29 | #include <krb.h> | |
30 | ||
31 | RCSID("$Header$"); | |
32 | ||
33 | int do_operation(char *first, char *last, char *idnumber, char *hashidnumber, | |
34 | char *data, u_long opcode); | |
35 | int do_secure_operation(char *login, char *idnumber, char *passwd, | |
36 | char *newpasswd, u_long opcode); | |
37 | int do_call(char *buf, int len, int seq_no, char *login); | |
38 | ||
39 | char *krb_realmofhost(char *); | |
6e6374cb | 40 | |
41 | static int reg_sock = -1; | |
8edc0757 | 42 | static int seq_no = 0; |
b7ed754f | 43 | static char *host; |
6e6374cb | 44 | #define UNKNOWN_HOST -1 |
45 | #define UNKNOWN_SERVICE -2 | |
46 | ||
8b7874ce | 47 | #ifndef FD_SET |
48 | #define FD_ZERO(p) ((p)->fds_bits[0] = 0) | |
49 | #define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n))) | |
50 | #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n))) | |
51 | #endif /* FD_SET */ | |
52 | ||
5eaef520 | 53 | int ureg_init(void) |
6e6374cb | 54 | { |
5eaef520 | 55 | struct servent *sp; |
56 | char **p, *s; | |
57 | struct hostent *hp; | |
58 | struct sockaddr_in s_in; | |
59 | ||
60 | initialize_ureg_error_table(); | |
61 | initialize_krb_error_table(); | |
62 | initialize_sms_error_table(); | |
63 | initialize_kadm_error_table(); | |
64 | ||
65 | seq_no = getpid(); | |
66 | ||
67 | host = NULL; | |
68 | host = getenv("REGSERVER"); | |
028ff1c1 | 69 | #ifdef HESIOD |
5eaef520 | 70 | if (!host || (strlen(host) == 0)) |
71 | { | |
72 | p = hes_resolve("registration", "sloc"); | |
73 | if (p) | |
74 | host = *p; | |
028ff1c1 | 75 | } |
7ff930df | 76 | #endif |
5eaef520 | 77 | if (!host || (strlen(host) == 0)) |
78 | { | |
7ac48069 | 79 | host = strdup(MOIRA_SERVER); |
5eaef520 | 80 | s = strchr(host, ':'); |
81 | if (s) | |
82 | *s = '\0'; | |
028ff1c1 | 83 | } |
5eaef520 | 84 | hp = gethostbyname(host); |
7ac48069 | 85 | host = strdup(hp->h_name); |
5eaef520 | 86 | if (hp == NULL) |
87 | return UNKNOWN_HOST; | |
6e6374cb | 88 | |
59ec8dae | 89 | sp = getservbyname("moira_ureg", "udp"); |
6e6374cb | 90 | |
5eaef520 | 91 | if (sp == NULL) |
92 | return UNKNOWN_SERVICE; | |
6e6374cb | 93 | |
5eaef520 | 94 | close(reg_sock); |
95 | reg_sock = socket(AF_INET, SOCK_DGRAM, 0); | |
96 | if (reg_sock < 0) | |
97 | return errno; | |
6e6374cb | 98 | |
5eaef520 | 99 | memset(&s_in, 0, sizeof(s_in)); |
100 | s_in.sin_port = sp->s_port; | |
101 | memcpy(&s_in.sin_addr, hp->h_addr, sizeof(struct in_addr)); | |
102 | s_in.sin_family = AF_INET; | |
103 | ||
104 | if (connect(reg_sock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) | |
105 | return errno; | |
106 | return 0; | |
6e6374cb | 107 | } |
108 | ||
5eaef520 | 109 | int verify_user(char *first, char *last, char *idnumber, |
110 | char *hashidnumber, char *login) | |
6e6374cb | 111 | { |
5eaef520 | 112 | char buf[1024]; |
113 | int version = ntohl((u_long)1); | |
114 | int call = ntohl((u_long)UREG_VERIFY_USER); | |
115 | des_cblock key; | |
116 | des_key_schedule ks; | |
44d12d58 | 117 | char *bp = buf; |
118 | int len; | |
5eaef520 | 119 | char crypt_src[1024]; |
120 | ||
121 | memcpy(bp, &version, sizeof(int)); | |
122 | bp += sizeof(int); | |
123 | seq_no++; | |
124 | memcpy(bp, &seq_no, sizeof(int)); | |
125 | ||
126 | bp += sizeof(int); | |
127 | ||
128 | memcpy(bp, &call, sizeof(int)); | |
129 | ||
130 | bp += sizeof(int); | |
131 | ||
132 | strcpy(bp, first); | |
133 | bp += strlen(bp) + 1; | |
134 | ||
135 | strcpy(bp, last); | |
136 | bp += strlen(bp) + 1; | |
137 | ||
138 | len = strlen(idnumber) + 1; | |
139 | memcpy(crypt_src, idnumber, len); | |
140 | ||
141 | memcpy(crypt_src + len, hashidnumber, 13); | |
142 | ||
143 | des_string_to_key(hashidnumber, key); | |
144 | des_key_sched(key, ks); | |
145 | des_pcbc_encrypt(crypt_src, bp, len + 13, ks, key, DES_ENCRYPT); | |
146 | bp += len + 14 + 8; | |
147 | len = bp - buf; | |
148 | return do_call(buf, len, seq_no, login); | |
6e6374cb | 149 | } |
150 | ||
5eaef520 | 151 | int do_operation(char *first, char *last, char *idnumber, char *hashidnumber, |
152 | char *data, u_long opcode) | |
6e6374cb | 153 | { |
5eaef520 | 154 | char buf[1024]; |
155 | int version = ntohl((u_long)1); | |
156 | int call = ntohl(opcode); | |
157 | des_cblock key; | |
158 | des_key_schedule ks; | |
44d12d58 | 159 | char *bp = buf; |
160 | int len; | |
5eaef520 | 161 | |
162 | char crypt_src[1024]; | |
163 | char *cbp; | |
164 | ||
165 | memcpy(bp, &version, sizeof(int)); | |
166 | bp += sizeof(int); | |
167 | seq_no++; | |
168 | memcpy(bp, &seq_no, sizeof(int)); | |
169 | ||
170 | bp += sizeof(int); | |
171 | ||
172 | memcpy(bp, &call, sizeof(int)); | |
173 | ||
174 | bp += sizeof(int); | |
175 | ||
176 | strcpy(bp, first); | |
177 | bp += strlen(bp) + 1; | |
178 | ||
179 | strcpy(bp, last); | |
180 | bp += strlen(bp) + 1; | |
6e6374cb | 181 | |
5eaef520 | 182 | len = strlen(idnumber) + 1; |
183 | cbp = crypt_src; | |
184 | ||
185 | memcpy(crypt_src, idnumber, len); | |
186 | cbp += len; | |
187 | ||
188 | memcpy(cbp, hashidnumber, 14); | |
189 | cbp += 14; | |
190 | ||
191 | len = strlen(data) + 1; | |
192 | memcpy(cbp, data, len); | |
193 | cbp += len; | |
194 | ||
195 | len = cbp - crypt_src; | |
196 | des_string_to_key(hashidnumber, key); | |
197 | des_key_sched(key, ks); | |
198 | des_pcbc_encrypt(crypt_src, bp, len, ks, key, 1); | |
199 | len = ((len + 7) >> 3) << 3; | |
200 | bp += len; | |
201 | ||
202 | len = bp - buf; | |
203 | return do_call(buf, len, seq_no, 0); | |
6e6374cb | 204 | } |
205 | ||
5eaef520 | 206 | int grab_login(char *first, char *last, char *idnumber, char *hashidnumber, |
207 | char *login) | |
6e6374cb | 208 | { |
5eaef520 | 209 | return do_operation(first, last, idnumber, hashidnumber, login, |
210 | UREG_RESERVE_LOGIN); | |
5dee7862 | 211 | } |
6e6374cb | 212 | |
5eaef520 | 213 | int enroll_login(char *first, char *last, char *idnumber, char *hashidnumber, |
214 | char *login) | |
5dee7862 | 215 | { |
5eaef520 | 216 | return do_operation(first, last, idnumber, hashidnumber, login, |
217 | UREG_SET_IDENT); | |
5dee7862 | 218 | } |
6e6374cb | 219 | |
5eaef520 | 220 | int set_password(char *first, char *last, char *idnumber, char *hashidnumber, |
221 | char *password) | |
5dee7862 | 222 | { |
5eaef520 | 223 | return do_operation(first, last, idnumber, hashidnumber, password, |
224 | UREG_SET_PASSWORD); | |
5dee7862 | 225 | } |
6e6374cb | 226 | |
5eaef520 | 227 | int get_krb(char *first, char *last, char *idnumber, char *hashidnumber, |
228 | char *password) | |
5dee7862 | 229 | { |
5eaef520 | 230 | return do_operation(first, last, idnumber, hashidnumber, password, |
231 | UREG_GET_KRB); | |
6e6374cb | 232 | } |
233 | ||
b7ed754f | 234 | |
235 | /* The handles the operations for secure passwords. | |
8de2273d | 236 | * To find out if a user has a secure instance, the newpasswd |
237 | * field is ignored (but must be a valid char *) | |
b7ed754f | 238 | * and the opcode = UREG_GET_SECURE need to be specified (but the |
239 | * other strings must be valid char*'s). This will return | |
240 | * UREG_ALREADY_REGISTERED if it is set, or SUCCESS if not. | |
241 | * To set the password, fill in the rest of the fields, and | |
242 | * use opcode = UREG_SET_SECURE. This returns SUCCESS or any number | |
243 | * of failure codes. | |
244 | */ | |
245 | ||
5eaef520 | 246 | int do_secure_operation(char *login, char *idnumber, char *passwd, |
247 | char *newpasswd, u_long opcode) | |
b7ed754f | 248 | { |
5eaef520 | 249 | char buf[1500], data[128], tktstring[128]; |
250 | int version = ntohl((u_long)1); | |
251 | int call = ntohl(opcode); | |
252 | char inst[INST_SZ], hosti[INST_SZ]; | |
253 | char *bp = buf, *src, *dst, *realm; | |
7ac48069 | 254 | int len, status; |
5eaef520 | 255 | KTEXT_ST cred; |
256 | CREDENTIALS creds; | |
257 | Key_schedule keys; | |
5eaef520 | 258 | |
259 | memmove(bp, &version, sizeof(int)); | |
260 | bp += sizeof(int); | |
261 | seq_no++; | |
262 | memmove(bp, &seq_no, sizeof(int)); | |
263 | ||
264 | bp += sizeof(int); | |
265 | memmove(bp, &call, sizeof(int)); | |
266 | ||
267 | bp += sizeof(int); | |
268 | ||
269 | /* put the login name in the firstname field */ | |
270 | strcpy(bp, login); | |
271 | bp += strlen(bp) + 1; | |
272 | ||
273 | /* the old lastname field */ | |
274 | strcpy(bp, ""); | |
275 | bp += strlen(bp) + 1; | |
276 | ||
277 | /* don't overwrite existing ticket file */ | |
7ac48069 | 278 | sprintf(tktstring, "/tmp/tkt_cpw_%ld", (long)getpid()); |
5eaef520 | 279 | krb_set_tkt_string(tktstring); |
280 | ||
281 | /* get realm and canonizalized hostname of server */ | |
282 | realm = krb_realmofhost(host); | |
283 | for (src = host, dst = hosti; *src && *src != '.'; src++) | |
284 | { | |
b7ed754f | 285 | if (isupper(*src)) |
286 | *dst++ = tolower(*src); | |
287 | else | |
288 | *dst++ = *src; | |
b7ed754f | 289 | } |
5eaef520 | 290 | *dst = '\0'; |
291 | inst[0] = '\0'; | |
292 | ||
293 | /* get changepw tickets. We use this service because it's the | |
294 | * only one that guarantees we used the password rather than a | |
295 | * ticket granting ticket. | |
296 | */ | |
297 | status = krb_get_pw_in_tkt(login, inst, realm, "changepw", hosti, 5, passwd); | |
298 | if (status) | |
299 | return status + krb_err_base; | |
300 | ||
301 | status = krb_mk_req(&cred, "changepw", hosti, realm, 0); | |
302 | if (status) | |
303 | return status + krb_err_base; | |
304 | ||
305 | /* round up to word boundry */ | |
306 | bp = (char *)((((u_long)bp) + 3) & 0xfffffffc); | |
307 | ||
308 | /* put the ticket in the packet */ | |
309 | len = cred.length; | |
310 | cred.length = htonl(cred.length); | |
311 | memmove(bp, &(cred), sizeof(int) + len); | |
312 | bp += sizeof(int) + len; | |
313 | ||
314 | /* encrypt the data in the session key */ | |
315 | sprintf(data, "%s,%s", idnumber, newpasswd); | |
316 | len = strlen(data); | |
317 | len = ((len + 7) >> 3) << 3; | |
318 | ||
319 | status = krb_get_cred("changepw", hosti, realm, &creds); | |
320 | if (status) | |
321 | { | |
322 | memset(data, 0, strlen(data)); | |
323 | return status + krb_err_base; | |
324 | } | |
325 | dest_tkt(); | |
b7ed754f | 326 | |
5eaef520 | 327 | des_key_sched(creds.session, keys); |
328 | des_pcbc_encrypt(data, bp + sizeof(int), len, keys, creds.session, 1); | |
329 | *((int *)bp) = htonl(len); | |
330 | memset(data, 0, strlen(data)); | |
b7ed754f | 331 | |
5eaef520 | 332 | bp += len + sizeof(int); |
b7ed754f | 333 | |
5eaef520 | 334 | len = bp - buf; |
335 | return do_call(buf, len, seq_no, 0); | |
b7ed754f | 336 | } |
337 | ||
5eaef520 | 338 | int do_call(char *buf, int len, int seq_no, char *login) |
6e6374cb | 339 | { |
5eaef520 | 340 | struct timeval timeout; |
341 | char ibuf[1024]; | |
342 | fd_set set; | |
343 | ||
344 | int retry = 0; | |
345 | ||
346 | do | |
347 | { | |
348 | if (write(reg_sock, buf, len) != len) | |
349 | return errno; | |
350 | ||
351 | FD_ZERO(&set); | |
352 | FD_SET(reg_sock, &set); | |
353 | timeout.tv_sec = 30; | |
354 | timeout.tv_usec = 0; | |
355 | do | |
356 | { | |
357 | int rtn; | |
358 | struct sockaddr_in s_in; | |
359 | int addrlen = sizeof(s_in); | |
360 | int vno; | |
361 | int sno; | |
362 | int stat; | |
363 | ||
364 | rtn = select(reg_sock + 1, &set, NULL, NULL, &timeout); | |
365 | if (rtn == 0) | |
366 | break; | |
367 | else if (rtn < 0) | |
368 | return errno; | |
369 | ||
370 | len = recvfrom(reg_sock, ibuf, BUFSIZ, 0, | |
371 | (struct sockaddr *)&s_in, &addrlen); | |
372 | if (len < 0) | |
373 | return errno; | |
374 | if (len < 12) | |
375 | return UREG_BROKEN_PACKET; | |
376 | memcpy(&vno, ibuf, sizeof(long)); | |
377 | vno = ntohl((u_long)vno); | |
378 | if (vno != 1) | |
379 | continue; | |
380 | memcpy(&sno, ibuf + 4, sizeof(long)); | |
381 | ||
382 | if (sno != seq_no) | |
383 | continue; | |
384 | ||
385 | memcpy(&stat, ibuf + 8, sizeof(long)); | |
386 | stat = ntohl((u_long)stat); | |
387 | if (login && len > 12) | |
388 | { | |
389 | memcpy(login, ibuf + 12, len - 12); | |
390 | login[len - 12] = '\0'; | |
391 | } | |
392 | else if (login) | |
393 | *login = '\0'; | |
394 | return stat; | |
395 | } | |
396 | while (1); | |
397 | } | |
398 | while (++retry < 10); | |
399 | return ETIMEDOUT; | |
400 | } |