2aafb6cedeb09b78e1e19a6ac0abe410ec4e665c
[platform/upstream/krb5.git] / src / clients / kpasswd / ksetpwd.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include <k5-platform.h>
3 #include <krb5.h>
4 #include <unistd.h>
5 #include <time.h>
6
7 #define TKTTIMELEFT     60*10   /* ten minutes */
8
9 static int verify_creds()
10 {
11     krb5_context    kcontext;
12     krb5_ccache             ccache;
13     krb5_error_code kres;
14
15     kres = krb5_init_context(&kcontext);
16     if( kres == 0 )
17     {
18         kres = krb5_cc_default( kcontext, &ccache );
19         if( kres == 0 )
20         {
21             krb5_principal  user_princ;
22
23             kres = krb5_cc_get_principal( kcontext, ccache, &user_princ );
24             if( kres == 0 )
25                 krb5_free_principal( kcontext, user_princ );
26             krb5_cc_close( kcontext, ccache );
27         }
28         krb5_free_context(kcontext);
29     }
30     return kres;
31 }
32
33 static void get_init_creds_opt_init( krb5_get_init_creds_opt *outOptions )
34 {
35     krb5_preauthtype    preauth[] = { KRB5_PADATA_ENC_TIMESTAMP };
36     krb5_enctype        etypes[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_CRC};
37     krb5_get_init_creds_opt_set_address_list(outOptions, NULL);
38     krb5_get_init_creds_opt_set_etype_list( outOptions, etypes, sizeof(etypes)/sizeof(krb5_enctype) );
39     krb5_get_init_creds_opt_set_preauth_list(outOptions, preauth, sizeof(preauth)/sizeof(krb5_preauthtype) );
40 }
41
42 typedef void * kbrccache_t;
43 #define CCACHE_PREFIX_DEFAULT "MEMORY:C_"
44
45 static kbrccache_t userinitcontext(
46     const char * user, const char * domain, const char * passwd, const char * cachename, int initialize,
47     int * outError )
48 {
49     krb5_context    kcontext = 0;
50     krb5_ccache             kcache = 0;
51     krb5_creds              kcreds;
52     krb5_principal  kme = 0;
53     krb5_error_code kres;
54     char *                  pPass = strdup( passwd );
55     char *                  pName = NULL;
56     char *                  pCacheName = NULL;
57     int                             numCreds = 0;
58
59     memset( &kcreds, 0, sizeof(kcreds) );
60     kres = krb5_init_context( &kcontext );
61     if( kres )
62         goto return_error;
63     if( domain )
64         kres = krb5_build_principal( kcontext, &kme, strlen(domain), domain, user, (char *) 0 );
65     else
66         kres = krb5_parse_name( kcontext, user, &kme );
67     if( kres )
68         goto fail;
69     krb5_unparse_name( kcontext, kme, &pName );
70     if( cachename )
71     {
72         if (asprintf(&pCacheName, "%s%s", cachename, pName) < 0)
73         {
74             kres = KRB5_CC_NOMEM;
75             goto fail;
76         }
77         kres = krb5_cc_resolve( kcontext, pCacheName, &kcache );
78         if( kres )
79         {
80             kres = krb5_cc_resolve( kcontext, CCACHE_PREFIX_DEFAULT, &kcache );
81             if( kres == 0 )
82                 pCacheName = strdup(CCACHE_PREFIX_DEFAULT);
83         }
84     }
85     else
86     {
87         kres = krb5_cc_default( kcontext, &kcache );
88         pCacheName = strdup( krb5_cc_get_name( kcontext, kcache ) );
89     }
90     if( kres )
91     {
92         krb5_free_context(kcontext);
93         goto return_error;
94     }
95     if( initialize )
96         krb5_cc_initialize( kcontext, kcache, kme );
97     if( kres == 0 && user && passwd )
98     {
99         long timeneeded = time(0L) +TKTTIMELEFT;
100         int have_credentials = 0;
101         krb5_cc_cursor cc_curs = NULL;
102         numCreds = 0;
103         if( (kres=krb5_cc_start_seq_get(kcontext, kcache, &cc_curs)) >= 0 )
104         {
105             while( (kres=krb5_cc_next_cred(kcontext, kcache, &cc_curs, &kcreds))== 0)
106             {
107                 numCreds++;
108                 if( krb5_principal_compare( kcontext, kme, kcreds.client ) )
109                 {
110                     if( kcreds.ticket_flags & TKT_FLG_INITIAL && kcreds.times.endtime>timeneeded )
111                         have_credentials = 1;
112                 }
113                 krb5_free_cred_contents( kcontext, &kcreds );
114                 if( have_credentials )
115                     break;
116             }
117             krb5_cc_end_seq_get( kcontext, kcache, &cc_curs );
118         }
119         else
120         {
121             const char * errmsg = error_message(kres);
122             fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg );
123         }
124         if( kres != 0 || have_credentials == 0 )
125         {
126             krb5_get_init_creds_opt *options = NULL;
127             kres = krb5_get_init_creds_opt_alloc(kcontext, &options);
128             if ( kres == 0 )
129             {
130                 get_init_creds_opt_init(options);
131 /*
132 ** no valid credentials - get new ones
133 */
134                 kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass,
135                                                      NULL /*prompter*/,
136                                                      NULL /*data*/,
137                                                      0 /*starttime*/,
138                                                      0 /*in_tkt_service*/,
139                                                      options /*options*/ );
140             }
141             if( kres == 0 )
142             {
143                 if( numCreds <= 0 )
144                     kres = krb5_cc_initialize( kcontext, kcache, kme );
145                 if( kres == 0 )
146                     kres = krb5_cc_store_cred( kcontext, kcache, &kcreds );
147                 if( kres == 0 )
148                     have_credentials = 1;
149             }
150             krb5_get_init_creds_opt_free(kcontext, options);
151         }
152 #ifdef NOTUSED
153         if( have_credentials )
154         {
155             int mstat;
156             kres = gss_krb5_ccache_name( &mstat, pCacheName, NULL );
157             if( getenv( ENV_DEBUG_LDAPKERB ) )
158                 fprintf( stderr, "gss credentials cache set to %s(%d)\n", pCacheName, kres );
159         }
160 #endif
161         krb5_cc_close( kcontext, kcache );
162     }
163 fail:
164     if( kres )
165     {
166         const char * errmsg = error_message(kres);
167         fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg );
168     }
169     krb5_free_principal( kcontext, kme );
170     krb5_free_cred_contents( kcontext, &kcreds );
171     if( pName )
172         free( pName );
173     free(pPass);
174     krb5_free_context(kcontext);
175
176 return_error:
177     if( kres )
178     {
179         if( pCacheName )
180         {
181             free(pCacheName);
182             pCacheName = NULL;
183         }
184     }
185     if( outError )
186         *outError = kres;
187     return pCacheName;
188 }
189
190 static int init_creds()
191 {
192     char user[512];
193     char * password = NULL;
194     int result;
195
196     user[0] = 0;
197     result = -1;
198
199     for(;;)
200     {
201         while( user[0] == 0 )
202         {
203             int userlen;
204             printf( "Username: ");
205             fflush(stdout);
206             if( fgets( user, sizeof(user), stdin ) == NULL )
207                 return -1;
208             userlen = strlen( user);
209             if( userlen < 2 )
210                 continue;
211             user[userlen-1] = 0;    /* get rid of the newline */
212             break;
213         }
214         {
215             kbrccache_t usercontext;
216             password = getpass( "Password: ");
217             if( ! password )
218                 return -1;
219             result = 0;
220             usercontext = userinitcontext( user, NULL, password, NULL, 1, &result );
221             if( usercontext )
222                 break;
223         }
224     }
225     return result;
226 }
227
228 int main( int argc, char ** argv )
229 {
230     char * new_password;
231     char * new_password2;
232     krb5_context    kcontext;
233     krb5_error_code kerr;
234     krb5_principal  target_principal;
235
236
237     if( argc < 2 )
238     {
239         fprintf( stderr, "Usage: setpass user@REALM\n");
240         exit(1);
241     }
242
243 /*
244 ** verify credentials -
245 */
246     if( verify_creds() )
247         init_creds();
248     if( verify_creds() )
249     {
250         fprintf( stderr, "No user credentials available\n");
251         exit(1);
252     }
253 /*
254 ** check the principal name -
255 */
256     krb5_init_context(&kcontext);
257     kerr = krb5_parse_name( kcontext, argv[1], &target_principal );
258
259     {
260         char * pname = NULL;
261         kerr = krb5_unparse_name( kcontext, target_principal, &pname );
262         printf( "Changing password for %s:\n", pname);
263         fflush( stdout );
264         free( pname );
265     }
266 /*
267 ** get the new password -
268 */
269     for (;;)
270     {
271         new_password = getpass("Enter new password: ");
272         new_password2 = getpass("Verify new password: ");
273         if( strcmp( new_password, new_password2 ) == 0)
274             break;
275         printf("Passwords do not match\n");
276         free( new_password );
277         free( new_password2 );
278     }
279 /*
280 ** change the password -
281 */
282     {
283         int pw_result;
284         krb5_ccache ccache;
285         krb5_data       pw_res_string, res_string;
286
287         kerr = krb5_cc_default( kcontext, &ccache );
288         if( kerr == 0 )
289         {
290             kerr = krb5_set_password_using_ccache(kcontext, ccache, new_password, target_principal,
291                                                   &pw_result, &pw_res_string, &res_string );
292             if( kerr )
293                 fprintf( stderr, "Failed: %s\n", error_message(kerr) );
294             else
295             {
296                 if( pw_result )
297                 {
298                     fprintf( stderr, "Failed(%d)", pw_result );
299                     if( pw_res_string.length > 0 )
300                         fprintf( stderr, ": %s", pw_res_string.data);
301                     if( res_string.length > 0 )
302                         fprintf( stderr, " %s", res_string.data);
303                     fprintf( stderr, "\n");
304                 }
305             }
306         }
307     }
308     return(0);
309 }