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