Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / kerberosIV / kadmin / kadm_funcs.c
1 /* 
2   Copyright (C) 1989 by the Massachusetts Institute of Technology
3
4    Export of this software from the United States of America is assumed
5    to require a specific license from the United States Government.
6    It is the responsibility of any person or organization contemplating
7    export to obtain such a license before exporting.
8
9 WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10 distribute this software and its documentation for any purpose and
11 without fee is hereby granted, provided that the above copyright
12 notice appear in all copies and that both that copyright notice and
13 this permission notice appear in supporting documentation, and that
14 the name of M.I.T. not be used in advertising or publicity pertaining
15 to distribution of the software without specific, written prior
16 permission.  M.I.T. makes no representations about the suitability of
17 this software for any purpose.  It is provided "as is" without express
18 or implied warranty.
19
20 */
21
22 /*
23  * Kerberos administration server-side database manipulation routines
24  */
25
26 /*
27  * kadm_funcs.c
28  * the actual database manipulation code
29  */
30
31 #include "kadm_locl.h"
32
33 RCSID("$Id: kadm_funcs.c,v 1.18 1999/09/16 20:41:40 assar Exp $");
34
35 static int
36 check_access(char *pname, char *pinst, char *prealm, enum acl_types acltype)
37 {
38     char checkname[MAX_K_NAME_SZ];
39     char filename[MaxPathLen];
40
41     snprintf(checkname, sizeof(checkname), "%s.%s@%s", pname, pinst, prealm);
42     
43     switch (acltype) {
44     case ADDACL:
45         snprintf(filename, sizeof(filename), "%s%s", acldir, ADD_ACL_FILE);
46         break;
47     case GETACL:
48         snprintf(filename, sizeof(filename), "%s%s", acldir, GET_ACL_FILE);
49         break;
50     case MODACL:
51         snprintf(filename, sizeof(filename), "%s%s", acldir, MOD_ACL_FILE);
52         break;
53     case DELACL:
54         snprintf(filename, sizeof(filename), "%s%s", acldir, DEL_ACL_FILE);
55         break;
56     default:
57         krb_log("WARNING in check_access: default case in switch");
58         return 0;
59     }
60     return(acl_check(filename, checkname));
61 }
62
63 static int
64 wildcard(char *str)
65 {
66     if (!strcmp(str, WILDCARD_STR))
67         return(1);
68     return(0);
69 }
70
71 static int
72 fail(int code, char *oper, char *princ)
73 {
74     krb_log("ERROR: %s: %s (%s)", oper, princ, error_message(code));
75     return code;
76 }
77
78 #define failadd(code) { fail(code, "ADD", victim); return code; }
79 #define faildelete(code) { fail(code, "DELETE", victim); return code; }
80 #define failget(code) { fail(code, "GET", victim); return code; }
81 #define failmod(code) { fail(code, "MOD", victim); return code; }
82 #define failchange(code) { fail(code, "CHANGE", admin); return code; }
83
84 int
85 kadm_add_entry (char *rname, char *rinstance, char *rrealm, 
86                 Kadm_vals *valsin, Kadm_vals *valsout)
87 {
88     long numfound;              /* check how many we get written */
89     int more;                   /* pointer to more grabbed records */
90     Principal data_i, data_o;           /* temporary principal */
91     u_char flags[4];
92     des_cblock newpw;
93     Principal default_princ;
94   
95     char admin[MAX_K_NAME_SZ], victim[MAX_K_NAME_SZ];
96
97     strlcpy(admin,
98                     krb_unparse_name_long(rname, rinstance, rrealm),
99                     sizeof(admin));
100     strlcpy(victim,
101                     krb_unparse_name_long(valsin->name,
102                                           valsin->instance,
103                                           NULL),
104                     sizeof(victim));
105
106     krb_log("ADD: %s by %s", victim, admin);
107
108     if (!check_access(rname, rinstance, rrealm, ADDACL)) {
109         krb_log("WARNING: ADD: %s permission denied", admin);
110         return KADM_UNAUTH;
111     }
112   
113     /* Need to check here for "legal" name and instance */
114     if (wildcard(valsin->name) || wildcard(valsin->instance)) {
115         failadd(KADM_ILL_WILDCARD);
116     }
117
118     numfound = kerb_get_principal(KERB_DEFAULT_NAME, KERB_DEFAULT_INST,
119                                   &default_princ, 1, &more);
120     if (numfound == -1) {
121         failadd(KADM_DB_INUSE);
122     } else if (numfound != 1) {
123         failadd(KADM_UK_RERROR);
124     }
125
126     kadm_vals_to_prin(valsin->fields, &data_i, valsin);
127     strlcpy(data_i.name, valsin->name, ANAME_SZ);
128     strlcpy(data_i.instance, valsin->instance, INST_SZ);
129
130     if (!IS_FIELD(KADM_EXPDATE,valsin->fields))
131         data_i.exp_date = default_princ.exp_date;
132     if (!IS_FIELD(KADM_ATTR,valsin->fields))
133         data_i.attributes = default_princ.attributes;
134     if (!IS_FIELD(KADM_MAXLIFE,valsin->fields))
135         data_i.max_life = default_princ.max_life; 
136
137     memset(&default_princ, 0, sizeof(default_princ));
138
139     /* convert to host order */
140     data_i.key_low = ntohl(data_i.key_low);
141     data_i.key_high = ntohl(data_i.key_high);
142
143
144     copy_to_key(&data_i.key_low, &data_i.key_high, newpw);
145
146     /* encrypt new key in master key */
147     kdb_encrypt_key (&newpw, &newpw, &server_parm.master_key,
148                      server_parm.master_key_schedule, DES_ENCRYPT);
149     copy_from_key(newpw, &data_i.key_low, &data_i.key_high);
150     memset(newpw, 0, sizeof(newpw));
151
152     data_o = data_i;
153     numfound = kerb_get_principal(valsin->name, valsin->instance, 
154                                   &data_o, 1, &more);
155     if (numfound == -1) {
156         failadd(KADM_DB_INUSE);
157     } else if (numfound) {
158         failadd(KADM_INUSE);
159     } else {
160         data_i.key_version++;
161         data_i.kdc_key_ver = server_parm.master_key_version;
162         strlcpy(data_i.mod_name, rname, sizeof(data_i.mod_name));
163         strlcpy(data_i.mod_instance, rinstance,
164                         sizeof(data_i.mod_instance));
165
166         numfound = kerb_put_principal(&data_i, 1);
167         if (numfound == -1) {
168             failadd(KADM_DB_INUSE);
169         } else if (numfound) {
170             failadd(KADM_UK_SERROR);
171         } else {
172             numfound = kerb_get_principal(valsin->name, valsin->instance, 
173                                           &data_o, 1, &more);
174             if ((numfound!=1) || (more!=0)) {
175                 failadd(KADM_UK_RERROR);
176             }
177             memset(flags, 0, sizeof(flags));
178             SET_FIELD(KADM_NAME,flags);
179             SET_FIELD(KADM_INST,flags);
180             SET_FIELD(KADM_EXPDATE,flags);
181             SET_FIELD(KADM_ATTR,flags);
182             SET_FIELD(KADM_MAXLIFE,flags);
183             kadm_prin_to_vals(flags, valsout, &data_o);
184             krb_log("ADD: %s added", victim);
185             return KADM_DATA;           /* Set all the appropriate fields */
186         }
187     }
188 }
189
190 int
191 kadm_delete_entry (char *rname, char *rinstance, char *rrealm, 
192                    Kadm_vals *valsin)
193 {
194     int ret;
195
196     char admin[MAX_K_NAME_SZ], victim[MAX_K_NAME_SZ];
197     
198     strlcpy(admin,
199                     krb_unparse_name_long(rname, rinstance, rrealm),
200                     sizeof(admin));
201     strlcpy(victim,
202                     krb_unparse_name_long(valsin->name,
203                                           valsin->instance,
204                                           NULL),
205                     sizeof(victim));
206
207     krb_log("DELETE: %s by %s", victim, admin);
208
209     if (!check_access(rname, rinstance, rrealm, DELACL)) {
210         krb_log("WARNING: DELETE: %s permission denied", admin);
211         return KADM_UNAUTH;
212     }
213     
214     /* Need to check here for "legal" name and instance */
215     if (wildcard(valsin->name) || wildcard(valsin->instance)) {
216         faildelete(KADM_ILL_WILDCARD);
217     }
218   
219 #define EQ(V,N,I) (strcmp((V)->name, (N)) == 0 && strcmp((V)->instance, (I)) == 0)
220
221     if(EQ(valsin, PWSERV_NAME, KRB_MASTER) ||
222        EQ(valsin, "K", "M") ||
223        EQ(valsin, "default", "") ||
224        EQ(valsin, KRB_TICKET_GRANTING_TICKET, server_parm.krbrlm)){
225         krb_log("WARNING: DELETE: %s is immutable", victim);
226         return KADM_IMMUTABLE; /* XXX */
227     }
228     
229     ret = kerb_delete_principal(valsin->name, valsin->instance);
230     if(ret == -1)
231         return KADM_DB_INUSE; /* XXX */
232     krb_log("DELETE: %s removed.", victim);
233     return KADM_SUCCESS;
234 }
235
236
237 int
238 kadm_get_entry (char *rname, char *rinstance, char *rrealm, 
239                 Kadm_vals *valsin, u_char *flags, Kadm_vals *valsout)
240 {
241     long numfound;              /* check how many were returned */
242     int more;                   /* To point to more name.instances */
243     Principal data_o;           /* Data object to hold Principal */
244     
245     char admin[MAX_K_NAME_SZ], victim[MAX_K_NAME_SZ];
246     
247     strlcpy(admin,
248                     krb_unparse_name_long(rname, rinstance, rrealm),
249                     sizeof(admin));
250     strlcpy(victim,
251                     krb_unparse_name_long(valsin->name,
252                                           valsin->instance,
253                                           NULL),
254                     sizeof(victim));
255     
256     krb_log("GET: %s by %s", victim, admin);
257
258     if (!check_access(rname, rinstance, rrealm, GETACL)) {
259         krb_log("WARNING: GET: %s permission denied", admin);
260         return KADM_UNAUTH;
261     }
262   
263     if (wildcard(valsin->name) || wildcard(valsin->instance)) {
264         failget(KADM_ILL_WILDCARD);
265     }
266
267     /* Look up the record in the database */
268     numfound = kerb_get_principal(valsin->name, valsin->instance, 
269                                   &data_o, 1, &more);
270     if (numfound == -1) {
271         failget(KADM_DB_INUSE);
272     }  else if (numfound) {     /* We got the record, let's return it */
273         kadm_prin_to_vals(flags, valsout, &data_o);
274         krb_log("GET: %s retrieved", victim);
275         return KADM_DATA; /* Set all the appropriate fields */
276     } else {
277         failget(KADM_NOENTRY);  /* Else whimper and moan */
278     }
279 }
280
281 int
282 kadm_mod_entry (char *rname, char *rinstance, char *rrealm, 
283                 Kadm_vals *valsin, Kadm_vals *valsin2, Kadm_vals *valsout)
284 {
285     long numfound;
286     int more;
287     Principal data_o, temp_key;
288     u_char fields[4];
289     des_cblock newpw;
290
291     char admin[MAX_K_NAME_SZ], victim[MAX_K_NAME_SZ];
292     
293     strlcpy(admin,
294                     krb_unparse_name_long(rname, rinstance, rrealm),
295                     sizeof(admin));
296     strlcpy(victim,
297                     krb_unparse_name_long(valsin->name,
298                                           valsin->instance,
299                                           NULL),
300                     sizeof(victim));
301     
302     krb_log("MOD: %s by %s", victim, admin);
303
304     if (wildcard(valsin->name) || wildcard(valsin->instance)) {
305         failmod(KADM_ILL_WILDCARD);
306     }
307   
308     if (!check_access(rname, rinstance, rrealm, MODACL)) {
309         krb_log("WARNING: MOD: %s permission denied", admin);
310         return KADM_UNAUTH;
311     }
312     
313     numfound = kerb_get_principal(valsin->name, valsin->instance, 
314                                   &data_o, 1, &more);
315     if (numfound == -1) {
316         failmod(KADM_DB_INUSE);
317     } else if (numfound) {
318         kadm_vals_to_prin(valsin2->fields, &temp_key, valsin2);
319         strlcpy(data_o.name, valsin->name, ANAME_SZ);
320         strlcpy(data_o.instance, valsin->instance, INST_SZ);
321         if (IS_FIELD(KADM_EXPDATE,valsin2->fields))
322             data_o.exp_date = temp_key.exp_date;
323         if (IS_FIELD(KADM_ATTR,valsin2->fields))
324             data_o.attributes = temp_key.attributes;
325         if (IS_FIELD(KADM_MAXLIFE,valsin2->fields))
326             data_o.max_life = temp_key.max_life; 
327         if (IS_FIELD(KADM_DESKEY,valsin2->fields)) {
328             data_o.key_version++;
329             data_o.kdc_key_ver = server_parm.master_key_version;
330
331
332             /* convert to host order */
333             temp_key.key_low = ntohl(temp_key.key_low);
334             temp_key.key_high = ntohl(temp_key.key_high);
335
336
337             copy_to_key(&temp_key.key_low, &temp_key.key_high, newpw);
338
339             /* encrypt new key in master key */
340             kdb_encrypt_key (&newpw, &newpw, &server_parm.master_key,
341                              server_parm.master_key_schedule, DES_ENCRYPT);
342             copy_from_key(newpw, &data_o.key_low, &data_o.key_high);
343             memset(newpw, 0, sizeof(newpw));
344         }
345         memset(&temp_key, 0, sizeof(temp_key));
346
347         strlcpy(data_o.mod_name, rname, sizeof(data_o.mod_name));
348         strlcpy(data_o.mod_instance, rinstance,
349                         sizeof(data_o.mod_instance));
350         more = kerb_put_principal(&data_o, 1);
351
352         memset(&data_o, 0, sizeof(data_o));
353
354         if (more == -1) {
355             failmod(KADM_DB_INUSE);
356         } else if (more) {
357             failmod(KADM_UK_SERROR);
358         } else {
359             numfound = kerb_get_principal(valsin->name, valsin->instance, 
360                                           &data_o, 1, &more);
361             if ((more!=0)||(numfound!=1)) {
362                 failmod(KADM_UK_RERROR);
363             }
364             memset(fields, 0, sizeof(fields));
365             SET_FIELD(KADM_NAME,fields);
366             SET_FIELD(KADM_INST,fields);
367             SET_FIELD(KADM_EXPDATE,fields);
368             SET_FIELD(KADM_ATTR,fields);
369             SET_FIELD(KADM_MAXLIFE,fields);
370             kadm_prin_to_vals(fields, valsout, &data_o);
371             krb_log("MOD: %s modified", victim);
372             return KADM_DATA;           /* Set all the appropriate fields */
373         }
374     }
375     else {
376         failmod(KADM_NOENTRY);
377     }
378 }
379
380 int
381 kadm_change (char *rname, char *rinstance, char *rrealm, unsigned char *newpw)
382 {
383     long numfound;
384     int more;
385     Principal data_o;
386     des_cblock local_pw;
387
388     char admin[MAX_K_NAME_SZ];
389     
390     strlcpy(admin,
391                     krb_unparse_name_long(rname, rinstance, rrealm),
392                     sizeof(admin));
393     
394     krb_log("CHANGE: %s", admin);
395
396     if (strcmp(server_parm.krbrlm, rrealm)) {
397         krb_log("ERROR: CHANGE: request from wrong realm %s", rrealm);
398         return(KADM_WRONG_REALM);
399     }
400
401     if (wildcard(rname) || wildcard(rinstance)) {
402         failchange(KADM_ILL_WILDCARD);
403     }
404
405     memcpy(local_pw, newpw, sizeof(local_pw));
406   
407     /* encrypt new key in master key */
408     kdb_encrypt_key (&local_pw, &local_pw, &server_parm.master_key,
409                      server_parm.master_key_schedule, DES_ENCRYPT);
410
411     numfound = kerb_get_principal(rname, rinstance, 
412                                   &data_o, 1, &more);
413     if (numfound == -1) {
414         failchange(KADM_DB_INUSE);
415     } else if (numfound) {
416         copy_from_key(local_pw, &data_o.key_low, &data_o.key_high);
417         data_o.key_version++;
418         data_o.kdc_key_ver = server_parm.master_key_version;
419         strlcpy(data_o.mod_name, rname, sizeof(data_o.mod_name));
420         strlcpy(data_o.mod_instance, rinstance,
421                         sizeof(data_o.mod_instance));
422         more = kerb_put_principal(&data_o, 1);
423         memset(local_pw, 0, sizeof(local_pw));
424         memset(&data_o, 0, sizeof(data_o));
425         if (more == -1) {
426             failchange(KADM_DB_INUSE);
427         } else if (more) {
428             failchange(KADM_UK_SERROR);
429         } else {
430             krb_log("CHANGE: %s's password changed", admin);
431             return KADM_SUCCESS;
432         }
433     }
434     else {
435         failchange(KADM_NOENTRY);
436     }
437 }