1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * ident	"%Z%%M%	%I%	%E% SMI"
24 *
25 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26 * Use is subject to license terms.
27 */
28
29import java.util.Date;
30import java.text.DateFormat;
31import java.text.NumberFormat;
32import java.text.ParseException;
33import java.util.Calendar;
34import java.util.ResourceBundle;
35import java.util.MissingResourceException;
36
37/**
38 * Class representing a Kerberos V5 principal
39 * Class data items correspond to fields in struct _kadm5_principal_ent_t_v2
40 */
41class Principal {
42
43    private static DateFormat df;
44    private static NumberFormat nf;
45    private static String neverString;
46
47    private static Integer INFINITE_LIFE = new Integer(Integer.MAX_VALUE);
48
49    Flags flags;
50
51    // For I18N
52    private static ResourceBundle rb;
53
54    String PrName;		// krb5_principal principal;
55    Date PrExpireTime;		// krb5_timestamp princ_expire_time;
56    String Policy;		// char *policy;
57    Date LastPwChange;		// krb5_timestamp last_pwd_change;
58    Date PwExpireTime;		// krb5_timestamp pw_expiration;
59    Integer MaxLife;	        // krb5_deltat max_life;
60    Integer MaxRenew;		// krb5_deltat max_renewable_life;
61    Date ModTime;		// krb5_timestamp mod_date;
62    String ModName;		// krb5_principal mod_name;
63    Date LastSuccess;		// krb5_timestamp last_success;
64    Date LastFailure;		// krb5_timestamp last_failed;
65    Integer NumFailures;	// krb5_kvno fail_auth_count;
66    String Comments;		// ==> entry in tl_data array
67    Integer Kvno;		// krb5_kvno kvno;
68    Integer Mkvno;		// krb5_kvno mkvno;
69
70    String PrPasswd;		// standalone field in Kadmin API
71    Kadmin Kadmin;
72    boolean isNew;		// newly created principal?
73    boolean dummy;		// use dummy data?
74    boolean newComments;	// are comments new or changed?
75    String EncTypes;		// enc type list to be used for key gen
76
77    /**
78     * Initialize new principal to defaults - this one is for new creations
79     */
80    public Principal() {
81        isNew = true;
82        dummy = true;
83        newComments = false;
84        PrName = new String("");
85        PrPasswd = new String("");
86        Calendar cal = Calendar.getInstance();
87        cal.setTime(new Date());	    /* start with now ... */
88        cal.add(Calendar.YEAR, 1);	    /* ... add a year ... XXX */
89        PrExpireTime = cal.getTime();  /* ... to get expiry */
90        Policy = new String("");
91        LastPwChange = new Date(0);    /* never */
92        PwExpireTime = null; // may be server side default
93        MaxLife = null; // may be server side default
94        MaxRenew = null; // may be server side default
95        ModTime = new Date();	    /* now */
96        ModName = System.getProperty("user.name");
97        LastSuccess = new Date(0);	    /* never */
98        LastFailure = new Date(0);	    /* never */
99        NumFailures = new Integer(0);
100        Comments = new String("");
101        Kvno = new Integer(0);
102        Mkvno = new Integer(0);
103        flags = new Flags();
104	EncTypes = new String("");
105    }
106
107    /*
108     * This is used for loading an existing principal
109     */
110    public Principal(String Pname) {
111	/* Get some specific data from somewhere */
112	this();
113	isNew = false;
114	PrName = Pname;
115	PwExpireTime = new Date(0);
116	loadPrincipal(Pname);
117    }
118
119    /*
120     * This is used for duplicating a new principal from an old one
121     */
122    public Principal(Principal old) {
123	/* Copy old principal to new one */
124	this();
125	copyPrincipal(old, this);
126    }
127
128    /*
129     * For real data, use Kadmin as a first argument
130     */
131    public Principal(Kadmin session, Defaults defaults) {
132	this();
133	dummy = false;
134	Kadmin = session;
135	setDefaults(defaults);
136    }
137
138    public Principal(Kadmin session, String Pname) {
139	this();
140	isNew = false;
141	dummy = false;
142	Kadmin = session;
143	PrName = Pname;
144	PwExpireTime = new Date(0);
145	loadPrincipal(Pname);
146    }
147
148    public Principal(Kadmin session, Principal old) {
149	this(old);
150	dummy = false;
151	Kadmin = session;
152    }
153
154    public void setDefaults(Defaults defaults) {
155        flags = new Flags(defaults.getFlags().getBits());
156        if (!defaults.getServerSide()) {
157            MaxLife  = defaults.getMaxTicketLife();
158            MaxRenew = defaults.getMaxTicketRenewableLife();
159        }
160        PrExpireTime = defaults.getAccountExpiryDate();
161    }
162
163    /**
164     * Copy relevant fields from old principal, overriding as necessary
165     */
166    public static void copyPrincipal(Principal old, Principal curr) {
167	curr.PrName = new String("");	    /* override */
168	curr.PrPasswd = new String("");	    /* override */
169	curr.PrExpireTime = new Date(old.PrExpireTime.getTime());
170	curr.Policy = new String(old.Policy);
171	curr.EncTypes = new String(old.EncTypes);
172	curr.LastPwChange = new Date(0);    /* override: never */
173	if (old.PwExpireTime == null)
174	    curr.PwExpireTime = null;
175	else
176	    curr.PwExpireTime = new Date(old.PwExpireTime.getTime());
177	curr.MaxLife = new Integer(old.MaxLife.intValue());
178	curr.MaxRenew = new Integer(old.MaxRenew.intValue());
179	curr.ModTime = new Date();	    /* override: now */
180	curr.ModName = System.getProperty("user.name");	    /* override */
181	curr.LastSuccess = new Date(0);	    /* override: never */
182	curr.LastFailure = new Date(0);	    /* override: never */
183	curr.NumFailures = new Integer(0);  /* override: none */
184	curr.Comments = new String(old.Comments);
185	curr.Kvno = new Integer(old.Kvno.intValue());
186	curr.Mkvno = new Integer(old.Mkvno.intValue());
187	curr.flags = new Flags(old.flags.getBits());
188    }
189
190    public boolean loadPrincipal(String name) {
191	if (dummy)
192		return true;
193	boolean b = Kadmin.loadPrincipal(name, this);
194	// System.out.println(this.toString());
195	return b;
196    }
197
198    public boolean savePrincipal() {
199	// System.out.println(this.toString());
200	if (dummy)
201		return true;
202	if (MaxLife == null)
203	  MaxLife = INFINITE_LIFE;
204	if (MaxRenew == null)
205	  MaxRenew = INFINITE_LIFE;
206	if (this.isNew)
207	    return Kadmin.createPrincipal(this);
208	else
209	    return Kadmin.savePrincipal(this);
210    }
211
212
213    public boolean setName(String name) {
214	// xxx: see where this gets called from to determine if a new Principal
215	// just added can have a duplicate name or whether that would have been
216	// screened out earlier.
217
218	PrName = name;
219	return true;
220    }
221
222    public boolean setComments(String comments) {
223	  // xxx: check to see if all characters are in the allowable list of
224	  // characters. The list needs to be I18N. No length restrictions on
225	  // Java side but what about the c side?
226        Comments = comments;
227        newComments = true;
228        return true;
229    }
230
231    public boolean setPolicy(String pol) {
232	  // xxx: is this a valid policy name? Should we assume that error is
233	  // already trapped before this point?
234	Policy = pol;
235	return true;
236    }
237
238    public boolean setPassword(String pw) {
239	  // xxx: check to see if the passwd follows the rules laid down by
240	  // the policy
241	PrPasswd = pw;
242	return true;
243    }
244
245    public boolean setEncType(String enctype) {
246	EncTypes = enctype;
247	// Don't have to check enc type list provided given that list was
248	// populated from the checkbox list
249	return true;
250    }
251
252    /**
253     * @param exp Contains a date formatted by the default locale,
254     * representing the expiry time for the principal's expiration.
255     */
256    public boolean setExpiry(String exp) {
257        exp = exp.trim();
258        if (exp.equalsIgnoreCase(neverString))
259           PrExpireTime = new Date(0);
260        else {
261            try {
262   	        PrExpireTime = df.parse(exp);
263            } catch (ParseException e) {
264	        return false;
265            } catch (NullPointerException e) {
266	        // gets thrown when parse string begins with text
267	        // probable JDK bug
268	        return false;
269            } catch (StringIndexOutOfBoundsException e) {
270	        // gets thrown when parse string contains only one number
271	        // probable JDK bug
272	        return false;
273            }
274        }
275        return true;
276    }
277
278    /**
279     * @param exp Contains a date formatted by the default locale,
280     * representing the expiry time for the password expiration.
281     */
282    public boolean setPwExpiry(String exp) {
283        exp = exp.trim();
284        if (exp.equals(""))
285            PwExpireTime = null;
286        else if (exp.equalsIgnoreCase(neverString))
287            PwExpireTime = new Date(0);
288        else {
289            try {
290    	        PwExpireTime = df.parse(exp);
291            } catch (ParseException e) {
292	        return false;
293            } catch (NullPointerException e) {
294	        // gets thrown when parse string begins with text
295	        // probable JDK bug
296	        return false;
297            }  catch (StringIndexOutOfBoundsException e) {
298	        // gets thrown when parse string contains only one number
299	        // probable JDK bug
300	        return false;
301            }
302        }
303        return true;
304    }
305
306    public String getModTime() {
307        if (ModTime.getTime() == 0)
308            return neverString;
309        else
310            return df.format(ModTime);
311    }
312
313    public String getEncType() {
314            return EncTypes;
315    }
316
317    public String getExpiry() {
318        if (PrExpireTime.getTime() == 0)
319            return neverString;
320        else
321            return df.format(PrExpireTime);
322    }
323
324    public String getLastSuccess() {
325        if (LastSuccess.getTime() == 0)
326            return neverString;
327        else
328            return df.format(LastSuccess);
329    }
330
331    public String getLastFailure() {
332        if (LastFailure.getTime() == 0)
333            return neverString;
334        else
335            return df.format(LastFailure);
336    }
337
338    public String getLastPwChange() {
339        if (LastPwChange.getTime() == 0)
340            return neverString;
341        else
342            return df.format(LastPwChange);
343    }
344
345    public String getPwExpireTime() {
346        if (PwExpireTime == null)
347            return new String("");
348        else if (PwExpireTime.getTime() == 0)
349            return neverString;
350        else
351            return df.format(PwExpireTime);
352    }
353
354    public String getMaxLife() {
355        if (MaxLife != null)
356            return nf.format(MaxLife.longValue());
357        else
358            return "";
359    }
360
361    public String getMaxRenew() {
362        if (MaxRenew != null)
363            return nf.format(MaxRenew.longValue());
364        else
365            return "";
366    }
367
368    /**
369     * @param vers Contains a number representing the key version.
370     */
371    public boolean setKvno(String vers) {
372	try {
373	    Kvno = new Integer(nf.parse(vers.trim()).intValue());
374	}catch (ParseException e) {
375	    return false;
376	}
377	return true;
378    }
379
380    /**
381     * @param val Contains a number representing the maximum lifetime, in
382     * seconds, of a ticket for this principal.
383     */
384    public boolean setMaxlife(String val) {
385	try {
386	    String noSpace = val.trim();
387	    if (noSpace.length() == 0)
388	        return true;
389	    MaxLife = new Integer(nf.parse(noSpace).intValue());
390	}catch (ParseException e) {
391	    return false;
392	}
393	return true;
394    }
395
396    /**
397     * @param val Contains a number representing the maximum renewable lifetime,
398     * in seconds, of a ticket for this principal.
399     */
400    public boolean setMaxrenew(String val) {
401	try {
402	    String noSpace = val.trim();
403	    if (noSpace.length() == 0)
404	        return true;
405	    MaxRenew = new Integer(nf.parse(noSpace).intValue());
406	}catch (ParseException e) {
407	    return false;
408	}
409	return true;
410    }
411
412    /**
413     * Toggles a particular flag.
414     * @param mask one of the statically defined masks indicating which flag to
415     * toggle.
416     */
417    public boolean setFlag(int mask) {
418        flags.toggleFlags(mask);
419        return true;
420    }
421
422    /**
423     * Obtain a string representation of this principal.
424     * @return a String containing the following information about this
425     * principal:<br>
426     * <ul>
427     * <li>principal name
428     *<li>policy being applied
429     *<li>expiry date
430     *<li>comments
431     *<li>key version number
432     *<li>password expire time
433     *<li>maximum lifetime
434     *<li>maximum renewable lifetime
435     * <li> flags
436     *</ul>
437     */
438    public String toString() {
439
440        StringBuffer sb = new StringBuffer();
441
442        sb.append(getString("Principal Name:") + "  " + PrName).append('\n');
443        sb.append(getString("Account Expires:") + "  "
444              + getExpiry()).append('\n');
445        sb.append(getString("Policy:") + "  " + Policy).append('\n');
446        sb.append(getString("Enc Types:") + "  " + EncTypes).append('\n');
447        sb.append(getString("Comments:") + "  " + Comments).append('\n');
448        sb.append(getString("Key Version:") + "	" + Kvno).append('\t');
449        sb.append(getString("Password Expires:") + "  "
450              + getPwExpireTime()).append('\n');
451        sb.append(getString("Maximum Lifetime (seconds):")
452	      + "	 " + getMaxLife()).append('\t');
453        sb.append(getString("Maximum Renewal (seconds):")
454	      + "	 " + getMaxRenew()).append('\n');
455        sb.append(getString("Flags:")).append('\n').append(flags.toString());
456
457        return sb.toString();
458    }
459
460    /**
461     * Call rb.getString(), but catch exception and return English
462     * key so that small spelling errors don't cripple the GUI
463     *
464     */
465    private static final String getString(String key) {
466        try {
467    	    String res = rb.getString(key);
468	    return res;
469        } catch (MissingResourceException e) {
470	    System.out.println("Missing resource "+key+", using English.");
471	    return key;
472        }
473    }
474
475    static {
476        rb = ResourceBundle.getBundle("GuiResource" /* NOI18N */);
477        df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
478                                            DateFormat.MEDIUM);
479        nf = NumberFormat.getInstance();
480        neverString = getString("Never");
481    }
482
483}
484