d3ef4e5b2fa9e400963109f756ad6fe534628447
[ircu2.10.12-pk.git] / ircd / umkpasswd.c
1 /*
2  * IRC - Internet Relay Chat, ircd/umkpasswd.c
3  * Copyright (C) 2002 hikari
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 1, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id$
20 */
21 #include "config.h"
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 /* #include <assert.h> -- Now using assert in ircd_log.h */
30
31 /* ircu headers */
32 #include "ircd_alloc.h"
33 #include "ircd_log.h" /* for ircd's assert.h */
34 #include "ircd_string.h"
35 #include "umkpasswd.h"
36 #include "s_debug.h"
37 #include "ircd_md5.h"
38
39 /* crypto mech headers */
40 #include "ircd_crypt.h"
41 #include "ircd_crypt_smd5.h"
42 #include "ircd_crypt_native.h"
43 #include "ircd_crypt_plain.h"
44
45 /* bleah, evil globals */
46 umkpasswd_conf_t* umkpasswd_conf;
47 crypt_mechs_t* crypt_mechs_root;
48 int log_inassert = 0;
49 time_t CurrentTime;
50
51 void sendto_opmask_butone(struct Client *one, unsigned int mask,
52                           const char *pattern, ...)
53 {
54   /* only needed with memdebug, which also calls Debug() */
55 }
56
57 void copyright(void)
58 {
59   fprintf(stderr, "umkpasswd - Copyright (c) 2002 hikari\n");
60 return;
61 }
62
63 void show_help(void)
64 {
65 #ifdef DEBUGMODE
66  char *debughelp = "[-d <level>] ";
67 #else
68  char *debughelp = "";
69 #endif
70
71  copyright();
72  /*fprintf(stderr, "umkpasswd [-l] [[[-a]||[-u]] <username>] [-y <class>] %s[-c <file>] -m <mech> [password]\n\n", debughelp);*/
73  fprintf(stderr, "umkpasswd [-l] %s-m <mech> [password]\n\n", debughelp);
74  fprintf(stderr, "  -l            List mechanisms available.\n");
75 #if 0
76  fprintf(stderr, "  -a <user>     Add user to conf file.\n");
77  fprintf(stderr, "  -u <user>     Update user's password field.\n");
78  fprintf(stderr, "  -y <class>    Class to place oper in.\n");
79 #endif
80  fprintf(stderr, "  -m <mech>     Mechanism to use [MANDATORY].\n");
81 #ifdef DEBUGMODE
82  fprintf(stderr, "  -d <level>    Debug level to run at.\n");
83 #endif
84 /*
85  fprintf(stderr, "  -c <file>     Conf file to use, default is DPATH/CPATH.\n\n");
86 */
87 return;
88 }
89
90 /* our implementation of debug() */
91 void debug(int level, const char *form, ...)
92 {
93 va_list vl;
94 int err = errno;
95
96   if (level <= (umkpasswd_conf->debuglevel))
97   {
98     va_start(vl, form);
99     vfprintf(stderr, form, vl);
100     fprintf(stderr, "\n");
101     va_end(vl);
102   }
103   errno = err;
104 }
105
106 /* quick implementation of log_write() for assert() call */
107 void log_write(enum LogSys subsys, enum LogLevel severity,
108                unsigned int flags, const char *fmt, ...)
109 {
110   va_list vl;
111   va_start(vl, fmt);
112   vfprintf(stderr, fmt, vl);
113   fprintf(stderr, "\n");
114   va_end(vl);
115 }
116
117 /* quick and dirty salt generator */
118 char *make_salt(const char *salts)
119 {
120 char *tmp = NULL;
121 long int n = 0;
122
123  /* try and get around them running this time after time in quick succession */
124  sleep(1);
125  srandom((unsigned int)time(NULL));
126
127  if((tmp = calloc(3, sizeof(char))) != NULL)
128  {
129   /* can't optimize this much more than just doing it twice */
130   n = ((float)(strlen(salts))*random()/(RAND_MAX+1.0));
131   memcpy(tmp, (salts+n), 1);
132   sleep(2);
133   n = ((float)(strlen(salts))*random()/(RAND_MAX+1.0));
134   memcpy((tmp+1), (salts+n), 1);
135
136   Debug((DEBUG_DEBUG, "salts = %s", salts));
137   Debug((DEBUG_DEBUG, "strlen(salts) = %d", strlen(salts)));
138  }
139
140 return tmp;
141 }
142
143 /* our implementation of ircd_crypt_register_mech() */
144 int ircd_crypt_register_mech(crypt_mech_t* mechanism)
145 {
146 crypt_mechs_t* crypt_mech;
147
148  Debug((DEBUG_INFO, "ircd_crypt_register_mech: registering mechanism: %s", mechanism->shortname));
149
150  /* try to allocate some memory for the new mechanism */
151  if ((crypt_mech = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t))) == NULL)
152  {
153   /* aww poot, we couldn't get any memory, scream a little then back out */
154   Debug((DEBUG_MALLOC, "ircd_crypt_register_mech: could not allocate memory for %s", mechanism->shortname));
155   return -1;
156  }
157
158  /* ok, we have memory, initialise it */
159  memset(crypt_mech, 0, sizeof(crypt_mechs_t));
160
161  /* assign the data */
162  crypt_mech->mech = mechanism;
163  crypt_mech->next = crypt_mech->prev = NULL;
164
165  /* first of all, is there anything there already? */
166  if(crypt_mechs_root->next == NULL)
167  {
168   /* nope, just add ourself */
169   crypt_mechs_root->next = crypt_mechs_root->prev = crypt_mech;
170  } else {
171   /* nice and simple, put ourself at the end */
172   crypt_mech->prev = crypt_mechs_root->prev;
173   crypt_mech->next = NULL;
174   crypt_mechs_root->prev = crypt_mech->prev->next = crypt_mech;
175  }
176
177  /* we're done */
178  Debug((DEBUG_INFO, "ircd_crypt_register_mech: registered mechanism: %s, crypt_function is at 0x%X.", crypt_mech->mech->shortname, &crypt_mech->mech->crypt_function));
179  Debug((DEBUG_INFO, "ircd_crypt_register_mech: %s: %s", crypt_mech->mech->shortname, crypt_mech->mech->description));
180
181 return 0;
182 }
183
184 char *basename_into(char *tmp, char *target)
185 {
186   unsigned int len, ii;
187
188   len = strlen(tmp);
189   for (ii = len; ii > 0; )
190     if (tmp[--ii] == '/')
191       break;
192   if (ii < len - 1)
193     return tmp + ii + (tmp[ii] == '/');
194   else if (tmp[ii] != '/')
195     return tmp;
196   else if (ii == 0)
197     return tmp;
198   else
199   {
200     while (ii > 0)
201       if (tmp[--ii] == '/')
202          break;
203     if (tmp[ii] == '/')
204         ii++;
205     for (len = 0; tmp[ii] != '/'; )
206       target[len++] = tmp[ii++];
207     target[len] = '\0';
208     return target;
209   }
210 }
211
212 void sum(char* tmp)
213 {
214 FILE* file;
215 MD5_CTX context;
216 int len;
217 unsigned char buffer[1024], digest[16];
218
219  if (NULL == (file = fopen(tmp, "r")))
220   exit(0);
221  MD5Init(&context);
222  while ((len = fread (buffer, 1, 1024, file)))
223   MD5Update(&context, buffer, len);
224  MD5Final(digest, &context);
225  fclose(file);
226
227  printf("%s: ", basename_into(tmp, (char*)buffer));
228  for (len = 0; len < 16; len++)
229   printf ("%02x", digest[len]);
230  printf("\n");
231  exit(0);
232 }
233
234 /* dump the loaded mechs list */
235 void show_mechs(void)
236 {
237 crypt_mechs_t* mechs;
238
239  copyright();
240  printf("\nAvailable mechanisms:\n");
241
242  if(crypt_mechs_root == NULL)
243   return;
244
245  mechs = crypt_mechs_root->next;
246
247  for(;;)
248  {
249   if(mechs == NULL)
250    return;
251
252   printf(" %s\t\t%s\n", mechs->mech->mechname, mechs->mech->description);
253
254   mechs = mechs->next;
255  }
256 }
257
258 /* load in the mech "modules" */
259 void load_mechs(void)
260 {
261  /* we need these loaded by hand for now */
262
263  ircd_register_crypt_native();
264  ircd_register_crypt_smd5();
265  ircd_register_crypt_plain(); /* yes I know it's slightly pointless */
266
267 return;
268 }
269
270 crypt_mechs_t* hunt_mech(const char* mechname)
271 {
272 crypt_mechs_t* mech;
273
274  assert(NULL != mechname);
275
276  if(crypt_mechs_root == NULL)
277   return NULL;
278
279  mech = crypt_mechs_root->next;
280
281  for(;;)
282  {
283   if(mech == NULL)
284    return NULL;
285
286   if(0 == (ircd_strcmp(mech->mech->mechname, mechname)))
287    return mech;
288
289   mech = mech->next;
290  }
291 }
292
293 char* crypt_pass(const char* pw, const char* mech)
294 {
295 crypt_mechs_t* crypt_mech;
296 char* salt, *untagged, *tagged;
297
298  assert(NULL != pw);
299  assert(NULL != mech);
300
301  Debug((DEBUG_DEBUG, "pw = %s\n", pw));
302  Debug((DEBUG_DEBUG, "mech = %s\n", mech));
303
304  if (NULL == (crypt_mech = hunt_mech(mech)))
305  {
306   printf("Unable to find mechanism %s\n", mech);
307   return NULL;
308  }
309
310  salt = make_salt(default_salts);
311
312  untagged = (char *)CryptFunc(crypt_mech->mech)(pw, salt);
313  tagged = (char *)MyMalloc(strlen(untagged)+CryptTokSize(crypt_mech->mech)+1);
314  memset(tagged, 0, strlen(untagged)+CryptTokSize(crypt_mech->mech)+1);
315  strncpy(tagged, CryptTok(crypt_mech->mech), CryptTokSize(crypt_mech->mech));
316  strncpy(tagged+CryptTokSize(crypt_mech->mech), untagged, strlen(untagged));
317
318 return tagged;
319 }
320
321 char* parse_arguments(int argc, char **argv)
322 {
323 int len = 0, c = 0;
324 const char* options = "a:d:lm:u:y:5:";
325
326  umkpasswd_conf = (umkpasswd_conf_t*)MyMalloc(sizeof(umkpasswd_conf_t));
327
328  umkpasswd_conf->flags = 0;
329  umkpasswd_conf->debuglevel = 0;
330  umkpasswd_conf->operclass = 0;
331  umkpasswd_conf->user = NULL;
332  umkpasswd_conf->mech = NULL;
333
334
335  len = strlen(DPATH) + strlen(CPATH) + 2;
336  umkpasswd_conf->conf = (char *)MyMalloc(len*sizeof(char));
337  memset(umkpasswd_conf->conf, 0, len*sizeof(char));
338  ircd_strncpy(umkpasswd_conf->conf, DPATH, strlen(DPATH));
339  *((umkpasswd_conf->conf) + strlen(DPATH)) = '/';
340  ircd_strncpy((umkpasswd_conf->conf) + strlen(DPATH) + 1, CPATH, strlen(CPATH));
341
342  len = 0;
343
344  while ((EOF != (c = getopt(argc, argv, options))) && !len)
345  {
346   switch (c)
347   {
348    case '5':
349     sum(optarg);
350    break;
351
352    case 'y':
353     umkpasswd_conf->operclass = atoi(optarg);
354     if (umkpasswd_conf->operclass < 0)
355      umkpasswd_conf->operclass = 0;
356    break;
357
358    case 'u':
359     if(umkpasswd_conf->flags & ACT_ADDOPER)
360     {
361      fprintf(stderr, "-a and -u are mutually exclusive.  Use either or neither.\n");
362      abort(); /* b0rk b0rk b0rk */
363     }
364
365     umkpasswd_conf->flags |= ACT_UPDOPER;
366     umkpasswd_conf->user = optarg;
367    break;
368
369    case 'm':
370     umkpasswd_conf->mech = optarg;
371    break;
372
373    case 'l':
374     load_mechs();
375     show_mechs();
376     exit(0);
377    break;
378
379    case 'd':
380     umkpasswd_conf->debuglevel = atoi(optarg);
381     if (umkpasswd_conf->debuglevel < 0)
382      umkpasswd_conf->debuglevel = 0;
383    break;
384
385    case 'c':
386     umkpasswd_conf->conf = optarg;
387    break;
388
389    case 'a':
390     if(umkpasswd_conf->flags & ACT_UPDOPER) 
391     {
392      fprintf(stderr, "-a and -u are mutually exclusive.  Use either or neither.\n");
393      abort(); /* b0rk b0rk b0rk */
394     }
395
396     umkpasswd_conf->flags |= ACT_ADDOPER;
397     umkpasswd_conf->user = optarg;
398    break;
399
400    default:
401     /* unknown option - spit out syntax and b0rk */
402     show_help();
403     exit(1);
404    break;
405   }
406  }
407
408  Debug((DEBUG_DEBUG, "flags = %d", umkpasswd_conf->flags));
409  Debug((DEBUG_DEBUG, "operclass = %d", umkpasswd_conf->operclass));
410  Debug((DEBUG_DEBUG, "debug = %d", umkpasswd_conf->debuglevel));
411
412  if (NULL != umkpasswd_conf->mech)
413   Debug((DEBUG_DEBUG, "mech = %s", umkpasswd_conf->mech));
414  else
415   Debug((DEBUG_DEBUG, "mech is unset"));
416
417  if (NULL != umkpasswd_conf->conf)
418   Debug((DEBUG_DEBUG, "conf = %s", umkpasswd_conf->conf));
419  else
420   Debug((DEBUG_DEBUG, "conf is unset"));
421
422  if (NULL != umkpasswd_conf->user)
423   Debug((DEBUG_DEBUG, "user = %s", umkpasswd_conf->user));
424  else
425   Debug((DEBUG_DEBUG, "user is unset"));
426
427 /* anything left over should be password */
428 return argv[optind];
429 }
430
431 int main(int argc, char **argv)
432 {
433 char* pw, *crypted_pw;
434
435  crypt_mechs_root = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t));
436  crypt_mechs_root->mech = NULL;
437  crypt_mechs_root->next = crypt_mechs_root->prev = NULL;
438
439  if (argc < 2)
440  {
441   show_help();
442   exit(0);
443  }
444
445  pw = parse_arguments(argc, argv);
446  load_mechs();
447
448  if (NULL == umkpasswd_conf->mech)
449  {
450   fprintf(stderr, "No mechanism specified.\n");
451   abort();
452  }
453
454  if (NULL == pw)
455  {
456   pw = getpass("Password: ");
457  }
458  crypted_pw = crypt_pass(pw, umkpasswd_conf->mech);
459
460  printf("Crypted Pass: %s\n", crypted_pw);
461  memset(pw, 0, strlen(pw));
462
463 return 0;
464 }