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