1 /* users.c version 0.333 */ 2 /* all versions previous to 0.333 are completely public domain */ 3 /* all contributed code falls under the same BSD style license as */ 4 /* noted below unless the contributing author places a copyright */ 5 /* notice in their file/s. */ 6 7 8 /* 9 * * Copyright (c) 2001 David T. Stiles 10 * * All rights reserved. 11 * * 12 * * Redistribution and use in source and binary forms, with or without 13 * * modification, are permitted provided that the following conditions 14 * * are met: 15 * * 1. Redistributions of source code must retain the above copyright 16 * * notice, this list of conditions and the following disclaimer. 17 * * 2. Redistributions in binary form must reproduce the above copyright 18 * * notice, this list of conditions and the following disclaimer in the 19 * * documentation and/or other materials provided with the distribution. 20 * * 3. All advertising materials mentioning features or use of this software 21 * * must display the following acknowledgement: 22 * * This product includes software developed by David T. Stiles 23 * * 4. The name David T. Stiles may not be used to endorse or promote 24 * * products derived from this software without specific prior written 25 * * permission. 26 * * 27 * * THIS SOFTWARE IS PROVIDED BY DAVID T. STILES `AS IS'' AND ANY 28 * * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * * ARE DISCLAIMED. IN NO EVENT SHALL DAVID T. STILES BE LIABLE 31 * * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * * SUCH DAMAGE. 38 * */ 39 40 /* this code would not be possible without the patience and intelligence */ 41 /* provided by many of the people from #c/efnet. I thank all of you sincerely. */ 42 43 /* user stuff. ugh! 44 * i load in the data file on users into a linked list that is defined in 45 * users.h. *usr is the anchor, *trv is is the pointer i use to travel 46 * through the list. *lag makes it so i do not need a doubly linked list by 47 * providing a pointer to the node previous to the one *trv is pointing at. 48 * i use crypt to generate password hashes. you may need to provide the 49 * flag -lcrypto in the makefile. i have to in slackware but not in openbsd. 50 */ 51 52 #include "users.h" 53 #include "bot.h" 54 55 extern char MSGTO[MAXDATASIZE]; 56 57 static struct user *usr; 58 static struct user *trv; 59 static struct user *lag; 60 static FILE *fp; 61 static long int total_users = 0; 62 63 64 /* call only once during the entire course of the program! or else... */ 65 int loadusers( char *filename ) 66 { 67 fp = fopen( filename, "r" ); 68 if( !fp ) return 1; 69 70 usr = (struct user *)malloc( sizeof( struct user ) ); 71 if( !usr ) return( 1 ); 72 lag = trv = usr; 73 74 while( !feof( fp ) ) { 75 fgets( trv->data, USERINFO, fp ); 76 clean_message( trv->data ); 77 if( !trv->data[0] ) break; 78 ++total_users; 79 lag = trv; 80 trv->next = (struct user *)malloc( sizeof( struct user ) ); 81 trv = trv->next; 82 if(!trv) return( 1 ); 83 } 84 85 free( trv ); 86 lag->next = NULL; 87 88 fclose( fp ); 89 90 return 0; 91 } 92 93 94 95 96 void saveusers( char *filename ) 97 { 98 fp = fopen( filename, "w" ); 99 if( !fp ) return; 100 101 trv = usr; 102 103 while( trv->next ) { fprintf( fp, "%s\n", trv->data ); trv = trv->next; } 104 fprintf( fp, "%s\n", trv->data ); 105 fclose( fp ); 106 107 return; 108 } 109 110 111 112 void rmuser( char *passwd, char *name, char *rmname ) 113 { 114 int x = 0; 115 char sndmsg[MAXDATASIZE]; 116 117 /* validate user before we do what they want */ 118 119 if( valid_login( name, passwd ) ) snprintf( sndmsg, MAXDATASIZE, "privmsg %s :credentials verified.", name ); 120 else { 121 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :access denied.", name ); 122 send_irc_message( sndmsg ); 123 return; 124 } 125 126 if( rmname[0] == '\0' ) return; 127 128 x = valid_user( rmname ); 129 if( !x ) { 130 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :user: %s not found.", name, rmname ); 131 send_irc_message( sndmsg ); 132 return; 133 } 134 135 lag->next = trv->next; 136 free( trv ); 137 --total_users; 138 139 140 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :user: %s removed.", name, rmname ); 141 send_irc_message( sndmsg ); 142 saveusers( "user.list" ); 143 return; 144 } 145 146 147 148 void adduser( char *pass, char *name, char *newupass, char *newuname ) 149 { 150 char sndmsg[MAXDATASIZE]; 151 char salt[MAXDATASIZE]; 152 char *hash; 153 154 /* validate user before we do what they want */ 155 if( valid_login( name, pass ) ) { 156 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :credentials verified.", name ); 157 send_irc_message( sndmsg ); 158 } 159 else { 160 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :access denied.", name ); 161 send_irc_message( sndmsg ); 162 return; 163 } 164 165 if( newupass[0] == '\0' ) { 166 snprintf( sndmsg, MAXDATASIZE, "PRIVMSG %s : new password is invalid", name ); 167 send_irc_message( sndmsg ); 168 return; 169 } 170 if( newuname[0] == '\0' ) { 171 snprintf( sndmsg, MAXDATASIZE, "PRIVMSG %s : new username is invalid", name ); 172 send_irc_message( sndmsg ); 173 return; 174 } 175 176 if( valid_user( newuname ) ) { 177 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :user exists.", name ); 178 send_irc_message( sndmsg ); 179 return; 180 } 181 182 lag->next = (struct user *)malloc( sizeof( struct user ) ); 183 trv = lag->next; 184 trv->next = NULL; 185 186 get_salt( salt ); 187 188 hash = crypt( newupass, salt ); 189 190 snprintf( trv->data, MAXDATASIZE, "%s %s 0", newuname, hash ); 191 192 ++total_users; 193 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :user: %s added.", name, newuname ); 194 send_irc_message( sndmsg ); 195 196 saveusers( "user.list" ); 197 return; 198 } 199 200 201 202 void chpass( char *passwd, char *name, char *newpass ) 203 { 204 int x; 205 char sndmsg[MAXDATASIZE]; 206 char tmpray[MAXDATASIZE]; 207 char salt[MAXDATASIZE]; 208 char *hash; 209 210 /* validate user before we do what they want */ 211 if( !valid_login( name, passwd ) ) { 212 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :access denied.", MSGTO ); 213 send_irc_message( sndmsg ); 214 return; 215 } 216 217 if( newpass[0] == '\0' ) { 218 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :null passwords are not allowed.", MSGTO ); 219 send_irc_message( sndmsg ); 220 return; 221 } 222 223 x = chop( trv->data, tmpray, 0, ' ' ); 224 x = chop( trv->data, tmpray, x, ' ' ); /* these two calls to chop() are to init x. the data is discarded */ 225 strncpy( tmpray, &trv->data[x], MAXDATASIZE ); 226 227 get_salt( salt ); 228 229 hash = crypt( newpass, salt ); 230 snprintf( trv->data, MAXDATASIZE, "%s %s %s", name, hash, tmpray ); 231 232 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :password changed.", MSGTO ); 233 send_irc_message( sndmsg ); 234 235 saveusers( "user.list" ); 236 return; 237 } 238 239 240 241 void whois( char *name ) 242 { 243 int position = 0; 244 char tmpray[MAXDATASIZE]; 245 246 position = valid_user( name ); 247 if( !position ) { 248 snprintf( tmpray, MAXDATASIZE, "privmsg %s :%s is not known to me.", MSGTO, name ); 249 send_irc_message( tmpray ); 250 return; 251 } 252 253 snprintf( tmpray, MAXDATASIZE, "privmsg %s :I know who %s is.", MSGTO, name ); 254 send_irc_message( tmpray ); 255 256 return; 257 } 258 259 260 261 /* returns a positive value if the user is found. */ 262 263 int valid_user( char *nickname ) 264 { 265 char checklistname[USERINFO]; 266 267 lag = usr; 268 trv = usr->next; 269 270 while( trv ){ 271 chop( trv->data, checklistname, 0, ' ' ); 272 if( strcmp( nickname, checklistname ) ) { 273 lag = trv; 274 trv = trv->next; 275 continue; 276 } 277 return 1; 278 } 279 280 return 0; 281 } 282 283 284 /* returns true/false */ 285 286 int valid_password( char *passwd ) 287 { 288 int x; 289 char checklistpword[MAXDATASIZE]; 290 char salt[MAXDATASIZE]; 291 char *hash; 292 293 x = chop( trv->data, checklistpword, 0, ' ' ); 294 x = chop( trv->data, checklistpword, x, ' ' ); /* this now holds the password in hashed form. */ 295 296 salt[0] = checklistpword[0]; /* the salt is held in the first two characters */ 297 salt[1] = checklistpword[1]; 298 salt[2] = '\0'; /* since this is address space on the stack, i will null terminate it explicitly */ 299 300 hash = crypt( passwd, salt ); 301 302 if( strcmp( hash, checklistpword ) ) return 0; /* passwd hashes don't match */ 303 return 1; 304 } 305 306 307 /*this is basically a wrapper for the two functions that verify users. */ 308 int valid_login( char *name, char *passwd ) 309 { 310 int position = 0; 311 312 if( !valid_user( name ) ) return 0; 313 position = valid_password( passwd ); 314 return position; 315 } 316 317 318 319 /* no comment right now. sorry. */ 320 321 void oppeople( char *chan, char *passwd, char *name, char *nick ) 322 { 323 char sndmsg[MAXDATASIZE]; 324 325 326 if( valid_login( name, passwd ) ){ 327 snprintf( sndmsg, MAXDATASIZE, "mode %s +o %s", chan, nick ); 328 send_irc_message( sndmsg ); 329 return; 330 } 331 332 snprintf( sndmsg, MAXDATASIZE, "privmsg %s :either your username or password is incorrect. channels require a #.", MSGTO ); 333 send_irc_message( sndmsg ); 334 335 return; 336 } 337 338 339 340 void get_salt( char *ray ) 341 { 342 343 long x; 344 345 x = 1 + (rand() % 26); 346 x += 64; 347 *ray = (char)x; 348 349 x = 1 + (rand() % 26); 350 x+= 64; 351 *(ray + 1) = (char)x; 352 *(ray + 2) = '\0'; 353 354 return; 355 } |